summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes2
-rw-r--r--.gitignore11
-rw-r--r--COPYING340
-rw-r--r--addons/copyable_captcha.php104
-rw-r--r--addons/funnyquestion.php160
-rw-r--r--addons/index.html1
-rw-r--r--addons/recaptcha.php136
-rw-r--r--admin_bans.php602
-rw-r--r--admin_categories.php266
-rw-r--r--admin_censoring.php168
-rw-r--r--admin_forums.php501
-rw-r--r--admin_groups.php645
-rw-r--r--admin_index.php110
-rw-r--r--admin_loader.php55
-rw-r--r--admin_maintenance.php361
-rw-r--r--admin_options.php884
-rw-r--r--admin_permissions.php191
-rw-r--r--admin_reports.php183
-rw-r--r--admin_statistics.php139
-rw-r--r--admin_users.php1095
-rw-r--r--cache/.htaccess4
-rw-r--r--cache/index.html1
-rw-r--r--common.js38
-rw-r--r--config.php17
-rw-r--r--db_update.php1911
-rw-r--r--delete.php140
-rw-r--r--docker/docker-compose.yml30
-rw-r--r--docker/mariadb/Dockerfile4
-rw-r--r--docker/php/Dockerfile4
-rw-r--r--docker/php/etc/php/conf.d/extensions.ini4
-rwxr-xr-xdocker/restart6
-rwxr-xr-xdocker/start12
-rwxr-xr-xdocker/stop5
-rw-r--r--edit.php293
-rw-r--r--extern.php547
l---------favicon.ico1
-rw-r--r--footer.php165
-rw-r--r--header.php332
-rw-r--r--help.php154
-rw-r--r--img/avatars/index.html1
-rw-r--r--img/index.html1
-rw-r--r--img/smilies/big_smile.pngbin0 -> 373 bytes
-rw-r--r--img/smilies/cool.pngbin0 -> 380 bytes
-rw-r--r--img/smilies/hmm.pngbin0 -> 422 bytes
-rw-r--r--img/smilies/index.html1
-rw-r--r--img/smilies/lol.pngbin0 -> 364 bytes
-rw-r--r--img/smilies/mad.pngbin0 -> 409 bytes
-rw-r--r--img/smilies/neutral.pngbin0 -> 415 bytes
-rw-r--r--img/smilies/roll.pngbin0 -> 386 bytes
-rw-r--r--img/smilies/sad.pngbin0 -> 420 bytes
-rw-r--r--img/smilies/smile.pngbin0 -> 426 bytes
-rw-r--r--img/smilies/tongue.pngbin0 -> 416 bytes
-rw-r--r--img/smilies/wink.pngbin0 -> 428 bytes
-rw-r--r--img/smilies/yikes.pngbin0 -> 406 bytes
-rw-r--r--img/test.pngbin0 -> 2055 bytes
-rw-r--r--include/addons.php84
-rw-r--r--include/cache.php263
-rw-r--r--include/common.php209
-rw-r--r--include/common_admin.php174
-rw-r--r--include/dblayer/common_db.php48
-rw-r--r--include/dblayer/index.html1
-rw-r--r--include/dblayer/mysql.php378
-rw-r--r--include/dblayer/mysql_innodb.php392
-rw-r--r--include/dblayer/mysqli.php385
-rw-r--r--include/dblayer/mysqli_innodb.php398
-rw-r--r--include/dblayer/pgsql.php442
-rw-r--r--include/dblayer/sqlite.php601
-rw-r--r--include/email.php364
-rw-r--r--include/functions.php2227
-rw-r--r--include/index.html1
-rw-r--r--include/parser.php987
-rw-r--r--include/search_idx.php316
-rw-r--r--include/srand.php151
-rw-r--r--include/template/admin.tpl38
-rw-r--r--include/template/help.tpl23
-rw-r--r--include/template/index.html1
-rw-r--r--include/template/main.tpl38
-rw-r--r--include/template/maintenance.tpl23
-rw-r--r--include/template/redirect.tpl25
-rw-r--r--include/user/index.html1
-rw-r--r--include/utf8/index.html1
-rw-r--r--include/utf8/mbstring/core.php144
-rw-r--r--include/utf8/mbstring/index.html1
-rw-r--r--include/utf8/native/core.php422
-rw-r--r--include/utf8/native/index.html1
-rw-r--r--include/utf8/ord.php78
-rw-r--r--include/utf8/str_ireplace.php72
-rw-r--r--include/utf8/str_pad.php59
-rw-r--r--include/utf8/str_split.php33
-rw-r--r--include/utf8/strcasecmp.php27
-rw-r--r--include/utf8/strcspn.php36
-rw-r--r--include/utf8/stristr.php34
-rw-r--r--include/utf8/strrev.php22
-rw-r--r--include/utf8/strspn.php32
-rw-r--r--include/utf8/substr_replace.php27
-rw-r--r--include/utf8/trim.php74
-rw-r--r--include/utf8/ucfirst.php35
-rw-r--r--include/utf8/ucwords.php46
-rw-r--r--include/utf8/utf8.php72
-rw-r--r--include/utf8/utils/ascii.php221
-rw-r--r--include/utf8/utils/bad.php430
-rw-r--r--include/utf8/utils/index.html1
-rw-r--r--include/utf8/utils/patterns.php67
-rw-r--r--include/utf8/utils/position.php171
-rw-r--r--include/utf8/utils/specials.php131
-rw-r--r--include/utf8/utils/unicode.php241
-rw-r--r--include/utf8/utils/validation.php186
-rw-r--r--index.php278
-rw-r--r--lang/English/admin_bans.php69
-rw-r--r--lang/English/admin_categories.php29
-rw-r--r--lang/English/admin_censoring.php21
-rw-r--r--lang/English/admin_common.php44
-rw-r--r--lang/English/admin_forums.php53
-rw-r--r--lang/English/admin_groups.php91
-rw-r--r--lang/English/admin_index.php63
-rw-r--r--lang/English/admin_maintenance.php40
-rw-r--r--lang/English/admin_options.php227
-rw-r--r--lang/English/admin_permissions.php36
-rw-r--r--lang/English/admin_reports.php21
-rw-r--r--lang/English/admin_users.php110
-rw-r--r--lang/English/common.php169
-rw-r--r--lang/English/copyable_captcha.php10
-rw-r--r--lang/English/delete.php16
-rw-r--r--lang/English/forum.php17
-rw-r--r--lang/English/funnyquestion.php8
-rw-r--r--lang/English/help.php66
-rw-r--r--lang/English/index.html1
-rw-r--r--lang/English/index.php20
-rw-r--r--lang/English/install.php100
-rw-r--r--lang/English/login.php28
-rw-r--r--lang/English/mail_templates/activate_email.tpl12
-rw-r--r--lang/English/mail_templates/activate_password.tpl14
-rw-r--r--lang/English/mail_templates/banned_email_change.tpl9
-rw-r--r--lang/English/mail_templates/banned_email_post.tpl9
-rw-r--r--lang/English/mail_templates/banned_email_register.tpl9
-rw-r--r--lang/English/mail_templates/dupe_email_change.tpl9
-rw-r--r--lang/English/mail_templates/dupe_email_register.tpl9
-rw-r--r--lang/English/mail_templates/form_email.tpl13
-rw-r--r--lang/English/mail_templates/index.html1
-rw-r--r--lang/English/mail_templates/new_reply.tpl11
-rw-r--r--lang/English/mail_templates/new_reply_full.tpl18
-rw-r--r--lang/English/mail_templates/new_report.tpl9
-rw-r--r--lang/English/mail_templates/new_topic.tpl11
-rw-r--r--lang/English/mail_templates/new_topic_full.tpl18
-rw-r--r--lang/English/mail_templates/new_user.tpl12
-rw-r--r--lang/English/mail_templates/rename.tpl12
-rw-r--r--lang/English/mail_templates/welcome.tpl12
-rw-r--r--lang/English/misc.php93
-rw-r--r--lang/English/post.php38
-rw-r--r--lang/English/prof_reg.php79
-rw-r--r--lang/English/profile.php143
-rw-r--r--lang/English/recaptcha_addon.php20
-rw-r--r--lang/English/register.php37
-rw-r--r--lang/English/search.php64
-rw-r--r--lang/English/stopwords.txt175
-rw-r--r--lang/English/topic.php33
-rw-r--r--lang/English/update.php76
-rw-r--r--lang/English/userlist.php13
-rw-r--r--lang/German/admin_bans.php69
-rw-r--r--lang/German/admin_categories.php29
-rw-r--r--lang/German/admin_censoring.php21
-rw-r--r--lang/German/admin_common.php44
-rw-r--r--lang/German/admin_forums.php53
-rw-r--r--lang/German/admin_groups.php92
-rw-r--r--lang/German/admin_index.php64
-rw-r--r--lang/German/admin_maintenance.php40
-rw-r--r--lang/German/admin_options.php227
-rw-r--r--lang/German/admin_permissions.php36
-rw-r--r--lang/German/admin_reports.php21
-rw-r--r--lang/German/admin_users.php110
-rw-r--r--lang/German/common.php169
-rw-r--r--lang/German/delete.php16
-rw-r--r--lang/German/forum.php17
-rw-r--r--lang/German/funnyquestion.php8
-rw-r--r--lang/German/help.php66
-rw-r--r--lang/German/index.html1
-rw-r--r--lang/German/index.php20
-rw-r--r--lang/German/install.php105
-rw-r--r--lang/German/login.php28
-rw-r--r--lang/German/mail_templates/activate_email.tpl12
-rw-r--r--lang/German/mail_templates/activate_password.tpl14
-rw-r--r--lang/German/mail_templates/banned_email_change.tpl9
-rw-r--r--lang/German/mail_templates/banned_email_post.tpl9
-rw-r--r--lang/German/mail_templates/banned_email_register.tpl9
-rw-r--r--lang/German/mail_templates/dupe_email_change.tpl9
-rw-r--r--lang/German/mail_templates/dupe_email_register.tpl9
-rw-r--r--lang/German/mail_templates/form_email.tpl13
-rw-r--r--lang/German/mail_templates/index.html1
-rw-r--r--lang/German/mail_templates/new_reply.tpl11
-rw-r--r--lang/German/mail_templates/new_reply_full.tpl18
-rw-r--r--lang/German/mail_templates/new_report.tpl9
-rw-r--r--lang/German/mail_templates/new_topic.tpl11
-rw-r--r--lang/German/mail_templates/new_topic_full.tpl18
-rw-r--r--lang/German/mail_templates/new_user.tpl12
-rw-r--r--lang/German/mail_templates/rename.tpl12
-rw-r--r--lang/German/mail_templates/welcome.tpl12
-rw-r--r--lang/German/misc.php93
-rw-r--r--lang/German/post.php38
-rw-r--r--lang/German/prof_reg.php79
-rw-r--r--lang/German/profile.php143
-rw-r--r--lang/German/register.php37
-rw-r--r--lang/German/search.php63
-rw-r--r--lang/German/stopwords.txt238
-rw-r--r--lang/German/topic.php33
-rw-r--r--lang/German/update.php76
-rw-r--r--lang/German/userlist.php13
-rw-r--r--lang/index.html1
-rw-r--r--login.php335
-rw-r--r--misc.php414
-rw-r--r--moderate.php1020
-rw-r--r--plugins/AP_reCAPTCHA.php123
-rw-r--r--plugins/index.html1
-rw-r--r--post.php781
-rw-r--r--profile.php1882
-rw-r--r--readme.md28
-rw-r--r--register.php448
-rw-r--r--robots.txt3
-rw-r--r--search.php914
-rw-r--r--style/Air.css1651
-rw-r--r--style/Air/base_admin.css177
-rw-r--r--style/Air/img/asterisk.pngbin0 -> 168 bytes
-rw-r--r--style/Air/img/bull.pngbin0 -> 107 bytes
-rw-r--r--style/Air/img/email.pngbin0 -> 390 bytes
-rw-r--r--style/Air/img/exclaim.pngbin0 -> 432 bytes
-rw-r--r--style/Air/img/ext.pngbin0 -> 130 bytes
-rw-r--r--style/Air/img/feed.pngbin0 -> 439 bytes
-rw-r--r--style/Air/img/help.pngbin0 -> 394 bytes
-rw-r--r--style/Air/img/index.html1
-rw-r--r--style/Air/index.html1
l---------style/ArchLinux.css1
-rw-r--r--style/ArchLinux/admin.tpl40
-rw-r--r--style/ArchLinux/arch.css162
-rw-r--r--style/ArchLinux/archfooter.php11
-rw-r--r--style/ArchLinux/archicon.svg1
-rw-r--r--style/ArchLinux/archlogo.svg1
-rw-r--r--style/ArchLinux/archnavbar.css76
-rw-r--r--style/ArchLinux/archnavbar.php17
l---------style/ArchLinux/base_admin.css1
-rw-r--r--style/ArchLinux/css.php7
-rw-r--r--style/ArchLinux/favicon.icobin0 -> 501 bytes
-rw-r--r--style/ArchLinux/help.tpl29
-rw-r--r--style/ArchLinux/index.html1
-rw-r--r--style/ArchLinux/main.tpl40
-rw-r--r--style/ArchLinux/maintenance.tpl29
-rw-r--r--style/ArchLinux/redirect.tpl31
l---------style/ArchLinux32.css1
-rw-r--r--style/ArchLinux32/admin.tpl40
-rw-r--r--style/ArchLinux32/arch.css162
-rw-r--r--style/ArchLinux32/arch32logo.pngbin0 -> 5508 bytes
-rw-r--r--style/ArchLinux32/archfooter.php11
-rw-r--r--style/ArchLinux32/archicon.svg1
-rw-r--r--style/ArchLinux32/archlogo.svg1
-rw-r--r--style/ArchLinux32/archnavbar.css76
-rw-r--r--style/ArchLinux32/archnavbar.php18
-rw-r--r--style/ArchLinux32/base_admin.css177
-rw-r--r--style/ArchLinux32/css.php7
-rw-r--r--style/ArchLinux32/favicon.icobin0 -> 501 bytes
-rw-r--r--style/ArchLinux32/help.tpl29
-rw-r--r--style/ArchLinux32/index.html1
-rw-r--r--style/ArchLinux32/main.tpl40
-rw-r--r--style/ArchLinux32/maintenance.tpl29
-rw-r--r--style/ArchLinux32/redirect.tpl31
-rw-r--r--style/Cobalt.css1150
-rw-r--r--style/Earth.css1650
-rw-r--r--style/Earth/base_admin.css177
-rw-r--r--style/Earth/img/asterisk.pngbin0 -> 168 bytes
-rw-r--r--style/Earth/img/bull.pngbin0 -> 107 bytes
-rw-r--r--style/Earth/img/email.pngbin0 -> 388 bytes
-rw-r--r--style/Earth/img/exclaim.pngbin0 -> 432 bytes
-rw-r--r--style/Earth/img/ext.pngbin0 -> 130 bytes
-rw-r--r--style/Earth/img/feed.pngbin0 -> 439 bytes
-rw-r--r--style/Earth/img/help.pngbin0 -> 379 bytes
-rw-r--r--style/Earth/img/index.html1
-rw-r--r--style/Earth/index.html1
-rw-r--r--style/Fire.css1650
-rw-r--r--style/Fire/base_admin.css177
-rw-r--r--style/Fire/img/asterisk.pngbin0 -> 168 bytes
-rw-r--r--style/Fire/img/bull.pngbin0 -> 107 bytes
-rw-r--r--style/Fire/img/email.pngbin0 -> 371 bytes
-rw-r--r--style/Fire/img/exclaim.pngbin0 -> 432 bytes
-rw-r--r--style/Fire/img/ext.pngbin0 -> 130 bytes
-rw-r--r--style/Fire/img/feed.pngbin0 -> 439 bytes
-rw-r--r--style/Fire/img/help.pngbin0 -> 380 bytes
-rw-r--r--style/Fire/img/index.html1
-rw-r--r--style/Fire/index.html1
-rw-r--r--style/Lithium.css1149
-rw-r--r--style/Mercury.css1150
-rw-r--r--style/Oxygen.css1150
-rw-r--r--style/Radium.css1150
-rw-r--r--style/Sulfur.css1149
-rw-r--r--style/Technetium.css1373
-rw-r--r--style/Technetium/bg.pngbin0 -> 578 bytes
-rw-r--r--style/Technetium/dark-shade.pngbin0 -> 157 bytes
-rw-r--r--style/Technetium/darker-shade.pngbin0 -> 172 bytes
-rw-r--r--style/Technetium/feed.pngbin0 -> 439 bytes
-rw-r--r--style/Technetium/icon-closed-sticky.pngbin0 -> 457 bytes
-rw-r--r--style/Technetium/icon-closed.pngbin0 -> 255 bytes
-rw-r--r--style/Technetium/icon-moved.pngbin0 -> 423 bytes
-rw-r--r--style/Technetium/icon-new-sticky.pngbin0 -> 505 bytes
-rw-r--r--style/Technetium/icon-new.pngbin0 -> 324 bytes
-rw-r--r--style/Technetium/icon-nonew-sticky.pngbin0 -> 443 bytes
-rw-r--r--style/Technetium/icon-nonew.pngbin0 -> 265 bytes
-rw-r--r--style/Technetium/index.html1
-rw-r--r--style/Technetium/inv-shade.pngbin0 -> 117 bytes
-rw-r--r--style/Technetium/light-shade.pngbin0 -> 120 bytes
-rw-r--r--style/imports/base_admin.css54
-rw-r--r--style/imports/index.html1
-rw-r--r--style/index.html1
-rw-r--r--userlist.php183
-rw-r--r--viewforum.php311
-rw-r--r--viewtopic.php486
311 files changed, 46389 insertions, 0 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..8359151
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+.gitattributes export-ignore
+.gitignore export-ignore
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ea07bb6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,11 @@
+/cache/*
+!/cache/index.html
+!/cache/.htaccess
+/include/user/*
+!/include/user/index.html
+/img/avatars/*
+!/img/avatars/index.html
+/.kateproject.d/
+/nbproject/
+/.idea/
+*~
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..5b6e7c6
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/addons/copyable_captcha.php b/addons/copyable_captcha.php
new file mode 100644
index 0000000..8f136d9
--- /dev/null
+++ b/addons/copyable_captcha.php
@@ -0,0 +1,104 @@
+<?php
+
+/**
+ * Copyable Captha plugin
+ * Copyright (C) 2016 artoodetoo
+ * Special thanks to Visman for his help
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+class addon_copyable_captcha extends flux_addon
+{
+ var $lang;
+ var $styles;
+ var $spans;
+
+ function register($manager)
+ {
+ global $pun_user;
+
+ if (!$pun_user['is_guest']) return;
+
+ $manager->bind('register_after_validation', array($this, 'hook_register_after_validation'));
+ $manager->bind('register_before_header', array($this, 'hook_register_before_header'));
+ $manager->bind('register_before_submit', array($this, 'hook_register_before_submit'));
+ }
+
+ function load_lang()
+ {
+ global $pun_user;
+
+ if (isset($this->lang)) return;
+
+ $user_lang = file_exists(PUN_ROOT.'lang/'.$pun_user['language'].'/copyable_captcha.php')
+ ? $pun_user['language']
+ : 'English';
+ require PUN_ROOT.'lang/'.$user_lang.'/copyable_captcha.php';
+
+ $this->lang = $lang_copyable_captcha;
+ }
+
+ function hook_register_after_validation()
+ {
+ global $errors, $cookie_name, $cookie_seed;
+
+ if (isset($_POST['req_word']) && isset($_COOKIE[$cookie_name.'_captcha']) && substr_count($_COOKIE[$cookie_name.'_captcha'], '-') === 1) {
+ list($hash, $time) = explode('-', $_COOKIE[$cookie_name.'_captcha']);
+ $word = $_POST['req_word'];
+ if ((int)$time <= time() - 120 || $hash !== sha1(strtolower($word).$cookie_seed.'secret'.$time)) {
+ $this->load_lang();
+ $errors[] = $this->lang['Captcha error'];
+ }
+ } else {
+ $this->load_lang();
+ $errors[] = $this->lang['Captcha error'];
+ }
+ }
+
+
+ function hook_register_before_header()
+ {
+ global $required_fields, $errors, $cookie_name, $cookie_seed;
+
+ $this->load_lang();
+ $required_fields['req_word'] = $this->lang['Captcha'];
+
+ $time = time();
+ $word = random_pass(mt_rand(4, 6));
+ $hash = sha1(strtolower($word).$cookie_seed.'secret'.$time);
+ forum_setcookie($cookie_name.'_captcha', $hash.'-'.$time, $time + 120);
+
+ $array = str_split($word);
+ $mixin = random_pass(mt_rand(1, 3));
+ $i = -1;
+ $this->styles = '';
+ foreach (str_split($mixin) as $ch) {
+ $i = mt_rand($i+1, count($array));
+ array_splice($array, $i, 0, $ch);
+ $this->styles .= '.masq i:nth-child('.($i + 1).'){display:none;} ';
+ }
+ $this->spans = '<i>'.implode('</i><i>', $array).'</i>';
+ }
+
+
+ function hook_register_before_submit()
+ {
+ global $lang_common;
+
+ $this->load_lang();
+
+?>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $this->lang['Captcha legend'] ?></legend>
+ <div class="infldset">
+ <style> .masq i {font-style:normal;} <?php echo $this->styles ?></style>
+ <p><?php echo sprintf($this->lang['Captcha info'], $this->spans) ?></p>
+ <label class="required"><strong><?php echo $this->lang['Captcha'] ?> <span><?php echo $lang_common['Required'] ?></span></strong><br /><input type="text" name="req_word" size="25" maxlength="25" /><br /></label>
+ </div>
+ </fieldset>
+ </div>
+<?php
+
+ }
+}
diff --git a/addons/funnyquestion.php b/addons/funnyquestion.php
new file mode 100644
index 0000000..e3cd4e9
--- /dev/null
+++ b/addons/funnyquestion.php
@@ -0,0 +1,160 @@
+<?php
+
+if (!defined('PUN')) {
+ exit;
+}
+
+class addon_funnyquestion extends flux_addon
+{
+
+ public function __construct()
+ {
+ global $funnyquestion_disabled, $funnyquestion_hash, $funny_questions, $funnyquestion_timeout, $funnyquestion_remember, $funnyquestion_wait, $pun_user, $lang_funnyquestion;
+
+ !isset($funnyquestion_disabled) && $funnyquestion_disabled = false;
+ !isset($funnyquestion_hash) && $funnyquestion_hash = dirname(__FILE__);
+ !isset($funny_questions) && $funny_questions = array(
+ 'What is the Ultimate Answer to the Ultimate Question of Life, The Universe, and Everything?' => '42'
+ );
+ !isset($funnyquestion_timeout) && $funnyquestion_timeout = 3600;
+ !isset($funnyquestion_remember) && $funnyquestion_remember = 3600 * 24;
+ !isset($funnyquestion_wait) && $funnyquestion_wait = 2;
+
+ if (file_exists(PUN_ROOT . 'lang/' . $pun_user['language'] . '/funnyquestion.php')) {
+ require PUN_ROOT . 'lang/' . $pun_user['language'] . '/funnyquestion.php';
+ } else {
+ require PUN_ROOT . 'lang/English/funnyquestion.php';
+ }
+ }
+
+ /**
+ * @param flux_addon_manager $manager
+ */
+ public function register($manager)
+ {
+ $manager->bind('register_before_submit', array($this, 'print_funnyquestion'));
+ $manager->bind('quickpost_before_submit', array($this, 'print_funnyquestion'));
+ $manager->bind('post_before_submit', array($this, 'print_funnyquestion'));
+ $manager->bind('register_before_validation', array($this, 'set_error_on_check_funnyquestion'));
+ $manager->bind('post_before_validation', array($this, 'set_error_on_check_funnyquestion'));
+ }
+
+ public function print_funnyquestion()
+ {
+ echo $this->get_funnyquestion();
+ }
+
+ public function set_error_on_check_funnyquestion()
+ {
+ global $errors, $lang_funnyquestion;
+ $this->check_funnyquestion() || $errors[] = $lang_funnyquestion['wrong-answer'];
+ }
+
+ /**
+ * @param string $answer
+ * @return string
+ */
+ private function normalize_funnyanswer($answer)
+ {
+ return preg_replace('/[^a-z0-9]/', '', strtolower($answer));
+ }
+
+ private function set_funnycookie()
+ {
+ global $funnyquestion_hash, $funnyquestion_remember;
+
+ $time = time();
+ forum_setcookie('funnyquestion_hash', sha1($time . get_remote_address() . $funnyquestion_hash),
+ $time + $funnyquestion_remember);
+ forum_setcookie('funnyquestion_time', $time, $time + $funnyquestion_remember);
+ }
+
+ /**
+ * @return bool
+ */
+ private function has_funnycookie()
+ {
+ global $funnyquestion_hash, $funnyquestion_remember;
+
+ return (!empty($_COOKIE['funnyquestion_hash']) && !empty($_COOKIE['funnyquestion_time'])
+ && time() - $funnyquestion_remember <= $_COOKIE['funnyquestion_time']
+ && sha1($_COOKIE['funnyquestion_time'] . get_remote_address() . $funnyquestion_hash) == $_COOKIE['funnyquestion_hash']);
+ }
+
+ /**
+ * @return string
+ */
+ private function get_funnyquestion()
+ {
+ global $funnyquestion_disabled, $funnyquestion_hash, $funny_questions, $lang_funnyquestion, $lang_common, $pun_user;
+
+ if ($funnyquestion_disabled || !$pun_user['is_guest'] || $this->has_funnycookie()) {
+ return '';
+ }
+
+ $time = time();
+ $question = array_rand($funny_questions);
+ # make sure the user is not able to tell us the question to answer
+ $hash = sha1($time . $question . $funnyquestion_hash);
+
+ return '<div class="inform">
+ <fieldset>
+ <legend>' . $lang_funnyquestion['question-label'] . '</legend>
+ <div class="infldset">
+ <input type="hidden" name="funnyquestion_time" value="' . $time . '" />
+ <input type="hidden" name="funnyquestion_hash" value="' . $hash . '" />
+ <label class="required">
+ <strong>' . $question . '<span>' . $lang_common['Required'] . '</span></strong><br />
+ <input type="text" name="funny_answer" value="" size="50" /><br />
+ </label>
+ </div>
+ </fieldset>
+ </div>';
+ }
+
+ /**
+ * @return bool
+ */
+ private function check_funnyquestion()
+ {
+ global $funnyquestion_disabled, $funnyquestion_hash, $funnyquestion_timeout, $funnyquestion_wait, $funny_questions, $pun_user;
+
+ if ($funnyquestion_disabled || !$pun_user['is_guest'] || $this->has_funnycookie()) {
+ return true;
+ }
+
+ if (!empty($_POST['funnyquestion_time'])
+ && !empty($_POST['funnyquestion_hash'])
+ && !empty($_POST['funny_answer'])
+ ) {
+ $now = time();
+ $time = $_POST['funnyquestion_time'];
+ $hash = $_POST['funnyquestion_hash'];
+ $user_answer = $this->normalize_funnyanswer($_POST['funny_answer']);
+ } else {
+ return false;
+ }
+
+ if ($now - $time > $funnyquestion_timeout) {
+ return false;
+ } elseif ($now - $time < $funnyquestion_wait) {
+ return false;
+ }
+
+ foreach ($funny_questions as $question => $answers) {
+ if (!is_array($answers)) {
+ $answers = array($answers);
+ }
+ foreach ($answers as $answer) {
+ if ($this->normalize_funnyanswer($answer) == $user_answer
+ && $hash == sha1($time . $question . $funnyquestion_hash)
+ ) {
+ $this->set_funnycookie();
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/addons/index.html b/addons/index.html
new file mode 100644
index 0000000..cf1a99a
--- /dev/null
+++ b/addons/index.html
@@ -0,0 +1 @@
+<html><head><title>.</title></head><body>.</body></html>
diff --git a/addons/recaptcha.php b/addons/recaptcha.php
new file mode 100644
index 0000000..668de1c
--- /dev/null
+++ b/addons/recaptcha.php
@@ -0,0 +1,136 @@
+<?php
+
+class addon_recaptcha extends flux_addon
+{
+ function register($manager)
+ {
+ global $pun_user;
+
+ if (!$this->is_configured()) return;
+
+ $this->get_language();
+
+ if ($this->enabled_location('register'))
+ {
+ $manager->bind('register_after_validation', array($this, 'hook_after_validation'));
+ $manager->bind('register_before_submit', array($this, 'hook_before_submit'));
+ }
+
+ if ($this->enabled_location('login'))
+ {
+ $manager->bind('login_after_validation', array($this, 'hook_after_validation'));
+ $manager->bind('login_before_submit', array($this, 'hook_before_submit'));
+ }
+
+ if ($this->enabled_location('guestpost') && $pun_user['is_guest'])
+ {
+ $manager->bind('post_after_validation', array($this, 'hook_after_validation'));
+ $manager->bind('post_before_submit', array($this, 'hook_before_submit'));
+ $manager->bind('quickpost_before_submit', array($this, 'hook_before_submit'));
+ }
+ }
+
+ function is_configured()
+ {
+ global $pun_config;
+
+ return !empty($pun_config['recaptcha_enabled']) && !empty($pun_config['recaptcha_site_key']) && !empty($pun_config['recaptcha_secret_key']);
+ }
+
+ function enabled_location($page)
+ {
+ global $pun_config;
+
+ return !empty($pun_config['recaptcha_location_'.$page]);
+ }
+
+ function get_language()
+ {
+ global $pun_user;
+
+ if (file_exists(PUN_ROOT.'lang/'.$pun_user['language'].'/recaptcha_addon.php'))
+ require PUN_ROOT.'lang/'.$pun_user['language'].'/recaptcha_addon.php';
+ else
+ require PUN_ROOT.'lang/English/recaptcha_addon.php';
+ }
+
+ function hook_after_validation()
+ {
+ global $errors, $lang_recaptcha;
+
+ if (empty($errors) && !$this->verify_user_response())
+ {
+ $errors[] = $lang_recaptcha['Error'];
+ }
+ }
+
+ function hook_before_submit()
+ {
+ global $pun_config, $lang_recaptcha;
+
+ $site_key = $pun_config['recaptcha_site_key'];
+
+ ?>
+ <div class="inform">
+ <fieldset>
+ <legend><?= $lang_recaptcha['Human']; ?></legend>
+ <div class="infldset">
+ <p><?= $lang_recaptcha['Prove']; ?></p>
+ <script src="https://www.google.com/recaptcha/api.js"></script>
+ <div class="g-recaptcha" data-sitekey="<?php echo pun_htmlspecialchars($site_key) ?>"></div>
+ </div>
+ </fieldset>
+ </div>
+ <?php
+ }
+
+ function verify_user_response()
+ {
+ global $pun_config;
+
+ if (empty($_POST['g-recaptcha-response'])) return false;
+
+ $secret = $pun_config['recaptcha_secret_key'];
+ $response = $_POST['g-recaptcha-response'];
+ $ip = get_remote_address();
+
+ $query = "secret=$secret&response=$response&remoteip=$ip";
+ $url = "https://www.google.com/recaptcha/api/siteverify?$query";
+
+ $response = $this->send_request($url);
+
+ return strpos($response, '"success": true') !== false;
+ }
+
+ function send_request($url)
+ {
+ if (function_exists('curl_version'))
+ return $this->send_curl_request($url);
+ else
+ return $this->get_remote_file($url);
+ }
+
+ function send_curl_request($url)
+ {
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+ $response = curl_exec($ch);
+ curl_close($ch);
+
+ return $response;
+ }
+
+ function get_remote_file($url)
+ {
+ global $lang_recaptcha;
+
+ $response = file_get_contents($url);
+
+ if ($response === false)
+ throw new Exception($lang_recaptcha['API error']);
+
+ return $response;
+ }
+}
diff --git a/admin_bans.php b/admin_bans.php
new file mode 100644
index 0000000..6ee8c58
--- /dev/null
+++ b/admin_bans.php
@@ -0,0 +1,602 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Tell header.php to use the admin template
+define('PUN_ADMIN_CONSOLE', 1);
+
+define('PUN_ROOT', dirname(__FILE__).'/');
+require PUN_ROOT.'include/common.php';
+require PUN_ROOT.'include/common_admin.php';
+
+
+if ($pun_user['g_id'] != PUN_ADMIN && ($pun_user['g_moderator'] != '1' || $pun_user['g_mod_ban_users'] == '0'))
+ message($lang_common['No permission'], false, '403 Forbidden');
+
+// Load the admin_bans.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_bans.php';
+
+// Add/edit a ban (stage 1)
+if (isset($_REQUEST['add_ban']) || isset($_GET['edit_ban']))
+{
+ if (isset($_GET['add_ban']) || isset($_POST['add_ban']))
+ {
+ // If the ID of the user to ban was provided through GET (a link from profile.php)
+ if (isset($_GET['add_ban']))
+ {
+ $user_id = intval($_GET['add_ban']);
+ if ($user_id < 2)
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+ $result = $db->query('SELECT group_id, username, email FROM '.$db->prefix.'users WHERE id='.$user_id) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
+ if ($db->num_rows($result))
+ list($group_id, $ban_user, $ban_email) = $db->fetch_row($result);
+ else
+ message($lang_admin_bans['No user ID message']);
+ }
+ else // Otherwise the username is in POST
+ {
+ $ban_user = pun_trim($_POST['new_ban_user']);
+
+ if ($ban_user != '')
+ {
+ $result = $db->query('SELECT id, group_id, username, email FROM '.$db->prefix.'users WHERE username=\''.$db->escape($ban_user).'\' AND id>1') or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
+ if ($db->num_rows($result))
+ list($user_id, $group_id, $ban_user, $ban_email) = $db->fetch_row($result);
+ else
+ message($lang_admin_bans['No user message']);
+ }
+ }
+
+ // Make sure we're not banning an admin or moderator
+ if (isset($group_id))
+ {
+ if ($group_id == PUN_ADMIN)
+ message(sprintf($lang_admin_bans['User is admin message'], pun_htmlspecialchars($ban_user)));
+
+ $result = $db->query('SELECT g_moderator FROM '.$db->prefix.'groups WHERE g_id='.$group_id) or error('Unable to fetch group info', __FILE__, __LINE__, $db->error());
+ $is_moderator_group = $db->result($result);
+
+ if ($is_moderator_group)
+ message(sprintf($lang_admin_bans['User is mod message'], pun_htmlspecialchars($ban_user)));
+ }
+
+ // If we have a $user_id, we can try to find the last known IP of that user
+ if (isset($user_id))
+ {
+ $result = $db->query('SELECT poster_ip FROM '.$db->prefix.'posts WHERE poster_id='.$user_id.' ORDER BY posted DESC LIMIT 1') or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
+ $ban_ip = ($db->num_rows($result)) ? $db->result($result) : '';
+
+ if ($ban_ip == '')
+ {
+ $result = $db->query('SELECT registration_ip FROM '.$db->prefix.'users WHERE id='.$user_id) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
+ $ban_ip = ($db->num_rows($result)) ? $db->result($result) : '';
+ }
+ }
+
+ $mode = 'add';
+ }
+ else // We are editing a ban
+ {
+ $ban_id = intval($_GET['edit_ban']);
+ if ($ban_id < 1)
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+ $result = $db->query('SELECT username, ip, email, message, expire FROM '.$db->prefix.'bans WHERE id='.$ban_id) or error('Unable to fetch ban info', __FILE__, __LINE__, $db->error());
+ if ($db->num_rows($result))
+ list($ban_user, $ban_ip, $ban_email, $ban_message, $ban_expire) = $db->fetch_row($result);
+ else
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+ $diff = ($pun_user['timezone'] + $pun_user['dst']) * 3600;
+ $ban_expire = ($ban_expire != '') ? gmdate('Y-m-d', $ban_expire + $diff) : '';
+
+ $mode = 'edit';
+ }
+
+ $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Bans']);
+ $focus_element = array('bans2', 'ban_user');
+ define('PUN_ACTIVE_PAGE', 'admin');
+ require PUN_ROOT.'header.php';
+
+ generate_admin_menu('bans');
+
+?>
+ <div class="blockform">
+ <h2><span><?php echo $lang_admin_bans['Ban advanced head'] ?></span></h2>
+ <div class="box">
+ <form id="bans2" method="post" action="admin_bans.php">
+ <div class="inform">
+ <input type="hidden" name="mode" value="<?php echo $mode ?>" />
+<?php if ($mode == 'edit'): ?> <input type="hidden" name="ban_id" value="<?php echo $ban_id ?>" />
+<?php endif; ?> <fieldset>
+ <legend><?php echo $lang_admin_bans['Ban advanced subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_bans['Username label'] ?></th>
+ <td>
+ <input type="text" name="ban_user" size="25" maxlength="25" value="<?php if (isset($ban_user)) echo pun_htmlspecialchars($ban_user); ?>" tabindex="1" />
+ <span><?php echo $lang_admin_bans['Username help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_bans['IP label'] ?></th>
+ <td>
+ <input type="text" name="ban_ip" size="45" maxlength="255" value="<?php if (isset($ban_ip)) echo pun_htmlspecialchars($ban_ip); ?>" tabindex="2" />
+ <span><?php echo $lang_admin_bans['IP help'] ?><?php if ($ban_user != '' && isset($user_id)) printf(' '.$lang_admin_bans['IP help link'], '<a href="admin_users.php?ip_stats='.$user_id.'">'.$lang_admin_common['here'].'</a>') ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_bans['E-mail label'] ?></th>
+ <td>
+ <input type="text" name="ban_email" size="40" maxlength="80" value="<?php if (isset($ban_email)) echo pun_htmlspecialchars($ban_email); ?>" tabindex="3" />
+ <span><?php echo $lang_admin_bans['E-mail help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ <p class="topspace"><strong class="warntext"><?php echo $lang_admin_bans['Ban IP range info'] ?></strong></p>
+ </div>
+ </fieldset>
+ </div>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_bans['Message expiry subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_bans['Ban message label'] ?></th>
+ <td>
+ <input type="text" name="ban_message" size="50" maxlength="255" value="<?php if (isset($ban_message)) echo pun_htmlspecialchars($ban_message); ?>" tabindex="4" />
+ <span><?php echo $lang_admin_bans['Ban message help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_bans['Expire date label'] ?></th>
+ <td>
+ <input type="text" name="ban_expire" size="17" maxlength="10" value="<?php if (isset($ban_expire)) echo $ban_expire; ?>" tabindex="5" />
+ <span><?php echo $lang_admin_bans['Expire date help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ <p class="submitend"><input type="submit" name="add_edit_ban" value="<?php echo $lang_admin_common['Save'] ?>" tabindex="6" /></p>
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+</div>
+<?php
+
+ require PUN_ROOT.'footer.php';
+}
+
+// Add/edit a ban (stage 2)
+else if (isset($_POST['add_edit_ban']))
+{
+ confirm_referrer('admin_bans.php');
+
+ $ban_user = pun_trim($_POST['ban_user']);
+ $ban_ip = pun_trim($_POST['ban_ip']);
+ $ban_email = strtolower(pun_trim($_POST['ban_email']));
+ $ban_message = pun_trim($_POST['ban_message']);
+ $ban_expire = pun_trim($_POST['ban_expire']);
+
+ if ($ban_user == '' && $ban_ip == '' && $ban_email == '')
+ message($lang_admin_bans['Must enter message']);
+ else if (strtolower($ban_user) == 'guest')
+ message($lang_admin_bans['Cannot ban guest message']);
+
+ // Make sure we're not banning an admin or moderator
+ if (!empty($ban_user))
+ {
+ $result = $db->query('SELECT group_id FROM '.$db->prefix.'users WHERE username=\''.$db->escape($ban_user).'\' AND id>1') or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
+ if ($db->num_rows($result))
+ {
+ $group_id = $db->result($result);
+
+ if ($group_id == PUN_ADMIN)
+ message(sprintf($lang_admin_bans['User is admin message'], pun_htmlspecialchars($ban_user)));
+
+ $result = $db->query('SELECT g_moderator FROM '.$db->prefix.'groups WHERE g_id='.$group_id) or error('Unable to fetch group info', __FILE__, __LINE__, $db->error());
+ $is_moderator_group = $db->result($result);
+
+ if ($is_moderator_group)
+ message(sprintf($lang_admin_bans['User is mod message'], pun_htmlspecialchars($ban_user)));
+ }
+ }
+
+ // Validate IP/IP range (it's overkill, I know)
+ if ($ban_ip != '')
+ {
+ $ban_ip = preg_replace('%\s{2,}%S', ' ', $ban_ip);
+ $addresses = explode(' ', $ban_ip);
+ $addresses = array_map('pun_trim', $addresses);
+
+ for ($i = 0; $i < count($addresses); ++$i)
+ {
+ if (strpos($addresses[$i], ':') !== false)
+ {
+ $octets = explode(':', $addresses[$i]);
+
+ for ($c = 0; $c < count($octets); ++$c)
+ {
+ $octets[$c] = ltrim($octets[$c], "0");
+
+ if ($c > 7 || (!empty($octets[$c]) && !ctype_xdigit($octets[$c])) || intval($octets[$c], 16) > 65535)
+ message($lang_admin_bans['Invalid IP message']);
+ }
+
+ $cur_address = implode(':', $octets);
+ $addresses[$i] = $cur_address;
+ }
+ else
+ {
+ $octets = explode('.', $addresses[$i]);
+
+ for ($c = 0; $c < count($octets); ++$c)
+ {
+ $octets[$c] = (strlen($octets[$c]) > 1) ? ltrim($octets[$c], "0") : $octets[$c];
+
+ if ($c > 3 || preg_match('%[^0-9]%', $octets[$c]) || intval($octets[$c]) > 255)
+ message($lang_admin_bans['Invalid IP message']);
+ }
+
+ $cur_address = implode('.', $octets);
+ $addresses[$i] = $cur_address;
+ }
+ }
+
+ $ban_ip = implode(' ', $addresses);
+ }
+
+ require PUN_ROOT.'include/email.php';
+ if ($ban_email != '')
+ {
+ // Validate email or domain format
+ if (!is_valid_email($ban_email) && !preg_match('%^[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,63})$%', $ban_email))
+ message($lang_admin_bans['Invalid e-mail message']);
+
+ // Let's ensure we are not adding a duplicate ban
+ $dup_conditions = array('(expire IS NULL OR expire > '.time().')');
+
+ // If we're adding an email address, we can also check for the domain
+ $domain_index = strpos($ban_email, '@');
+
+ if ($domain_index !== false && $_POST['mode'] == 'add')
+ {
+ // We are not checking for domains when editing bans, as that might
+ // prevent editing other fields of already existing email bans for
+ // which a domain ban was added later.
+ $ban_domain = substr($ban_email, $domain_index + 1);
+ $dup_conditions[] = 'email IN (\''.$db->escape($ban_email).'\', \''.$db->escape($ban_domain).'\')';
+ }
+ else
+ $dup_conditions[] = 'email = \''.$db->escape($ban_email).'\'';
+
+ // When editing, we also need to exclude the current ban
+ if ($_POST['mode'] == 'edit')
+ $dup_conditions[] = 'id != '.intval($_POST['ban_id']);
+
+ $result = $db->query('SELECT email FROM '.$db->prefix.'bans WHERE '.implode(' AND ', $dup_conditions)) or error('Unable to check for duplicate bans', __FILE__, __LINE__, $db->error());
+ if ($match = $db->result($result))
+ {
+ $is_domain = strpos($match, '@') === false;
+
+ if ($is_domain)
+ message(sprintf($lang_admin_bans['Duplicate domain message'], $match));
+ else
+ message(sprintf($lang_admin_bans['Duplicate e-mail message'], $match));
+ }
+ }
+
+ if ($ban_expire != '' && $ban_expire != 'Never')
+ {
+ $ban_expire = strtotime($ban_expire.' GMT');
+
+ if ($ban_expire == -1 || !$ban_expire)
+ message($lang_admin_bans['Invalid date message'].' '.$lang_admin_bans['Invalid date reasons']);
+
+ $diff = ($pun_user['timezone'] + $pun_user['dst']) * 3600;
+ $ban_expire -= $diff;
+
+ if ($ban_expire <= time())
+ message($lang_admin_bans['Invalid date message'].' '.$lang_admin_bans['Invalid date reasons']);
+ }
+ else
+ $ban_expire = 'NULL';
+
+ $ban_user = ($ban_user != '') ? '\''.$db->escape($ban_user).'\'' : 'NULL';
+ $ban_ip = ($ban_ip != '') ? '\''.$db->escape($ban_ip).'\'' : 'NULL';
+ $ban_email = ($ban_email != '') ? '\''.$db->escape($ban_email).'\'' : 'NULL';
+ $ban_message = ($ban_message != '') ? '\''.$db->escape($ban_message).'\'' : 'NULL';
+
+ if ($_POST['mode'] == 'add')
+ $db->query('INSERT INTO '.$db->prefix.'bans (username, ip, email, message, expire, ban_creator) VALUES('.$ban_user.', '.$ban_ip.', '.$ban_email.', '.$ban_message.', '.$ban_expire.', '.$pun_user['id'].')') or error('Unable to add ban', __FILE__, __LINE__, $db->error());
+ else
+ $db->query('UPDATE '.$db->prefix.'bans SET username='.$ban_user.', ip='.$ban_ip.', email='.$ban_email.', message='.$ban_message.', expire='.$ban_expire.' WHERE id='.intval($_POST['ban_id'])) or error('Unable to update ban', __FILE__, __LINE__, $db->error());
+
+ // Regenerate the bans cache
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_bans_cache();
+
+ if ($_POST['mode'] == 'edit')
+ redirect('admin_bans.php', $lang_admin_bans['Ban edited redirect']);
+ else
+ redirect('admin_bans.php', $lang_admin_bans['Ban added redirect']);
+}
+
+// Remove a ban
+else if (isset($_GET['del_ban']))
+{
+ confirm_referrer('admin_bans.php');
+
+ $ban_id = intval($_GET['del_ban']);
+ if ($ban_id < 1)
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+ $db->query('DELETE FROM '.$db->prefix.'bans WHERE id='.$ban_id) or error('Unable to delete ban', __FILE__, __LINE__, $db->error());
+
+ // Regenerate the bans cache
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_bans_cache();
+
+ redirect('admin_bans.php', $lang_admin_bans['Ban removed redirect']);
+}
+
+// Find bans
+else if (isset($_GET['find_ban']))
+{
+ $form = isset($_GET['form']) ? $_GET['form'] : array();
+
+ // trim() all elements in $form
+ $form = array_map('pun_trim', $form);
+ $conditions = $query_str = array();
+
+ $expire_after = isset($_GET['expire_after']) ? pun_trim($_GET['expire_after']) : '';
+ $expire_before = isset($_GET['expire_before']) ? pun_trim($_GET['expire_before']) : '';
+ $order_by = isset($_GET['order_by']) && in_array($_GET['order_by'], array('username', 'ip', 'email', 'expire')) ? 'b.'.$_GET['order_by'] : 'b.username';
+ $direction = isset($_GET['direction']) && $_GET['direction'] == 'DESC' ? 'DESC' : 'ASC';
+
+ $query_str[] = 'order_by='.$order_by;
+ $query_str[] = 'direction='.$direction;
+
+ // Try to convert date/time to timestamps
+ if ($expire_after != '')
+ {
+ $query_str[] = 'expire_after='.$expire_after;
+
+ $expire_after = strtotime($expire_after);
+ if ($expire_after === false || $expire_after == -1)
+ message($lang_admin_bans['Invalid date message']);
+
+ $conditions[] = 'b.expire>'.$expire_after;
+ }
+ if ($expire_before != '')
+ {
+ $query_str[] = 'expire_before='.$expire_before;
+
+ $expire_before = strtotime($expire_before);
+ if ($expire_before === false || $expire_before == -1)
+ message($lang_admin_bans['Invalid date message']);
+
+ $conditions[] = 'b.expire<'.$expire_before;
+ }
+
+ $like_command = ($db_type == 'pgsql') ? 'ILIKE' : 'LIKE';
+ foreach ($form as $key => $input)
+ {
+ if ($input != '' && in_array($key, array('username', 'ip', 'email', 'message')))
+ {
+ $conditions[] = 'b.'.$db->escape($key).' '.$like_command.' \''.$db->escape(str_replace(array('*', '_'), array('%', '\\_'), $input)).'\'';
+ $query_str[] = 'form%5B'.$key.'%5D='.urlencode($input);
+ }
+ }
+
+ // Fetch ban count
+ $result = $db->query('SELECT COUNT(id) FROM '.$db->prefix.'bans as b WHERE b.id>0'.(!empty($conditions) ? ' AND '.implode(' AND ', $conditions) : '')) or error('Unable to fetch ban list', __FILE__, __LINE__, $db->error());
+ $num_bans = $db->result($result);
+
+ // Determine the ban offset (based on $_GET['p'])
+ $num_pages = ceil($num_bans / 50);
+
+ $p = (!isset($_GET['p']) || $_GET['p'] <= 1 || $_GET['p'] > $num_pages) ? 1 : intval($_GET['p']);
+ $start_from = 50 * ($p - 1);
+
+ // Generate paging links
+ $paging_links = '<span class="pages-label">'.$lang_common['Pages'].' </span>'.paginate($num_pages, $p, 'admin_bans.php?find_ban=&amp;'.implode('&amp;', $query_str));
+
+ $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Bans'], $lang_admin_bans['Results head']);
+ define('PUN_ACTIVE_PAGE', 'admin');
+ require PUN_ROOT.'header.php';
+
+?>
+<div class="linkst">
+ <div class="inbox crumbsplus">
+ <ul class="crumbs">
+ <li><a href="admin_index.php"><?php echo $lang_admin_common['Admin'].' '.$lang_admin_common['Index'] ?></a></li>
+ <li><span>»&#160;</span><a href="admin_bans.php"><?php echo $lang_admin_common['Bans'] ?></a></li>
+ <li><span>»&#160;</span><strong><?php echo $lang_admin_bans['Results head'] ?></strong></li>
+ </ul>
+ <div class="pagepost">
+ <p class="pagelink"><?php echo $paging_links ?></p>
+ </div>
+ <div class="clearer"></div>
+ </div>
+</div>
+
+
+<div id="bans1" class="blocktable">
+ <h2><span><?php echo $lang_admin_bans['Results head'] ?></span></h2>
+ <div class="box">
+ <div class="inbox">
+ <table>
+ <thead>
+ <tr>
+ <th class="tcl" scope="col"><?php echo $lang_admin_bans['Results username head'] ?></th>
+ <th class="tc2" scope="col"><?php echo $lang_admin_bans['Results e-mail head'] ?></th>
+ <th class="tc3" scope="col"><?php echo $lang_admin_bans['Results IP address head'] ?></th>
+ <th class="tc4" scope="col"><?php echo $lang_admin_bans['Results expire head'] ?></th>
+ <th class="tc5" scope="col"><?php echo $lang_admin_bans['Results message head'] ?></th>
+ <th class="tc6" scope="col"><?php echo $lang_admin_bans['Results banned by head'] ?></th>
+ <th class="tcr" scope="col"><?php echo $lang_admin_bans['Results actions head'] ?></th>
+ </tr>
+ </thead>
+ <tbody>
+<?php
+
+ $result = $db->query('SELECT b.id, b.username, b.ip, b.email, b.message, b.expire, b.ban_creator, u.username AS ban_creator_username FROM '.$db->prefix.'bans AS b LEFT JOIN '.$db->prefix.'users AS u ON b.ban_creator=u.id WHERE b.id>0'.(!empty($conditions) ? ' AND '.implode(' AND ', $conditions) : '').' ORDER BY '.$db->escape($order_by).' '.$db->escape($direction).' LIMIT '.$start_from.', 50') or error('Unable to fetch ban list', __FILE__, __LINE__, $db->error());
+ if ($db->num_rows($result))
+ {
+ while ($ban_data = $db->fetch_assoc($result))
+ {
+
+ $actions = '<a href="admin_bans.php?edit_ban='.$ban_data['id'].'">'.$lang_admin_common['Edit'].'</a> | <a href="admin_bans.php?del_ban='.$ban_data['id'].'">'.$lang_admin_common['Remove'].'</a>';
+ $expire = format_time($ban_data['expire'], true);
+
+?>
+ <tr>
+ <td class="tcl"><?php echo ($ban_data['username'] != '') ? pun_htmlspecialchars($ban_data['username']) : '&#160;' ?></td>
+ <td class="tc2"><?php echo ($ban_data['email'] != '') ? pun_htmlspecialchars($ban_data['email']) : '&#160;' ?></td>
+ <td class="tc3"><?php echo ($ban_data['ip'] != '') ? pun_htmlspecialchars($ban_data['ip']) : '&#160;' ?></td>
+ <td class="tc4"><?php echo $expire ?></td>
+ <td class="tc5"><?php echo ($ban_data['message'] != '') ? pun_htmlspecialchars($ban_data['message']) : '&#160;' ?></td>
+ <td class="tc6"><?php echo ($ban_data['ban_creator_username'] != '') ? '<a href="profile.php?id='.$ban_data['ban_creator'].'">'.pun_htmlspecialchars($ban_data['ban_creator_username']).'</a>' : $lang_admin_bans['Unknown'] ?></td>
+ <td class="tcr"><?php echo $actions ?></td>
+ </tr>
+<?php
+
+ }
+ }
+ else
+ echo "\t\t\t\t".'<tr><td class="tcl" colspan="7">'.$lang_admin_bans['No match'].'</td></tr>'."\n";
+
+?>
+ </tbody>
+ </table>
+ </div>
+ </div>
+</div>
+
+<div class="linksb">
+ <div class="inbox crumbsplus">
+ <div class="pagepost">
+ <p class="pagelink"><?php echo $paging_links ?></p>
+ </div>
+ <ul class="crumbs">
+ <li><a href="admin_index.php"><?php echo $lang_admin_common['Admin'].' '.$lang_admin_common['Index'] ?></a></li>
+ <li><span>»&#160;</span><a href="admin_bans.php"><?php echo $lang_admin_common['Bans'] ?></a></li>
+ <li><span>»&#160;</span><strong><?php echo $lang_admin_bans['Results head'] ?></strong></li>
+ </ul>
+ <div class="clearer"></div>
+ </div>
+</div>
+<?php
+
+ require PUN_ROOT.'footer.php';
+}
+
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Bans']);
+$focus_element = array('bans', 'new_ban_user');
+define('PUN_ACTIVE_PAGE', 'admin');
+require PUN_ROOT.'header.php';
+
+generate_admin_menu('bans');
+
+?>
+ <div class="blockform">
+ <h2><span><?php echo $lang_admin_bans['New ban head'] ?></span></h2>
+ <div class="box">
+ <form id="bans" method="post" action="admin_bans.php?action=more">
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_bans['Add ban subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_bans['Username label'] ?><div><input type="submit" name="add_ban" value="<?php echo $lang_admin_common['Add'] ?>" tabindex="2" /></div></th>
+ <td>
+ <input type="text" name="new_ban_user" size="25" maxlength="25" tabindex="1" />
+ <span><?php echo $lang_admin_bans['Username advanced help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ </form>
+ </div>
+
+ <h2 class="block2"><span><?php echo $lang_admin_bans['Ban search head'] ?></span></h2>
+ <div class="box">
+ <form id="find_bans" method="get" action="admin_bans.php">
+ <p class="submittop"><input type="submit" name="find_ban" value="<?php echo $lang_admin_bans['Submit search'] ?>" tabindex="3" /></p>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_bans['Ban search subhead'] ?></legend>
+ <div class="infldset">
+ <p><?php echo $lang_admin_bans['Ban search info'] ?></p>
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_bans['Username label'] ?></th>
+ <td><input type="text" name="form[username]" size="25" maxlength="25" tabindex="4" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_bans['IP label'] ?></th>
+ <td><input type="text" name="form[ip]" size="30" maxlength="255" tabindex="5" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_bans['E-mail label'] ?></th>
+ <td><input type="text" name="form[email]" size="30" maxlength="80" tabindex="6" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_bans['Message label'] ?></th>
+ <td><input type="text" name="form[message]" size="30" maxlength="255" tabindex="7" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_bans['Expire after label'] ?></th>
+ <td><input type="text" name="expire_after" size="10" maxlength="10" tabindex="8" />
+ <span><?php echo $lang_admin_bans['Date help'] ?></span></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_bans['Expire before label'] ?></th>
+ <td><input type="text" name="expire_before" size="10" maxlength="10" tabindex="9" />
+ <span><?php echo $lang_admin_bans['Date help'] ?></span></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_bans['Order by label'] ?></th>
+ <td>
+ <select name="order_by" tabindex="10">
+ <option value="username" selected="selected"><?php echo $lang_admin_bans['Order by username'] ?></option>
+ <option value="ip"><?php echo $lang_admin_bans['Order by ip'] ?></option>
+ <option value="email"><?php echo $lang_admin_bans['Order by e-mail'] ?></option>
+ <option value="expire"><?php echo $lang_admin_bans['Order by expire'] ?></option>
+ </select>&#160;&#160;&#160;<select name="direction" tabindex="11">
+ <option value="ASC" selected="selected"><?php echo $lang_admin_bans['Ascending'] ?></option>
+ <option value="DESC"><?php echo $lang_admin_bans['Descending'] ?></option>
+ </select>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ <p class="submitend"><input type="submit" name="find_ban" value="<?php echo $lang_admin_bans['Submit search'] ?>" tabindex="12" /></p>
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+</div>
+<?php
+
+require PUN_ROOT.'footer.php';
diff --git a/admin_categories.php b/admin_categories.php
new file mode 100644
index 0000000..756540a
--- /dev/null
+++ b/admin_categories.php
@@ -0,0 +1,266 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Tell header.php to use the admin template
+define('PUN_ADMIN_CONSOLE', 1);
+
+define('PUN_ROOT', dirname(__FILE__).'/');
+require PUN_ROOT.'include/common.php';
+require PUN_ROOT.'include/common_admin.php';
+
+
+if ($pun_user['g_id'] != PUN_ADMIN)
+ message($lang_common['No permission'], false, '403 Forbidden');
+
+// Load the admin_categories.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_categories.php';
+
+// Add a new category
+if (isset($_POST['add_cat']))
+{
+ confirm_referrer('admin_categories.php');
+
+ $new_cat_name = pun_trim($_POST['new_cat_name']);
+ if ($new_cat_name == '')
+ message($lang_admin_categories['Must enter name message']);
+
+ $db->query('INSERT INTO '.$db->prefix.'categories (cat_name) VALUES(\''.$db->escape($new_cat_name).'\')') or error('Unable to create category', __FILE__, __LINE__, $db->error());
+
+ redirect('admin_categories.php', $lang_admin_categories['Category added redirect']);
+}
+
+// Delete a category
+else if (isset($_POST['del_cat']) || isset($_POST['del_cat_comply']))
+{
+ confirm_referrer('admin_categories.php');
+
+ $cat_to_delete = intval($_POST['cat_to_delete']);
+ if ($cat_to_delete < 1)
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+ if (isset($_POST['del_cat_comply'])) // Delete a category with all forums and posts
+ {
+ @set_time_limit(0);
+
+ $result = $db->query('SELECT id FROM '.$db->prefix.'forums WHERE cat_id='.$cat_to_delete) or error('Unable to fetch forum list', __FILE__, __LINE__, $db->error());
+ $num_forums = $db->num_rows($result);
+
+ for ($i = 0; $i < $num_forums; ++$i)
+ {
+ $cur_forum = $db->result($result, $i);
+
+ // Prune all posts and topics
+ prune($cur_forum, 1, -1);
+
+ // Delete the forum
+ $db->query('DELETE FROM '.$db->prefix.'forums WHERE id='.$cur_forum) or error('Unable to delete forum', __FILE__, __LINE__, $db->error());
+ }
+
+ // Locate any "orphaned redirect topics" and delete them
+ $result = $db->query('SELECT t1.id FROM '.$db->prefix.'topics AS t1 LEFT JOIN '.$db->prefix.'topics AS t2 ON t1.moved_to=t2.id WHERE t2.id IS NULL AND t1.moved_to IS NOT NULL') or error('Unable to fetch redirect topics', __FILE__, __LINE__, $db->error());
+ $num_orphans = $db->num_rows($result);
+
+ if ($num_orphans)
+ {
+ for ($i = 0; $i < $num_orphans; ++$i)
+ $orphans[] = $db->result($result, $i);
+
+ $db->query('DELETE FROM '.$db->prefix.'topics WHERE id IN('.implode(',', $orphans).')') or error('Unable to delete redirect topics', __FILE__, __LINE__, $db->error());
+ }
+
+ // Delete the category
+ $db->query('DELETE FROM '.$db->prefix.'categories WHERE id='.$cat_to_delete) or error('Unable to delete category', __FILE__, __LINE__, $db->error());
+
+ // Regenerate the quick jump cache
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_quickjump_cache();
+
+ redirect('admin_categories.php', $lang_admin_categories['Category deleted redirect']);
+ }
+ else // If the user hasn't confirmed the delete
+ {
+ $result = $db->query('SELECT cat_name FROM '.$db->prefix.'categories WHERE id='.$cat_to_delete) or error('Unable to fetch category info', __FILE__, __LINE__, $db->error());
+ $cat_name = $db->result($result);
+
+ $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Categories']);
+ define('PUN_ACTIVE_PAGE', 'admin');
+ require PUN_ROOT.'header.php';
+
+ generate_admin_menu('categories');
+
+?>
+ <div class="blockform">
+ <h2><span><?php echo $lang_admin_categories['Delete category head'] ?></span></h2>
+ <div class="box">
+ <form method="post" action="admin_categories.php">
+ <div class="inform">
+ <input type="hidden" name="cat_to_delete" value="<?php echo $cat_to_delete ?>" />
+ <fieldset>
+ <legend><?php echo $lang_admin_categories['Confirm delete subhead'] ?></legend>
+ <div class="infldset">
+ <p><?php printf($lang_admin_categories['Confirm delete info'], pun_htmlspecialchars($cat_name)) ?></p>
+ <p class="warntext"><?php echo $lang_admin_categories['Delete category warn'] ?></p>
+ </div>
+ </fieldset>
+ </div>
+ <p class="buttons"><input type="submit" name="del_cat_comply" value="<?php echo $lang_admin_common['Delete'] ?>" /><a href="javascript:history.go(-1)"><?php echo $lang_admin_common['Go back'] ?></a></p>
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+</div>
+<?php
+
+ require PUN_ROOT.'footer.php';
+ }
+}
+
+else if (isset($_POST['update'])) // Change position and name of the categories
+{
+ confirm_referrer('admin_categories.php');
+
+ $categories = $_POST['cat'];
+ if (empty($categories))
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+ foreach ($categories as $cat_id => $cur_cat)
+ {
+ $cur_cat['name'] = pun_trim($cur_cat['name']);
+ $cur_cat['order'] = pun_trim($cur_cat['order']);
+
+ if ($cur_cat['name'] == '')
+ message($lang_admin_categories['Must enter name message']);
+
+ if ($cur_cat['order'] == '' || preg_match('%[^0-9]%', $cur_cat['order']))
+ message($lang_admin_categories['Must enter integer message']);
+
+ $db->query('UPDATE '.$db->prefix.'categories SET cat_name=\''.$db->escape($cur_cat['name']).'\', disp_position='.$cur_cat['order'].' WHERE id='.intval($cat_id)) or error('Unable to update category', __FILE__, __LINE__, $db->error());
+ }
+
+ // Regenerate the quick jump cache
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_quickjump_cache();
+
+ redirect('admin_categories.php', $lang_admin_categories['Categories updated redirect']);
+}
+
+// Generate an array with all categories
+$result = $db->query('SELECT id, cat_name, disp_position FROM '.$db->prefix.'categories ORDER BY disp_position') or error('Unable to fetch category list', __FILE__, __LINE__, $db->error());
+$num_cats = $db->num_rows($result);
+
+for ($i = 0; $i < $num_cats; ++$i)
+ $cat_list[] = $db->fetch_assoc($result);
+
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Categories']);
+define('PUN_ACTIVE_PAGE', 'admin');
+require PUN_ROOT.'header.php';
+
+generate_admin_menu('categories');
+
+?>
+ <div class="blockform">
+ <h2><span><?php echo $lang_admin_categories['Add categories head'] ?></span></h2>
+ <div class="box">
+ <form method="post" action="admin_categories.php">
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_categories['Add categories subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_categories['Add category label'] ?><div><input type="submit" name="add_cat" value="<?php echo $lang_admin_categories['Add new submit'] ?>" tabindex="2" /></div></th>
+ <td>
+ <input type="text" name="new_cat_name" size="35" maxlength="80" tabindex="1" />
+ <span><?php printf($lang_admin_categories['Add category help'], '<a href="admin_forums.php">'.$lang_admin_common['Forums'].'</a>') ?></span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ </form>
+ </div>
+
+<?php if ($num_cats): ?> <h2 class="block2"><span><?php echo $lang_admin_categories['Delete categories head'] ?></span></h2>
+ <div class="box">
+ <form method="post" action="admin_categories.php">
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_categories['Delete categories subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_categories['Delete category label'] ?><div><input type="submit" name="del_cat" value="<?php echo $lang_admin_common['Delete'] ?>" tabindex="4" /></div></th>
+ <td>
+ <select name="cat_to_delete" tabindex="3">
+<?php
+
+ foreach ($cat_list as $cur_cat)
+ echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$cur_cat['id'].'">'.pun_htmlspecialchars($cur_cat['cat_name']).'</option>'."\n";
+
+?>
+ </select>
+ <span><?php echo $lang_admin_categories['Delete category help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ </form>
+ </div>
+<?php endif; ?>
+
+<?php if ($num_cats): ?> <h2 class="block2"><span><?php echo $lang_admin_categories['Edit categories head'] ?></span></h2>
+ <div class="box">
+ <form method="post" action="admin_categories.php">
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_categories['Edit categories subhead'] ?></legend>
+ <div class="infldset">
+ <table id="categoryedit">
+ <thead>
+ <tr>
+ <th class="tcl" scope="col"><?php echo $lang_admin_categories['Category name label'] ?></th>
+ <th scope="col"><?php echo $lang_admin_categories['Category position label'] ?></th>
+ </tr>
+ </thead>
+ <tbody>
+<?php
+
+ foreach ($cat_list as $cur_cat)
+ {
+
+?>
+ <tr>
+ <td class="tcl"><input type="text" name="cat[<?php echo $cur_cat['id'] ?>][name]" value="<?php echo pun_htmlspecialchars($cur_cat['cat_name']) ?>" size="35" maxlength="80" /></td>
+ <td><input type="text" name="cat[<?php echo $cur_cat['id'] ?>][order]" value="<?php echo $cur_cat['disp_position'] ?>" size="3" maxlength="3" /></td>
+ </tr>
+<?php
+
+ }
+
+?>
+ </tbody>
+ </table>
+ <div class="fsetsubmit"><input type="submit" name="update" value="<?php echo $lang_admin_common['Update'] ?>" /></div>
+ </div>
+ </fieldset>
+ </div>
+ </form>
+ </div>
+<?php endif; ?> </div>
+ <div class="clearer"></div>
+</div>
+<?php
+
+require PUN_ROOT.'footer.php';
diff --git a/admin_censoring.php b/admin_censoring.php
new file mode 100644
index 0000000..94a4f0a
--- /dev/null
+++ b/admin_censoring.php
@@ -0,0 +1,168 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Tell header.php to use the admin template
+define('PUN_ADMIN_CONSOLE', 1);
+
+define('PUN_ROOT', dirname(__FILE__).'/');
+require PUN_ROOT.'include/common.php';
+require PUN_ROOT.'include/common_admin.php';
+
+
+if ($pun_user['g_id'] != PUN_ADMIN)
+ message($lang_common['No permission'], false, '403 Forbidden');
+
+// Load the admin_censoring.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_censoring.php';
+
+// Add a censor word
+if (isset($_POST['add_word']))
+{
+ confirm_referrer('admin_censoring.php');
+
+ $search_for = pun_trim($_POST['new_search_for']);
+ $replace_with = pun_trim($_POST['new_replace_with']);
+
+ if ($search_for == '')
+ message($lang_admin_censoring['Must enter word message']);
+
+ $db->query('INSERT INTO '.$db->prefix.'censoring (search_for, replace_with) VALUES (\''.$db->escape($search_for).'\', \''.$db->escape($replace_with).'\')') or error('Unable to add censor word', __FILE__, __LINE__, $db->error());
+
+ // Regenerate the censoring cache
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_censoring_cache();
+
+ redirect('admin_censoring.php', $lang_admin_censoring['Word added redirect']);
+}
+
+// Update a censor word
+else if (isset($_POST['update']))
+{
+ confirm_referrer('admin_censoring.php');
+
+ $id = intval(key($_POST['update']));
+
+ $search_for = pun_trim($_POST['search_for'][$id]);
+ $replace_with = pun_trim($_POST['replace_with'][$id]);
+
+ if ($search_for == '')
+ message($lang_admin_censoring['Must enter word message']);
+
+ $db->query('UPDATE '.$db->prefix.'censoring SET search_for=\''.$db->escape($search_for).'\', replace_with=\''.$db->escape($replace_with).'\' WHERE id='.$id) or error('Unable to update censor word', __FILE__, __LINE__, $db->error());
+
+ // Regenerate the censoring cache
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_censoring_cache();
+
+ redirect('admin_censoring.php', $lang_admin_censoring['Word updated redirect']);
+}
+
+// Remove a censor word
+else if (isset($_POST['remove']))
+{
+ confirm_referrer('admin_censoring.php');
+
+ $id = intval(key($_POST['remove']));
+
+ $db->query('DELETE FROM '.$db->prefix.'censoring WHERE id='.$id) or error('Unable to delete censor word', __FILE__, __LINE__, $db->error());
+
+ // Regenerate the censoring cache
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_censoring_cache();
+
+ redirect('admin_censoring.php', $lang_admin_censoring['Word removed redirect']);
+}
+
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Censoring']);
+$focus_element = array('censoring', 'new_search_for');
+define('PUN_ACTIVE_PAGE', 'admin');
+require PUN_ROOT.'header.php';
+
+generate_admin_menu('censoring');
+
+?>
+ <div class="blockform">
+ <h2><span><?php echo $lang_admin_censoring['Censoring head'] ?></span></h2>
+ <div class="box">
+ <form id="censoring" method="post" action="admin_censoring.php">
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_censoring['Add word subhead'] ?></legend>
+ <div class="infldset">
+ <p><?php echo $lang_admin_censoring['Add word info'].' '.($pun_config['o_censoring'] == '1' ? sprintf($lang_admin_censoring['Censoring enabled'], '<a href="admin_options.php#censoring">'.$lang_admin_common['Options'].'</a>') : sprintf($lang_admin_censoring['Censoring disabled'], '<a href="admin_options.php#censoring">'.$lang_admin_common['Options'].'</a>')) ?></p>
+ <table>
+ <thead>
+ <tr>
+ <th class="tcl" scope="col"><?php echo $lang_admin_censoring['Censored word label'] ?></th>
+ <th class="tc2" scope="col"><?php echo $lang_admin_censoring['Replacement label'] ?></th>
+ <th class="hidehead" scope="col"><?php echo $lang_admin_censoring['Action label'] ?></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td class="tcl"><input type="text" name="new_search_for" size="24" maxlength="60" tabindex="1" /></td>
+ <td class="tc2"><input type="text" name="new_replace_with" size="24" maxlength="60" tabindex="2" /></td>
+ <td><input type="submit" name="add_word" value="<?php echo $lang_admin_common['Add'] ?>" tabindex="3" /></td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_censoring['Edit remove subhead'] ?></legend>
+ <div class="infldset">
+<?php
+
+$result = $db->query('SELECT id, search_for, replace_with FROM '.$db->prefix.'censoring ORDER BY id') or error('Unable to fetch censor word list', __FILE__, __LINE__, $db->error());
+if ($db->num_rows($result))
+{
+
+?>
+ <table>
+ <thead>
+ <tr>
+ <th class="tcl" scope="col"><?php echo $lang_admin_censoring['Censored word label'] ?></th>
+ <th class="tc2" scope="col"><?php echo $lang_admin_censoring['Replacement label'] ?></th>
+ <th class="hidehead" scope="col"><?php echo $lang_admin_censoring['Action label'] ?></th>
+ </tr>
+ </thead>
+ <tbody>
+<?php
+
+ while ($cur_word = $db->fetch_assoc($result))
+ echo "\t\t\t\t\t\t\t\t".'<tr><td class="tcl"><input type="text" name="search_for['.$cur_word['id'].']" value="'.pun_htmlspecialchars($cur_word['search_for']).'" size="24" maxlength="60" /></td><td class="tc2"><input type="text" name="replace_with['.$cur_word['id'].']" value="'.pun_htmlspecialchars($cur_word['replace_with']).'" size="24" maxlength="60" /></td><td><input type="submit" name="update['.$cur_word['id'].']" value="'.$lang_admin_common['Update'].'" />&#160;<input type="submit" name="remove['.$cur_word['id'].']" value="'.$lang_admin_common['Remove'].'" /></td></tr>'."\n";
+
+?>
+ </tbody>
+ </table>
+<?php
+
+}
+else
+ echo "\t\t\t\t\t\t\t".'<p>'.$lang_admin_censoring['No words in list'].'</p>'."\n";
+
+?>
+ </div>
+ </fieldset>
+ </div>
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+</div>
+<?php
+
+require PUN_ROOT.'footer.php';
diff --git a/admin_forums.php b/admin_forums.php
new file mode 100644
index 0000000..c39bf74
--- /dev/null
+++ b/admin_forums.php
@@ -0,0 +1,501 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Tell header.php to use the admin template
+define('PUN_ADMIN_CONSOLE', 1);
+
+define('PUN_ROOT', dirname(__FILE__).'/');
+require PUN_ROOT.'include/common.php';
+require PUN_ROOT.'include/common_admin.php';
+
+
+if ($pun_user['g_id'] != PUN_ADMIN)
+ message($lang_common['No permission'], false, '403 Forbidden');
+
+// Load the admin_forums.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_forums.php';
+
+// Add a "default" forum
+if (isset($_POST['add_forum']))
+{
+ confirm_referrer('admin_forums.php');
+
+ $add_to_cat = intval($_POST['add_to_cat']);
+ if ($add_to_cat < 1)
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+ $db->query('INSERT INTO '.$db->prefix.'forums (forum_name, cat_id) VALUES(\''.$db->escape($lang_admin_forums['New forum']).'\', '.$add_to_cat.')') or error('Unable to create forum', __FILE__, __LINE__, $db->error());
+ $new_fid = $db->insert_id();
+
+ // Regenerate the quick jump cache
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_quickjump_cache();
+
+ redirect('admin_forums.php?edit_forum='.$new_fid, $lang_admin_forums['Forum added redirect']);
+}
+
+// Delete a forum
+else if (isset($_GET['del_forum']))
+{
+ confirm_referrer('admin_forums.php');
+
+ $forum_id = intval($_GET['del_forum']);
+ if ($forum_id < 1)
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+ if (isset($_POST['del_forum_comply'])) // Delete a forum with all posts
+ {
+ @set_time_limit(0);
+
+ // Prune all posts and topics
+ prune($forum_id, 1, -1);
+
+ // Locate any "orphaned redirect topics" and delete them
+ $result = $db->query('SELECT t1.id FROM '.$db->prefix.'topics AS t1 LEFT JOIN '.$db->prefix.'topics AS t2 ON t1.moved_to=t2.id WHERE t2.id IS NULL AND t1.moved_to IS NOT NULL') or error('Unable to fetch redirect topics', __FILE__, __LINE__, $db->error());
+ $num_orphans = $db->num_rows($result);
+
+ if ($num_orphans)
+ {
+ for ($i = 0; $i < $num_orphans; ++$i)
+ $orphans[] = $db->result($result, $i);
+
+ $db->query('DELETE FROM '.$db->prefix.'topics WHERE id IN('.implode(',', $orphans).')') or error('Unable to delete redirect topics', __FILE__, __LINE__, $db->error());
+ }
+
+ // Delete the forum and any forum specific group permissions
+ $db->query('DELETE FROM '.$db->prefix.'forums WHERE id='.$forum_id) or error('Unable to delete forum', __FILE__, __LINE__, $db->error());
+ $db->query('DELETE FROM '.$db->prefix.'forum_perms WHERE forum_id='.$forum_id) or error('Unable to delete group forum permissions', __FILE__, __LINE__, $db->error());
+
+ // Delete any subscriptions for this forum
+ $db->query('DELETE FROM '.$db->prefix.'forum_subscriptions WHERE forum_id='.$forum_id) or error('Unable to delete subscriptions', __FILE__, __LINE__, $db->error());
+
+ // Regenerate the quick jump cache
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_quickjump_cache();
+
+ redirect('admin_forums.php', $lang_admin_forums['Forum deleted redirect']);
+ }
+ else // If the user hasn't confirmed the delete
+ {
+ $result = $db->query('SELECT forum_name FROM '.$db->prefix.'forums WHERE id='.$forum_id) or error('Unable to fetch forum info', __FILE__, __LINE__, $db->error());
+ $forum_name = pun_htmlspecialchars($db->result($result));
+
+ $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Forums']);
+ define('PUN_ACTIVE_PAGE', 'admin');
+ require PUN_ROOT.'header.php';
+
+ generate_admin_menu('forums');
+
+?>
+ <div class="blockform">
+ <h2><span><?php echo $lang_admin_forums['Confirm delete head'] ?></span></h2>
+ <div class="box">
+ <form method="post" action="admin_forums.php?del_forum=<?php echo $forum_id ?>">
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_forums['Confirm delete subhead'] ?></legend>
+ <div class="infldset">
+ <p><?php printf($lang_admin_forums['Confirm delete info'], $forum_name) ?></p>
+ <p class="warntext"><?php echo $lang_admin_forums['Confirm delete warn'] ?></p>
+ </div>
+ </fieldset>
+ </div>
+ <p class="buttons"><input type="submit" name="del_forum_comply" value="<?php echo $lang_admin_common['Delete'] ?>" /><a href="javascript:history.go(-1)"><?php echo $lang_admin_common['Go back'] ?></a></p>
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+</div>
+<?php
+
+ require PUN_ROOT.'footer.php';
+ }
+}
+
+// Update forum positions
+else if (isset($_POST['update_positions']))
+{
+ confirm_referrer('admin_forums.php');
+
+ foreach ($_POST['position'] as $forum_id => $disp_position)
+ {
+ $disp_position = trim($disp_position);
+ if ($disp_position == '' || preg_match('%[^0-9]%', $disp_position))
+ message($lang_admin_forums['Must be integer message']);
+
+ $db->query('UPDATE '.$db->prefix.'forums SET disp_position='.$disp_position.' WHERE id='.intval($forum_id)) or error('Unable to update forum', __FILE__, __LINE__, $db->error());
+ }
+
+ // Regenerate the quick jump cache
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_quickjump_cache();
+
+ redirect('admin_forums.php', $lang_admin_forums['Forums updated redirect']);
+}
+
+else if (isset($_GET['edit_forum']))
+{
+ $forum_id = intval($_GET['edit_forum']);
+ if ($forum_id < 1)
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+ // Update group permissions for $forum_id
+ if (isset($_POST['save']))
+ {
+ confirm_referrer('admin_forums.php');
+
+ // Start with the forum details
+ $forum_name = pun_trim($_POST['forum_name']);
+ $forum_desc = pun_linebreaks(pun_trim($_POST['forum_desc']));
+ $cat_id = intval($_POST['cat_id']);
+ $sort_by = intval($_POST['sort_by']);
+ $redirect_url = isset($_POST['redirect_url']) ? pun_trim($_POST['redirect_url']) : null;
+
+ if ($forum_name == '')
+ message($lang_admin_forums['Must enter name message']);
+
+ if ($cat_id < 1)
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+ $forum_desc = ($forum_desc != '') ? '\''.$db->escape($forum_desc).'\'' : 'NULL';
+ $redirect_url = ($redirect_url != '') ? '\''.$db->escape($redirect_url).'\'' : 'NULL';
+
+ $db->query('UPDATE '.$db->prefix.'forums SET forum_name=\''.$db->escape($forum_name).'\', forum_desc='.$forum_desc.', redirect_url='.$redirect_url.', sort_by='.$sort_by.', cat_id='.$cat_id.' WHERE id='.$forum_id) or error('Unable to update forum', __FILE__, __LINE__, $db->error());
+
+ // Now let's deal with the permissions
+ if (isset($_POST['read_forum_old']))
+ {
+ $result = $db->query('SELECT g_id, g_read_board, g_post_replies, g_post_topics FROM '.$db->prefix.'groups WHERE g_id!='.PUN_ADMIN) or error('Unable to fetch user group list', __FILE__, __LINE__, $db->error());
+ while ($cur_group = $db->fetch_assoc($result))
+ {
+ $read_forum_new = ($cur_group['g_read_board'] == '1') ? isset($_POST['read_forum_new'][$cur_group['g_id']]) ? '1' : '0' : intval($_POST['read_forum_old'][$cur_group['g_id']]);
+ $post_replies_new = isset($_POST['post_replies_new'][$cur_group['g_id']]) ? '1' : '0';
+ $post_topics_new = isset($_POST['post_topics_new'][$cur_group['g_id']]) ? '1' : '0';
+
+ // Check if the new settings differ from the old
+ if ($read_forum_new != $_POST['read_forum_old'][$cur_group['g_id']] || $post_replies_new != $_POST['post_replies_old'][$cur_group['g_id']] || $post_topics_new != $_POST['post_topics_old'][$cur_group['g_id']])
+ {
+ // If the new settings are identical to the default settings for this group, delete its row in forum_perms
+ if ($read_forum_new == '1' && $post_replies_new == $cur_group['g_post_replies'] && $post_topics_new == $cur_group['g_post_topics'])
+ $db->query('DELETE FROM '.$db->prefix.'forum_perms WHERE group_id='.$cur_group['g_id'].' AND forum_id='.$forum_id) or error('Unable to delete group forum permissions', __FILE__, __LINE__, $db->error());
+ else
+ {
+ // Run an UPDATE and see if it affected a row, if not, INSERT
+ $db->query('UPDATE '.$db->prefix.'forum_perms SET read_forum='.$read_forum_new.', post_replies='.$post_replies_new.', post_topics='.$post_topics_new.' WHERE group_id='.$cur_group['g_id'].' AND forum_id='.$forum_id) or error('Unable to insert group forum permissions', __FILE__, __LINE__, $db->error());
+ if (!$db->affected_rows())
+ $db->query('INSERT INTO '.$db->prefix.'forum_perms (group_id, forum_id, read_forum, post_replies, post_topics) VALUES('.$cur_group['g_id'].', '.$forum_id.', '.$read_forum_new.', '.$post_replies_new.', '.$post_topics_new.')') or error('Unable to insert group forum permissions', __FILE__, __LINE__, $db->error());
+ }
+ }
+ }
+ }
+
+ // Regenerate the quick jump cache
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_quickjump_cache();
+
+ redirect('admin_forums.php', $lang_admin_forums['Forum updated redirect']);
+ }
+ else if (isset($_POST['revert_perms']))
+ {
+ confirm_referrer('admin_forums.php');
+
+ $db->query('DELETE FROM '.$db->prefix.'forum_perms WHERE forum_id='.$forum_id) or error('Unable to delete group forum permissions', __FILE__, __LINE__, $db->error());
+
+ // Regenerate the quick jump cache
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_quickjump_cache();
+
+ redirect('admin_forums.php?edit_forum='.$forum_id, $lang_admin_forums['Perms reverted redirect']);
+ }
+
+ // Fetch forum info
+ $result = $db->query('SELECT id, forum_name, forum_desc, redirect_url, num_topics, sort_by, cat_id FROM '.$db->prefix.'forums WHERE id='.$forum_id) or error('Unable to fetch forum info', __FILE__, __LINE__, $db->error());
+ if (!$db->num_rows($result))
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+ $cur_forum = $db->fetch_assoc($result);
+
+ $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Forums']);
+ define('PUN_ACTIVE_PAGE', 'admin');
+ require PUN_ROOT.'header.php';
+
+ generate_admin_menu('forums');
+
+?>
+ <div class="blockform">
+ <h2><span><?php echo $lang_admin_forums['Edit forum head'] ?></span></h2>
+ <div class="box">
+ <form id="edit_forum" method="post" action="admin_forums.php?edit_forum=<?php echo $forum_id ?>">
+ <p class="submittop"><input type="submit" name="save" value="<?php echo $lang_admin_common['Save changes'] ?>" tabindex="6" /></p>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_forums['Edit details subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_forums['Forum name label'] ?></th>
+ <td><input type="text" name="forum_name" size="35" maxlength="80" value="<?php echo pun_htmlspecialchars($cur_forum['forum_name']) ?>" tabindex="1" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_forums['Forum description label'] ?></th>
+ <td><textarea name="forum_desc" rows="3" cols="50" tabindex="2"><?php echo pun_htmlspecialchars($cur_forum['forum_desc']) ?></textarea></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_forums['Category label'] ?></th>
+ <td>
+ <select name="cat_id" tabindex="3">
+<?php
+
+ $result = $db->query('SELECT id, cat_name FROM '.$db->prefix.'categories ORDER BY disp_position') or error('Unable to fetch category list', __FILE__, __LINE__, $db->error());
+ while ($cur_cat = $db->fetch_assoc($result))
+ {
+ $selected = ($cur_cat['id'] == $cur_forum['cat_id']) ? ' selected="selected"' : '';
+ echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$cur_cat['id'].'"'.$selected.'>'.pun_htmlspecialchars($cur_cat['cat_name']).'</option>'."\n";
+ }
+
+?>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_forums['Sort by label'] ?></th>
+ <td>
+ <select name="sort_by" tabindex="4">
+ <option value="0"<?php if ($cur_forum['sort_by'] == '0') echo ' selected="selected"' ?>><?php echo $lang_admin_forums['Last post'] ?></option>
+ <option value="1"<?php if ($cur_forum['sort_by'] == '1') echo ' selected="selected"' ?>><?php echo $lang_admin_forums['Topic start'] ?></option>
+ <option value="2"<?php if ($cur_forum['sort_by'] == '2') echo ' selected="selected"' ?>><?php echo $lang_admin_forums['Subject'] ?></option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_forums['Redirect label'] ?></th>
+ <td><?php echo ($cur_forum['num_topics']) ? $lang_admin_forums['Redirect help'] : '<input type="text" name="redirect_url" size="45" maxlength="100" value="'.pun_htmlspecialchars($cur_forum['redirect_url']).'" tabindex="5" />'; ?></td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_forums['Group permissions subhead'] ?></legend>
+ <div class="infldset">
+ <p><?php printf($lang_admin_forums['Group permissions info'], '<a href="admin_groups.php">'.$lang_admin_common['User groups'].'</a>') ?></p>
+ <table id="forumperms">
+ <thead>
+ <tr>
+ <th class="atcl">&#160;</th>
+ <th><?php echo $lang_admin_forums['Read forum label'] ?></th>
+ <th><?php echo $lang_admin_forums['Post replies label'] ?></th>
+ <th><?php echo $lang_admin_forums['Post topics label'] ?></th>
+ </tr>
+ </thead>
+ <tbody>
+<?php
+
+ $result = $db->query('SELECT g.g_id, g.g_title, g.g_read_board, g.g_post_replies, g.g_post_topics, fp.read_forum, fp.post_replies, fp.post_topics FROM '.$db->prefix.'groups AS g LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (g.g_id=fp.group_id AND fp.forum_id='.$forum_id.') WHERE g.g_id!='.PUN_ADMIN.' ORDER BY g.g_id') or error('Unable to fetch group forum permission list', __FILE__, __LINE__, $db->error());
+
+ $cur_index = 7;
+
+ while ($cur_perm = $db->fetch_assoc($result))
+ {
+ $read_forum = ($cur_perm['read_forum'] != '0') ? true : false;
+ $post_replies = (($cur_perm['g_post_replies'] == '0' && $cur_perm['post_replies'] == '1') || ($cur_perm['g_post_replies'] == '1' && $cur_perm['post_replies'] != '0')) ? true : false;
+ $post_topics = (($cur_perm['g_post_topics'] == '0' && $cur_perm['post_topics'] == '1') || ($cur_perm['g_post_topics'] == '1' && $cur_perm['post_topics'] != '0')) ? true : false;
+
+ // Determine if the current settings differ from the default or not
+ $read_forum_def = ($cur_perm['read_forum'] == '0') ? false : true;
+ $post_replies_def = (($post_replies && $cur_perm['g_post_replies'] == '0') || (!$post_replies && ($cur_perm['g_post_replies'] == '' || $cur_perm['g_post_replies'] == '1'))) ? false : true;
+ $post_topics_def = (($post_topics && $cur_perm['g_post_topics'] == '0') || (!$post_topics && ($cur_perm['g_post_topics'] == '' || $cur_perm['g_post_topics'] == '1'))) ? false : true;
+
+?>
+ <tr>
+ <th class="atcl"><?php echo pun_htmlspecialchars($cur_perm['g_title']) ?></th>
+ <td<?php if (!$read_forum_def) echo ' class="nodefault"'; ?>>
+ <input type="hidden" name="read_forum_old[<?php echo $cur_perm['g_id'] ?>]" value="<?php echo ($read_forum) ? '1' : '0'; ?>" />
+ <input type="checkbox" name="read_forum_new[<?php echo $cur_perm['g_id'] ?>]" value="1"<?php echo ($read_forum) ? ' checked="checked"' : ''; ?><?php echo ($cur_perm['g_read_board'] == '0') ? ' disabled="disabled"' : ''; ?> tabindex="<?php echo $cur_index++ ?>" />
+ </td>
+ <td<?php if (!$post_replies_def && $cur_forum['redirect_url'] == '') echo ' class="nodefault"'; ?>>
+ <input type="hidden" name="post_replies_old[<?php echo $cur_perm['g_id'] ?>]" value="<?php echo ($post_replies) ? '1' : '0'; ?>" />
+ <input type="checkbox" name="post_replies_new[<?php echo $cur_perm['g_id'] ?>]" value="1"<?php echo ($post_replies) ? ' checked="checked"' : ''; ?><?php echo ($cur_forum['redirect_url'] != '') ? ' disabled="disabled"' : ''; ?> tabindex="<?php echo $cur_index++ ?>" />
+ </td>
+ <td<?php if (!$post_topics_def && $cur_forum['redirect_url'] == '') echo ' class="nodefault"'; ?>>
+ <input type="hidden" name="post_topics_old[<?php echo $cur_perm['g_id'] ?>]" value="<?php echo ($post_topics) ? '1' : '0'; ?>" />
+ <input type="checkbox" name="post_topics_new[<?php echo $cur_perm['g_id'] ?>]" value="1"<?php echo ($post_topics) ? ' checked="checked"' : ''; ?><?php echo ($cur_forum['redirect_url'] != '') ? ' disabled="disabled"' : ''; ?> tabindex="<?php echo $cur_index++ ?>" />
+ </td>
+ </tr>
+<?php
+
+ }
+
+?>
+ </tbody>
+ </table>
+ <div class="fsetsubmit"><input type="submit" name="revert_perms" value="<?php echo $lang_admin_forums['Revert to default'] ?>" tabindex="<?php echo $cur_index++ ?>" /></div>
+ </div>
+ </fieldset>
+ </div>
+ <p class="submitend"><input type="submit" name="save" value="<?php echo $lang_admin_common['Save changes'] ?>" tabindex="<?php echo $cur_index++ ?>" /></p>
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+</div>
+
+<?php
+
+ require PUN_ROOT.'footer.php';
+}
+
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Forums']);
+define('PUN_ACTIVE_PAGE', 'admin');
+require PUN_ROOT.'header.php';
+
+generate_admin_menu('forums');
+
+?>
+ <div class="blockform">
+ <h2><span><?php echo $lang_admin_forums['Add forum head'] ?></span></h2>
+ <div class="box">
+ <form method="post" action="admin_forums.php?action=adddel">
+<?php
+
+$result = $db->query('SELECT id, cat_name FROM '.$db->prefix.'categories ORDER BY disp_position') or error('Unable to fetch category list', __FILE__, __LINE__, $db->error());
+
+if ($db->num_rows($result) > 0)
+{
+
+?>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_forums['Create new subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_forums['Add forum label'] ?><div><input type="submit" name="add_forum" value="<?php echo $lang_admin_forums['Add forum'] ?>" tabindex="2" /></div></th>
+ <td>
+ <select name="add_to_cat" tabindex="1">
+<?php
+
+ while ($cur_cat = $db->fetch_assoc($result))
+ echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$cur_cat['id'].'">'.pun_htmlspecialchars($cur_cat['cat_name']).'</option>'."\n";
+
+?>
+ </select>
+ <span><?php echo $lang_admin_forums['Add forum help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+<?php
+
+}
+else
+{
+
+?>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_common['None'] ?></legend>
+ <div class="infldset">
+ <p><?php echo $lang_admin_forums['No categories exist'] ?></p>
+ </div>
+ </fieldset>
+ </div>
+<?php
+
+}
+
+?>
+ </form>
+ </div>
+<?php
+
+// Display all the categories and forums
+$result = $db->query('SELECT c.id AS cid, c.cat_name, f.id AS fid, f.forum_name, f.disp_position FROM '.$db->prefix.'categories AS c INNER JOIN '.$db->prefix.'forums AS f ON c.id=f.cat_id ORDER BY c.disp_position, c.id, f.disp_position') or error('Unable to fetch category/forum list', __FILE__, __LINE__, $db->error());
+
+if ($db->num_rows($result) > 0)
+{
+
+?>
+ <h2 class="block2"><span><?php echo $lang_admin_forums['Edit forums head'] ?></span></h2>
+ <div class="box">
+ <form id="edforum" method="post" action="admin_forums.php?action=edit">
+ <p class="submittop"><input type="submit" name="update_positions" value="<?php echo $lang_admin_forums['Update positions'] ?>" tabindex="3" /></p>
+<?php
+
+$cur_index = 4;
+
+$cur_category = 0;
+while ($cur_forum = $db->fetch_assoc($result))
+{
+ if ($cur_forum['cid'] != $cur_category) // A new category since last iteration?
+ {
+ if ($cur_category != 0)
+ echo "\t\t\t\t\t\t\t".'</tbody>'."\n\t\t\t\t\t\t\t".'</table>'."\n\t\t\t\t\t\t".'</div>'."\n\t\t\t\t\t".'</fieldset>'."\n\t\t\t\t".'</div>'."\n";
+
+?>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_forums['Category subhead'] ?> <?php echo pun_htmlspecialchars($cur_forum['cat_name']) ?></legend>
+ <div class="infldset">
+ <table>
+ <thead>
+ <tr>
+ <th class="tcl"><?php echo $lang_admin_common['Action'] ?></th>
+ <th class="tc2"><?php echo $lang_admin_forums['Position label'] ?></th>
+ <th class="tcr"><?php echo $lang_admin_forums['Forum label'] ?></th>
+ </tr>
+ </thead>
+ <tbody>
+<?php
+
+ $cur_category = $cur_forum['cid'];
+ }
+
+?>
+ <tr>
+ <td class="tcl"><a href="admin_forums.php?edit_forum=<?php echo $cur_forum['fid'] ?>" tabindex="<?php echo $cur_index++ ?>"><?php echo $lang_admin_forums['Edit link'] ?></a> | <a href="admin_forums.php?del_forum=<?php echo $cur_forum['fid'] ?>" tabindex="<?php echo $cur_index++ ?>"><?php echo $lang_admin_forums['Delete link'] ?></a></td>
+ <td class="tc2"><input type="text" name="position[<?php echo $cur_forum['fid'] ?>]" size="3" maxlength="3" value="<?php echo $cur_forum['disp_position'] ?>" tabindex="<?php echo $cur_index++ ?>" /></td>
+ <td class="tcr"><strong><?php echo pun_htmlspecialchars($cur_forum['forum_name']) ?></strong></td>
+ </tr>
+<?php
+
+}
+
+?>
+ </tbody>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ <p class="submitend"><input type="submit" name="update_positions" value="<?php echo $lang_admin_forums['Update positions'] ?>" tabindex="<?php echo $cur_index++ ?>" /></p>
+ </form>
+ </div>
+<?php
+
+}
+
+?>
+ </div>
+ <div class="clearer"></div>
+</div>
+<?php
+
+require PUN_ROOT.'footer.php';
diff --git a/admin_groups.php b/admin_groups.php
new file mode 100644
index 0000000..db205d7
--- /dev/null
+++ b/admin_groups.php
@@ -0,0 +1,645 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Tell header.php to use the admin template
+define('PUN_ADMIN_CONSOLE', 1);
+
+define('PUN_ROOT', dirname(__FILE__).'/');
+require PUN_ROOT.'include/common.php';
+require PUN_ROOT.'include/common_admin.php';
+
+
+if ($pun_user['g_id'] != PUN_ADMIN)
+ message($lang_common['No permission'], false, '403 Forbidden');
+
+// Load the admin_censoring.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_groups.php';
+
+
+// Fetch all groups
+$result = $db->query('SELECT * FROM '.$db->prefix.'groups ORDER BY g_id') or error('Unable to fetch user groups', __FILE__, __LINE__, $db->error());
+$groups = array();
+while ($cur_group = $db->fetch_assoc($result))
+ $groups[$cur_group['g_id']] = $cur_group;
+
+// Add/edit a group (stage 1)
+if (isset($_POST['add_group']) || isset($_GET['edit_group']))
+{
+ if (isset($_POST['add_group']))
+ {
+ $base_group = intval($_POST['base_group']);
+ $group = $groups[$base_group];
+
+ $mode = 'add';
+ }
+ else // We are editing a group
+ {
+ $group_id = intval($_GET['edit_group']);
+ if ($group_id < 1 || !isset($groups[$group_id]))
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+ $group = $groups[$group_id];
+
+ $mode = 'edit';
+ }
+
+
+ $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['User groups']);
+ $required_fields = array('req_title' => $lang_admin_groups['Group title label']);
+ $focus_element = array('groups2', 'req_title');
+ define('PUN_ACTIVE_PAGE', 'admin');
+ require PUN_ROOT.'header.php';
+
+ generate_admin_menu('groups');
+
+?>
+ <div class="blockform">
+ <h2><span><?php echo $lang_admin_groups['Group settings head'] ?></span></h2>
+ <div class="box">
+ <form id="groups2" method="post" action="admin_groups.php" onsubmit="return process_form(this)">
+ <p class="submittop"><input type="submit" name="add_edit_group" value="<?php echo $lang_admin_common['Save'] ?>" /></p>
+ <div class="inform">
+ <input type="hidden" name="mode" value="<?php echo $mode ?>" />
+<?php if ($mode == 'edit'): ?> <input type="hidden" name="group_id" value="<?php echo $group_id ?>" />
+<?php endif; ?><?php if ($mode == 'add'): ?> <input type="hidden" name="base_group" value="<?php echo $base_group ?>" />
+<?php endif; ?> <fieldset>
+ <legend><?php echo $lang_admin_groups['Group settings subhead'] ?></legend>
+ <div class="infldset">
+ <p><?php echo $lang_admin_groups['Group settings info'] ?></p>
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_groups['Group title label'] ?></th>
+ <td>
+ <input type="text" name="req_title" size="25" maxlength="50" value="<?php if ($mode == 'edit') echo pun_htmlspecialchars($group['g_title']); ?>" tabindex="1" />
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_groups['User title label'] ?></th>
+ <td>
+ <input type="text" name="user_title" size="25" maxlength="50" value="<?php echo pun_htmlspecialchars($group['g_user_title']) ?>" tabindex="2" />
+ <span><?php printf($lang_admin_groups['User title help'], ($group['g_id'] != PUN_GUEST ? $lang_common['Member'] : $lang_common['Guest'])) ?></span>
+ </td>
+ </tr>
+<?php if ($group['g_id'] != PUN_ADMIN): if ($group['g_id'] != PUN_GUEST): ?> <tr>
+ <th scope="row"><?php echo $lang_admin_groups['Promote users label'] ?></th>
+ <td>
+ <select name="promote_next_group" tabindex="3">
+ <option value="0"><?php echo $lang_admin_groups['Disable promotion'] ?></option>
+<?php
+
+foreach ($groups as $cur_group)
+{
+ if (($cur_group['g_id'] != $group['g_id'] || $mode == 'add') && $cur_group['g_id'] != PUN_ADMIN && $cur_group['g_id'] != PUN_GUEST)
+ {
+ if ($cur_group['g_id'] == $group['g_promote_next_group'])
+ echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$cur_group['g_id'].'" selected="selected">'.pun_htmlspecialchars($cur_group['g_title']).'</option>'."\n";
+ else
+ echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$cur_group['g_id'].'">'.pun_htmlspecialchars($cur_group['g_title']).'</option>'."\n";
+ }
+}
+
+?>
+ </select>
+ <input type="text" name="promote_min_posts" size="5" maxlength="10" value="<?php echo pun_htmlspecialchars($group['g_promote_min_posts']) ?>" tabindex="4" />
+ <span><?php printf($lang_admin_groups['Promote users help'], $lang_admin_groups['Disable promotion']) ?></span>
+ </td>
+ </tr>
+<?php if ($mode != 'edit' || $pun_config['o_default_user_group'] != $group['g_id']): ?> <tr>
+ <th scope="row"> <?php echo $lang_admin_groups['Mod privileges label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="moderator" value="1"<?php if ($group['g_moderator'] == '1') echo ' checked="checked"' ?> tabindex="5" />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="moderator" value="0"<?php if ($group['g_moderator'] == '0') echo ' checked="checked"' ?> tabindex="6" />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_groups['Mod privileges help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_groups['Edit profile label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="mod_edit_users" value="1"<?php if ($group['g_mod_edit_users'] == '1') echo ' checked="checked"' ?> tabindex="7" />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="mod_edit_users" value="0"<?php if ($group['g_mod_edit_users'] == '0') echo ' checked="checked"' ?> tabindex="8" />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_groups['Edit profile help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_groups['Rename users label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="mod_rename_users" value="1"<?php if ($group['g_mod_rename_users'] == '1') echo ' checked="checked"' ?> tabindex="9" />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="mod_rename_users" value="0"<?php if ($group['g_mod_rename_users'] == '0') echo ' checked="checked"' ?> tabindex="10" />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_groups['Rename users help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_groups['Change passwords label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="mod_change_passwords" value="1"<?php if ($group['g_mod_change_passwords'] == '1') echo ' checked="checked"' ?> tabindex="11" />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="mod_change_passwords" value="0"<?php if ($group['g_mod_change_passwords'] == '0') echo ' checked="checked"' ?> tabindex="12" />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_groups['Change passwords help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_groups['Mod promote users label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="mod_promote_users" value="1"<?php if ($group['g_mod_promote_users'] == '1') echo ' checked="checked"' ?> tabindex="13" />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="mod_promote_users" value="0"<?php if ($group['g_mod_promote_users'] == '0') echo ' checked="checked"' ?> tabindex="14" />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_groups['Mod promote users help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_groups['Ban users label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="mod_ban_users" value="1"<?php if ($group['g_mod_ban_users'] == '1') echo ' checked="checked"' ?> tabindex="15" />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="mod_ban_users" value="0"<?php if ($group['g_mod_ban_users'] == '0') echo ' checked="checked"' ?> tabindex="16" />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_groups['Ban users help'] ?></span>
+ </td>
+ </tr>
+<?php endif; endif; ?> <tr>
+ <th scope="row"><?php echo $lang_admin_groups['Read board label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="read_board" value="1"<?php if ($group['g_read_board'] == '1') echo ' checked="checked"' ?> tabindex="17" />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="read_board" value="0"<?php if ($group['g_read_board'] == '0') echo ' checked="checked"' ?> tabindex="18" />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_groups['Read board help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_groups['View user info label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="view_users" value="1"<?php if ($group['g_view_users'] == '1') echo ' checked="checked"' ?> tabindex="19" />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="view_users" value="0"<?php if ($group['g_view_users'] == '0') echo ' checked="checked"' ?> tabindex="20" />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_groups['View user info help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_groups['Post replies label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="post_replies" value="1"<?php if ($group['g_post_replies'] == '1') echo ' checked="checked"' ?> tabindex="21" />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="post_replies" value="0"<?php if ($group['g_post_replies'] == '0') echo ' checked="checked"' ?> tabindex="22" />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_groups['Post replies help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_groups['Post topics label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="post_topics" value="1"<?php if ($group['g_post_topics'] == '1') echo ' checked="checked"' ?> tabindex="23" />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="post_topics" value="0"<?php if ($group['g_post_topics'] == '0') echo ' checked="checked"' ?> tabindex="24" />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_groups['Post topics help'] ?></span>
+ </td>
+ </tr>
+<?php if ($group['g_id'] != PUN_GUEST): ?> <tr>
+ <th scope="row"><?php echo $lang_admin_groups['Edit posts label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="edit_posts" value="1"<?php if ($group['g_edit_posts'] == '1') echo ' checked="checked"' ?> tabindex="25" />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="edit_posts" value="0"<?php if ($group['g_edit_posts'] == '0') echo ' checked="checked"' ?> tabindex="26" />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_groups['Edit posts help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_groups['Delete posts label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="delete_posts" value="1"<?php if ($group['g_delete_posts'] == '1') echo ' checked="checked"' ?> tabindex="27" />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="delete_posts" value="0"<?php if ($group['g_delete_posts'] == '0') echo ' checked="checked"' ?> tabindex="28" />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_groups['Delete posts help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_groups['Delete topics label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="delete_topics" value="1"<?php if ($group['g_delete_topics'] == '1') echo ' checked="checked"' ?> tabindex="29" />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="delete_topics" value="0"<?php if ($group['g_delete_topics'] == '0') echo ' checked="checked"' ?> tabindex="30" />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_groups['Delete topics help'] ?></span>
+ </td>
+ </tr>
+<?php endif; ?> <tr>
+ <th scope="row"><?php echo $lang_admin_groups['Post links label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="post_links" value="1"<?php if ($group['g_post_links'] == '1') echo ' checked="checked"' ?> tabindex="31" />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="post_links" value="0"<?php if ($group['g_post_links'] == '0') echo ' checked="checked"' ?> tabindex="32" />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_groups['Post links help'] ?></span>
+ </td>
+ </tr>
+<?php if ($group['g_id'] != PUN_GUEST): ?> <tr>
+ <th scope="row"><?php echo $lang_admin_groups['Set own title label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="set_title" value="1"<?php if ($group['g_set_title'] == '1') echo ' checked="checked"' ?> tabindex="33" />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="set_title" value="0"<?php if ($group['g_set_title'] == '0') echo ' checked="checked"' ?> tabindex="34" />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_groups['Set own title help'] ?></span>
+ </td>
+ </tr>
+<?php endif; ?> <tr>
+ <th scope="row"><?php echo $lang_admin_groups['User search label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="search" value="1"<?php if ($group['g_search'] == '1') echo ' checked="checked"' ?> tabindex="35" />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="search" value="0"<?php if ($group['g_search'] == '0') echo ' checked="checked"' ?> tabindex="36" />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_groups['User search help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_groups['User list search label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="search_users" value="1"<?php if ($group['g_search_users'] == '1') echo ' checked="checked"' ?> tabindex="37" />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="search_users" value="0"<?php if ($group['g_search_users'] == '0') echo ' checked="checked"' ?> tabindex="38" />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_groups['User list search help'] ?></span>
+ </td>
+ </tr>
+<?php if ($group['g_id'] != PUN_GUEST): ?> <tr>
+ <th scope="row"><?php echo $lang_admin_groups['Send e-mails label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="send_email" value="1"<?php if ($group['g_send_email'] == '1') echo ' checked="checked"' ?> tabindex="39" />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="send_email" value="0"<?php if ($group['g_send_email'] == '0') echo ' checked="checked"' ?> tabindex="40" />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_groups['Send e-mails help'] ?></span>
+ </td>
+ </tr>
+<?php endif; ?> <tr>
+ <th scope="row"><?php echo $lang_admin_groups['Post flood label'] ?></th>
+ <td>
+ <input type="text" name="post_flood" size="5" maxlength="4" value="<?php echo $group['g_post_flood'] ?>" tabindex="41" />
+ <span><?php echo $lang_admin_groups['Post flood help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_groups['Search flood label'] ?></th>
+ <td>
+ <input type="text" name="search_flood" size="5" maxlength="4" value="<?php echo $group['g_search_flood'] ?>" tabindex="42" />
+ <span><?php echo $lang_admin_groups['Search flood help'] ?></span>
+ </td>
+ </tr>
+<?php if ($group['g_id'] != PUN_GUEST): ?> <tr>
+ <th scope="row"><?php echo $lang_admin_groups['E-mail flood label'] ?></th>
+ <td>
+ <input type="text" name="email_flood" size="5" maxlength="4" value="<?php echo $group['g_email_flood'] ?>" tabindex="43" />
+ <span><?php echo $lang_admin_groups['E-mail flood help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_groups['Report flood label'] ?></th>
+ <td>
+ <input type="text" name="report_flood" size="5" maxlength="4" value="<?php echo $group['g_report_flood'] ?>" tabindex="44" />
+ <span><?php echo $lang_admin_groups['Report flood help'] ?></span>
+ </td>
+ </tr>
+<?php endif; endif; ?> </table>
+<?php if ($group['g_moderator'] == '1' ): ?> <p class="warntext"><?php echo $lang_admin_groups['Moderator info'] ?></p>
+<?php endif; ?> </div>
+ </fieldset>
+ </div>
+ <p class="submitend"><input type="submit" name="add_edit_group" value="<?php echo $lang_admin_common['Save'] ?>" tabindex="45" /></p>
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+</div>
+<?php
+
+ require PUN_ROOT.'footer.php';
+}
+
+
+// Add/edit a group (stage 2)
+else if (isset($_POST['add_edit_group']))
+{
+ confirm_referrer('admin_groups.php');
+
+ // Is this the admin group? (special rules apply)
+ $is_admin_group = (isset($_POST['group_id']) && $_POST['group_id'] == PUN_ADMIN) ? true : false;
+
+ $title = pun_trim($_POST['req_title']);
+ $user_title = pun_trim($_POST['user_title']);
+
+ $promote_min_posts = isset($_POST['promote_min_posts']) ? intval($_POST['promote_min_posts']) : '0';
+ if (isset($_POST['promote_next_group']) &&
+ isset($groups[$_POST['promote_next_group']]) &&
+ !in_array($_POST['promote_next_group'], array(PUN_ADMIN, PUN_GUEST)) &&
+ (!isset($_POST['group_id']) || $_POST['promote_next_group'] != $_POST['group_id']))
+ $promote_next_group = $_POST['promote_next_group'];
+ else
+ $promote_next_group = '0';
+
+ $moderator = isset($_POST['moderator']) && $_POST['moderator'] == '1' ? '1' : '0';
+ $mod_edit_users = $moderator == '1' && isset($_POST['mod_edit_users']) && $_POST['mod_edit_users'] == '1' ? '1' : '0';
+ $mod_rename_users = $moderator == '1' && isset($_POST['mod_rename_users']) && $_POST['mod_rename_users'] == '1' ? '1' : '0';
+ $mod_change_passwords = $moderator == '1' && isset($_POST['mod_change_passwords']) && $_POST['mod_change_passwords'] == '1' ? '1' : '0';
+ $mod_ban_users = $moderator == '1' && isset($_POST['mod_ban_users']) && $_POST['mod_ban_users'] == '1' ? '1' : '0';
+ $mod_promote_users = $moderator == '1' && isset($_POST['mod_promote_users']) && $_POST['mod_promote_users'] == '1' ? '1' : '0';
+ $read_board = isset($_POST['read_board']) ? intval($_POST['read_board']) : '1';
+ $view_users = (isset($_POST['view_users']) && $_POST['view_users'] == '1') || $is_admin_group ? '1' : '0';
+ $post_replies = isset($_POST['post_replies']) ? intval($_POST['post_replies']) : '1';
+ $post_topics = isset($_POST['post_topics']) ? intval($_POST['post_topics']) : '1';
+ $edit_posts = isset($_POST['edit_posts']) ? intval($_POST['edit_posts']) : ($is_admin_group) ? '1' : '0';
+ $delete_posts = isset($_POST['delete_posts']) ? intval($_POST['delete_posts']) : ($is_admin_group) ? '1' : '0';
+ $delete_topics = isset($_POST['delete_topics']) ? intval($_POST['delete_topics']) : ($is_admin_group) ? '1' : '0';
+ $post_links = isset($_POST['post_links']) ? intval($_POST['post_links']) : '1';
+ $set_title = isset($_POST['set_title']) ? intval($_POST['set_title']) : ($is_admin_group) ? '1' : '0';
+ $search = isset($_POST['search']) ? intval($_POST['search']) : '1';
+ $search_users = isset($_POST['search_users']) ? intval($_POST['search_users']) : '1';
+ $send_email = (isset($_POST['send_email']) && $_POST['send_email'] == '1') || $is_admin_group ? '1' : '0';
+ $post_flood = (isset($_POST['post_flood']) && $_POST['post_flood'] >= 0) ? intval($_POST['post_flood']) : '0';
+ $search_flood = (isset($_POST['search_flood']) && $_POST['search_flood'] >= 0) ? intval($_POST['search_flood']) : '0';
+ $email_flood = (isset($_POST['email_flood']) && $_POST['email_flood'] >= 0) ? intval($_POST['email_flood']) : '0';
+ $report_flood = (isset($_POST['report_flood']) && $_POST['report_flood'] >= 0) ? intval($_POST['report_flood']) : '0';
+
+ if ($title == '')
+ message($lang_admin_groups['Must enter title message']);
+
+ $user_title = ($user_title != '') ? '\''.$db->escape($user_title).'\'' : 'NULL';
+
+ if ($_POST['mode'] == 'add')
+ {
+ $result = $db->query('SELECT 1 FROM '.$db->prefix.'groups WHERE g_title=\''.$db->escape($title).'\'') or error('Unable to check group title collision', __FILE__, __LINE__, $db->error());
+ if ($db->num_rows($result))
+ message(sprintf($lang_admin_groups['Title already exists message'], pun_htmlspecialchars($title)));
+
+ $db->query('INSERT INTO '.$db->prefix.'groups (g_title, g_user_title, g_promote_min_posts, g_promote_next_group, g_moderator, g_mod_edit_users, g_mod_rename_users, g_mod_change_passwords, g_mod_ban_users, g_mod_promote_users, g_read_board, g_view_users, g_post_replies, g_post_topics, g_edit_posts, g_delete_posts, g_delete_topics, g_post_links, g_set_title, g_search, g_search_users, g_send_email, g_post_flood, g_search_flood, g_email_flood, g_report_flood) VALUES(\''.$db->escape($title).'\', '.$user_title.', '.$promote_min_posts.', '.$promote_next_group.', '.$moderator.', '.$mod_edit_users.', '.$mod_rename_users.', '.$mod_change_passwords.', '.$mod_ban_users.', '.$mod_promote_users.', '.$read_board.', '.$view_users.', '.$post_replies.', '.$post_topics.', '.$edit_posts.', '.$delete_posts.', '.$delete_topics.', '.$post_links.', '.$set_title.', '.$search.', '.$search_users.', '.$send_email.', '.$post_flood.', '.$search_flood.', '.$email_flood.', '.$report_flood.')') or error('Unable to add group', __FILE__, __LINE__, $db->error());
+ $new_group_id = $db->insert_id();
+
+ // Now lets copy the forum specific permissions from the group which this group is based on
+ $result = $db->query('SELECT forum_id, read_forum, post_replies, post_topics FROM '.$db->prefix.'forum_perms WHERE group_id='.intval($_POST['base_group'])) or error('Unable to fetch group forum permission list', __FILE__, __LINE__, $db->error());
+ while ($cur_forum_perm = $db->fetch_assoc($result))
+ $db->query('INSERT INTO '.$db->prefix.'forum_perms (group_id, forum_id, read_forum, post_replies, post_topics) VALUES('.$new_group_id.', '.$cur_forum_perm['forum_id'].', '.$cur_forum_perm['read_forum'].', '.$cur_forum_perm['post_replies'].', '.$cur_forum_perm['post_topics'].')') or error('Unable to insert group forum permissions', __FILE__, __LINE__, $db->error());
+ }
+ else
+ {
+ $result = $db->query('SELECT 1 FROM '.$db->prefix.'groups WHERE g_title=\''.$db->escape($title).'\' AND g_id!='.intval($_POST['group_id'])) or error('Unable to check group title collision', __FILE__, __LINE__, $db->error());
+ if ($db->num_rows($result))
+ message(sprintf($lang_admin_groups['Title already exists message'], pun_htmlspecialchars($title)));
+
+ $db->query('UPDATE '.$db->prefix.'groups SET g_title=\''.$db->escape($title).'\', g_user_title='.$user_title.', g_promote_min_posts='.$promote_min_posts.', g_promote_next_group='.$promote_next_group.', g_moderator='.$moderator.', g_mod_edit_users='.$mod_edit_users.', g_mod_rename_users='.$mod_rename_users.', g_mod_change_passwords='.$mod_change_passwords.', g_mod_ban_users='.$mod_ban_users.', g_mod_promote_users='.$mod_promote_users.', g_read_board='.$read_board.', g_view_users='.$view_users.', g_post_replies='.$post_replies.', g_post_topics='.$post_topics.', g_edit_posts='.$edit_posts.', g_delete_posts='.$delete_posts.', g_delete_topics='.$delete_topics.', g_post_links='.$post_links.', g_set_title='.$set_title.', g_search='.$search.', g_search_users='.$search_users.', g_send_email='.$send_email.', g_post_flood='.$post_flood.', g_search_flood='.$search_flood.', g_email_flood='.$email_flood.', g_report_flood='.$report_flood.' WHERE g_id='.intval($_POST['group_id'])) or error('Unable to update group', __FILE__, __LINE__, $db->error());
+
+ // Promote all users who would be promoted to this group on their next post
+ if ($promote_next_group)
+ $db->query('UPDATE '.$db->prefix.'users SET group_id = '.$promote_next_group.' WHERE group_id = '.intval($_POST['group_id']).' AND num_posts >= '.$promote_min_posts) or error('Unable to auto-promote existing users', __FILE__, __LINE__, $db->error());
+ }
+
+ // Regenerate the quick jump cache
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ $group_id = $_POST['mode'] == 'add' ? $new_group_id : intval($_POST['group_id']);
+ generate_quickjump_cache($group_id);
+
+ if ($_POST['mode'] == 'edit')
+ redirect('admin_groups.php', $lang_admin_groups['Group edited redirect']);
+ else
+ redirect('admin_groups.php', $lang_admin_groups['Group added redirect']);
+}
+
+
+// Set default group
+else if (isset($_POST['set_default_group']))
+{
+ confirm_referrer('admin_groups.php');
+
+ $group_id = intval($_POST['default_group']);
+
+ // Make sure it's not the admin or guest groups
+ if ($group_id == PUN_ADMIN || $group_id == PUN_GUEST)
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+ // Make sure it's not a moderator group
+ if ($groups[$group_id]['g_moderator'] != 0)
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+ $db->query('UPDATE '.$db->prefix.'config SET conf_value='.$group_id.' WHERE conf_name=\'o_default_user_group\'') or error('Unable to update board config', __FILE__, __LINE__, $db->error());
+
+ // Regenerate the config cache
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_config_cache();
+
+ redirect('admin_groups.php', $lang_admin_groups['Default group redirect']);
+}
+
+
+// Remove a group
+else if (isset($_GET['del_group']))
+{
+ confirm_referrer('admin_groups.php');
+
+ $group_id = isset($_POST['group_to_delete']) ? intval($_POST['group_to_delete']) : intval($_GET['del_group']);
+ if ($group_id < 5)
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+ // Make sure we don't remove the default group
+ if ($group_id == $pun_config['o_default_user_group'])
+ message($lang_admin_groups['Cannot remove default message']);
+
+ // Check if this group has any members
+ $result = $db->query('SELECT g.g_title, COUNT(u.id) FROM '.$db->prefix.'groups AS g INNER JOIN '.$db->prefix.'users AS u ON g.g_id=u.group_id WHERE g.g_id='.$group_id.' GROUP BY g.g_id, g_title') or error('Unable to fetch group info', __FILE__, __LINE__, $db->error());
+
+ // If the group doesn't have any members or if we've already selected a group to move the members to
+ if (!$db->num_rows($result) || isset($_POST['del_group']))
+ {
+ if (isset($_POST['del_group_comply']) || isset($_POST['del_group']))
+ {
+ if (isset($_POST['del_group']))
+ {
+ $move_to_group = intval($_POST['move_to_group']);
+ $db->query('UPDATE '.$db->prefix.'users SET group_id='.$move_to_group.' WHERE group_id='.$group_id) or error('Unable to move users into group', __FILE__, __LINE__, $db->error());
+ }
+
+ // Delete the group and any forum specific permissions
+ $db->query('DELETE FROM '.$db->prefix.'groups WHERE g_id='.$group_id) or error('Unable to delete group', __FILE__, __LINE__, $db->error());
+ $db->query('DELETE FROM '.$db->prefix.'forum_perms WHERE group_id='.$group_id) or error('Unable to delete group forum permissions', __FILE__, __LINE__, $db->error());
+
+ // Don't let users be promoted to this group
+ $db->query('UPDATE '.$db->prefix.'groups SET g_promote_next_group=0 WHERE g_promote_next_group='.$group_id) or error('Unable to remove group as promotion target', __FILE__, __LINE__, $db->error());
+
+ redirect('admin_groups.php', $lang_admin_groups['Group removed redirect']);
+ }
+ else
+ {
+ $result = $db->query('SELECT g_title FROM '.$db->prefix.'groups WHERE g_id='.$group_id) or error('Unable to fetch group title', __FILE__, __LINE__, $db->error());
+ $group_title = $db->result($result);
+
+ $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['User groups']);
+ define('PUN_ACTIVE_PAGE', 'admin');
+ require PUN_ROOT.'header.php';
+
+ generate_admin_menu('groups');
+
+?>
+ <div class="blockform">
+ <h2><span><?php echo $lang_admin_groups['Group delete head'] ?></span></h2>
+ <div class="box">
+ <form method="post" action="admin_groups.php?del_group=<?php echo $group_id ?>">
+ <div class="inform">
+ <input type="hidden" name="group_to_delete" value="<?php echo $group_id ?>" />
+ <fieldset>
+ <legend><?php echo $lang_admin_groups['Confirm delete subhead'] ?></legend>
+ <div class="infldset">
+ <p><?php printf($lang_admin_groups['Confirm delete info'], pun_htmlspecialchars($group_title)) ?></p>
+ <p class="warntext"><?php echo $lang_admin_groups['Confirm delete warn'] ?></p>
+ </div>
+ </fieldset>
+ </div>
+ <p class="buttons"><input type="submit" name="del_group_comply" value="<?php echo $lang_admin_common['Delete'] ?>" tabindex="1" /><a href="javascript:history.go(-1)" tabindex="2"><?php echo $lang_admin_common['Go back'] ?></a></p>
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+</div>
+<?php
+
+ require PUN_ROOT.'footer.php';
+ }
+ }
+
+ list($group_title, $group_members) = $db->fetch_row($result);
+
+ $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['User groups']);
+ define('PUN_ACTIVE_PAGE', 'admin');
+ require PUN_ROOT.'header.php';
+
+ generate_admin_menu('groups');
+
+?>
+ <div class="blockform">
+ <h2><span><?php echo $lang_admin_groups['Delete group head'] ?></span></h2>
+ <div class="box">
+ <form id="groups" method="post" action="admin_groups.php?del_group=<?php echo $group_id ?>">
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_groups['Move users subhead'] ?></legend>
+ <div class="infldset">
+ <p><?php printf($lang_admin_groups['Move users info'], pun_htmlspecialchars($group_title), forum_number_format($group_members)) ?></p>
+ <label><?php echo $lang_admin_groups['Move users label'] ?>
+ <select name="move_to_group">
+<?php
+
+ $result = $db->query('SELECT g_id, g_title FROM '.$db->prefix.'groups WHERE g_id!='.PUN_GUEST.' AND g_id!='.$group_id.' ORDER BY g_title') or error('Unable to fetch user group list', __FILE__, __LINE__, $db->error());
+
+ while ($cur_group = $db->fetch_assoc($result))
+ {
+ if ($cur_group['g_id'] == PUN_MEMBER) // Pre-select the pre-defined Members group
+ echo "\t\t\t\t\t\t\t\t\t\t".'<option value="'.$cur_group['g_id'].'" selected="selected">'.pun_htmlspecialchars($cur_group['g_title']).'</option>'."\n";
+ else
+ echo "\t\t\t\t\t\t\t\t\t\t".'<option value="'.$cur_group['g_id'].'">'.pun_htmlspecialchars($cur_group['g_title']).'</option>'."\n";
+ }
+
+?>
+ </select>
+ <br /></label>
+ </div>
+ </fieldset>
+ </div>
+ <p class="buttons"><input type="submit" name="del_group" value="<?php echo $lang_admin_groups['Delete group'] ?>" /><a href="javascript:history.go(-1)"><?php echo $lang_admin_common['Go back'] ?></a></p>
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+</div>
+<?php
+
+ require PUN_ROOT.'footer.php';
+}
+
+
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['User groups']);
+define('PUN_ACTIVE_PAGE', 'admin');
+require PUN_ROOT.'header.php';
+
+generate_admin_menu('groups');
+
+?>
+ <div class="blockform">
+ <h2><span><?php echo $lang_admin_groups['Add groups head'] ?></span></h2>
+ <div class="box">
+ <form id="groups" method="post" action="admin_groups.php">
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_groups['Add group subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_groups['New group label'] ?><div><input type="submit" name="add_group" value="<?php echo $lang_admin_common['Add'] ?>" tabindex="2" /></div></th>
+ <td>
+ <select id="base_group" name="base_group" tabindex="1">
+<?php
+
+foreach ($groups as $cur_group)
+{
+ if ($cur_group['g_id'] != PUN_ADMIN && $cur_group['g_id'] != PUN_GUEST)
+ {
+ if ($cur_group['g_id'] == $pun_config['o_default_user_group'])
+ echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$cur_group['g_id'].'" selected="selected">'.pun_htmlspecialchars($cur_group['g_title']).'</option>'."\n";
+ else
+ echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$cur_group['g_id'].'">'.pun_htmlspecialchars($cur_group['g_title']).'</option>'."\n";
+ }
+}
+
+?>
+ </select>
+ <span><?php echo $lang_admin_groups['New group help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_groups['Default group subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_groups['Default group label'] ?><div><input type="submit" name="set_default_group" value="<?php echo $lang_admin_common['Save'] ?>" tabindex="4" /></div></th>
+ <td>
+ <select id="default_group" name="default_group" tabindex="3">
+<?php
+
+foreach ($groups as $cur_group)
+{
+ if ($cur_group['g_id'] > PUN_GUEST && $cur_group['g_moderator'] == 0)
+ {
+ if ($cur_group['g_id'] == $pun_config['o_default_user_group'])
+ echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$cur_group['g_id'].'" selected="selected">'.pun_htmlspecialchars($cur_group['g_title']).'</option>'."\n";
+ else
+ echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$cur_group['g_id'].'">'.pun_htmlspecialchars($cur_group['g_title']).'</option>'."\n";
+ }
+}
+
+?>
+ </select>
+ <span><?php echo $lang_admin_groups['Default group help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ </form>
+ </div>
+
+ <h2 class="block2"><span><?php echo $lang_admin_groups['Existing groups head'] ?></span></h2>
+ <div class="box">
+ <div class="fakeform">
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_groups['Edit groups subhead'] ?></legend>
+ <div class="infldset">
+ <p><?php echo $lang_admin_groups['Edit groups info'] ?></p>
+ <table>
+<?php
+
+$cur_index = 5;
+
+foreach ($groups as $cur_group)
+ echo "\t\t\t\t\t\t\t\t".'<tr><th scope="row"><a href="admin_groups.php?edit_group='.$cur_group['g_id'].'" tabindex="'.$cur_index++.'">'.$lang_admin_groups['Edit link'].'</a>'.(($cur_group['g_id'] > PUN_MEMBER) ? ' | <a href="admin_groups.php?del_group='.$cur_group['g_id'].'" tabindex="'.$cur_index++.'">'.$lang_admin_groups['Delete link'].'</a>' : '').'</th><td>'.pun_htmlspecialchars($cur_group['g_title']).'</td></tr>'."\n";
+
+?>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="clearer"></div>
+</div>
+<?php
+
+require PUN_ROOT.'footer.php';
diff --git a/admin_index.php b/admin_index.php
new file mode 100644
index 0000000..7692bf2
--- /dev/null
+++ b/admin_index.php
@@ -0,0 +1,110 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Tell header.php to use the admin template
+define('PUN_ADMIN_CONSOLE', 1);
+
+define('PUN_ROOT', dirname(__FILE__).'/');
+require PUN_ROOT.'include/common.php';
+require PUN_ROOT.'include/common_admin.php';
+
+
+if (!$pun_user['is_admmod'])
+ message($lang_common['No permission'], false, '403 Forbidden');
+
+// Load the admin_index.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_index.php';
+
+$action = isset($_GET['action']) ? $_GET['action'] : null;
+
+// Check for upgrade
+if ($action == 'check_upgrade')
+{
+ if (!ini_get('allow_url_fopen'))
+ message($lang_admin_index['fopen disabled message']);
+
+ $latest_version = trim(@file_get_contents('http://fluxbb.org/latest_version'));
+ if (empty($latest_version))
+ message($lang_admin_index['Upgrade check failed message']);
+
+ if (version_compare($pun_config['o_cur_version'], $latest_version, '>='))
+ message($lang_admin_index['Running latest version message']);
+ else
+ message(sprintf($lang_admin_index['New version available message'], '<a href="http://fluxbb.org/">FluxBB.org</a>'));
+}
+// Remove install.php
+else if ($action == 'remove_install_file')
+{
+ $deleted = @unlink(PUN_ROOT.'install.php');
+
+ if ($deleted)
+ redirect('admin_index.php', $lang_admin_index['Deleted install.php redirect']);
+ else
+ message($lang_admin_index['Delete install.php failed']);
+}
+
+$install_file_exists = is_file(PUN_ROOT.'install.php');
+
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Index']);
+define('PUN_ACTIVE_PAGE', 'admin');
+require PUN_ROOT.'header.php';
+
+generate_admin_menu('index');
+
+?>
+ <div class="block">
+ <h2><span><?php echo $lang_admin_index['Forum admin head'] ?></span></h2>
+ <div id="adintro" class="box">
+ <div class="inbox">
+ <p><?php echo $lang_admin_index['Welcome to admin'] ?></p>
+ <ul>
+ <li><span><?php echo $lang_admin_index['Welcome 1'] ?></span></li>
+ <li><span><?php echo $lang_admin_index['Welcome 2'] ?></span></li>
+ <li><span><?php echo $lang_admin_index['Welcome 3'] ?></span></li>
+ <li><span><?php echo $lang_admin_index['Welcome 4'] ?></span></li>
+ <li><span><?php echo $lang_admin_index['Welcome 5'] ?></span></li>
+ <li><span><?php echo $lang_admin_index['Welcome 6'] ?></span></li>
+ <li><span><?php echo $lang_admin_index['Welcome 7'] ?></span></li>
+ <li><span><?php echo $lang_admin_index['Welcome 8'] ?></span></li>
+ <li><span><?php echo $lang_admin_index['Welcome 9'] ?></span></li>
+ </ul>
+ </div>
+ </div>
+
+<?php if ($install_file_exists) : ?>
+ <h2 class="block2"><span><?php echo $lang_admin_index['Alerts head'] ?></span></h2>
+ <div id="adalerts" class="box">
+ <p><?php printf($lang_admin_index['Install file exists'], '<a href="admin_index.php?action=remove_install_file">'.$lang_admin_index['Delete install file'].'</a>') ?></p>
+ </div>
+<?php endif; ?>
+
+ <h2 class="block2"><span><?php echo $lang_admin_index['About head'] ?></span></h2>
+ <div id="adstats" class="box">
+ <div class="inbox">
+ <dl>
+ <dt><?php echo $lang_admin_index['FluxBB version label'] ?></dt>
+ <dd>
+ <?php printf($lang_admin_index['FluxBB version data']."\n", $pun_config['o_cur_version'], '<a href="admin_index.php?action=check_upgrade">'.$lang_admin_index['Check for upgrade'].'</a>') ?>
+ </dd>
+ <dt><?php echo $lang_admin_index['Server statistics label'] ?></dt>
+ <dd>
+ <a href="admin_statistics.php"><?php echo $lang_admin_index['View server statistics'] ?></a>
+ </dd>
+ <dt><?php echo $lang_admin_index['Support label'] ?></dt>
+ <dd>
+ <a href="http://fluxbb.org/forums/index.php"><?php echo $lang_admin_index['Forum label'] ?></a> - <a href="http://fluxbb.org/community/irc.html"><?php echo $lang_admin_index['IRC label'] ?></a>
+ </dd>
+ </dl>
+ </div>
+ </div>
+ </div>
+ <div class="clearer"></div>
+</div>
+<?php
+
+require PUN_ROOT.'footer.php';
diff --git a/admin_loader.php b/admin_loader.php
new file mode 100644
index 0000000..a505e26
--- /dev/null
+++ b/admin_loader.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Tell header.php to use the admin template
+define('PUN_ADMIN_CONSOLE', 1);
+
+define('PUN_ROOT', dirname(__FILE__).'/');
+require PUN_ROOT.'include/common.php';
+require PUN_ROOT.'include/common_admin.php';
+
+
+if (!$pun_user['is_admmod'])
+ message($lang_common['No permission'], false, '403 Forbidden');
+
+// The plugin to load should be supplied via GET
+$plugin = isset($_GET['plugin']) ? $_GET['plugin'] : '';
+if (!preg_match('%^AM?P_(\w*?)\.php$%i', $plugin))
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+// AP_ == Admins only, AMP_ == admins and moderators
+$prefix = substr($plugin, 0, strpos($plugin, '_'));
+if ($pun_user['g_moderator'] == '1' && $prefix == 'AP')
+ message($lang_common['No permission'], false, '403 Forbidden');
+
+// Make sure the file actually exists
+if (!file_exists(PUN_ROOT.'plugins/'.$plugin))
+ message(sprintf($lang_admin_common['No plugin message'], $plugin));
+
+// Construct REQUEST_URI if it isn't set
+if (!isset($_SERVER['REQUEST_URI']))
+ $_SERVER['REQUEST_URI'] = (isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : '').'?'.(isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : '');
+
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], str_replace('_', ' ', substr($plugin, strpos($plugin, '_') + 1, -4)));
+define('PUN_ACTIVE_PAGE', 'admin');
+require PUN_ROOT.'header.php';
+
+// Attempt to load the plugin. We don't use @ here to suppress error messages,
+// because if we did and a parse error occurred in the plugin, we would only
+// get the "blank page of death"
+include PUN_ROOT.'plugins/'.$plugin;
+if (!defined('PUN_PLUGIN_LOADED'))
+ message(sprintf($lang_admin_common['Plugin failed message'], $plugin));
+
+// Output the clearer div
+?>
+ <div class="clearer"></div>
+</div>
+<?php
+
+require PUN_ROOT.'footer.php';
diff --git a/admin_maintenance.php b/admin_maintenance.php
new file mode 100644
index 0000000..45a6376
--- /dev/null
+++ b/admin_maintenance.php
@@ -0,0 +1,361 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Tell header.php to use the admin template
+define('PUN_ADMIN_CONSOLE', 1);
+// Tell common.php that we don't want output buffering
+define('PUN_DISABLE_BUFFERING', 1);
+
+define('PUN_ROOT', dirname(__FILE__).'/');
+require PUN_ROOT.'include/common.php';
+require PUN_ROOT.'include/common_admin.php';
+
+
+if ($pun_user['g_id'] != PUN_ADMIN)
+ message($lang_common['No permission'], false, '403 Forbidden');
+
+// Load the admin_maintenance.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_maintenance.php';
+
+$action = isset($_REQUEST['action']) ? pun_trim($_REQUEST['action']) : '';
+
+if ($action == 'rebuild')
+{
+ confirm_referrer('admin_maintenance.php');
+
+ check_csrf($_GET['csrf_token']);
+
+ $per_page = isset($_GET['i_per_page']) ? intval($_GET['i_per_page']) : 0;
+ $start_at = isset($_GET['i_start_at']) ? intval($_GET['i_start_at']) : 0;
+
+ // Check per page is > 0
+ if ($per_page < 1)
+ message($lang_admin_maintenance['Posts must be integer message']);
+
+ @set_time_limit(0);
+
+ // If this is the first cycle of posts we empty the search index before we proceed
+ if (isset($_GET['i_empty_index']))
+ {
+ $db->truncate_table('search_matches') or error('Unable to empty search index match table', __FILE__, __LINE__, $db->error());
+ $db->truncate_table('search_words') or error('Unable to empty search index words table', __FILE__, __LINE__, $db->error());
+
+ // Reset the sequence for the search words (not needed for SQLite)
+ switch ($db_type)
+ {
+ case 'mysql':
+ case 'mysqli':
+ case 'mysql_innodb':
+ case 'mysqli_innodb':
+ $result = $db->query('ALTER TABLE '.$db->prefix.'search_words auto_increment=1') or error('Unable to update table auto_increment', __FILE__, __LINE__, $db->error());
+ break;
+
+ case 'pgsql';
+ $result = $db->query('SELECT setval(\''.$db->prefix.'search_words_id_seq\', 1, false)') or error('Unable to update sequence', __FILE__, __LINE__, $db->error());
+ }
+ }
+
+ $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_maintenance['Rebuilding search index']);
+
+?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title><?php echo generate_page_title($page_title) ?></title>
+<style type="text/css">
+body {
+ font: 12px Verdana, Arial, Helvetica, sans-serif;
+ color: #333333;
+ background-color: #FFFFFF
+}
+
+h1 {
+ font-size: 16px;
+ font-weight: normal;
+}
+</style>
+</head>
+<body>
+
+<h1><?php echo $lang_admin_maintenance['Rebuilding index info'] ?></h1>
+<hr />
+
+<?php
+
+ $query_str = '';
+
+ require PUN_ROOT.'include/search_idx.php';
+
+ // Fetch posts to process this cycle
+ $result = $db->query('SELECT p.id, p.message, t.subject, t.first_post_id FROM '.$db->prefix.'posts AS p INNER JOIN '.$db->prefix.'topics AS t ON t.id=p.topic_id WHERE p.id >= '.$start_at.' ORDER BY p.id ASC LIMIT '.$per_page) or error('Unable to fetch posts', __FILE__, __LINE__, $db->error());
+
+ $end_at = 0;
+ while ($cur_item = $db->fetch_assoc($result))
+ {
+ echo '<p><span>'.sprintf($lang_admin_maintenance['Processing post'], $cur_item['id']).'</span></p>'."\n";
+
+ if ($cur_item['id'] == $cur_item['first_post_id'])
+ update_search_index('post', $cur_item['id'], $cur_item['message'], $cur_item['subject']);
+ else
+ update_search_index('post', $cur_item['id'], $cur_item['message']);
+
+ $end_at = $cur_item['id'];
+ }
+
+ // Check if there is more work to do
+ if ($end_at > 0)
+ {
+ $result = $db->query('SELECT id FROM '.$db->prefix.'posts WHERE id > '.$end_at.' ORDER BY id ASC LIMIT 1') or error('Unable to fetch next ID', __FILE__, __LINE__, $db->error());
+
+ if ($db->num_rows($result) > 0)
+ $query_str = '?action=rebuild&csrf_token='.pun_csrf_token().'&i_per_page='.$per_page.'&i_start_at='.$db->result($result);
+ }
+
+ $db->end_transaction();
+ $db->close();
+
+ exit('<meta http-equiv="refresh" content="0;url=admin_maintenance.php'.$query_str.'" /><hr /><p>'.sprintf($lang_admin_maintenance['Javascript redirect failed'], '<a href="admin_maintenance.php'.$query_str.'">'.$lang_admin_maintenance['Click here'].'</a>').'</p>');
+}
+
+if ($action == 'prune')
+{
+ $prune_from = pun_trim($_POST['prune_from']);
+ $prune_sticky = intval($_POST['prune_sticky']);
+
+ if (isset($_POST['prune_comply']))
+ {
+ confirm_referrer('admin_maintenance.php');
+
+ $prune_days = intval($_POST['prune_days']);
+ $prune_date = ($prune_days) ? time() - ($prune_days * 86400) : -1;
+
+ @set_time_limit(0);
+
+ if ($prune_from == 'all')
+ {
+ $result = $db->query('SELECT id FROM '.$db->prefix.'forums') or error('Unable to fetch forum list', __FILE__, __LINE__, $db->error());
+ $num_forums = $db->num_rows($result);
+
+ for ($i = 0; $i < $num_forums; ++$i)
+ {
+ $fid = $db->result($result, $i);
+
+ prune($fid, $prune_sticky, $prune_date);
+ update_forum($fid);
+ }
+ }
+ else
+ {
+ $prune_from = intval($prune_from);
+ prune($prune_from, $prune_sticky, $prune_date);
+ update_forum($prune_from);
+ }
+
+ // Locate any "orphaned redirect topics" and delete them
+ $result = $db->query('SELECT t1.id FROM '.$db->prefix.'topics AS t1 LEFT JOIN '.$db->prefix.'topics AS t2 ON t1.moved_to=t2.id WHERE t2.id IS NULL AND t1.moved_to IS NOT NULL') or error('Unable to fetch redirect topics', __FILE__, __LINE__, $db->error());
+ $num_orphans = $db->num_rows($result);
+
+ if ($num_orphans)
+ {
+ for ($i = 0; $i < $num_orphans; ++$i)
+ $orphans[] = $db->result($result, $i);
+
+ $db->query('DELETE FROM '.$db->prefix.'topics WHERE id IN('.implode(',', $orphans).')') or error('Unable to delete redirect topics', __FILE__, __LINE__, $db->error());
+ }
+
+ redirect('admin_maintenance.php', $lang_admin_maintenance['Posts pruned redirect']);
+ }
+
+ $prune_days = pun_trim($_POST['req_prune_days']);
+ if ($prune_days == '' || preg_match('%[^0-9]%', $prune_days))
+ message($lang_admin_maintenance['Days must be integer message']);
+
+ $prune_date = time() - ($prune_days * 86400);
+
+ // Concatenate together the query for counting number of topics to prune
+ $sql = 'SELECT COUNT(id) FROM '.$db->prefix.'topics WHERE last_post<'.$prune_date.' AND moved_to IS NULL';
+
+ if ($prune_sticky == '0')
+ $sql .= ' AND sticky=0';
+
+ if ($prune_from != 'all')
+ {
+ $prune_from = intval($prune_from);
+ $sql .= ' AND forum_id='.$prune_from;
+
+ // Fetch the forum name (just for cosmetic reasons)
+ $result = $db->query('SELECT forum_name FROM '.$db->prefix.'forums WHERE id='.$prune_from) or error('Unable to fetch forum name', __FILE__, __LINE__, $db->error());
+ $forum = '"'.pun_htmlspecialchars($db->result($result)).'"';
+ }
+ else
+ $forum = $lang_admin_maintenance['All forums'];
+
+ $result = $db->query($sql) or error('Unable to fetch topic prune count', __FILE__, __LINE__, $db->error());
+ $num_topics = $db->result($result);
+
+ if (!$num_topics)
+ message(sprintf($lang_admin_maintenance['No old topics message'], $prune_days));
+
+
+ $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Prune']);
+ define('PUN_ACTIVE_PAGE', 'admin');
+ require PUN_ROOT.'header.php';
+
+ generate_admin_menu('maintenance');
+
+?>
+ <div class="blockform">
+ <h2><span><?php echo $lang_admin_maintenance['Prune head'] ?></span></h2>
+ <div class="box">
+ <form method="post" action="admin_maintenance.php">
+ <div class="inform">
+ <input type="hidden" name="action" value="prune" />
+ <input type="hidden" name="prune_days" value="<?php echo $prune_days ?>" />
+ <input type="hidden" name="prune_sticky" value="<?php echo $prune_sticky ?>" />
+ <input type="hidden" name="prune_from" value="<?php echo $prune_from ?>" />
+ <fieldset>
+ <legend><?php echo $lang_admin_maintenance['Confirm prune subhead'] ?></legend>
+ <div class="infldset">
+ <p><?php printf($lang_admin_maintenance['Confirm prune info'], $prune_days, $forum, forum_number_format($num_topics)) ?></p>
+ <p class="warntext"><?php echo $lang_admin_maintenance['Confirm prune warn'] ?></p>
+ </div>
+ </fieldset>
+ </div>
+ <p class="buttons"><input type="submit" name="prune_comply" value="<?php echo $lang_admin_common['Prune'] ?>" /><a href="javascript:history.go(-1)"><?php echo $lang_admin_common['Go back'] ?></a></p>
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+</div>
+<?php
+
+ require PUN_ROOT.'footer.php';
+ exit;
+}
+
+
+// Get the first post ID from the db
+$result = $db->query('SELECT id FROM '.$db->prefix.'posts ORDER BY id ASC LIMIT 1') or error('Unable to fetch topic info', __FILE__, __LINE__, $db->error());
+if ($db->num_rows($result))
+ $first_id = $db->result($result);
+
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Maintenance']);
+define('PUN_ACTIVE_PAGE', 'admin');
+require PUN_ROOT.'header.php';
+
+generate_admin_menu('maintenance');
+
+?>
+ <div class="blockform">
+ <h2><span><?php echo $lang_admin_maintenance['Maintenance head'] ?></span></h2>
+ <div class="box">
+ <form method="get" action="admin_maintenance.php">
+ <div class="inform">
+ <input type="hidden" name="action" value="rebuild" />
+ <input type="hidden" name="csrf_token" value="<?php echo pun_csrf_token() ?>" />
+ <fieldset>
+ <legend><?php echo $lang_admin_maintenance['Rebuild index subhead'] ?></legend>
+ <div class="infldset">
+ <p><?php printf($lang_admin_maintenance['Rebuild index info'], '<a href="admin_options.php#maintenance">'.$lang_admin_common['Maintenance mode'].'</a>') ?></p>
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_maintenance['Posts per cycle label'] ?></th>
+ <td>
+ <input type="text" name="i_per_page" size="7" maxlength="7" value="300" tabindex="1" />
+ <span><?php echo $lang_admin_maintenance['Posts per cycle help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_maintenance['Starting post label'] ?></th>
+ <td>
+ <input type="text" name="i_start_at" size="7" maxlength="7" value="<?php echo (isset($first_id)) ? $first_id : 0 ?>" tabindex="2" />
+ <span><?php echo $lang_admin_maintenance['Starting post help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_maintenance['Empty index label'] ?></th>
+ <td class="inputadmin">
+ <label><input type="checkbox" name="i_empty_index" value="1" tabindex="3" checked="checked" />&#160;&#160;<?php echo $lang_admin_maintenance['Empty index help'] ?></label>
+ </td>
+ </tr>
+ </table>
+ <p class="topspace"><?php echo $lang_admin_maintenance['Rebuild completed info'] ?></p>
+ <div class="fsetsubmit"><input type="submit" name="rebuild_index" value="<?php echo $lang_admin_maintenance['Rebuild index'] ?>" tabindex="4" /></div>
+ </div>
+ </fieldset>
+ </div>
+ </form>
+
+ <form method="post" action="admin_maintenance.php" onsubmit="return process_form(this)">
+ <div class="inform">
+ <input type="hidden" name="action" value="prune" />
+ <fieldset>
+ <legend><?php echo $lang_admin_maintenance['Prune subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_maintenance['Days old label'] ?></th>
+ <td>
+ <input type="text" name="req_prune_days" size="3" maxlength="3" tabindex="5" />
+ <span><?php echo $lang_admin_maintenance['Days old help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_maintenance['Prune sticky label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="prune_sticky" value="1" tabindex="6" checked="checked" />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="prune_sticky" value="0" />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_maintenance['Prune sticky help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_maintenance['Prune from label'] ?></th>
+ <td>
+ <select name="prune_from" tabindex="7">
+ <option value="all"><?php echo $lang_admin_maintenance['All forums'] ?></option>
+<?php
+
+ $result = $db->query('SELECT c.id AS cid, c.cat_name, f.id AS fid, f.forum_name FROM '.$db->prefix.'categories AS c INNER JOIN '.$db->prefix.'forums AS f ON c.id=f.cat_id WHERE f.redirect_url IS NULL ORDER BY c.disp_position, c.id, f.disp_position') or error('Unable to fetch category/forum list', __FILE__, __LINE__, $db->error());
+
+ $cur_category = 0;
+ while ($forum = $db->fetch_assoc($result))
+ {
+ if ($forum['cid'] != $cur_category) // Are we still in the same category?
+ {
+ if ($cur_category)
+ echo "\t\t\t\t\t\t\t\t\t\t\t".'</optgroup>'."\n";
+
+ echo "\t\t\t\t\t\t\t\t\t\t\t".'<optgroup label="'.pun_htmlspecialchars($forum['cat_name']).'">'."\n";
+ $cur_category = $forum['cid'];
+ }
+
+ echo "\t\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$forum['fid'].'">'.pun_htmlspecialchars($forum['forum_name']).'</option>'."\n";
+ }
+
+?>
+ </optgroup>
+ </select>
+ <span><?php echo $lang_admin_maintenance['Prune from help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ <p class="topspace"><?php printf($lang_admin_maintenance['Prune info'], '<a href="admin_options.php#maintenance">'.$lang_admin_common['Maintenance mode'].'</a>') ?></p>
+ <div class="fsetsubmit"><input type="submit" name="prune" value="<?php echo $lang_admin_common['Prune'] ?>" tabindex="8" /></div>
+ </div>
+ </fieldset>
+ </div>
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+</div>
+<?php
+
+require PUN_ROOT.'footer.php';
diff --git a/admin_options.php b/admin_options.php
new file mode 100644
index 0000000..2cb687a
--- /dev/null
+++ b/admin_options.php
@@ -0,0 +1,884 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Tell header.php to use the admin template
+define('PUN_ADMIN_CONSOLE', 1);
+
+define('PUN_ROOT', dirname(__FILE__).'/');
+require PUN_ROOT.'include/common.php';
+require PUN_ROOT.'include/common_admin.php';
+
+
+if ($pun_user['g_id'] != PUN_ADMIN)
+ message($lang_common['No permission'], false, '403 Forbidden');
+
+// Load the admin_options.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_options.php';
+
+if (isset($_POST['form_sent']))
+{
+ confirm_referrer('admin_options.php', $lang_admin_options['Bad HTTP Referer message']);
+
+ $form = array(
+ 'board_title' => pun_trim($_POST['form']['board_title']),
+ 'board_desc' => pun_trim($_POST['form']['board_desc']),
+ 'base_url' => pun_trim($_POST['form']['base_url']),
+ 'default_timezone' => floatval($_POST['form']['default_timezone']),
+ 'default_dst' => $_POST['form']['default_dst'] != '1' ? '0' : '1',
+ 'default_lang' => pun_trim($_POST['form']['default_lang']),
+ 'default_style' => pun_trim($_POST['form']['default_style']),
+ 'time_format' => pun_trim($_POST['form']['time_format']),
+ 'date_format' => pun_trim($_POST['form']['date_format']),
+ 'timeout_visit' => (intval($_POST['form']['timeout_visit']) > 0) ? intval($_POST['form']['timeout_visit']) : 1,
+ 'timeout_online' => (intval($_POST['form']['timeout_online']) > 0) ? intval($_POST['form']['timeout_online']) : 1,
+ 'redirect_delay' => (intval($_POST['form']['redirect_delay']) >= 0) ? intval($_POST['form']['redirect_delay']) : 0,
+ 'show_version' => $_POST['form']['show_version'] != '1' ? '0' : '1',
+ 'show_user_info' => $_POST['form']['show_user_info'] != '1' ? '0' : '1',
+ 'show_post_count' => $_POST['form']['show_post_count'] != '1' ? '0' : '1',
+ 'smilies' => $_POST['form']['smilies'] != '1' ? '0' : '1',
+ 'smilies_sig' => $_POST['form']['smilies_sig'] != '1' ? '0' : '1',
+ 'make_links' => $_POST['form']['make_links'] != '1' ? '0' : '1',
+ 'topic_review' => (intval($_POST['form']['topic_review']) >= 0) ? intval($_POST['form']['topic_review']) : 0,
+ 'disp_topics_default' => intval($_POST['form']['disp_topics_default']),
+ 'disp_posts_default' => intval($_POST['form']['disp_posts_default']),
+ 'indent_num_spaces' => (intval($_POST['form']['indent_num_spaces']) >= 0) ? intval($_POST['form']['indent_num_spaces']) : 0,
+ 'quote_depth' => (intval($_POST['form']['quote_depth']) > 0) ? intval($_POST['form']['quote_depth']) : 1,
+ 'quickpost' => $_POST['form']['quickpost'] != '1' ? '0' : '1',
+ 'users_online' => $_POST['form']['users_online'] != '1' ? '0' : '1',
+ 'censoring' => $_POST['form']['censoring'] != '1' ? '0' : '1',
+ 'signatures' => $_POST['form']['signatures'] != '1' ? '0' : '1',
+ 'show_dot' => $_POST['form']['show_dot'] != '1' ? '0' : '1',
+ 'topic_views' => $_POST['form']['topic_views'] != '1' ? '0' : '1',
+ 'quickjump' => $_POST['form']['quickjump'] != '1' ? '0' : '1',
+ 'gzip' => $_POST['form']['gzip'] != '1' ? '0' : '1',
+ 'search_all_forums' => $_POST['form']['search_all_forums'] != '1' ? '0' : '1',
+ 'additional_navlinks' => pun_trim($_POST['form']['additional_navlinks']),
+ 'feed_type' => intval($_POST['form']['feed_type']),
+ 'feed_ttl' => intval($_POST['form']['feed_ttl']),
+ 'report_method' => intval($_POST['form']['report_method']),
+ 'mailing_list' => pun_trim($_POST['form']['mailing_list']),
+ 'avatars' => $_POST['form']['avatars'] != '1' ? '0' : '1',
+ 'avatars_dir' => pun_trim($_POST['form']['avatars_dir']),
+ 'avatars_width' => (intval($_POST['form']['avatars_width']) > 0) ? intval($_POST['form']['avatars_width']) : 1,
+ 'avatars_height' => (intval($_POST['form']['avatars_height']) > 0) ? intval($_POST['form']['avatars_height']) : 1,
+ 'avatars_size' => (intval($_POST['form']['avatars_size']) > 0) ? intval($_POST['form']['avatars_size']) : 1,
+ 'admin_email' => strtolower(pun_trim($_POST['form']['admin_email'])),
+ 'webmaster_email' => strtolower(pun_trim($_POST['form']['webmaster_email'])),
+ 'forum_subscriptions' => $_POST['form']['forum_subscriptions'] != '1' ? '0' : '1',
+ 'topic_subscriptions' => $_POST['form']['topic_subscriptions'] != '1' ? '0' : '1',
+ 'smtp_host' => pun_trim($_POST['form']['smtp_host']),
+ 'smtp_user' => pun_trim($_POST['form']['smtp_user']),
+ 'smtp_ssl' => $_POST['form']['smtp_ssl'] != '1' ? '0' : '1',
+ 'regs_allow' => $_POST['form']['regs_allow'] != '1' ? '0' : '1',
+ 'regs_verify' => $_POST['form']['regs_verify'] != '1' ? '0' : '1',
+ 'regs_report' => $_POST['form']['regs_report'] != '1' ? '0' : '1',
+ 'rules' => $_POST['form']['rules'] != '1' ? '0' : '1',
+ 'rules_message' => pun_trim($_POST['form']['rules_message']),
+ 'default_email_setting' => intval($_POST['form']['default_email_setting']),
+ 'announcement' => $_POST['form']['announcement'] != '1' ? '0' : '1',
+ 'announcement_message' => pun_trim($_POST['form']['announcement_message']),
+ 'maintenance' => $_POST['form']['maintenance'] != '1' ? '0' : '1',
+ 'maintenance_message' => pun_trim($_POST['form']['maintenance_message']),
+ );
+
+ if ($form['board_title'] == '')
+ message($lang_admin_options['Must enter title message']);
+
+ // Make sure base_url doesn't end with a slash
+ if (substr($form['base_url'], -1) == '/')
+ $form['base_url'] = substr($form['base_url'], 0, -1);
+
+ // Convert IDN to Punycode if needed
+ if (preg_match('/[^\x00-\x7F]/', $form['base_url']))
+ {
+ if (!function_exists('idn_to_ascii'))
+ message($lang_admin_options['Base URL problem']);
+ else
+ $form['base_url'] = idn_to_ascii($form['base_url']);
+ }
+
+ $languages = forum_list_langs();
+ if (!in_array($form['default_lang'], $languages))
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+ $styles = forum_list_styles();
+ if (!in_array($form['default_style'], $styles))
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+ if ($form['time_format'] == '')
+ $form['time_format'] = 'H:i:s';
+
+ if ($form['date_format'] == '')
+ $form['date_format'] = 'Y-m-d';
+
+
+ require PUN_ROOT.'include/email.php';
+
+ if (!is_valid_email($form['admin_email']))
+ message($lang_admin_options['Invalid e-mail message']);
+
+ if (!is_valid_email($form['webmaster_email']))
+ message($lang_admin_options['Invalid webmaster e-mail message']);
+
+ if ($form['mailing_list'] != '')
+ $form['mailing_list'] = strtolower(preg_replace('%\s%S', '', $form['mailing_list']));
+
+ // Make sure avatars_dir doesn't end with a slash
+ if (substr($form['avatars_dir'], -1) == '/')
+ $form['avatars_dir'] = substr($form['avatars_dir'], 0, -1);
+
+ if ($form['additional_navlinks'] != '')
+ $form['additional_navlinks'] = pun_trim(pun_linebreaks($form['additional_navlinks']));
+
+ // Change or enter a SMTP password
+ if (isset($_POST['form']['smtp_change_pass']))
+ {
+ $smtp_pass1 = isset($_POST['form']['smtp_pass1']) ? pun_trim($_POST['form']['smtp_pass1']) : '';
+ $smtp_pass2 = isset($_POST['form']['smtp_pass2']) ? pun_trim($_POST['form']['smtp_pass2']) : '';
+
+ if ($smtp_pass1 == $smtp_pass2)
+ $form['smtp_pass'] = $smtp_pass1;
+ else
+ message($lang_admin_options['SMTP passwords did not match']);
+ }
+
+ if ($form['announcement_message'] != '')
+ $form['announcement_message'] = pun_linebreaks($form['announcement_message']);
+ else
+ {
+ $form['announcement_message'] = $lang_admin_options['Enter announcement here'];
+ $form['announcement'] = '0';
+ }
+
+ if ($form['rules_message'] != '')
+ $form['rules_message'] = pun_linebreaks($form['rules_message']);
+ else
+ {
+ $form['rules_message'] = $lang_admin_options['Enter rules here'];
+ $form['rules'] = '0';
+ }
+
+ if ($form['maintenance_message'] != '')
+ $form['maintenance_message'] = pun_linebreaks($form['maintenance_message']);
+ else
+ {
+ $form['maintenance_message'] = $lang_admin_options['Default maintenance message'];
+ $form['maintenance'] = '0';
+ }
+
+ // Make sure the number of displayed topics and posts is between 3 and 75
+ if ($form['disp_topics_default'] < 3)
+ $form['disp_topics_default'] = 3;
+ else if ($form['disp_topics_default'] > 75)
+ $form['disp_topics_default'] = 75;
+
+ if ($form['disp_posts_default'] < 3)
+ $form['disp_posts_default'] = 3;
+ else if ($form['disp_posts_default'] > 75)
+ $form['disp_posts_default'] = 75;
+
+ if ($form['feed_type'] < 0 || $form['feed_type'] > 2)
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+ if ($form['feed_ttl'] < 0)
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+ if ($form['report_method'] < 0 || $form['report_method'] > 2)
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+ if ($form['default_email_setting'] < 0 || $form['default_email_setting'] > 2)
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+ if ($form['timeout_online'] >= $form['timeout_visit'])
+ message($lang_admin_options['Timeout error message']);
+
+ foreach ($form as $key => $input)
+ {
+ // Only update values that have changed
+ if (array_key_exists('o_'.$key, $pun_config) && $pun_config['o_'.$key] != $input)
+ {
+ if ($input != '' || is_int($input))
+ $value = '\''.$db->escape($input).'\'';
+ else
+ $value = 'NULL';
+
+ $db->query('UPDATE '.$db->prefix.'config SET conf_value='.$value.' WHERE conf_name=\'o_'.$db->escape($key).'\'') or error('Unable to update board config', __FILE__, __LINE__, $db->error());
+ }
+ }
+
+ // Regenerate the config cache
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_config_cache();
+ clear_feed_cache();
+
+ redirect('admin_options.php', $lang_admin_options['Options updated redirect']);
+}
+
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Options']);
+define('PUN_ACTIVE_PAGE', 'admin');
+require PUN_ROOT.'header.php';
+
+generate_admin_menu('options');
+
+?>
+ <div class="blockform">
+ <h2><span><?php echo $lang_admin_options['Options head'] ?></span></h2>
+ <div class="box">
+ <form method="post" action="admin_options.php">
+ <p class="submittop"><input type="submit" name="save" value="<?php echo $lang_admin_common['Save changes'] ?>" /></p>
+ <div class="inform">
+ <input type="hidden" name="form_sent" value="1" />
+ <fieldset>
+ <legend><?php echo $lang_admin_options['Essentials subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Board title label'] ?></th>
+ <td>
+ <input type="text" name="form[board_title]" size="50" maxlength="255" value="<?php echo pun_htmlspecialchars($pun_config['o_board_title']) ?>" />
+ <span><?php echo $lang_admin_options['Board title help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Board desc label'] ?></th>
+ <td>
+ <textarea name="form[board_desc]" cols="60" rows="3"><?php echo pun_htmlspecialchars($pun_config['o_board_desc']) ?></textarea>
+ <span><?php echo $lang_admin_options['Board desc help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Base URL label'] ?></th>
+ <td>
+ <input type="text" name="form[base_url]" size="50" maxlength="100" value="<?php echo pun_htmlspecialchars($pun_config['o_base_url']) ?>" />
+ <span><?php echo $lang_admin_options['Base URL help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Timezone label'] ?></th>
+ <td>
+ <select name="form[default_timezone]">
+ <option value="-12"<?php if ($pun_config['o_default_timezone'] == -12) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-12:00'] ?></option>
+ <option value="-11"<?php if ($pun_config['o_default_timezone'] == -11) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-11:00'] ?></option>
+ <option value="-10"<?php if ($pun_config['o_default_timezone'] == -10) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-10:00'] ?></option>
+ <option value="-9.5"<?php if ($pun_config['o_default_timezone'] == -9.5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-09:30'] ?></option>
+ <option value="-9"<?php if ($pun_config['o_default_timezone'] == -9) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-09:00'] ?></option>
+ <option value="-8.5"<?php if ($pun_config['o_default_timezone'] == -8.5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-08:30'] ?></option>
+ <option value="-8"<?php if ($pun_config['o_default_timezone'] == -8) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-08:00'] ?></option>
+ <option value="-7"<?php if ($pun_config['o_default_timezone'] == -7) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-07:00'] ?></option>
+ <option value="-6"<?php if ($pun_config['o_default_timezone'] == -6) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-06:00'] ?></option>
+ <option value="-5"<?php if ($pun_config['o_default_timezone'] == -5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-05:00'] ?></option>
+ <option value="-4"<?php if ($pun_config['o_default_timezone'] == -4) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-04:00'] ?></option>
+ <option value="-3.5"<?php if ($pun_config['o_default_timezone'] == -3.5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-03:30'] ?></option>
+ <option value="-3"<?php if ($pun_config['o_default_timezone'] == -3) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-03:00'] ?></option>
+ <option value="-2"<?php if ($pun_config['o_default_timezone'] == -2) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-02:00'] ?></option>
+ <option value="-1"<?php if ($pun_config['o_default_timezone'] == -1) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-01:00'] ?></option>
+ <option value="0"<?php if ($pun_config['o_default_timezone'] == 0) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC'] ?></option>
+ <option value="1"<?php if ($pun_config['o_default_timezone'] == 1) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+01:00'] ?></option>
+ <option value="2"<?php if ($pun_config['o_default_timezone'] == 2) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+02:00'] ?></option>
+ <option value="3"<?php if ($pun_config['o_default_timezone'] == 3) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+03:00'] ?></option>
+ <option value="3.5"<?php if ($pun_config['o_default_timezone'] == 3.5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+03:30'] ?></option>
+ <option value="4"<?php if ($pun_config['o_default_timezone'] == 4) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+04:00'] ?></option>
+ <option value="4.5"<?php if ($pun_config['o_default_timezone'] == 4.5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+04:30'] ?></option>
+ <option value="5"<?php if ($pun_config['o_default_timezone'] == 5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+05:00'] ?></option>
+ <option value="5.5"<?php if ($pun_config['o_default_timezone'] == 5.5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+05:30'] ?></option>
+ <option value="5.75"<?php if ($pun_config['o_default_timezone'] == 5.75) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+05:45'] ?></option>
+ <option value="6"<?php if ($pun_config['o_default_timezone'] == 6) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+06:00'] ?></option>
+ <option value="6.5"<?php if ($pun_config['o_default_timezone'] == 6.5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+06:30'] ?></option>
+ <option value="7"<?php if ($pun_config['o_default_timezone'] == 7) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+07:00'] ?></option>
+ <option value="8"<?php if ($pun_config['o_default_timezone'] == 8) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+08:00'] ?></option>
+ <option value="8.75"<?php if ($pun_config['o_default_timezone'] == 8.75) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+08:45'] ?></option>
+ <option value="9"<?php if ($pun_config['o_default_timezone'] == 9) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+09:00'] ?></option>
+ <option value="9.5"<?php if ($pun_config['o_default_timezone'] == 9.5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+09:30'] ?></option>
+ <option value="10"<?php if ($pun_config['o_default_timezone'] == 10) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+10:00'] ?></option>
+ <option value="10.5"<?php if ($pun_config['o_default_timezone'] == 10.5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+10:30'] ?></option>
+ <option value="11"<?php if ($pun_config['o_default_timezone'] == 11) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+11:00'] ?></option>
+ <option value="11.5"<?php if ($pun_config['o_default_timezone'] == 11.5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+11:30'] ?></option>
+ <option value="12"<?php if ($pun_config['o_default_timezone'] == 12) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+12:00'] ?></option>
+ <option value="12.75"<?php if ($pun_config['o_default_timezone'] == 12.75) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+12:45'] ?></option>
+ <option value="13"<?php if ($pun_config['o_default_timezone'] == 13) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+13:00'] ?></option>
+ <option value="14"<?php if ($pun_config['o_default_timezone'] == 14) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+14:00'] ?></option>
+ </select>
+ <span><?php echo $lang_admin_options['Timezone help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['DST label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[default_dst]" value="1"<?php if ($pun_config['o_default_dst'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[default_dst]" value="0"<?php if ($pun_config['o_default_dst'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['DST help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Language label'] ?></th>
+ <td>
+ <select name="form[default_lang]">
+<?php
+
+ $languages = forum_list_langs();
+
+ foreach ($languages as $temp)
+ {
+ if ($pun_config['o_default_lang'] == $temp)
+ echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$temp.'" selected="selected">'.$temp.'</option>'."\n";
+ else
+ echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$temp.'">'.$temp.'</option>'."\n";
+ }
+
+?>
+ </select>
+ <span><?php echo $lang_admin_options['Language help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Default style label'] ?></th>
+ <td>
+ <select name="form[default_style]">
+<?php
+
+ $styles = forum_list_styles();
+
+ foreach ($styles as $temp)
+ {
+ if ($pun_config['o_default_style'] == $temp)
+ echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$temp.'" selected="selected">'.str_replace('_', ' ', $temp).'</option>'."\n";
+ else
+ echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$temp.'">'.str_replace('_', ' ', $temp).'</option>'."\n";
+ }
+
+?>
+ </select>
+ <span><?php echo $lang_admin_options['Default style help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+<?php
+
+ $diff = ($pun_user['timezone'] + $pun_user['dst']) * 3600;
+ $timestamp = time() + $diff;
+
+?>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_options['Timeouts subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Time format label'] ?></th>
+ <td>
+ <input type="text" name="form[time_format]" size="25" maxlength="25" value="<?php echo pun_htmlspecialchars($pun_config['o_time_format']) ?>" />
+ <span><?php printf($lang_admin_options['Time format help'], gmdate($pun_config['o_time_format'], $timestamp), '<a href="http://www.php.net/manual/en/function.date.php">'.$lang_admin_options['PHP manual'].'</a>') ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Date format label'] ?></th>
+ <td>
+ <input type="text" name="form[date_format]" size="25" maxlength="25" value="<?php echo pun_htmlspecialchars($pun_config['o_date_format']) ?>" />
+ <span><?php printf($lang_admin_options['Date format help'], gmdate($pun_config['o_date_format'], $timestamp), '<a href="http://www.php.net/manual/en/function.date.php">'.$lang_admin_options['PHP manual'].'</a>') ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Visit timeout label'] ?></th>
+ <td>
+ <input type="text" name="form[timeout_visit]" size="5" maxlength="5" value="<?php echo $pun_config['o_timeout_visit'] ?>" />
+ <span><?php echo $lang_admin_options['Visit timeout help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Online timeout label'] ?></th>
+ <td>
+ <input type="text" name="form[timeout_online]" size="5" maxlength="5" value="<?php echo $pun_config['o_timeout_online'] ?>" />
+ <span><?php echo $lang_admin_options['Online timeout help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Redirect time label'] ?></th>
+ <td>
+ <input type="text" name="form[redirect_delay]" size="3" maxlength="3" value="<?php echo $pun_config['o_redirect_delay'] ?>" />
+ <span><?php echo $lang_admin_options['Redirect time help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_options['Display subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Version number label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[show_version]" value="1"<?php if ($pun_config['o_show_version'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[show_version]" value="0"<?php if ($pun_config['o_show_version'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Version number help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Info in posts label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[show_user_info]" value="1"<?php if ($pun_config['o_show_user_info'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[show_user_info]" value="0"<?php if ($pun_config['o_show_user_info'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Info in posts help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Post count label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[show_post_count]" value="1"<?php if ($pun_config['o_show_post_count'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[show_post_count]" value="0"<?php if ($pun_config['o_show_post_count'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Post count help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Smilies label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[smilies]" value="1"<?php if ($pun_config['o_smilies'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[smilies]" value="0"<?php if ($pun_config['o_smilies'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Smilies help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Smilies sigs label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[smilies_sig]" value="1"<?php if ($pun_config['o_smilies_sig'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[smilies_sig]" value="0"<?php if ($pun_config['o_smilies_sig'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Smilies sigs help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Clickable links label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[make_links]" value="1"<?php if ($pun_config['o_make_links'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[make_links]" value="0"<?php if ($pun_config['o_make_links'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Clickable links help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Topic review label'] ?></th>
+ <td>
+ <input type="text" name="form[topic_review]" size="3" maxlength="3" value="<?php echo $pun_config['o_topic_review'] ?>" />
+ <span><?php echo $lang_admin_options['Topic review help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Topics per page label'] ?></th>
+ <td>
+ <input type="text" name="form[disp_topics_default]" size="3" maxlength="2" value="<?php echo $pun_config['o_disp_topics_default'] ?>" />
+ <span><?php echo $lang_admin_options['Topics per page help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Posts per page label'] ?></th>
+ <td>
+ <input type="text" name="form[disp_posts_default]" size="3" maxlength="2" value="<?php echo $pun_config['o_disp_posts_default'] ?>" />
+ <span><?php echo $lang_admin_options['Posts per page help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Indent label'] ?></th>
+ <td>
+ <input type="text" name="form[indent_num_spaces]" size="3" maxlength="3" value="<?php echo $pun_config['o_indent_num_spaces'] ?>" />
+ <span><?php echo $lang_admin_options['Indent help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Quote depth label'] ?></th>
+ <td>
+ <input type="text" name="form[quote_depth]" size="3" maxlength="3" value="<?php echo $pun_config['o_quote_depth'] ?>" />
+ <span><?php echo $lang_admin_options['Quote depth help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_options['Features subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Quick post label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[quickpost]" value="1"<?php if ($pun_config['o_quickpost'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[quickpost]" value="0"<?php if ($pun_config['o_quickpost'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Quick post help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Users online label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[users_online]" value="1"<?php if ($pun_config['o_users_online'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[users_online]" value="0"<?php if ($pun_config['o_users_online'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Users online help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><a name="censoring"></a><?php echo $lang_admin_options['Censor words label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[censoring]" value="1"<?php if ($pun_config['o_censoring'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[censoring]" value="0"<?php if ($pun_config['o_censoring'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php printf($lang_admin_options['Censor words help'], '<a href="admin_censoring.php">'.$lang_admin_common['Censoring'].'</a>') ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><a name="signatures"></a><?php echo $lang_admin_options['Signatures label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[signatures]" value="1"<?php if ($pun_config['o_signatures'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[signatures]" value="0"<?php if ($pun_config['o_signatures'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Signatures help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['User has posted label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[show_dot]" value="1"<?php if ($pun_config['o_show_dot'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[show_dot]" value="0"<?php if ($pun_config['o_show_dot'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['User has posted help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Topic views label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[topic_views]" value="1"<?php if ($pun_config['o_topic_views'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[topic_views]" value="0"<?php if ($pun_config['o_topic_views'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Topic views help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Quick jump label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[quickjump]" value="1"<?php if ($pun_config['o_quickjump'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[quickjump]" value="0"<?php if ($pun_config['o_quickjump'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Quick jump help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['GZip label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[gzip]" value="1"<?php if ($pun_config['o_gzip'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[gzip]" value="0"<?php if ($pun_config['o_gzip'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['GZip help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Search all label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[search_all_forums]" value="1"<?php if ($pun_config['o_search_all_forums'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[search_all_forums]" value="0"<?php if ($pun_config['o_search_all_forums'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Search all help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Menu items label'] ?></th>
+ <td>
+ <textarea name="form[additional_navlinks]" rows="3" cols="55"><?php echo pun_htmlspecialchars($pun_config['o_additional_navlinks']) ?></textarea>
+ <span><?php echo $lang_admin_options['Menu items help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_options['Feed subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Default feed label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[feed_type]" value="0"<?php if ($pun_config['o_feed_type'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_options['None'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[feed_type]" value="1"<?php if ($pun_config['o_feed_type'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_options['RSS'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[feed_type]" value="2"<?php if ($pun_config['o_feed_type'] == '2') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_options['Atom'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Default feed help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Feed TTL label'] ?></th>
+ <td>
+ <select name="form[feed_ttl]">
+ <option value="0"<?php if ($pun_config['o_feed_ttl'] == '0') echo ' selected="selected"'; ?>><?php echo $lang_admin_options['No cache'] ?></option>
+<?php
+
+ $times = array(5, 15, 30, 60);
+
+ foreach ($times as $time)
+ echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$time.'"'.($pun_config['o_feed_ttl'] == $time ? ' selected="selected"' : '').'>'.sprintf($lang_admin_options['Minutes'], $time).'</option>'."\n";
+
+?>
+ </select>
+ <span><?php echo $lang_admin_options['Feed TTL help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_options['Reports subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Reporting method label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[report_method]" value="0"<?php if ($pun_config['o_report_method'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_options['Internal'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[report_method]" value="1"<?php if ($pun_config['o_report_method'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_options['By e-mail'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[report_method]" value="2"<?php if ($pun_config['o_report_method'] == '2') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_options['Both'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Reporting method help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Mailing list label'] ?></th>
+ <td>
+ <textarea name="form[mailing_list]" rows="5" cols="55"><?php echo pun_htmlspecialchars($pun_config['o_mailing_list']) ?></textarea>
+ <span><?php echo $lang_admin_options['Mailing list help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_options['Avatars subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Use avatars label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[avatars]" value="1"<?php if ($pun_config['o_avatars'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[avatars]" value="0"<?php if ($pun_config['o_avatars'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Use avatars help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Upload directory label'] ?></th>
+ <td>
+ <input type="text" name="form[avatars_dir]" size="35" maxlength="50" value="<?php echo pun_htmlspecialchars($pun_config['o_avatars_dir']) ?>" />
+ <span><?php echo $lang_admin_options['Upload directory help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Max width label'] ?></th>
+ <td>
+ <input type="text" name="form[avatars_width]" size="5" maxlength="5" value="<?php echo $pun_config['o_avatars_width'] ?>" />
+ <span><?php echo $lang_admin_options['Max width help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Max height label'] ?></th>
+ <td>
+ <input type="text" name="form[avatars_height]" size="5" maxlength="5" value="<?php echo $pun_config['o_avatars_height'] ?>" />
+ <span><?php echo $lang_admin_options['Max height help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Max size label'] ?></th>
+ <td>
+ <input type="text" name="form[avatars_size]" size="6" maxlength="6" value="<?php echo $pun_config['o_avatars_size'] ?>" />
+ <span><?php echo $lang_admin_options['Max size help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_options['E-mail subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Admin e-mail label'] ?></th>
+ <td>
+ <input type="text" name="form[admin_email]" size="50" maxlength="80" value="<?php echo pun_htmlspecialchars($pun_config['o_admin_email']) ?>" />
+ <span><?php echo $lang_admin_options['Admin e-mail help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Webmaster e-mail label'] ?></th>
+ <td>
+ <input type="text" name="form[webmaster_email]" size="50" maxlength="80" value="<?php echo pun_htmlspecialchars($pun_config['o_webmaster_email']) ?>" />
+ <span><?php echo $lang_admin_options['Webmaster e-mail help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Forum subscriptions label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[forum_subscriptions]" value="1"<?php if ($pun_config['o_forum_subscriptions'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[forum_subscriptions]" value="0"<?php if ($pun_config['o_forum_subscriptions'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Forum subscriptions help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Topic subscriptions label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[topic_subscriptions]" value="1"<?php if ($pun_config['o_topic_subscriptions'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[topic_subscriptions]" value="0"<?php if ($pun_config['o_topic_subscriptions'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Topic subscriptions help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['SMTP address label'] ?></th>
+ <td>
+ <input type="text" name="form[smtp_host]" size="30" value="<?php echo pun_htmlspecialchars($pun_config['o_smtp_host']) ?>" />
+ <span><?php echo $lang_admin_options['SMTP address help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['SMTP username label'] ?></th>
+ <td>
+ <input type="text" name="form[smtp_user]" size="25" value="<?php echo pun_htmlspecialchars($pun_config['o_smtp_user']) ?>" />
+ <span><?php echo $lang_admin_options['SMTP username help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['SMTP password label'] ?></th>
+ <td>
+ <label><input type="checkbox" name="form[smtp_change_pass]" value="1" />&#160;<?php echo $lang_admin_options['SMTP change password help'] ?></label>
+<?php $smtp_pass = !empty($pun_config['o_smtp_pass']) ? random_key(pun_strlen($pun_config['o_smtp_pass']), true) : ''; ?>
+ <input type="password" name="form[smtp_pass1]" size="25" value="<?php echo $smtp_pass ?>" />
+ <input type="password" name="form[smtp_pass2]" size="25" value="<?php echo $smtp_pass ?>" />
+ <span><?php echo $lang_admin_options['SMTP password help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['SMTP SSL label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[smtp_ssl]" value="1"<?php if ($pun_config['o_smtp_ssl'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[smtp_ssl]" value="0"<?php if ($pun_config['o_smtp_ssl'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['SMTP SSL help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_options['Registration subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Allow new label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[regs_allow]" value="1"<?php if ($pun_config['o_regs_allow'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[regs_allow]" value="0"<?php if ($pun_config['o_regs_allow'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Allow new help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Verify label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[regs_verify]" value="1"<?php if ($pun_config['o_regs_verify'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[regs_verify]" value="0"<?php if ($pun_config['o_regs_verify'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Verify help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Report new label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[regs_report]" value="1"<?php if ($pun_config['o_regs_report'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[regs_report]" value="0"<?php if ($pun_config['o_regs_report'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Report new help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Use rules label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[rules]" value="1"<?php if ($pun_config['o_rules'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[rules]" value="0"<?php if ($pun_config['o_rules'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Use rules help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Rules label'] ?></th>
+ <td>
+ <textarea name="form[rules_message]" rows="10" cols="55"><?php echo pun_htmlspecialchars($pun_config['o_rules_message']) ?></textarea>
+ <span><?php echo $lang_admin_options['Rules help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['E-mail default label'] ?></th>
+ <td>
+ <span><?php echo $lang_admin_options['E-mail default help'] ?></span>
+ <label><input type="radio" name="form[default_email_setting]" id="form_default_email_setting_0" value="0"<?php if ($pun_config['o_default_email_setting'] == '0') echo ' checked="checked"' ?> />&#160;<?php echo $lang_admin_options['Display e-mail label'] ?></label>
+ <label><input type="radio" name="form[default_email_setting]" id="form_default_email_setting_1" value="1"<?php if ($pun_config['o_default_email_setting'] == '1') echo ' checked="checked"' ?> />&#160;<?php echo $lang_admin_options['Hide allow form label'] ?></label>
+ <label><input type="radio" name="form[default_email_setting]" id="form_default_email_setting_2" value="2"<?php if ($pun_config['o_default_email_setting'] == '2') echo ' checked="checked"' ?> />&#160;<?php echo $lang_admin_options['Hide both label'] ?></label>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_options['Announcement subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Display announcement label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[announcement]" value="1"<?php if ($pun_config['o_announcement'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[announcement]" value="0"<?php if ($pun_config['o_announcement'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Display announcement help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Announcement message label'] ?></th>
+ <td>
+ <textarea name="form[announcement_message]" rows="5" cols="55"><?php echo pun_htmlspecialchars($pun_config['o_announcement_message']) ?></textarea>
+ <span><?php echo $lang_admin_options['Announcement message help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_options['Maintenance subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><a name="maintenance"></a><?php echo $lang_admin_options['Maintenance mode label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[maintenance]" value="1"<?php if ($pun_config['o_maintenance'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[maintenance]" value="0"<?php if ($pun_config['o_maintenance'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_options['Maintenance mode help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_options['Maintenance message label'] ?></th>
+ <td>
+ <textarea name="form[maintenance_message]" rows="5" cols="55"><?php echo pun_htmlspecialchars($pun_config['o_maintenance_message']) ?></textarea>
+ <span><?php echo $lang_admin_options['Maintenance message help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ <p class="submitend"><input type="submit" name="save" value="<?php echo $lang_admin_common['Save changes'] ?>" /></p>
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+</div>
+<?php
+
+require PUN_ROOT.'footer.php';
diff --git a/admin_permissions.php b/admin_permissions.php
new file mode 100644
index 0000000..806b651
--- /dev/null
+++ b/admin_permissions.php
@@ -0,0 +1,191 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Tell header.php to use the admin template
+define('PUN_ADMIN_CONSOLE', 1);
+
+define('PUN_ROOT', dirname(__FILE__).'/');
+require PUN_ROOT.'include/common.php';
+require PUN_ROOT.'include/common_admin.php';
+
+
+if ($pun_user['g_id'] != PUN_ADMIN)
+ message($lang_common['No permission'], false, '403 Forbidden');
+
+// Load the admin_permissions.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_permissions.php';
+
+if (isset($_POST['form_sent']))
+{
+ confirm_referrer('admin_permissions.php');
+
+ $form = array_map('intval', $_POST['form']);
+
+ foreach ($form as $key => $input)
+ {
+ // Make sure the input is never a negative value
+ if($input < 0)
+ $input = 0;
+
+ // Only update values that have changed
+ if (array_key_exists('p_'.$key, $pun_config) && $pun_config['p_'.$key] != $input)
+ $db->query('UPDATE '.$db->prefix.'config SET conf_value='.$input.' WHERE conf_name=\'p_'.$db->escape($key).'\'') or error('Unable to update board config', __FILE__, __LINE__, $db->error());
+ }
+
+ // Regenerate the config cache
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_config_cache();
+
+ redirect('admin_permissions.php', $lang_admin_permissions['Perms updated redirect']);
+}
+
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Permissions']);
+define('PUN_ACTIVE_PAGE', 'admin');
+require PUN_ROOT.'header.php';
+
+generate_admin_menu('permissions');
+
+?>
+ <div class="blockform">
+ <h2><span><?php echo $lang_admin_permissions['Permissions head'] ?></span></h2>
+ <div class="box">
+ <form method="post" action="admin_permissions.php">
+ <p class="submittop"><input type="submit" name="save" value="<?php echo $lang_admin_common['Save changes'] ?>" /></p>
+ <div class="inform">
+ <input type="hidden" name="form_sent" value="1" />
+ <fieldset>
+ <legend><?php echo $lang_admin_permissions['Posting subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_permissions['BBCode label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[message_bbcode]" value="1"<?php if ($pun_config['p_message_bbcode'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[message_bbcode]" value="0"<?php if ($pun_config['p_message_bbcode'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_permissions['BBCode help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_permissions['Image tag label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[message_img_tag]" value="1"<?php if ($pun_config['p_message_img_tag'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[message_img_tag]" value="0"<?php if ($pun_config['p_message_img_tag'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_permissions['Image tag help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_permissions['All caps message label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[message_all_caps]" value="1"<?php if ($pun_config['p_message_all_caps'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[message_all_caps]" value="0"<?php if ($pun_config['p_message_all_caps'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_permissions['All caps message help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_permissions['All caps subject label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[subject_all_caps]" value="1"<?php if ($pun_config['p_subject_all_caps'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[subject_all_caps]" value="0"<?php if ($pun_config['p_subject_all_caps'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_permissions['All caps subject help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_permissions['Require e-mail label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[force_guest_email]" value="1"<?php if ($pun_config['p_force_guest_email'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[force_guest_email]" value="0"<?php if ($pun_config['p_force_guest_email'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_permissions['Require e-mail help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_permissions['Signatures subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_permissions['BBCode sigs label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[sig_bbcode]" value="1"<?php if ($pun_config['p_sig_bbcode'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[sig_bbcode]" value="0"<?php if ($pun_config['p_sig_bbcode'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_permissions['BBCode sigs help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_permissions['Image tag sigs label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[sig_img_tag]" value="1"<?php if ($pun_config['p_sig_img_tag'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[sig_img_tag]" value="0"<?php if ($pun_config['p_sig_img_tag'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_permissions['Image tag sigs help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_permissions['All caps sigs label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[sig_all_caps]" value="1"<?php if ($pun_config['p_sig_all_caps'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[sig_all_caps]" value="0"<?php if ($pun_config['p_sig_all_caps'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_permissions['All caps sigs help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_permissions['Max sig length label'] ?></th>
+ <td>
+ <input type="text" name="form[sig_length]" size="5" maxlength="5" value="<?php echo $pun_config['p_sig_length'] ?>" />
+ <span class="clearb"><?php echo $lang_admin_permissions['Max sig length help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_permissions['Max sig lines label'] ?></th>
+ <td>
+ <input type="text" name="form[sig_lines]" size="3" maxlength="3" value="<?php echo $pun_config['p_sig_lines'] ?>" />
+ <span class="clearb"><?php echo $lang_admin_permissions['Max sig lines help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_permissions['Registration subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_permissions['Banned e-mail label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[allow_banned_email]" value="1"<?php if ($pun_config['p_allow_banned_email'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[allow_banned_email]" value="0"<?php if ($pun_config['p_allow_banned_email'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_permissions['Banned e-mail help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_permissions['Duplicate e-mail label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="form[allow_dupe_email]" value="1"<?php if ($pun_config['p_allow_dupe_email'] == '1') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="form[allow_dupe_email]" value="0"<?php if ($pun_config['p_allow_dupe_email'] == '0') echo ' checked="checked"' ?> />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_permissions['Duplicate e-mail help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ <p class="submitend"><input type="submit" name="save" value="<?php echo $lang_admin_common['Save changes'] ?>" /></p>
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+</div>
+<?php
+
+require PUN_ROOT.'footer.php';
diff --git a/admin_reports.php b/admin_reports.php
new file mode 100644
index 0000000..77f2163
--- /dev/null
+++ b/admin_reports.php
@@ -0,0 +1,183 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Tell header.php to use the admin template
+define('PUN_ADMIN_CONSOLE', 1);
+
+define('PUN_ROOT', dirname(__FILE__).'/');
+require PUN_ROOT.'include/common.php';
+require PUN_ROOT.'include/common_admin.php';
+
+
+if (!$pun_user['is_admmod'])
+ message($lang_common['No permission'], false, '403 Forbidden');
+
+// Load the admin_reports.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_reports.php';
+
+// Zap a report
+if (isset($_POST['zap_id']))
+{
+ confirm_referrer('admin_reports.php');
+
+ $zap_id = intval(key($_POST['zap_id']));
+
+ $result = $db->query('SELECT zapped FROM '.$db->prefix.'reports WHERE id='.$zap_id) or error('Unable to fetch report info', __FILE__, __LINE__, $db->error());
+ $zapped = $db->result($result);
+
+ if ($zapped == '')
+ $db->query('UPDATE '.$db->prefix.'reports SET zapped='.time().', zapped_by='.$pun_user['id'].' WHERE id='.$zap_id) or error('Unable to zap report', __FILE__, __LINE__, $db->error());
+
+ // Delete old reports (which cannot be viewed anyway)
+ $result = $db->query('SELECT zapped FROM '.$db->prefix.'reports WHERE zapped IS NOT NULL ORDER BY zapped DESC LIMIT 10,1') or error('Unable to fetch read reports to delete', __FILE__, __LINE__, $db->error());
+ if ($db->num_rows($result) > 0)
+ {
+ $zapped_threshold = $db->result($result);
+ $db->query('DELETE FROM '.$db->prefix.'reports WHERE zapped <= '.$zapped_threshold) or error('Unable to delete old read reports', __FILE__, __LINE__, $db->error());
+ }
+
+ redirect('admin_reports.php', $lang_admin_reports['Report zapped redirect']);
+}
+
+
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Reports']);
+define('PUN_ACTIVE_PAGE', 'admin');
+require PUN_ROOT.'header.php';
+
+generate_admin_menu('reports');
+
+?>
+ <div class="blockform">
+ <h2><span><?php echo $lang_admin_reports['New reports head'] ?></span></h2>
+ <div class="box">
+ <form method="post" action="admin_reports.php?action=zap">
+<?php
+
+$result = $db->query('SELECT r.id, r.topic_id, r.forum_id, r.reported_by, r.created, r.message, p.id AS pid, t.subject, f.forum_name, u.username AS reporter FROM '.$db->prefix.'reports AS r LEFT JOIN '.$db->prefix.'posts AS p ON r.post_id=p.id LEFT JOIN '.$db->prefix.'topics AS t ON r.topic_id=t.id LEFT JOIN '.$db->prefix.'forums AS f ON r.forum_id=f.id LEFT JOIN '.$db->prefix.'users AS u ON r.reported_by=u.id WHERE r.zapped IS NULL ORDER BY created DESC') or error('Unable to fetch report list', __FILE__, __LINE__, $db->error());
+
+if ($db->num_rows($result))
+{
+ while ($cur_report = $db->fetch_assoc($result))
+ {
+ $reporter = ($cur_report['reporter'] != '') ? '<a href="profile.php?id='.$cur_report['reported_by'].'">'.pun_htmlspecialchars($cur_report['reporter']).'</a>' : $lang_admin_reports['Deleted user'];
+ $forum = ($cur_report['forum_name'] != '') ? '<span><a href="viewforum.php?id='.$cur_report['forum_id'].'">'.pun_htmlspecialchars($cur_report['forum_name']).'</a></span>' : '<span>'.$lang_admin_reports['Deleted'].'</span>';
+ $topic = ($cur_report['subject'] != '') ? '<span>»&#160;<a href="viewtopic.php?id='.$cur_report['topic_id'].'">'.pun_htmlspecialchars($cur_report['subject']).'</a></span>' : '<span>»&#160;'.$lang_admin_reports['Deleted'].'</span>';
+ $post = str_replace("\n", '<br />', pun_htmlspecialchars($cur_report['message']));
+ $post_id = ($cur_report['pid'] != '') ? '<span>»&#160;<a href="viewtopic.php?pid='.$cur_report['pid'].'#p'.$cur_report['pid'].'">'.sprintf($lang_admin_reports['Post ID'], $cur_report['pid']).'</a></span>' : '<span>»&#160;'.$lang_admin_reports['Deleted'].'</span>';
+ $report_location = array($forum, $topic, $post_id);
+
+?>
+ <div class="inform">
+ <fieldset>
+ <legend><?php printf($lang_admin_reports['Report subhead'], format_time($cur_report['created'])) ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php printf($lang_admin_reports['Reported by'], $reporter) ?></th>
+ <td class="location"><?php echo implode(' ', $report_location) ?></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_reports['Reason'] ?><div><input type="submit" name="zap_id[<?php echo $cur_report['id'] ?>]" value="<?php echo $lang_admin_reports['Zap'] ?>" /></div></th>
+ <td><?php echo $post ?></td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+<?php
+
+ }
+}
+else
+{
+
+?>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_common['None'] ?></legend>
+ <div class="infldset">
+ <p><?php echo $lang_admin_reports['No new reports'] ?></p>
+ </div>
+ </fieldset>
+ </div>
+<?php
+
+}
+
+?>
+ </form>
+ </div>
+ </div>
+
+ <div class="blockform block2">
+ <h2><span><?php echo $lang_admin_reports['Last 10 head'] ?></span></h2>
+ <div class="box">
+ <div class="fakeform">
+<?php
+
+$result = $db->query('SELECT r.id, r.topic_id, r.forum_id, r.reported_by, r.message, r.zapped, r.zapped_by AS zapped_by_id, p.id AS pid, t.subject, f.forum_name, u.username AS reporter, u2.username AS zapped_by FROM '.$db->prefix.'reports AS r LEFT JOIN '.$db->prefix.'posts AS p ON r.post_id=p.id LEFT JOIN '.$db->prefix.'topics AS t ON r.topic_id=t.id LEFT JOIN '.$db->prefix.'forums AS f ON r.forum_id=f.id LEFT JOIN '.$db->prefix.'users AS u ON r.reported_by=u.id LEFT JOIN '.$db->prefix.'users AS u2 ON r.zapped_by=u2.id WHERE r.zapped IS NOT NULL ORDER BY zapped DESC LIMIT 10') or error('Unable to fetch report list', __FILE__, __LINE__, $db->error());
+
+if ($db->num_rows($result))
+{
+ while ($cur_report = $db->fetch_assoc($result))
+ {
+ $reporter = ($cur_report['reporter'] != '') ? '<a href="profile.php?id='.$cur_report['reported_by'].'">'.pun_htmlspecialchars($cur_report['reporter']).'</a>' : $lang_admin_reports['Deleted user'];
+ $forum = ($cur_report['forum_name'] != '') ? '<span><a href="viewforum.php?id='.$cur_report['forum_id'].'">'.pun_htmlspecialchars($cur_report['forum_name']).'</a></span>' : '<span>'.$lang_admin_reports['Deleted'].'</span>';
+ $topic = ($cur_report['subject'] != '') ? '<span>»&#160;<a href="viewtopic.php?id='.$cur_report['topic_id'].'">'.pun_htmlspecialchars($cur_report['subject']).'</a></span>' : '<span>»&#160;'.$lang_admin_reports['Deleted'].'</span>';
+ $post = str_replace("\n", '<br />', pun_htmlspecialchars($cur_report['message']));
+ $post_id = ($cur_report['pid'] != '') ? '<span>»&#160;<a href="viewtopic.php?pid='.$cur_report['pid'].'#p'.$cur_report['pid'].'">'.sprintf($lang_admin_reports['Post ID'], $cur_report['pid']).'</a></span>' : '<span>»&#160;'.$lang_admin_reports['Deleted'].'</span>';
+ $zapped_by = ($cur_report['zapped_by'] != '') ? '<strong>'.pun_htmlspecialchars($cur_report['zapped_by']).'</strong>' : $lang_admin_reports['NA'];
+ $report_location = array($forum, $topic, $post_id);
+
+?>
+ <div class="inform">
+ <fieldset>
+ <legend><?php printf($lang_admin_reports['Zapped subhead'], format_time($cur_report['zapped']), $zapped_by) ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php printf($lang_admin_reports['Reported by'], $reporter) ?></th>
+ <td class="location"><?php echo implode(' ', $report_location) ?></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_reports['Reason'] ?></th>
+ <td><?php echo $post ?></td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+<?php
+
+ }
+}
+else
+{
+
+?>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_common['None'] ?></legend>
+ <div class="infldset">
+ <p><?php echo $lang_admin_reports['No zapped reports'] ?></p>
+ </div>
+ </fieldset>
+ </div>
+<?php
+
+}
+
+?>
+ </div>
+ </div>
+ </div>
+ <div class="clearer"></div>
+</div>
+<?php
+
+require PUN_ROOT.'footer.php';
diff --git a/admin_statistics.php b/admin_statistics.php
new file mode 100644
index 0000000..901e14c
--- /dev/null
+++ b/admin_statistics.php
@@ -0,0 +1,139 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Tell header.php to use the admin template
+define('PUN_ADMIN_CONSOLE', 1);
+
+define('PUN_ROOT', dirname(__FILE__).'/');
+require PUN_ROOT.'include/common.php';
+require PUN_ROOT.'include/common_admin.php';
+
+
+if (!$pun_user['is_admmod'])
+ message($lang_common['No permission'], false, '403 Forbidden');
+
+// Load the admin_index.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_index.php';
+
+$action = isset($_GET['action']) ? $_GET['action'] : null;
+
+
+// Show phpinfo() output
+if ($action == 'phpinfo' && $pun_user['g_id'] == PUN_ADMIN)
+{
+ // Is phpinfo() a disabled function?
+ if (strpos(strtolower((string) ini_get('disable_functions')), 'phpinfo') !== false)
+ message($lang_admin_index['PHPinfo disabled message']);
+
+ phpinfo();
+ exit;
+}
+
+
+// Get the server load averages (if possible)
+if (@file_exists('/proc/loadavg') && is_readable('/proc/loadavg'))
+{
+ // We use @ just in case
+ $fh = @fopen('/proc/loadavg', 'r');
+ $load_averages = @fread($fh, 64);
+ @fclose($fh);
+
+ if (($fh = @fopen('/proc/loadavg', 'r')))
+ {
+ $load_averages = fread($fh, 64);
+ fclose($fh);
+ }
+ else
+ $load_averages = '';
+
+ $load_averages = @explode(' ', $load_averages);
+ $server_load = isset($load_averages[2]) ? $load_averages[0].' '.$load_averages[1].' '.$load_averages[2] : $lang_admin_index['Not available'];
+}
+else if (!in_array(PHP_OS, array('WINNT', 'WIN32')) && preg_match('%averages?: ([0-9\.]+),?\s+([0-9\.]+),?\s+([0-9\.]+)%i', @exec('uptime'), $load_averages))
+ $server_load = $load_averages[1].' '.$load_averages[2].' '.$load_averages[3];
+else
+ $server_load = $lang_admin_index['Not available'];
+
+
+// Get number of current visitors
+$result = $db->query('SELECT COUNT(user_id) FROM '.$db->prefix.'online WHERE idle=0') or error('Unable to fetch online count', __FILE__, __LINE__, $db->error());
+$num_online = $db->result($result);
+
+
+// Collect some additional info about MySQL
+if ($db_type == 'mysql' || $db_type == 'mysqli' || $db_type == 'mysql_innodb' || $db_type == 'mysqli_innodb')
+{
+ // Calculate total db size/row count
+ $result = $db->query('SHOW TABLE STATUS LIKE \''.$db->prefix.'%\'') or error('Unable to fetch table status', __FILE__, __LINE__, $db->error());
+
+ $total_records = $total_size = 0;
+ while ($status = $db->fetch_assoc($result))
+ {
+ $total_records += $status['Rows'];
+ $total_size += $status['Data_length'] + $status['Index_length'];
+ }
+
+ $total_size = file_size($total_size);
+}
+
+
+// Check for the existence of various PHP opcode caches/optimizers
+if (function_exists('mmcache'))
+ $php_accelerator = '<a href="http://'.$lang_admin_index['Turck MMCache link'].'">'.$lang_admin_index['Turck MMCache'].'</a>';
+else if (isset($_PHPA))
+ $php_accelerator = '<a href="http://'.$lang_admin_index['ionCube PHP Accelerator link'].'">'.$lang_admin_index['ionCube PHP Accelerator'].'</a>';
+else if (ini_get('apc.enabled'))
+ $php_accelerator ='<a href="http://'.$lang_admin_index['Alternative PHP Cache (APC) link'].'">'.$lang_admin_index['Alternative PHP Cache (APC)'].'</a>';
+else if (ini_get('zend_optimizer.optimization_level'))
+ $php_accelerator = '<a href="http://'.$lang_admin_index['Zend Optimizer link'].'">'.$lang_admin_index['Zend Optimizer'].'</a>';
+else if (ini_get('eaccelerator.enable'))
+ $php_accelerator = '<a href="http://'.$lang_admin_index['eAccelerator link'].'">'.$lang_admin_index['eAccelerator'].'</a>';
+else if (ini_get('xcache.cacher'))
+ $php_accelerator = '<a href="http://'.$lang_admin_index['XCache link'].'">'.$lang_admin_index['XCache'].'</a>';
+else
+ $php_accelerator = $lang_admin_index['NA'];
+
+
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Server statistics']);
+define('PUN_ACTIVE_PAGE', 'admin');
+require PUN_ROOT.'header.php';
+
+generate_admin_menu('index');
+
+?>
+ <div class="block">
+ <h2><span><?php echo $lang_admin_index['Server statistics head'] ?></span></h2>
+ <div id="adstats" class="box">
+ <div class="inbox">
+ <dl>
+ <dt><?php echo $lang_admin_index['Server load label'] ?></dt>
+ <dd>
+ <?php printf($lang_admin_index['Server load data']."\n", $server_load, $num_online) ?>
+ </dd>
+<?php if ($pun_user['g_id'] == PUN_ADMIN): ?> <dt><?php echo $lang_admin_index['Environment label'] ?></dt>
+ <dd>
+ <?php printf($lang_admin_index['Environment data OS'], PHP_OS) ?><br />
+ <?php printf($lang_admin_index['Environment data version'], phpversion(), '<a href="admin_statistics.php?action=phpinfo">'.$lang_admin_index['Show info'].'</a>') ?><br />
+ <?php printf($lang_admin_index['Environment data acc']."\n", $php_accelerator) ?>
+ </dd>
+ <dt><?php echo $lang_admin_index['Database label'] ?></dt>
+ <dd>
+ <?php echo implode(' ', $db->get_version())."\n" ?>
+<?php if (isset($total_records) && isset($total_size)): ?> <br /><?php printf($lang_admin_index['Database data rows']."\n", forum_number_format($total_records)) ?>
+ <br /><?php printf($lang_admin_index['Database data size']."\n", $total_size) ?>
+<?php endif; ?> </dd>
+<?php endif; ?>
+ </dl>
+ </div>
+ </div>
+ </div>
+ <div class="clearer"></div>
+</div>
+<?php
+
+require PUN_ROOT.'footer.php';
diff --git a/admin_users.php b/admin_users.php
new file mode 100644
index 0000000..ac076d8
--- /dev/null
+++ b/admin_users.php
@@ -0,0 +1,1095 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Tell header.php to use the admin template
+define('PUN_ADMIN_CONSOLE', 1);
+
+define('PUN_ROOT', dirname(__FILE__).'/');
+require PUN_ROOT.'include/common.php';
+require PUN_ROOT.'include/common_admin.php';
+
+
+if (!$pun_user['is_admmod'])
+ message($lang_common['No permission'], false, '403 Forbidden');
+
+// Load the admin_users.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_users.php';
+
+// Show IP statistics for a certain user ID
+if (isset($_GET['ip_stats']))
+{
+ $ip_stats = intval($_GET['ip_stats']);
+ if ($ip_stats < 1)
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+ // Fetch ip count
+ $result = $db->query('SELECT poster_ip, MAX(posted) AS last_used FROM '.$db->prefix.'posts WHERE poster_id='.$ip_stats.' GROUP BY poster_ip') or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
+ $num_ips = $db->num_rows($result);
+
+ // Determine the ip offset (based on $_GET['p'])
+ $num_pages = ceil($num_ips / 50);
+
+ $p = (!isset($_GET['p']) || $_GET['p'] <= 1 || $_GET['p'] > $num_pages) ? 1 : intval($_GET['p']);
+ $start_from = 50 * ($p - 1);
+
+ // Generate paging links
+ $paging_links = '<span class="pages-label">'.$lang_common['Pages'].' </span>'.paginate($num_pages, $p, 'admin_users.php?ip_stats='.$ip_stats );
+
+ $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Users'], $lang_admin_users['Results head']);
+ define('PUN_ACTIVE_PAGE', 'admin');
+ require PUN_ROOT.'header.php';
+
+?>
+<div class="linkst">
+ <div class="inbox crumbsplus">
+ <ul class="crumbs">
+ <li><a href="admin_index.php"><?php echo $lang_admin_common['Admin'].' '.$lang_admin_common['Index'] ?></a></li>
+ <li><span>»&#160;</span><a href="admin_users.php"><?php echo $lang_admin_common['Users'] ?></a></li>
+ <li><span>»&#160;</span><strong><?php echo $lang_admin_users['Results head'] ?></strong></li>
+ </ul>
+ <div class="pagepost">
+ <p class="pagelink"><?php echo $paging_links ?></p>
+ </div>
+ <div class="clearer"></div>
+ </div>
+</div>
+
+<div id="users1" class="blocktable">
+ <h2><span><?php echo $lang_admin_users['Results head'] ?></span></h2>
+ <div class="box">
+ <div class="inbox">
+ <table>
+ <thead>
+ <tr>
+ <th class="tcl" scope="col"><?php echo $lang_admin_users['Results IP address head'] ?></th>
+ <th class="tc2" scope="col"><?php echo $lang_admin_users['Results last used head'] ?></th>
+ <th class="tc3" scope="col"><?php echo $lang_admin_users['Results times found head'] ?></th>
+ <th class="tcr" scope="col"><?php echo $lang_admin_users['Results action head'] ?></th>
+ </tr>
+ </thead>
+ <tbody>
+<?php
+
+ $result = $db->query('SELECT poster_ip, MAX(posted) AS last_used, COUNT(id) AS used_times FROM '.$db->prefix.'posts WHERE poster_id='.$ip_stats.' GROUP BY poster_ip ORDER BY last_used DESC LIMIT '.$start_from.', 50') or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
+ if ($db->num_rows($result))
+ {
+ while ($cur_ip = $db->fetch_assoc($result))
+ {
+
+?>
+ <tr>
+ <td class="tcl"><a href="moderate.php?get_host=<?php echo pun_htmlspecialchars($cur_ip['poster_ip']) ?>"><?php echo pun_htmlspecialchars($cur_ip['poster_ip']) ?></a></td>
+ <td class="tc2"><?php echo format_time($cur_ip['last_used']) ?></td>
+ <td class="tc3"><?php echo $cur_ip['used_times'] ?></td>
+ <td class="tcr"><a href="admin_users.php?show_users=<?php echo pun_htmlspecialchars($cur_ip['poster_ip']) ?>"><?php echo $lang_admin_users['Results find more link'] ?></a></td>
+ </tr>
+<?php
+
+ }
+ }
+ else
+ echo "\t\t\t\t".'<tr><td class="tcl" colspan="4">'.$lang_admin_users['Results no posts found'].'</td></tr>'."\n";
+
+?>
+ </tbody>
+ </table>
+ </div>
+ </div>
+</div>
+
+<div class="linksb">
+ <div class="inbox crumbsplus">
+ <div class="pagepost">
+ <p class="pagelink"><?php echo $paging_links ?></p>
+ </div>
+ <ul class="crumbs">
+ <li><a href="admin_index.php"><?php echo $lang_admin_common['Admin'].' '.$lang_admin_common['Index'] ?></a></li>
+ <li><span>»&#160;</span><a href="admin_users.php"><?php echo $lang_admin_common['Users'] ?></a></li>
+ <li><span>»&#160;</span><strong><?php echo $lang_admin_users['Results head'] ?></strong></li>
+ </ul>
+ <div class="clearer"></div>
+ </div>
+</div>
+<?php
+
+ require PUN_ROOT.'footer.php';
+}
+
+
+if (isset($_GET['show_users']))
+{
+ $ip = pun_trim($_GET['show_users']);
+
+ if (!@preg_match('%^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$%', $ip) && !@preg_match('%^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$%', $ip))
+ message($lang_admin_users['Bad IP message']);
+
+ // Fetch user count
+ $result = $db->query('SELECT DISTINCT poster_id, poster FROM '.$db->prefix.'posts WHERE poster_ip=\''.$db->escape($ip).'\'') or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
+ $num_users = $db->num_rows($result);
+
+ // Determine the user offset (based on $_GET['p'])
+ $num_pages = ceil($num_users / 50);
+
+ $p = (!isset($_GET['p']) || $_GET['p'] <= 1 || $_GET['p'] > $num_pages) ? 1 : intval($_GET['p']);
+ $start_from = 50 * ($p - 1);
+
+ // Generate paging links
+ $paging_links = '<span class="pages-label">'.$lang_common['Pages'].' </span>'.paginate($num_pages, $p, 'admin_users.php?show_users='.$ip);
+
+ $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Users'], $lang_admin_users['Results head']);
+ define('PUN_ACTIVE_PAGE', 'admin');
+ require PUN_ROOT.'header.php';
+
+?>
+<div class="linkst">
+ <div class="inbox crumbsplus">
+ <ul class="crumbs">
+ <li><a href="admin_index.php"><?php echo $lang_admin_common['Admin'].' '.$lang_admin_common['Index'] ?></a></li>
+ <li><span>»&#160;</span><a href="admin_users.php"><?php echo $lang_admin_common['Users'] ?></a></li>
+ <li><span>»&#160;</span><strong><?php echo $lang_admin_users['Results head'] ?></strong></li>
+ </ul>
+ <div class="pagepost">
+ <p class="pagelink"><?php echo $paging_links ?></p>
+ </div>
+ <div class="clearer"></div>
+ </div>
+</div>
+
+<div id="users2" class="blocktable">
+ <h2><span><?php echo $lang_admin_users['Results head'] ?></span></h2>
+ <div class="box">
+ <div class="inbox">
+ <table>
+ <thead>
+ <tr>
+ <th class="tcl" scope="col"><?php echo $lang_admin_users['Results username head'] ?></th>
+ <th class="tc2" scope="col"><?php echo $lang_admin_users['Results e-mail head'] ?></th>
+ <th class="tc3" scope="col"><?php echo $lang_admin_users['Results title head'] ?></th>
+ <th class="tc4" scope="col"><?php echo $lang_admin_users['Results posts head'] ?></th>
+ <th class="tc5" scope="col"><?php echo $lang_admin_users['Results admin note head'] ?></th>
+ <th class="tcr" scope="col"><?php echo $lang_admin_users['Results actions head'] ?></th>
+ </tr>
+ </thead>
+ <tbody>
+<?php
+
+ $result = $db->query('SELECT DISTINCT poster_id, poster FROM '.$db->prefix.'posts WHERE poster_ip=\''.$db->escape($ip).'\' ORDER BY poster ASC LIMIT '.$start_from.', 50') or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
+ $num_posts = $db->num_rows($result);
+
+ if ($num_posts)
+ {
+ $posters = $poster_ids = array();
+ while ($cur_poster = $db->fetch_assoc($result))
+ {
+ $posters[] = $cur_poster;
+ $poster_ids[] = $cur_poster['poster_id'];
+ }
+
+ $result = $db->query('SELECT u.id, u.username, u.email, u.title, u.num_posts, u.admin_note, g.g_id, g.g_user_title FROM '.$db->prefix.'users AS u INNER JOIN '.$db->prefix.'groups AS g ON g.g_id=u.group_id WHERE u.id>1 AND u.id IN('.implode(',', $poster_ids).')') or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
+
+ $user_data = array();
+ while ($cur_user = $db->fetch_assoc($result))
+ $user_data[$cur_user['id']] = $cur_user;
+
+ // Loop through users and print out some info
+ foreach ($posters as $cur_poster)
+ {
+ if (isset($user_data[$cur_poster['poster_id']]))
+ {
+ $user_title = get_title($user_data[$cur_poster['poster_id']]);
+
+ $actions = '<a href="admin_users.php?ip_stats='.$user_data[$cur_poster['poster_id']]['id'].'">'.$lang_admin_users['Results view IP link'].'</a> | <a href="search.php?action=show_user_posts&amp;user_id='.$user_data[$cur_poster['poster_id']]['id'].'">'.$lang_admin_users['Results show posts link'].'</a>';
+
+?>
+ <tr>
+ <td class="tcl"><?php echo '<a href="profile.php?id='.$user_data[$cur_poster['poster_id']]['id'].'">'.pun_htmlspecialchars($user_data[$cur_poster['poster_id']]['username']).'</a>' ?></td>
+ <td class="tc2"><a href="mailto:<?php echo pun_htmlspecialchars($user_data[$cur_poster['poster_id']]['email']) ?>"><?php echo pun_htmlspecialchars($user_data[$cur_poster['poster_id']]['email']) ?></a></td>
+ <td class="tc3"><?php echo $user_title ?></td>
+ <td class="tc4"><?php echo forum_number_format($user_data[$cur_poster['poster_id']]['num_posts']) ?></td>
+ <td class="tc5"><?php echo ($user_data[$cur_poster['poster_id']]['admin_note'] != '') ? pun_htmlspecialchars($user_data[$cur_poster['poster_id']]['admin_note']) : '&#160;' ?></td>
+ <td class="tcr"><?php echo $actions ?></td>
+ </tr>
+<?php
+
+ }
+ else
+ {
+
+?>
+ <tr>
+ <td class="tcl"><?php echo pun_htmlspecialchars($cur_poster['poster']) ?></td>
+ <td class="tc2">&#160;</td>
+ <td class="tc3"><?php echo $lang_admin_users['Results guest'] ?></td>
+ <td class="tc4">&#160;</td>
+ <td class="tc5">&#160;</td>
+ <td class="tcr">&#160;</td>
+ </tr>
+<?php
+
+ }
+ }
+ }
+ else
+ echo "\t\t\t\t".'<tr><td class="tcl" colspan="6">'.$lang_admin_users['Results no IP found'].'</td></tr>'."\n";
+
+?>
+ </tbody>
+ </table>
+ </div>
+ </div>
+</div>
+
+<div class="linksb">
+ <div class="inbox crumbsplus">
+ <div class="pagepost">
+ <p class="pagelink"><?php echo $paging_links ?></p>
+ </div>
+ <ul class="crumbs">
+ <li><a href="admin_index.php"><?php echo $lang_admin_common['Admin'].' '.$lang_admin_common['Index'] ?></a></li>
+ <li><span>»&#160;</span><a href="admin_users.php"><?php echo $lang_admin_common['Users'] ?></a></li>
+ <li><span>»&#160;</span><strong><?php echo $lang_admin_users['Results head'] ?></strong></li>
+ </ul>
+ <div class="clearer"></div>
+ </div>
+</div>
+<?php
+ require PUN_ROOT.'footer.php';
+}
+
+
+// Move multiple users to other user groups
+else if (isset($_POST['move_users']) || isset($_POST['move_users_comply']))
+{
+ if ($pun_user['g_id'] > PUN_ADMIN)
+ message($lang_common['No permission'], false, '403 Forbidden');
+
+ confirm_referrer('admin_users.php');
+
+ if (isset($_POST['users']))
+ {
+ $user_ids = is_array($_POST['users']) ? array_keys($_POST['users']) : explode(',', $_POST['users']);
+ $user_ids = array_map('intval', $user_ids);
+
+ // Delete invalid IDs
+ $user_ids = array_diff($user_ids, array(0, 1));
+ }
+ else
+ $user_ids = array();
+
+ if (empty($user_ids))
+ message($lang_admin_users['No users selected']);
+
+ // Are we trying to batch move any admins?
+ $result = $db->query('SELECT COUNT(*) FROM '.$db->prefix.'users WHERE id IN ('.implode(',', $user_ids).') AND group_id='.PUN_ADMIN) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
+ if ($db->result($result) > 0)
+ message($lang_admin_users['No move admins message']);
+
+ // Fetch all user groups
+ $all_groups = array();
+ $result = $db->query('SELECT g_id, g_title FROM '.$db->prefix.'groups WHERE g_id NOT IN ('.PUN_GUEST.','.PUN_ADMIN.') ORDER BY g_title ASC') or error('Unable to fetch groups', __FILE__, __LINE__, $db->error());
+ while ($row = $db->fetch_row($result))
+ $all_groups[$row[0]] = $row[1];
+
+ if (isset($_POST['move_users_comply']))
+ {
+ $new_group = isset($_POST['new_group']) && isset($all_groups[$_POST['new_group']]) ? $_POST['new_group'] : message($lang_admin_users['Invalid group message']);
+
+ // Is the new group a moderator group?
+ $result = $db->query('SELECT g_moderator FROM '.$db->prefix.'groups WHERE g_id='.$new_group) or error('Unable to fetch group info', __FILE__, __LINE__, $db->error());
+ $new_group_mod = $db->result($result);
+
+ // Fetch user groups
+ $user_groups = array();
+ $result = $db->query('SELECT id, group_id FROM '.$db->prefix.'users WHERE id IN ('.implode(',', $user_ids).')') or error('Unable to fetch user groups', __FILE__, __LINE__, $db->error());
+ while ($cur_user = $db->fetch_assoc($result))
+ {
+ if (!isset($user_groups[$cur_user['group_id']]))
+ $user_groups[$cur_user['group_id']] = array();
+
+ $user_groups[$cur_user['group_id']][] = $cur_user['id'];
+ }
+
+ // Are any users moderators?
+ $group_ids = array_keys($user_groups);
+ $result = $db->query('SELECT g_id, g_moderator FROM '.$db->prefix.'groups WHERE g_id IN ('.implode(',', $group_ids).')') or error('Unable to fetch group moderators', __FILE__, __LINE__, $db->error());
+ while ($cur_group = $db->fetch_assoc($result))
+ {
+ if ($cur_group['g_moderator'] == '0')
+ unset($user_groups[$cur_group['g_id']]);
+ }
+
+ if (!empty($user_groups) && $new_group != PUN_ADMIN && $new_group_mod != '1')
+ {
+ // Fetch forum list and clean up their moderator list
+ $result = $db->query('SELECT id, moderators FROM '.$db->prefix.'forums') or error('Unable to fetch forum list', __FILE__, __LINE__, $db->error());
+ while ($cur_forum = $db->fetch_assoc($result))
+ {
+ $cur_moderators = ($cur_forum['moderators'] != '') ? unserialize($cur_forum['moderators']) : array();
+
+ foreach ($user_groups as $group_users)
+ $cur_moderators = array_diff($cur_moderators, $group_users);
+
+ $cur_moderators = (!empty($cur_moderators)) ? '\''.$db->escape(serialize($cur_moderators)).'\'' : 'NULL';
+ $db->query('UPDATE '.$db->prefix.'forums SET moderators='.$cur_moderators.' WHERE id='.$cur_forum['id']) or error('Unable to update forum', __FILE__, __LINE__, $db->error());
+ }
+ }
+
+ // Change user group
+ $db->query('UPDATE '.$db->prefix.'users SET group_id='.$new_group.' WHERE id IN ('.implode(',', $user_ids).')') or error('Unable to change user group', __FILE__, __LINE__, $db->error());
+
+ redirect('admin_users.php', $lang_admin_users['Users move redirect']);
+ }
+
+ $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Users'], $lang_admin_users['Move users']);
+ define('PUN_ACTIVE_PAGE', 'admin');
+ require PUN_ROOT.'header.php';
+
+ generate_admin_menu('users');
+
+?>
+ <div class="blockform">
+ <h2><span><?php echo $lang_admin_users['Move users'] ?></span></h2>
+ <div class="box">
+ <form name="confirm_move_users" method="post" action="admin_users.php">
+ <input type="hidden" name="users" value="<?php echo implode(',', $user_ids) ?>" />
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_users['Move users subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['New group label'] ?></th>
+ <td>
+ <select name="new_group" tabindex="1">
+<?php foreach ($all_groups as $gid => $group) : ?> <option value="<?php echo $gid ?>"><?php echo pun_htmlspecialchars($group) ?></option>
+<?php endforeach; ?>
+ </select>
+ <span><?php echo $lang_admin_users['New group help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ <p class="submitend"><input type="submit" name="move_users_comply" value="<?php echo $lang_admin_common['Save'] ?>" tabindex="2" /></p>
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+</div>
+<?php
+
+ require PUN_ROOT.'footer.php';
+}
+
+
+// Delete multiple users
+else if (isset($_POST['delete_users']) || isset($_POST['delete_users_comply']))
+{
+ if ($pun_user['g_id'] > PUN_ADMIN)
+ message($lang_common['No permission'], false, '403 Forbidden');
+
+ confirm_referrer('admin_users.php');
+
+ if (isset($_POST['users']))
+ {
+ $user_ids = is_array($_POST['users']) ? array_keys($_POST['users']) : explode(',', $_POST['users']);
+ $user_ids = array_map('intval', $user_ids);
+
+ // Delete invalid IDs
+ $user_ids = array_diff($user_ids, array(0, 1));
+ }
+ else
+ $user_ids = array();
+
+ if (empty($user_ids))
+ message($lang_admin_users['No users selected']);
+
+ // Are we trying to delete any admins?
+ $result = $db->query('SELECT COUNT(*) FROM '.$db->prefix.'users WHERE id IN ('.implode(',', $user_ids).') AND group_id='.PUN_ADMIN) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
+ if ($db->result($result) > 0)
+ message($lang_admin_users['No delete admins message']);
+
+ if (isset($_POST['delete_users_comply']))
+ {
+ // Fetch user groups
+ $user_groups = array();
+ $result = $db->query('SELECT id, group_id FROM '.$db->prefix.'users WHERE id IN ('.implode(',', $user_ids).')') or error('Unable to fetch user groups', __FILE__, __LINE__, $db->error());
+ while ($cur_user = $db->fetch_assoc($result))
+ {
+ if (!isset($user_groups[$cur_user['group_id']]))
+ $user_groups[$cur_user['group_id']] = array();
+
+ $user_groups[$cur_user['group_id']][] = $cur_user['id'];
+ }
+
+ // Are any users moderators?
+ $group_ids = array_keys($user_groups);
+ $result = $db->query('SELECT g_id, g_moderator FROM '.$db->prefix.'groups WHERE g_id IN ('.implode(',', $group_ids).')') or error('Unable to fetch group moderators', __FILE__, __LINE__, $db->error());
+ while ($cur_group = $db->fetch_assoc($result))
+ {
+ if ($cur_group['g_moderator'] == '0')
+ unset($user_groups[$cur_group['g_id']]);
+ }
+
+ // Fetch forum list and clean up their moderator list
+ $result = $db->query('SELECT id, moderators FROM '.$db->prefix.'forums') or error('Unable to fetch forum list', __FILE__, __LINE__, $db->error());
+ while ($cur_forum = $db->fetch_assoc($result))
+ {
+ $cur_moderators = ($cur_forum['moderators'] != '') ? unserialize($cur_forum['moderators']) : array();
+
+ foreach ($user_groups as $group_users)
+ $cur_moderators = array_diff($cur_moderators, $group_users);
+
+ $cur_moderators = (!empty($cur_moderators)) ? '\''.$db->escape(serialize($cur_moderators)).'\'' : 'NULL';
+ $db->query('UPDATE '.$db->prefix.'forums SET moderators='.$cur_moderators.' WHERE id='.$cur_forum['id']) or error('Unable to update forum', __FILE__, __LINE__, $db->error());
+ }
+
+ // Delete any subscriptions
+ $db->query('DELETE FROM '.$db->prefix.'topic_subscriptions WHERE user_id IN ('.implode(',', $user_ids).')') or error('Unable to delete topic subscriptions', __FILE__, __LINE__, $db->error());
+ $db->query('DELETE FROM '.$db->prefix.'forum_subscriptions WHERE user_id IN ('.implode(',', $user_ids).')') or error('Unable to delete forum subscriptions', __FILE__, __LINE__, $db->error());
+
+ // Remove them from the online list (if they happen to be logged in)
+ $db->query('DELETE FROM '.$db->prefix.'online WHERE user_id IN ('.implode(',', $user_ids).')') or error('Unable to remove users from online list', __FILE__, __LINE__, $db->error());
+
+ // Should we delete all posts made by these users?
+ if (isset($_POST['delete_posts']))
+ {
+ require PUN_ROOT.'include/search_idx.php';
+ @set_time_limit(0);
+
+ // Find all posts made by this user
+ $result = $db->query('SELECT p.id, p.topic_id, t.forum_id FROM '.$db->prefix.'posts AS p INNER JOIN '.$db->prefix.'topics AS t ON t.id=p.topic_id INNER JOIN '.$db->prefix.'forums AS f ON f.id=t.forum_id WHERE p.poster_id IN ('.implode(',', $user_ids).')') or error('Unable to fetch posts', __FILE__, __LINE__, $db->error());
+ if ($db->num_rows($result))
+ {
+ while ($cur_post = $db->fetch_assoc($result))
+ {
+ // Determine whether this post is the "topic post" or not
+ $result2 = $db->query('SELECT id FROM '.$db->prefix.'posts WHERE topic_id='.$cur_post['topic_id'].' ORDER BY posted LIMIT 1') or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
+
+ if ($db->result($result2) == $cur_post['id'])
+ delete_topic($cur_post['topic_id']);
+ else
+ delete_post($cur_post['id'], $cur_post['topic_id']);
+
+ update_forum($cur_post['forum_id']);
+ }
+ }
+ }
+ else
+ // Set all their posts to guest
+ $db->query('UPDATE '.$db->prefix.'posts SET poster_id=1 WHERE poster_id IN ('.implode(',', $user_ids).')') or error('Unable to update posts', __FILE__, __LINE__, $db->error());
+
+ // Delete the users
+ $db->query('DELETE FROM '.$db->prefix.'users WHERE id IN ('.implode(',', $user_ids).')') or error('Unable to delete users', __FILE__, __LINE__, $db->error());
+
+ // Delete user avatars
+ foreach ($user_ids as $user_id)
+ delete_avatar($user_id);
+
+ // Regenerate the users info cache
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_users_info_cache();
+
+ redirect('admin_users.php', $lang_admin_users['Users delete redirect']);
+ }
+
+ $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Users'], $lang_admin_users['Delete users']);
+ define('PUN_ACTIVE_PAGE', 'admin');
+ require PUN_ROOT.'header.php';
+
+ generate_admin_menu('users');
+
+?>
+ <div class="blockform">
+ <h2><span><?php echo $lang_admin_users['Delete users'] ?></span></h2>
+ <div class="box">
+ <form name="confirm_del_users" method="post" action="admin_users.php">
+ <input type="hidden" name="users" value="<?php echo implode(',', $user_ids) ?>" />
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_users['Confirm delete legend'] ?></legend>
+ <div class="infldset">
+ <p><?php echo $lang_admin_users['Confirm delete info'] ?></p>
+ <div class="rbox">
+ <label><input type="checkbox" name="delete_posts" value="1" checked="checked" /><?php echo $lang_admin_users['Delete posts'] ?><br /></label>
+ </div>
+ <p class="warntext"><strong><?php echo $lang_admin_users['Delete warning'] ?></strong></p>
+ </div>
+ </fieldset>
+ </div>
+ <p class="buttons"><input type="submit" name="delete_users_comply" value="<?php echo $lang_admin_users['Delete'] ?>" /> <a href="javascript:history.go(-1)"><?php echo $lang_admin_common['Go back'] ?></a></p>
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+</div>
+<?php
+
+ require PUN_ROOT.'footer.php';
+}
+
+
+// Ban multiple users
+else if (isset($_POST['ban_users']) || isset($_POST['ban_users_comply']))
+{
+ if ($pun_user['g_id'] != PUN_ADMIN && ($pun_user['g_moderator'] != '1' || $pun_user['g_mod_ban_users'] == '0'))
+ message($lang_common['No permission'], false, '403 Forbidden');
+
+ confirm_referrer('admin_users.php');
+
+ if (isset($_POST['users']))
+ {
+ $user_ids = is_array($_POST['users']) ? array_keys($_POST['users']) : explode(',', $_POST['users']);
+ $user_ids = array_map('intval', $user_ids);
+
+ // Delete invalid IDs
+ $user_ids = array_diff($user_ids, array(0, 1));
+ }
+ else
+ $user_ids = array();
+
+ if (empty($user_ids))
+ message($lang_admin_users['No users selected']);
+
+ // Are we trying to ban any admins?
+ $result = $db->query('SELECT COUNT(*) FROM '.$db->prefix.'users WHERE id IN ('.implode(',', $user_ids).') AND group_id='.PUN_ADMIN) or error('Unable to fetch group info', __FILE__, __LINE__, $db->error());
+ if ($db->result($result) > 0)
+ message($lang_admin_users['No ban admins message']);
+
+ // Also, we cannot ban moderators
+ $result = $db->query('SELECT COUNT(*) FROM '.$db->prefix.'users AS u INNER JOIN '.$db->prefix.'groups AS g ON u.group_id=g.g_id WHERE g.g_moderator=1 AND u.id IN ('.implode(',', $user_ids).')') or error('Unable to fetch moderator group info', __FILE__, __LINE__, $db->error());
+ if ($db->result($result) > 0)
+ message($lang_admin_users['No ban mods message']);
+
+ if (isset($_POST['ban_users_comply']))
+ {
+ $ban_message = pun_trim($_POST['ban_message']);
+ $ban_expire = pun_trim($_POST['ban_expire']);
+ $ban_the_ip = isset($_POST['ban_the_ip']) ? intval($_POST['ban_the_ip']) : 0;
+
+ if ($ban_expire != '' && $ban_expire != 'Never')
+ {
+ $ban_expire = strtotime($ban_expire.' GMT');
+
+ if ($ban_expire == -1 || !$ban_expire)
+ message($lang_admin_users['Invalid date message'].' '.$lang_admin_users['Invalid date reasons']);
+
+ $diff = ($pun_user['timezone'] + $pun_user['dst']) * 3600;
+ $ban_expire -= $diff;
+
+ if ($ban_expire <= time())
+ message($lang_admin_users['Invalid date message'].' '.$lang_admin_users['Invalid date reasons']);
+ }
+ else
+ $ban_expire = 'NULL';
+
+ $ban_message = ($ban_message != '') ? '\''.$db->escape($ban_message).'\'' : 'NULL';
+
+ // Fetch user information
+ $user_info = array();
+ $result = $db->query('SELECT id, username, email, registration_ip FROM '.$db->prefix.'users WHERE id IN ('.implode(',', $user_ids).')') or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
+ while ($cur_user = $db->fetch_assoc($result))
+ $user_info[$cur_user['id']] = array('username' => $cur_user['username'], 'email' => $cur_user['email'], 'ip' => $cur_user['registration_ip']);
+
+ // Overwrite the registration IP with one from the last post (if it exists)
+ if ($ban_the_ip != 0)
+ {
+ $result = $db->query('SELECT p.poster_id, p.poster_ip FROM '.$db->prefix.'posts AS p INNER JOIN (SELECT MAX(id) AS id FROM '.$db->prefix.'posts WHERE poster_id IN ('.implode(',', $user_ids).') GROUP BY poster_id) AS i ON p.id=i.id') or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
+ while ($cur_address = $db->fetch_assoc($result))
+ $user_info[$cur_address['poster_id']]['ip'] = $cur_address['poster_ip'];
+ }
+
+ // And insert the bans!
+ foreach ($user_ids as $user_id)
+ {
+ $ban_username = '\''.$db->escape($user_info[$user_id]['username']).'\'';
+ $ban_email = '\''.$db->escape($user_info[$user_id]['email']).'\'';
+ $ban_ip = ($ban_the_ip != 0) ? '\''.$db->escape($user_info[$user_id]['ip']).'\'' : 'NULL';
+
+ $db->query('INSERT INTO '.$db->prefix.'bans (username, ip, email, message, expire, ban_creator) VALUES('.$ban_username.', '.$ban_ip.', '.$ban_email.', '.$ban_message.', '.$ban_expire.', '.$pun_user['id'].')') or error('Unable to add ban', __FILE__, __LINE__, $db->error());
+ }
+
+ // Regenerate the bans cache
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_bans_cache();
+
+ redirect('admin_users.php', $lang_admin_users['Users banned redirect']);
+ }
+
+ $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Bans']);
+ $focus_element = array('bans2', 'ban_message');
+ define('PUN_ACTIVE_PAGE', 'admin');
+ require PUN_ROOT.'header.php';
+
+ generate_admin_menu('users');
+
+?>
+ <div class="blockform">
+ <h2><span><?php echo $lang_admin_users['Ban users'] ?></span></h2>
+ <div class="box">
+ <form id="bans2" name="confirm_ban_users" method="post" action="admin_users.php">
+ <input type="hidden" name="users" value="<?php echo implode(',', $user_ids) ?>" />
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_users['Message expiry subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['Ban message label'] ?></th>
+ <td>
+ <input type="text" name="ban_message" size="50" maxlength="255" tabindex="1" />
+ <span><?php echo $lang_admin_users['Ban message help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['Expire date label'] ?></th>
+ <td>
+ <input type="text" name="ban_expire" size="17" maxlength="10" tabindex="2" />
+ <span><?php echo $lang_admin_users['Expire date help'] ?></span>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['Ban IP label'] ?></th>
+ <td>
+ <label class="conl"><input type="radio" name="ban_the_ip" tabindex="3" value="1" checked="checked" />&#160;<strong><?php echo $lang_admin_common['Yes'] ?></strong></label>
+ <label class="conl"><input type="radio" name="ban_the_ip" tabindex="4" value="0" checked="checked" />&#160;<strong><?php echo $lang_admin_common['No'] ?></strong></label>
+ <span class="clearb"><?php echo $lang_admin_users['Ban IP help'] ?></span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ <p class="submitend"><input type="submit" name="ban_users_comply" value="<?php echo $lang_admin_common['Save'] ?>" tabindex="3" /></p>
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+</div>
+<?php
+
+ require PUN_ROOT.'footer.php';
+}
+
+
+else if (isset($_GET['find_user']))
+{
+ $form = isset($_GET['form']) ? $_GET['form'] : array();
+
+ // trim() all elements in $form
+ $form = array_map('pun_trim', $form);
+ $conditions = $query_str = array();
+
+ $posts_greater = isset($_GET['posts_greater']) ? pun_trim($_GET['posts_greater']) : '';
+ $posts_less = isset($_GET['posts_less']) ? pun_trim($_GET['posts_less']) : '';
+ $last_post_after = isset($_GET['last_post_after']) ? pun_trim($_GET['last_post_after']) : '';
+ $last_post_before = isset($_GET['last_post_before']) ? pun_trim($_GET['last_post_before']) : '';
+ $last_visit_after = isset($_GET['last_visit_after']) ? pun_trim($_GET['last_visit_after']) : '';
+ $last_visit_before = isset($_GET['last_visit_before']) ? pun_trim($_GET['last_visit_before']) : '';
+ $registered_after = isset($_GET['registered_after']) ? pun_trim($_GET['registered_after']) : '';
+ $registered_before = isset($_GET['registered_before']) ? pun_trim($_GET['registered_before']) : '';
+ $order_by = isset($_GET['order_by']) && in_array($_GET['order_by'], array('username', 'email', 'num_posts', 'last_post', 'last_visit', 'registered')) ? $_GET['order_by'] : 'username';
+ $direction = isset($_GET['direction']) && $_GET['direction'] == 'DESC' ? 'DESC' : 'ASC';
+ $user_group = isset($_GET['user_group']) ? intval($_GET['user_group']) : -1;
+
+ $query_str[] = 'order_by='.$order_by;
+ $query_str[] = 'direction='.$direction;
+ $query_str[] = 'user_group='.$user_group;
+
+ if (preg_match('%[^0-9]%', $posts_greater.$posts_less))
+ message($lang_admin_users['Non numeric message']);
+
+ // Try to convert date/time to timestamps
+ if ($last_post_after != '')
+ {
+ $query_str[] = 'last_post_after='.$last_post_after;
+
+ $last_post_after = strtotime($last_post_after);
+ if ($last_post_after === false || $last_post_after == -1)
+ message($lang_admin_users['Invalid date time message']);
+
+ $conditions[] = 'u.last_post>'.$last_post_after;
+ }
+ if ($last_post_before != '')
+ {
+ $query_str[] = 'last_post_before='.$last_post_before;
+
+ $last_post_before = strtotime($last_post_before);
+ if ($last_post_before === false || $last_post_before == -1)
+ message($lang_admin_users['Invalid date time message']);
+
+ $conditions[] = 'u.last_post<'.$last_post_before;
+ }
+ if ($last_visit_after != '')
+ {
+ $query_str[] = 'last_visit_after='.$last_visit_after;
+
+ $last_visit_after = strtotime($last_visit_after);
+ if ($last_visit_after === false || $last_visit_after == -1)
+ message($lang_admin_users['Invalid date time message']);
+
+ $conditions[] = 'u.last_visit>'.$last_visit_after;
+ }
+ if ($last_visit_before != '')
+ {
+ $query_str[] = 'last_visit_before='.$last_visit_before;
+
+ $last_visit_before = strtotime($last_visit_before);
+ if ($last_visit_before === false || $last_visit_before == -1)
+ message($lang_admin_users['Invalid date time message']);
+
+ $conditions[] = 'u.last_visit<'.$last_visit_before;
+ }
+ if ($registered_after != '')
+ {
+ $query_str[] = 'registered_after='.$registered_after;
+
+ $registered_after = strtotime($registered_after);
+ if ($registered_after === false || $registered_after == -1)
+ message($lang_admin_users['Invalid date time message']);
+
+ $conditions[] = 'u.registered>'.$registered_after;
+ }
+ if ($registered_before != '')
+ {
+ $query_str[] = 'registered_before='.$registered_before;
+
+ $registered_before = strtotime($registered_before);
+ if ($registered_before === false || $registered_before == -1)
+ message($lang_admin_users['Invalid date time message']);
+
+ $conditions[] = 'u.registered<'.$registered_before;
+ }
+
+ $like_command = ($db_type == 'pgsql') ? 'ILIKE' : 'LIKE';
+ foreach ($form as $key => $input)
+ {
+ if ($input != '' && in_array($key, array('username', 'email', 'title', 'realname', 'url', 'jabber', 'icq', 'msn', 'aim', 'yahoo', 'location', 'signature', 'admin_note')))
+ {
+ $conditions[] = 'u.'.$db->escape($key).' '.$like_command.' \''.$db->escape(str_replace(array('*', '_'), array('%', '\\_'), $input)).'\'';
+ $query_str[] = 'form%5B'.$key.'%5D='.urlencode($input);
+ }
+ }
+
+ if ($posts_greater != '')
+ {
+ $query_str[] = 'posts_greater='.$posts_greater;
+ $conditions[] = 'u.num_posts>'.$posts_greater;
+ }
+ if ($posts_less != '')
+ {
+ $query_str[] = 'posts_less='.$posts_less;
+ $conditions[] = 'u.num_posts<'.$posts_less;
+ }
+
+ if ($user_group > -1)
+ $conditions[] = 'u.group_id='.$user_group;
+
+ // Fetch user count
+ $result = $db->query('SELECT COUNT(id) FROM '.$db->prefix.'users AS u LEFT JOIN '.$db->prefix.'groups AS g ON g.g_id=u.group_id WHERE u.id>1'.(!empty($conditions) ? ' AND '.implode(' AND ', $conditions) : '')) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
+ $num_users = $db->result($result);
+
+ // Determine the user offset (based on $_GET['p'])
+ $num_pages = ceil($num_users / 50);
+
+ $p = (!isset($_GET['p']) || $_GET['p'] <= 1 || $_GET['p'] > $num_pages) ? 1 : intval($_GET['p']);
+ $start_from = 50 * ($p - 1);
+
+ // Generate paging links
+ $paging_links = '<span class="pages-label">'.$lang_common['Pages'].' </span>'.paginate($num_pages, $p, 'admin_users.php?find_user=&amp;'.implode('&amp;', $query_str));
+
+ // Some helper variables for permissions
+ $can_delete = $can_move = $pun_user['g_id'] == PUN_ADMIN;
+ $can_ban = $pun_user['g_id'] == PUN_ADMIN || ($pun_user['g_moderator'] == '1' && $pun_user['g_mod_ban_users'] == '1');
+ $can_action = ($can_delete || $can_ban || $can_move) && $num_users > 0;
+
+ $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Users'], $lang_admin_users['Results head']);
+ $page_head = array('js' => '<script type="text/javascript" src="common.js"></script>');
+ define('PUN_ACTIVE_PAGE', 'admin');
+ require PUN_ROOT.'header.php';
+
+?>
+<div class="linkst">
+ <div class="inbox crumbsplus">
+ <ul class="crumbs">
+ <li><a href="admin_index.php"><?php echo $lang_admin_common['Admin'].' '.$lang_admin_common['Index'] ?></a></li>
+ <li><span>»&#160;</span><a href="admin_users.php"><?php echo $lang_admin_common['Users'] ?></a></li>
+ <li><span>»&#160;</span><strong><?php echo $lang_admin_users['Results head'] ?></strong></li>
+ </ul>
+ <div class="pagepost">
+ <p class="pagelink"><?php echo $paging_links ?></p>
+ </div>
+ <div class="clearer"></div>
+ </div>
+</div>
+
+
+<form id="search-users-form" action="admin_users.php" method="post">
+<div id="users2" class="blocktable">
+ <h2><span><?php echo $lang_admin_users['Results head'] ?></span></h2>
+ <div class="box">
+ <div class="inbox">
+ <table>
+ <thead>
+ <tr>
+ <th class="tcl" scope="col"><?php echo $lang_admin_users['Results username head'] ?></th>
+ <th class="tc2" scope="col"><?php echo $lang_admin_users['Results e-mail head'] ?></th>
+ <th class="tc3" scope="col"><?php echo $lang_admin_users['Results title head'] ?></th>
+ <th class="tc4" scope="col"><?php echo $lang_admin_users['Results posts head'] ?></th>
+ <th class="tc5" scope="col"><?php echo $lang_admin_users['Results admin note head'] ?></th>
+ <th class="tcr" scope="col"><?php echo $lang_admin_users['Results actions head'] ?></th>
+<?php if ($can_action): ?> <th class="tcmod" scope="col"><?php echo $lang_admin_users['Select'] ?></th>
+<?php endif; ?>
+ </tr>
+ </thead>
+ <tbody>
+<?php
+
+ $result = $db->query('SELECT u.id, u.username, u.email, u.title, u.num_posts, u.admin_note, g.g_id, g.g_user_title FROM '.$db->prefix.'users AS u LEFT JOIN '.$db->prefix.'groups AS g ON g.g_id=u.group_id WHERE u.id>1'.(!empty($conditions) ? ' AND '.implode(' AND ', $conditions) : '').' ORDER BY '.$db->escape($order_by).' '.$db->escape($direction).' LIMIT '.$start_from.', 50') or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
+ if ($db->num_rows($result))
+ {
+ while ($user_data = $db->fetch_assoc($result))
+ {
+ $user_title = get_title($user_data);
+
+ // This script is a special case in that we want to display "Not verified" for non-verified users
+ if (($user_data['g_id'] == '' || $user_data['g_id'] == PUN_UNVERIFIED) && $user_title != $lang_common['Banned'])
+ $user_title = '<span class="warntext">'.$lang_admin_users['Not verified'].'</span>';
+
+ $actions = '<a href="admin_users.php?ip_stats='.$user_data['id'].'">'.$lang_admin_users['Results view IP link'].'</a> | <a href="search.php?action=show_user_posts&amp;user_id='.$user_data['id'].'">'.$lang_admin_users['Results show posts link'].'</a>';
+
+?>
+ <tr>
+ <td class="tcl"><?php echo '<a href="profile.php?id='.$user_data['id'].'">'.pun_htmlspecialchars($user_data['username']).'</a>' ?></td>
+ <td class="tc2"><a href="mailto:<?php echo pun_htmlspecialchars($user_data['email']) ?>"><?php echo pun_htmlspecialchars($user_data['email']) ?></a></td>
+ <td class="tc3"><?php echo $user_title ?></td>
+ <td class="tc4"><?php echo forum_number_format($user_data['num_posts']) ?></td>
+ <td class="tc5"><?php echo ($user_data['admin_note'] != '') ? pun_htmlspecialchars($user_data['admin_note']) : '&#160;' ?></td>
+ <td class="tcr"><?php echo $actions ?></td>
+<?php if ($can_action): ?> <td class="tcmod"><input type="checkbox" name="users[<?php echo $user_data['id'] ?>]" value="1" /></td>
+<?php endif; ?>
+ </tr>
+<?php
+
+ }
+ }
+ else
+ echo "\t\t\t\t".'<tr><td class="tcl" colspan="6">'.$lang_admin_users['No match'].'</td></tr>'."\n";
+
+?>
+ </tbody>
+ </table>
+ </div>
+ </div>
+</div>
+
+<div class="linksb">
+ <div class="inbox crumbsplus">
+ <div class="pagepost">
+ <p class="pagelink"><?php echo $paging_links ?></p>
+<?php if ($can_action): ?> <p class="conr modbuttons"><a href="#" onclick="return select_checkboxes('search-users-form', this, '<?php echo $lang_admin_users['Unselect all'] ?>')"><?php echo $lang_admin_users['Select all'] ?></a> <?php if ($can_ban) : ?><input type="submit" name="ban_users" value="<?php echo $lang_admin_users['Ban'] ?>" /><?php endif; if ($can_delete) : ?><input type="submit" name="delete_users" value="<?php echo $lang_admin_users['Delete'] ?>" /><?php endif; if ($can_move) : ?><input type="submit" name="move_users" value="<?php echo $lang_admin_users['Change group'] ?>" /><?php endif; ?></p>
+<?php endif; ?>
+ </div>
+ <ul class="crumbs">
+ <li><a href="admin_index.php"><?php echo $lang_admin_common['Admin'].' '.$lang_admin_common['Index'] ?></a></li>
+ <li><span>»&#160;</span><a href="admin_users.php"><?php echo $lang_admin_common['Users'] ?></a></li>
+ <li><span>»&#160;</span><strong><?php echo $lang_admin_users['Results head'] ?></strong></li>
+ </ul>
+ <div class="clearer"></div>
+ </div>
+</div>
+</form>
+<?php
+
+ require PUN_ROOT.'footer.php';
+}
+
+
+else
+{
+ $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Users']);
+ $focus_element = array('find_user', 'form[username]');
+ define('PUN_ACTIVE_PAGE', 'admin');
+ require PUN_ROOT.'header.php';
+
+ generate_admin_menu('users');
+
+?>
+ <div class="blockform">
+ <h2><span><?php echo $lang_admin_users['User search head'] ?></span></h2>
+ <div class="box">
+ <form id="find_user" method="get" action="admin_users.php">
+ <p class="submittop"><input type="submit" name="find_user" value="<?php echo $lang_admin_users['Submit search'] ?>" tabindex="1" /></p>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_users['User search subhead'] ?></legend>
+ <div class="infldset">
+ <p><?php echo $lang_admin_users['User search info'] ?></p>
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['Username label'] ?></th>
+ <td><input type="text" name="form[username]" size="25" maxlength="25" tabindex="2" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['E-mail address label'] ?></th>
+ <td><input type="text" name="form[email]" size="30" maxlength="80" tabindex="3" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['Title label'] ?></th>
+ <td><input type="text" name="form[title]" size="30" maxlength="50" tabindex="4" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['Real name label'] ?></th>
+ <td><input type="text" name="form[realname]" size="30" maxlength="40" tabindex="5" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['Website label'] ?></th>
+ <td><input type="text" name="form[url]" size="35" maxlength="100" tabindex="6" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['Jabber label'] ?></th>
+ <td><input type="text" name="form[jabber]" size="30" maxlength="75" tabindex="7" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['ICQ label'] ?></th>
+ <td><input type="text" name="form[icq]" size="12" maxlength="12" tabindex="8" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['MSN label'] ?></th>
+ <td><input type="text" name="form[msn]" size="30" maxlength="50" tabindex="9" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['AOL label'] ?></th>
+ <td><input type="text" name="form[aim]" size="20" maxlength="20" tabindex="10" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['Yahoo label'] ?></th>
+ <td><input type="text" name="form[yahoo]" size="20" maxlength="20" tabindex="11" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['Location label'] ?></th>
+ <td><input type="text" name="form[location]" size="30" maxlength="30" tabindex="12" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['Signature label'] ?></th>
+ <td><input type="text" name="form[signature]" size="35" maxlength="512" tabindex="13" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['Admin note label'] ?></th>
+ <td><input type="text" name="form[admin_note]" size="30" maxlength="30" tabindex="14" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['Posts more than label'] ?></th>
+ <td><input type="text" name="posts_greater" size="5" maxlength="8" tabindex="15" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['Posts less than label'] ?></th>
+ <td><input type="text" name="posts_less" size="5" maxlength="8" tabindex="16" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['Last post after label'] ?></th>
+ <td><input type="text" name="last_post_after" size="24" maxlength="19" tabindex="17" />
+ <span><?php echo $lang_admin_users['Date help'] ?></span></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['Last post before label'] ?></th>
+ <td><input type="text" name="last_post_before" size="24" maxlength="19" tabindex="18" />
+ <span><?php echo $lang_admin_users['Date help'] ?></span></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['Last visit after label'] ?></th>
+ <td><input type="text" name="last_visit_after" size="24" maxlength="19" tabindex="17" />
+ <span><?php echo $lang_admin_users['Date help'] ?></span></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['Last visit before label'] ?></th>
+ <td><input type="text" name="last_visit_before" size="24" maxlength="19" tabindex="18" />
+ <span><?php echo $lang_admin_users['Date help'] ?></span></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['Registered after label'] ?></th>
+ <td><input type="text" name="registered_after" size="24" maxlength="19" tabindex="19" />
+ <span><?php echo $lang_admin_users['Date help'] ?></span></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['Registered before label'] ?></th>
+ <td><input type="text" name="registered_before" size="24" maxlength="19" tabindex="20" />
+ <span><?php echo $lang_admin_users['Date help'] ?></span></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['Order by label'] ?></th>
+ <td>
+ <select name="order_by" tabindex="21">
+ <option value="username" selected="selected"><?php echo $lang_admin_users['Order by username'] ?></option>
+ <option value="email"><?php echo $lang_admin_users['Order by e-mail'] ?></option>
+ <option value="num_posts"><?php echo $lang_admin_users['Order by posts'] ?></option>
+ <option value="last_post"><?php echo $lang_admin_users['Order by last post'] ?></option>
+ <option value="last_visit"><?php echo $lang_admin_users['Order by last visit'] ?></option>
+ <option value="registered"><?php echo $lang_admin_users['Order by registered'] ?></option>
+ </select>&#160;&#160;&#160;<select name="direction" tabindex="22">
+ <option value="ASC" selected="selected"><?php echo $lang_admin_users['Ascending'] ?></option>
+ <option value="DESC"><?php echo $lang_admin_users['Descending'] ?></option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['User group label'] ?></th>
+ <td>
+ <select name="user_group" tabindex="23">
+ <option value="-1" selected="selected"><?php echo $lang_admin_users['All groups'] ?></option>
+ <option value="0"><?php echo $lang_admin_users['Unverified users'] ?></option>
+<?php
+
+ $result = $db->query('SELECT g_id, g_title FROM '.$db->prefix.'groups WHERE g_id!='.PUN_GUEST.' ORDER BY g_title') or error('Unable to fetch user group list', __FILE__, __LINE__, $db->error());
+
+ while ($cur_group = $db->fetch_assoc($result))
+ echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$cur_group['g_id'].'">'.pun_htmlspecialchars($cur_group['g_title']).'</option>'."\n";
+
+?>
+ </select>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ <p class="submitend"><input type="submit" name="find_user" value="<?php echo $lang_admin_users['Submit search'] ?>" tabindex="25" /></p>
+ </form>
+ </div>
+
+ <h2 class="block2"><span><?php echo $lang_admin_users['IP search head'] ?></span></h2>
+ <div class="box">
+ <form method="get" action="admin_users.php">
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_admin_users['IP search subhead'] ?></legend>
+ <div class="infldset">
+ <table class="aligntop">
+ <tr>
+ <th scope="row"><?php echo $lang_admin_users['IP address label'] ?><div><input type="submit" value="<?php echo $lang_admin_users['Find IP address'] ?>" tabindex="26" /></div></th>
+ <td><input type="text" name="show_users" size="18" maxlength="15" tabindex="24" />
+ <span><?php echo $lang_admin_users['IP address help'] ?></span></td>
+ </tr>
+ </table>
+ </div>
+ </fieldset>
+ </div>
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+</div>
+<?php
+
+ require PUN_ROOT.'footer.php';
+}
diff --git a/cache/.htaccess b/cache/.htaccess
new file mode 100644
index 0000000..e67301e
--- /dev/null
+++ b/cache/.htaccess
@@ -0,0 +1,4 @@
+<Limit GET POST PUT>
+Order Allow,Deny
+Deny from All
+</Limit>
diff --git a/cache/index.html b/cache/index.html
new file mode 100644
index 0000000..89337b2
--- /dev/null
+++ b/cache/index.html
@@ -0,0 +1 @@
+<html><head><title>.</title></head><body>.</body></html>
diff --git a/common.js b/common.js
new file mode 100644
index 0000000..47a7155
--- /dev/null
+++ b/common.js
@@ -0,0 +1,38 @@
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+function select_checkboxes(curFormId, link, new_string)
+{
+ var curForm = document.getElementById(curFormId);
+ var inputlist = curForm.getElementsByTagName("input");
+ for (i = 0; i < inputlist.length; i++)
+ {
+ if (inputlist[i].getAttribute("type") == 'checkbox' && inputlist[i].disabled == false)
+ inputlist[i].checked = true;
+ }
+
+ link.setAttribute('onclick', 'return unselect_checkboxes(\'' + curFormId + '\', this, \'' + link.innerHTML + '\')');
+ link.innerHTML = new_string;
+
+ return false;
+}
+
+function unselect_checkboxes(curFormId, link, new_string)
+{
+ var curForm = document.getElementById(curFormId);
+ var inputlist = curForm.getElementsByTagName("input");
+ for (i = 0; i < inputlist.length; i++)
+ {
+ if (inputlist[i].getAttribute("type") == 'checkbox' && inputlist[i].disabled == false)
+ inputlist[i].checked = false;
+ }
+
+ link.setAttribute('onclick', 'return select_checkboxes(\'' + curFormId + '\', this, \'' + link.innerHTML + '\')');
+ link.innerHTML = new_string;
+
+ return false;
+}
diff --git a/config.php b/config.php
new file mode 100644
index 0000000..c09b89d
--- /dev/null
+++ b/config.php
@@ -0,0 +1,17 @@
+<?php
+
+$db_type = 'mysqli';
+$db_host = 'localhost';
+$db_name = 'fluxbb';
+$db_username = 'fluxbb';
+$db_password = 'dzI3ODdkOHNnYSB4';
+$db_prefix = 'fluxbb_';
+$p_connect = false;
+
+$cookie_name = 'pun_cookie_143ac0';
+$cookie_domain = '';
+$cookie_path = '/';
+$cookie_secure = 0;
+$cookie_seed = '52856129188e6704';
+
+define('PUN', 1);
diff --git a/db_update.php b/db_update.php
new file mode 100644
index 0000000..2964bf3
--- /dev/null
+++ b/db_update.php
@@ -0,0 +1,1911 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// The FluxBB version this script updates to
+define('UPDATE_TO', '1.5.11');
+
+define('UPDATE_TO_DB_REVISION', 21);
+define('UPDATE_TO_SI_REVISION', 2);
+define('UPDATE_TO_PARSER_REVISION', 2);
+
+define('MIN_PHP_VERSION', '4.4.0');
+define('MIN_MYSQL_VERSION', '4.1.2');
+define('MIN_PGSQL_VERSION', '7.0.0');
+define('PUN_SEARCH_MIN_WORD', 3);
+define('PUN_SEARCH_MAX_WORD', 20);
+
+// The MySQL connection character set that was used for FluxBB 1.2 - in 99% of cases this should be detected automatically,
+// but can be overridden using the below constant if required.
+//define('FORUM_DEFAULT_CHARSET', 'latin1');
+
+
+// The number of items to process per page view (lower this if the update script times out during UTF-8 conversion)
+define('PER_PAGE', 300);
+
+// Don't set to UTF-8 until after we've found out what the default character set is
+define('FORUM_NO_SET_NAMES', 1);
+
+// Make sure we are running at least MIN_PHP_VERSION
+if (!function_exists('version_compare') || version_compare(PHP_VERSION, MIN_PHP_VERSION, '<'))
+ exit('You are running PHP version '.PHP_VERSION.'. FluxBB '.UPDATE_TO.' requires at least PHP '.MIN_PHP_VERSION.' to run properly. You must upgrade your PHP installation before you can continue.');
+
+define('PUN_ROOT', dirname(__FILE__).'/');
+
+// Attempt to load the configuration file config.php
+if (file_exists(PUN_ROOT.'config.php'))
+ include PUN_ROOT.'config.php';
+
+// If we have the 1.3-legacy constant defined, define the proper 1.4 constant so we don't get an incorrect "need to install" message
+if (defined('FORUM'))
+ define('PUN', FORUM);
+
+// If PUN isn't defined, config.php is missing or corrupt
+if (!defined('PUN'))
+{
+ header('Location: install.php');
+ exit;
+}
+
+// Enable debug mode
+if (!defined('PUN_DEBUG'))
+ define('PUN_DEBUG', 1);
+
+// Load the functions script
+require PUN_ROOT.'include/functions.php';
+
+// Load UTF-8 functions
+require PUN_ROOT.'include/utf8/utf8.php';
+
+// Strip out "bad" UTF-8 characters
+forum_remove_bad_characters();
+
+// Reverse the effect of register_globals
+forum_unregister_globals();
+
+// Turn on full PHP error reporting
+error_reporting(E_ALL);
+
+// Force POSIX locale (to prevent functions such as strtolower() from messing up UTF-8 strings)
+setlocale(LC_CTYPE, 'C');
+
+// Turn off magic_quotes_runtime
+if (get_magic_quotes_runtime())
+ set_magic_quotes_runtime(0);
+
+// Strip slashes from GET/POST/COOKIE (if magic_quotes_gpc is enabled)
+if (get_magic_quotes_gpc())
+{
+ function stripslashes_array($array)
+ {
+ return is_array($array) ? array_map('stripslashes_array', $array) : stripslashes($array);
+ }
+
+ $_GET = stripslashes_array($_GET);
+ $_POST = stripslashes_array($_POST);
+ $_COOKIE = stripslashes_array($_COOKIE);
+ $_REQUEST = stripslashes_array($_REQUEST);
+}
+
+// If a cookie name is not specified in config.php, we use the default (forum_cookie)
+if (empty($cookie_name))
+ $cookie_name = 'pun_cookie';
+
+// If the cache directory is not specified, we use the default setting
+if (!defined('FORUM_CACHE_DIR'))
+ define('FORUM_CACHE_DIR', PUN_ROOT.'cache/');
+
+// Turn off PHP time limit
+@set_time_limit(0);
+
+// Define a few commonly used constants
+define('PUN_UNVERIFIED', 0);
+define('PUN_ADMIN', 1);
+define('PUN_MOD', 2);
+define('PUN_GUEST', 3);
+define('PUN_MEMBER', 4);
+
+// Load DB abstraction layer and try to connect
+require PUN_ROOT.'include/dblayer/common_db.php';
+
+$db->start_transaction();
+
+// Check what the default character set is - since 1.2 didn't specify any we will use whatever the default was (usually latin1)
+$old_connection_charset = defined('FORUM_DEFAULT_CHARSET') ? FORUM_DEFAULT_CHARSET : $db->get_names();
+
+// Set the connection to UTF-8 now
+$db->set_names('utf8');
+
+// Get the forum config
+$result = $db->query('SELECT * FROM '.$db->prefix.'config') or error('Unable to fetch config.', __FILE__, __LINE__, $db->error());
+while ($cur_config_item = $db->fetch_row($result))
+ $pun_config[$cur_config_item[0]] = $cur_config_item[1];
+
+// Load language file
+$default_lang = $pun_config['o_default_lang'];
+
+if (!file_exists(PUN_ROOT.'lang/'.$default_lang.'/update.php'))
+ $default_lang = 'English';
+
+require PUN_ROOT.'lang/'.$default_lang.'/common.php';
+require PUN_ROOT.'lang/'.$default_lang.'/update.php';
+
+// Check current version
+$cur_version = $pun_config['o_cur_version'];
+
+if (version_compare($cur_version, '1.2', '<'))
+ error(sprintf($lang_update['Version mismatch error'], $db_name));
+
+// Do some DB type specific checks
+$mysql = false;
+switch ($db_type)
+{
+ case 'mysql':
+ case 'mysqli':
+ case 'mysql_innodb':
+ case 'mysqli_innodb':
+ $mysql_info = $db->get_version();
+ if (version_compare($mysql_info['version'], MIN_MYSQL_VERSION, '<'))
+ error(sprintf($lang_update['You are running error'], 'MySQL', $mysql_info['version'], UPDATE_TO, MIN_MYSQL_VERSION));
+
+ $mysql = true;
+ break;
+
+ case 'pgsql':
+ $pgsql_info = $db->get_version();
+ if (version_compare($pgsql_info['version'], MIN_PGSQL_VERSION, '<'))
+ error(sprintf($lang_update['You are running error'], 'PostgreSQL', $pgsql_info['version'], UPDATE_TO, MIN_PGSQL_VERSION));
+
+ break;
+}
+
+// Check the database, search index and parser revision and the current version
+if (isset($pun_config['o_database_revision']) && $pun_config['o_database_revision'] >= UPDATE_TO_DB_REVISION &&
+ isset($pun_config['o_searchindex_revision']) && $pun_config['o_searchindex_revision'] >= UPDATE_TO_SI_REVISION &&
+ isset($pun_config['o_parser_revision']) && $pun_config['o_parser_revision'] >= UPDATE_TO_PARSER_REVISION &&
+ version_compare($pun_config['o_cur_version'], UPDATE_TO, '>='))
+ error($lang_update['No update error']);
+
+$default_style = $pun_config['o_default_style'];
+if (!file_exists(PUN_ROOT.'style/'.$default_style.'.css'))
+ $default_style = 'Air';
+
+// Start a session, used to queue up errors if duplicate users occur when converting from FluxBB v1.2.
+session_start();
+
+//
+// Determines whether $str is UTF-8 encoded or not
+//
+function seems_utf8($str)
+{
+ $str_len = strlen($str);
+ for ($i = 0; $i < $str_len; ++$i)
+ {
+ if (ord($str[$i]) < 0x80) continue; # 0bbbbbbb
+ else if ((ord($str[$i]) & 0xE0) == 0xC0) $n=1; # 110bbbbb
+ else if ((ord($str[$i]) & 0xF0) == 0xE0) $n=2; # 1110bbbb
+ else if ((ord($str[$i]) & 0xF8) == 0xF0) $n=3; # 11110bbb
+ else if ((ord($str[$i]) & 0xFC) == 0xF8) $n=4; # 111110bb
+ else if ((ord($str[$i]) & 0xFE) == 0xFC) $n=5; # 1111110b
+ else return false; # Does not match any model
+
+ for ($j = 0; $j < $n; ++$j) # n bytes matching 10bbbbbb follow ?
+ {
+ if ((++$i == strlen($str)) || ((ord($str[$i]) & 0xC0) != 0x80))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+//
+// Translates the number from a HTML numeric entity into an UTF-8 character
+//
+function dcr2utf8($src)
+{
+ $dest = '';
+ if ($src < 0)
+ return false;
+ else if ($src <= 0x007f)
+ $dest .= chr($src);
+ else if ($src <= 0x07ff)
+ {
+ $dest .= chr(0xc0 | ($src >> 6));
+ $dest .= chr(0x80 | ($src & 0x003f));
+ }
+ else if ($src == 0xFEFF)
+ {
+ // nop -- zap the BOM
+ }
+ else if ($src >= 0xD800 && $src <= 0xDFFF)
+ {
+ // found a surrogate
+ return false;
+ }
+ else if ($src <= 0xffff)
+ {
+ $dest .= chr(0xe0 | ($src >> 12));
+ $dest .= chr(0x80 | (($src >> 6) & 0x003f));
+ $dest .= chr(0x80 | ($src & 0x003f));
+ }
+ else if ($src <= 0x10ffff)
+ {
+ $dest .= chr(0xf0 | ($src >> 18));
+ $dest .= chr(0x80 | (($src >> 12) & 0x3f));
+ $dest .= chr(0x80 | (($src >> 6) & 0x3f));
+ $dest .= chr(0x80 | ($src & 0x3f));
+ }
+ else
+ {
+ // out of range
+ return false;
+ }
+
+ return $dest;
+}
+
+
+//
+// Attempts to convert $str from $old_charset to UTF-8. Also converts HTML entities (including numeric entities) to UTF-8 characters
+//
+function convert_to_utf8(&$str, $old_charset)
+{
+ if (is_null($str) || $str == '')
+ return false;
+
+ $save = $str;
+
+ // Replace literal entities (for non-UTF-8 compliant html_entity_encode)
+ if (version_compare(PHP_VERSION, '5.0.0', '<') && $old_charset == 'ISO-8859-1' || $old_charset == 'ISO-8859-15')
+ $str = html_entity_decode($str, ENT_QUOTES, $old_charset);
+
+ if ($old_charset != 'UTF-8' && !seems_utf8($str))
+ {
+ if (function_exists('iconv'))
+ $str = iconv(!empty($old_charset) ? $old_charset : 'ISO-8859-1', 'UTF-8', $str);
+ else if (function_exists('mb_convert_encoding'))
+ $str = mb_convert_encoding($str, 'UTF-8', !empty($old_charset) ? $old_charset : 'ISO-8859-1');
+ else if ($old_charset == 'ISO-8859-1')
+ $str = utf8_encode($str);
+ }
+
+ // Replace literal entities (for UTF-8 compliant html_entity_encode)
+ if (version_compare(PHP_VERSION, '5.0.0', '>='))
+ $str = html_entity_decode($str, ENT_QUOTES, 'UTF-8');
+
+ // Replace numeric entities
+ $str = preg_replace_callback('%&#([0-9]+);%', 'utf8_callback_1', $str);
+ $str = preg_replace_callback('%&#x([a-f0-9]+);%i', 'utf8_callback_2', $str);
+
+ // Remove "bad" characters
+ $str = remove_bad_characters($str);
+
+ return ($save != $str);
+}
+
+
+function utf8_callback_1($matches)
+{
+ return dcr2utf8($matches[1]);
+}
+
+
+function utf8_callback_2($matches)
+{
+ return dcr2utf8(hexdec($matches[1]));
+}
+
+
+//
+// Alter a table to be utf8. MySQL only
+// Function based on update_convert_table_utf8() from the Drupal project (http://drupal.org/)
+//
+function alter_table_utf8($table)
+{
+ global $mysql, $db;
+ static $types;
+
+ if (!$mysql)
+ return;
+
+ if (!isset($types))
+ {
+ $types = array(
+ 'char' => 'binary',
+ 'varchar' => 'varbinary',
+ 'tinytext' => 'tinyblob',
+ 'mediumtext' => 'mediumblob',
+ 'text' => 'blob',
+ 'longtext' => 'longblob'
+ );
+ }
+
+ // Set table default charset to utf8
+ $db->query('ALTER TABLE '.$table.' CHARACTER SET utf8') or error('Unable to set table character set', __FILE__, __LINE__, $db->error());
+
+ // Find out which columns need converting and build SQL statements
+ $result = $db->query('SHOW FULL COLUMNS FROM '.$table) or error('Unable to fetch column information', __FILE__, __LINE__, $db->error());
+ while ($cur_column = $db->fetch_assoc($result))
+ {
+ if (is_null($cur_column['Collation']))
+ continue;
+
+ list($type) = explode('(', $cur_column['Type']);
+ if (isset($types[$type]) && strpos($cur_column['Collation'], 'utf8') === false)
+ {
+ $allow_null = ($cur_column['Null'] == 'YES');
+ $collate = (substr($cur_column['Collation'], -3) == 'bin') ? 'utf8_bin' : 'utf8_general_ci';
+
+ $db->alter_field($table, $cur_column['Field'], preg_replace('%'.$type.'%i', $types[$type], $cur_column['Type']), $allow_null, $cur_column['Default'], null, true) or error('Unable to alter field to binary', __FILE__, __LINE__, $db->error());
+ $db->alter_field($table, $cur_column['Field'], $cur_column['Type'].' CHARACTER SET utf8 COLLATE '.$collate, $allow_null, $cur_column['Default'], null, true) or error('Unable to alter field to utf8', __FILE__, __LINE__, $db->error());
+ }
+ }
+}
+
+//
+// Safely converts text type columns into utf8
+// If finished returns true, otherwise returns $end_at
+//
+function convert_table_utf8($table, $callback, $old_charset, $key = null, $start_at = null, $error_callback = null)
+{
+ global $mysql, $db, $old_connection_charset;
+
+ $finished = true;
+ $end_at = 0;
+ if ($mysql)
+ {
+ // Only set up the tables if we are doing this in 1 go, or it's the first go
+ if (is_null($start_at) || $start_at == 0)
+ {
+ // Drop any temp table that exists, in-case it's left over from a failed update
+ $db->drop_table($table.'_utf8', true) or error('Unable to drop left over temp table', __FILE__, __LINE__, $db->error());
+
+ // Copy the table
+ $db->query('CREATE TABLE '.$table.'_utf8 LIKE '.$table) or error('Unable to create new table', __FILE__, __LINE__, $db->error());
+
+ // Set table default charset to utf8
+ alter_table_utf8($table.'_utf8');
+ }
+
+ // Change to the old character set so MySQL doesn't attempt to perform conversion on the data from the old table
+ $db->set_names($old_connection_charset);
+
+ // Move & Convert everything
+ $result = $db->query('SELECT * FROM '.$table.(is_null($start_at) ? '' : ' WHERE '.$key.'>'.$start_at).' ORDER BY '.$key.' ASC'.(is_null($start_at) ? '' : ' LIMIT '.PER_PAGE), false) or error('Unable to select from old table', __FILE__, __LINE__, $db->error());
+
+ // Change back to utf8 mode so we can insert it into the new table
+ $db->set_names('utf8');
+
+ while ($cur_item = $db->fetch_assoc($result))
+ {
+ $cur_item = call_user_func($callback, $cur_item, $old_charset);
+
+ $temp = array();
+ foreach ($cur_item as $idx => $value)
+ $temp[$idx] = is_null($value) ? 'NULL' : '\''.$db->escape($value).'\'';
+
+ $db->query('INSERT INTO '.$table.'_utf8('.implode(',', array_keys($temp)).') VALUES ('.implode(',', array_values($temp)).')') or (is_null($error_callback) ? error('Unable to insert data to new table', __FILE__, __LINE__, $db->error()) : call_user_func($error_callback, $cur_item));
+
+ $end_at = $cur_item[$key];
+ }
+
+ // If we aren't doing this all in 1 go and $end_at has a value (i.e. we have processed at least 1 row), figure out if we have more to do or not
+ if (!is_null($start_at) && $end_at > 0)
+ {
+ $result = $db->query('SELECT 1 FROM '.$table.' WHERE '.$key.'>'.$end_at.' ORDER BY '.$key.' ASC LIMIT 1') or error('Unable to check for next row', __FILE__, __LINE__, $db->error());
+ $finished = $db->num_rows($result) == 0;
+ }
+
+ // Only swap the tables if we are doing this in 1 go, or it's the last go
+ if ($finished)
+ {
+ // Delete old table
+ $db->drop_table($table, true) or error('Unable to drop old table', __FILE__, __LINE__, $db->error());
+
+ // Rename table
+ $db->query('ALTER TABLE '.$table.'_utf8 RENAME '.$table) or error('Unable to rename new table', __FILE__, __LINE__, $db->error());
+
+ return true;
+ }
+
+ return $end_at;
+ }
+ else
+ {
+ // Convert everything
+ $result = $db->query('SELECT * FROM '.$table.(is_null($start_at) ? '' : ' WHERE '.$key.'>'.$start_at).' ORDER BY '.$key.' ASC'.(is_null($start_at ) ? '' : ' LIMIT '.PER_PAGE)) or error('Unable to select from table', __FILE__, __LINE__, $db->error());
+ while ($cur_item = $db->fetch_assoc($result))
+ {
+ $cur_item = call_user_func($callback, $cur_item, $old_charset);
+
+ $temp = array();
+ foreach ($cur_item as $idx => $value)
+ $temp[] = $idx.'='.(is_null($value) ? 'NULL' : '\''.$db->escape($value).'\'');
+
+ if (!empty($temp))
+ $db->query('UPDATE '.$table.' SET '.implode(', ', $temp).' WHERE '.$key.'=\''.$db->escape($cur_item[$key]).'\'') or error('Unable to update data', __FILE__, __LINE__, $db->error());
+
+ $end_at = $cur_item[$key];
+ }
+
+ if (!is_null($start_at) && $end_at > 0)
+ {
+ $result = $db->query('SELECT 1 FROM '.$table.' WHERE '.$key.'>'.$end_at.' ORDER BY '.$key.' ASC LIMIT 1') or error('Unable to check for next row', __FILE__, __LINE__, $db->error());
+ if ($db->num_rows($result) == 0)
+ return true;
+
+ return $end_at;
+ }
+
+ return true;
+ }
+}
+
+
+header('Content-type: text/html; charset=utf-8');
+
+// Empty all output buffers and stop buffering
+while (@ob_end_clean());
+
+
+$stage = isset($_REQUEST['stage']) ? $_REQUEST['stage'] : '';
+$old_charset = isset($_REQUEST['req_old_charset']) ? str_replace('ISO8859', 'ISO-8859', strtoupper($_REQUEST['req_old_charset'])) : 'ISO-8859-1';
+$start_at = isset($_REQUEST['start_at']) ? intval($_REQUEST['start_at']) : 0;
+$query_str = '';
+
+// Show form
+if (empty($stage))
+{
+ if (file_exists(FORUM_CACHE_DIR.'db_update.lock'))
+ {
+ // Deal with newlines, tabs and multiple spaces
+ $pattern = array("\t", ' ', ' ');
+ $replace = array('&#160; &#160; ', '&#160; ', ' &#160;');
+ $message = str_replace($pattern, $replace, $pun_config['o_maintenance_message']);
+
+?>
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php echo $lang_common['lang_identifier'] ?>" lang="<?php echo $lang_common['lang_identifier'] ?>" dir="<?php echo $lang_common['lang_direction'] ?>">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title><?php echo $lang_update['Maintenance'] ?></title>
+<link rel="stylesheet" type="text/css" href="style/<?php echo $default_style ?>.css" />
+</head>
+<body>
+
+<div id="punmaint" class="pun">
+<div class="top-box"><div><!-- Top Corners --></div></div>
+<div class="punwrap">
+
+<div id="brdmain">
+<div class="block">
+ <h2><?php echo $lang_update['Maintenance'] ?></h2>
+ <div class="box">
+ <div class="inbox">
+ <p><?php echo $message ?></p>
+ </div>
+ </div>
+</div>
+</div>
+
+</div>
+<div class="end-box"><div><!-- Bottom Corners --></div></div>
+</div>
+
+</body>
+</html>
+<?php
+
+ }
+ else
+ {
+
+?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php echo $lang_common['lang_identifier'] ?>" lang="<?php echo $lang_common['lang_identifier'] ?>" dir="<?php echo $lang_common['lang_direction'] ?>">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title><?php echo $lang_update['Update'] ?></title>
+<link rel="stylesheet" type="text/css" href="style/<?php echo $default_style ?>.css" />
+</head>
+<body onload="document.getElementById('install').req_db_pass.focus();document.getElementById('install').start.disabled=false;">
+
+<div id="pundb_update" class="pun">
+<div class="top-box"><div><!-- Top Corners --></div></div>
+<div class="punwrap">
+
+<div id="brdheader" class="block">
+ <div class="box">
+ <div id="brdtitle" class="inbox">
+ <h1><span><?php echo $lang_update['Update'] ?></span></h1>
+ <div id="brddesc"><p><?php echo $lang_update['Update message'] ?></p><p><strong><?php echo $lang_update['Note']; ?></strong> <?php echo $lang_update['Members message']; ?></p></div>
+ </div>
+ </div>
+</div>
+
+<div id="brdmain">
+<div class="blockform">
+ <h2><span><?php echo $lang_update['Update'] ?></span></h2>
+ <div class="box">
+ <form id="install" method="post" action="db_update.php">
+ <input type="hidden" name="stage" value="start" />
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_update['Administrator only'] ?></legend>
+ <div class="infldset">
+ <p><?php echo $lang_update['Database password info'] ?></p>
+ <p><strong><?php echo $lang_update['Note']; ?></strong> <?php echo $lang_update['Database password note'] ?></p>
+ <label class="required"><strong><?php echo $lang_update['Database password'] ?> <span><?php echo $lang_update['Required'] ?></span></strong><br /><input type="password" id="req_db_pass" name="req_db_pass" /><br /></label>
+ <p><?php echo $lang_update['Maintenance message info'] ?></p>
+ <div class="txtarea">
+ <label class="required"><strong><?php echo $lang_update['Maintenance message'] ?> <span><?php echo $lang_update['Required'] ?></span></strong><br />
+ <textarea name="req_maintenance_message" rows="4" cols="65"><?php echo pun_htmlspecialchars($pun_config['o_maintenance_message']) ?></textarea><br /></label>
+ </div>
+ </div>
+ </fieldset>
+ </div>
+ <div class="inform">
+ <div class="forminfo">
+ <p><?php echo $lang_update['Intro 1'] ?></p>
+ <p><?php echo $lang_update['Intro 2'] ?></p>
+<?php
+
+ if (strpos($cur_version, '1.2') === 0)
+ {
+ if (!function_exists('iconv') && !function_exists('mb_convert_encoding'))
+ {
+
+?>
+ <p><?php echo $lang_update['No charset conversion'] ?></p>
+<?php
+
+ }
+
+?>
+ </div>
+ </div>
+ <div class="inform">
+ <div class="forminfo">
+ <p><?php echo $lang_update['Enable conversion'] ?></p>
+ <p><?php echo $lang_update['Current character set'] ?></p>
+ </div>
+ <fieldset>
+ <legend><?php echo $lang_update['Charset conversion'] ?></legend>
+ <div class="infldset">
+ <div class="rbox">
+ <label><input type="checkbox" name="convert_charset" value="1" checked="checked" /><?php echo $lang_update['Enable conversion label'] ?><br /></label>
+ </div>
+ <label>
+ <strong><?php echo $lang_update['Current character set label'] ?></strong><br /><?php echo $lang_update['Current character set info'] ?><br />
+ <input type="text" name="req_old_charset" size="12" maxlength="20" value="<?php echo $old_charset ?>" /><br />
+ </label>
+ </div>
+ </fieldset>
+<?php
+
+ }
+ else
+ echo "\t\t\t\t".'</div>'."\n";
+
+?>
+ </div>
+ <p class="buttons"><input type="submit" name="start" value="<?php echo $lang_update['Start update'] ?>" /></p>
+ </form>
+ </div>
+</div>
+</div>
+
+</div>
+<div class="end-box"><div><!-- Bottom Corners --></div></div>
+</div>
+
+</body>
+</html>
+<?php
+
+ }
+ $db->end_transaction();
+ $db->close();
+ exit;
+
+}
+
+// Read the lock file
+$lock = file_exists(FORUM_CACHE_DIR.'db_update.lock') ? trim(file_get_contents(FORUM_CACHE_DIR.'db_update.lock')) : false;
+$lock_error = false;
+
+// Generate or fetch the UID - this confirms we have a valid admin
+if (isset($_POST['req_db_pass']))
+{
+ $req_db_pass = strtolower(pun_trim($_POST['req_db_pass']));
+
+ switch ($db_type)
+ {
+ // For SQLite we compare against the database file name, since the password is left blank
+ case 'sqlite':
+ if ($req_db_pass != strtolower($db_name))
+ error(sprintf($lang_update['Invalid file error'], 'config.php'));
+
+ break;
+ // For everything else, check the password matches
+ default:
+ if ($req_db_pass != strtolower($db_password))
+ error(sprintf($lang_update['Invalid password error'], 'config.php'));
+
+ break;
+ }
+
+ // Generate a unique id to identify this session, only if this is a valid session
+ $uid = pun_hash($req_db_pass.'|'.uniqid(rand(), true));
+ if ($lock) // We already have a lock file
+ $lock_error = true;
+ else // Create the lock file
+ {
+ $fh = @fopen(FORUM_CACHE_DIR.'db_update.lock', 'wb');
+ if (!$fh)
+ error(sprintf($lang_update['Unable to lock error'], 'cache'));
+
+ fwrite($fh, $uid);
+ fclose($fh);
+
+ // Update maintenance message
+ if ($_POST['req_maintenance_message'] != '')
+ $maintenance_message = pun_trim(pun_linebreaks($_POST['req_maintenance_message']));
+ else
+ {
+ // Load the admin_options.php language file
+ require PUN_ROOT.'lang/'.$default_lang.'/admin_options.php';
+
+ $maintenance_message = $lang_admin_options['Default maintenance message'];
+ }
+
+ $db->query('UPDATE '.$db->prefix.'config SET conf_value=\''.$db->escape($maintenance_message).'\' WHERE conf_name=\'o_maintenance_message\'') or error('Unable to update board config', __FILE__, __LINE__, $db->error());
+
+ // Regenerate the config cache
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_config_cache();
+ }
+}
+else if (isset($_GET['uid']))
+{
+ $uid = pun_trim($_GET['uid']);
+ if (!$lock || $lock !== $uid) // The lock doesn't exist or doesn't match the given UID
+ $lock_error = true;
+}
+else
+ error($lang_update['No password error']);
+
+// If there is an error with the lock file
+if ($lock_error)
+ error(sprintf($lang_update['Script runs error'], FORUM_CACHE_DIR.'db_update.lock'));
+
+switch ($stage)
+{
+ // Start by updating the database structure
+ case 'start':
+ $query_str = '?stage=preparse_posts';
+
+ // If we don't need to update the database, skip this stage
+ if (isset($pun_config['o_database_revision']) && $pun_config['o_database_revision'] >= UPDATE_TO_DB_REVISION)
+ break;
+
+ // Make all email fields VARCHAR(80)
+ $db->alter_field('bans', 'email', 'VARCHAR(80)', true) or error('Unable to alter email field', __FILE__, __LINE__, $db->error());
+ $db->alter_field('posts', 'poster_email', 'VARCHAR(80)', true) or error('Unable to alter poster_email field', __FILE__, __LINE__, $db->error());
+ $db->alter_field('users', 'email', 'VARCHAR(80)', false, '') or error('Unable to alter email field', __FILE__, __LINE__, $db->error());
+ $db->alter_field('users', 'jabber', 'VARCHAR(80)', true) or error('Unable to alter jabber field', __FILE__, __LINE__, $db->error());
+ $db->alter_field('users', 'msn', 'VARCHAR(80)', true) or error('Unable to alter msn field', __FILE__, __LINE__, $db->error());
+ $db->alter_field('users', 'activate_string', 'VARCHAR(80)', true) or error('Unable to alter activate_string field', __FILE__, __LINE__, $db->error());
+
+ // Make all IP fields VARCHAR(39) to support IPv6
+ $db->alter_field('posts', 'poster_ip', 'VARCHAR(39)', true) or error('Unable to alter poster_ip field', __FILE__, __LINE__, $db->error());
+ $db->alter_field('users', 'registration_ip', 'VARCHAR(39)', false, '0.0.0.0') or error('Unable to alter registration_ip field', __FILE__, __LINE__, $db->error());
+
+ // Make the message field MEDIUMTEXT to allow proper conversion of 65535 character posts to UTF-8
+ $db->alter_field('posts', 'message', 'MEDIUMTEXT', true) or error('Unable to alter message field', __FILE__, __LINE__, $db->error());
+
+ // Add the DST option to the users table
+ $db->add_field('users', 'dst', 'TINYINT(1)', false, 0, 'timezone') or error('Unable to add dst field', __FILE__, __LINE__, $db->error());
+
+ // Add the last_post column to the online table
+ $db->add_field('online', 'last_post', 'INT(10) UNSIGNED', true, null, null) or error('Unable to add last_post field', __FILE__, __LINE__, $db->error());
+
+ // Add the last_search column to the online table
+ $db->add_field('online', 'last_search', 'INT(10) UNSIGNED', true, null, null) or error('Unable to add last_search field', __FILE__, __LINE__, $db->error());
+
+ // Add the last_search column to the users table
+ $db->add_field('users', 'last_search', 'INT(10) UNSIGNED', true, null, 'last_post') or error('Unable to add last_search field', __FILE__, __LINE__, $db->error());
+
+ // Drop use_avatar column from users table
+ $db->drop_field('users', 'use_avatar') or error('Unable to drop use_avatar field', __FILE__, __LINE__, $db->error());
+
+ // Drop save_pass column from users table
+ $db->drop_field('users', 'save_pass') or error('Unable to drop save_pass field', __FILE__, __LINE__, $db->error());
+
+ // Drop g_edit_subjects_interval column from groups table
+ $db->drop_field('groups', 'g_edit_subjects_interval');
+
+ // Add database revision number
+ if (!array_key_exists('o_database_revision', $pun_config))
+ $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_database_revision\', \'0\')') or error('Unable to insert config value \'o_database_revision\'', __FILE__, __LINE__, $db->error());
+
+ // Add search index revision number
+ if (!array_key_exists('o_searchindex_revision', $pun_config))
+ $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_searchindex_revision\', \'0\')') or error('Unable to insert config value \'o_searchindex_revision\'', __FILE__, __LINE__, $db->error());
+
+ // Add parser revision number
+ if (!array_key_exists('o_parser_revision', $pun_config))
+ $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_parser_revision\', \'0\')') or error('Unable to insert config value \'o_parser_revision\'', __FILE__, __LINE__, $db->error());
+
+ // Add default email setting option
+ if (!array_key_exists('o_default_email_setting', $pun_config))
+ $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_default_email_setting\', \'1\')') or error('Unable to insert config value \'o_default_email_setting\'', __FILE__, __LINE__, $db->error());
+
+ // Make sure we have o_additional_navlinks (was added in 1.2.1)
+ if (!array_key_exists('o_additional_navlinks', $pun_config))
+ $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_additional_navlinks\', \'\')') or error('Unable to insert config value \'o_additional_navlinks\'', __FILE__, __LINE__, $db->error());
+
+ // Insert new config option o_topic_views
+ if (!array_key_exists('o_topic_views', $pun_config))
+ $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_topic_views\', \'1\')') or error('Unable to insert config value \'o_topic_views\'', __FILE__, __LINE__, $db->error());
+
+ // Insert new config option o_signatures
+ if (!array_key_exists('o_signatures', $pun_config))
+ $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_signatures\', \'1\')') or error('Unable to insert config value \'o_signatures\'', __FILE__, __LINE__, $db->error());
+
+ // Insert new config option o_smtp_ssl
+ if (!array_key_exists('o_smtp_ssl', $pun_config))
+ $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_smtp_ssl\', \'0\')') or error('Unable to insert config value \'o_smtp_ssl\'', __FILE__, __LINE__, $db->error());
+
+ // Insert new config option o_default_dst
+ if (!array_key_exists('o_default_dst', $pun_config))
+ $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_default_dst\', \'0\')') or error('Unable to insert config value \'o_default_dst\'', __FILE__, __LINE__, $db->error());
+
+ // Insert new config option o_quote_depth
+ if (!array_key_exists('o_quote_depth', $pun_config))
+ $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_quote_depth\', \'3\')') or error('Unable to insert config value \'o_quote_depth\'', __FILE__, __LINE__, $db->error());
+
+ // Insert new config option o_feed_type
+ if (!array_key_exists('o_feed_type', $pun_config))
+ $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_feed_type\', \'2\')') or error('Unable to insert config value \'o_feed_type\'', __FILE__, __LINE__, $db->error());
+
+ // Insert new config option o_feed_ttl
+ if (!array_key_exists('o_feed_ttl', $pun_config))
+ $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_feed_ttl\', \'0\')') or error('Unable to insert config value \'o_feed_ttl\'', __FILE__, __LINE__, $db->error());
+
+ // Insert config option o_base_url which was removed in 1.3
+ if (!array_key_exists('o_base_url', $pun_config))
+ {
+ // If it isn't in $pun_config['o_base_url'] it should be in $base_url, but just in-case it isn't we can make a guess at it
+ if (!isset($base_url))
+ {
+ // Make an educated guess regarding base_url
+ $base_url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://'; // protocol
+ $base_url .= preg_replace('%:(80|443)$%', '', $_SERVER['HTTP_HOST']); // host[:port]
+ $base_url .= str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'])); // path
+ }
+
+ if (substr($base_url, -1) == '/')
+ $base_url = substr($base_url, 0, -1);
+
+ $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_base_url\', \''.$db->escape($base_url).'\')') or error('Unable to insert config value \'o_base_url\'', __FILE__, __LINE__, $db->error());
+ }
+
+ if (strpos($cur_version, '1.2') === 0)
+ {
+ // Groups are almost the same as 1.2:
+ // unverified: 32000 -> 0
+
+ $db->query('UPDATE '.$db->prefix.'users SET group_id = 0 WHERE group_id = 32000') or error('Unable to update unverified users', __FILE__, __LINE__, $db->error());
+ }
+ else if (strpos($cur_version, '1.3') === 0)
+ {
+ // Groups have changed quite a lot from 1.3:
+ // unverified: 0 -> 0
+ // admin: 1 -> 1
+ // mod: ? -> 2
+ // guest: 2 -> 3
+ // member: ? -> 4
+
+ $result = $db->query('SELECT MAX(g_id) + 1 FROM '.$db->prefix.'groups') or error('Unable to select temp group ID', __FILE__, __LINE__, $db->error());
+ $temp_id = $db->result($result);
+
+ $result = $db->query('SELECT g_id FROM '.$db->prefix.'groups WHERE g_moderator = 1 AND g_id > 1 LIMIT 1') or error('Unable to select moderator group', __FILE__, __LINE__, $db->error());
+ if ($db->num_rows($result))
+ $mod_gid = $db->result($result);
+ else
+ {
+ $db->query('INSERT INTO '.$db->prefix.'groups (g_title, g_user_title, g_moderator, g_mod_edit_users, g_mod_rename_users, g_mod_change_passwords, g_mod_ban_users, g_read_board, g_view_users, g_post_replies, g_post_topics, g_edit_posts, g_delete_posts, g_delete_topics, g_set_title, g_search, g_search_users, g_send_email, g_post_flood, g_search_flood, g_email_flood, g_report_flood) VALUES('."'Moderators', 'Moderator', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0)") or error('Unable to add group', __FILE__, __LINE__, $db->error());
+ $mod_gid = $db->insert_id();
+ }
+
+ $member_gid = $pun_config['o_default_user_group'];
+
+ // move the mod group to a temp place
+ $db->query('UPDATE '.$db->prefix.'groups SET g_id = '.$temp_id.' WHERE g_id = '.$mod_gid) or error('Unable to update group ID', __FILE__, __LINE__, $db->error());
+ $db->query('UPDATE '.$db->prefix.'users SET group_id = '.$temp_id.' WHERE group_id = '.$mod_gid) or error('Unable to update users group ID', __FILE__, __LINE__, $db->error());
+ $db->query('UPDATE '.$db->prefix.'forum_perms SET group_id = '.$temp_id.' WHERE group_id = '.$mod_gid) or error('Unable to forum_perms group ID', __FILE__, __LINE__, $db->error());
+ if ($member_gid == $mod_gid) $member_gid = $temp_id;
+
+ // move whoever is in 3 to a spare slot
+ $db->query('UPDATE '.$db->prefix.'groups SET g_id = '.$mod_gid.' WHERE g_id = 3') or error('Unable to update group ID', __FILE__, __LINE__, $db->error());
+ $db->query('UPDATE '.$db->prefix.'users SET group_id = '.$mod_gid.' WHERE group_id = 3') or error('Unable to update users group ID', __FILE__, __LINE__, $db->error());
+ $db->query('UPDATE '.$db->prefix.'forum_perms SET group_id = '.$mod_gid.' WHERE group_id = 3') or error('Unable to forum_perms group ID', __FILE__, __LINE__, $db->error());
+ if ($member_gid == 3) $member_gid = $mod_gid;
+
+ // move guest to 3
+ $db->query('UPDATE '.$db->prefix.'groups SET g_id = 3 WHERE g_id = 2') or error('Unable to update group ID', __FILE__, __LINE__, $db->error());
+ $db->query('UPDATE '.$db->prefix.'users SET group_id = 3 WHERE group_id = 2') or error('Unable to update users group ID', __FILE__, __LINE__, $db->error());
+ $db->query('UPDATE '.$db->prefix.'forum_perms SET group_id = 3 WHERE group_id = 2') or error('Unable to forum_perms group ID', __FILE__, __LINE__, $db->error());
+ if ($member_gid == 2) $member_gid = 3;
+
+ // move mod group in temp place to 2
+ $db->query('UPDATE '.$db->prefix.'groups SET g_id = 2 WHERE g_id = '.$temp_id) or error('Unable to update group ID', __FILE__, __LINE__, $db->error());
+ $db->query('UPDATE '.$db->prefix.'users SET group_id = 2 WHERE group_id = '.$temp_id) or error('Unable to update users group ID', __FILE__, __LINE__, $db->error());
+ $db->query('UPDATE '.$db->prefix.'forum_perms SET group_id = 2 WHERE group_id = '.$temp_id) or error('Unable to forum_perms group ID', __FILE__, __LINE__, $db->error());
+ if ($member_gid == $temp_id) $member_gid = 2;
+
+ // Only move stuff around if it isn't already in the right place
+ if ($member_gid != $mod_gid || $member_gid != 4)
+ {
+ // move members to temp place
+ $db->query('UPDATE '.$db->prefix.'groups SET g_id = '.$temp_id.' WHERE g_id = '.$member_gid) or error('Unable to update group ID', __FILE__, __LINE__, $db->error());
+ $db->query('UPDATE '.$db->prefix.'users SET group_id = '.$temp_id.' WHERE group_id = '.$member_gid) or error('Unable to update users group ID', __FILE__, __LINE__, $db->error());
+ $db->query('UPDATE '.$db->prefix.'forum_perms SET group_id = '.$temp_id.' WHERE group_id = '.$member_gid) or error('Unable to forum_perms group ID', __FILE__, __LINE__, $db->error());
+
+ // move whoever is in 4 to members place
+ $db->query('UPDATE '.$db->prefix.'groups SET g_id = '.$member_gid.' WHERE g_id = 4') or error('Unable to update group ID', __FILE__, __LINE__, $db->error());
+ $db->query('UPDATE '.$db->prefix.'users SET group_id = '.$member_gid.' WHERE group_id = 4') or error('Unable to update users group ID', __FILE__, __LINE__, $db->error());
+ $db->query('UPDATE '.$db->prefix.'forum_perms SET group_id = '.$member_gid.' WHERE group_id = 4') or error('Unable to forum_perms group ID', __FILE__, __LINE__, $db->error());
+
+ // move members in temp place to 4
+ $db->query('UPDATE '.$db->prefix.'groups SET g_id = 4 WHERE g_id = '.$temp_id) or error('Unable to update group ID', __FILE__, __LINE__, $db->error());
+ $db->query('UPDATE '.$db->prefix.'users SET group_id = 4 WHERE group_id = '.$temp_id) or error('Unable to update users group ID', __FILE__, __LINE__, $db->error());
+ $db->query('UPDATE '.$db->prefix.'forum_perms SET group_id = 4 WHERE group_id = '.$temp_id) or error('Unable to forum_perms group ID', __FILE__, __LINE__, $db->error());
+ }
+
+ $db->query('UPDATE '.$db->prefix.'config SET conf_value=\''.$member_gid.'\' WHERE conf_name=\'o_default_user_group\'') or error('Unable to update default user group ID', __FILE__, __LINE__, $db->error());
+ }
+
+ // Server time zone is now simply the default time zone
+ if (!array_key_exists('o_default_timezone', $pun_config))
+ $db->query('UPDATE '.$db->prefix.'config SET conf_name = \'o_default_timezone\' WHERE conf_name = \'o_server_timezone\'') or error('Unable to update time zone config', __FILE__, __LINE__, $db->error());
+
+ // Increase visit timeout to 30 minutes (only if it hasn't been changed from the default)
+ if (!array_key_exists('o_database_revision', $pun_config) && $pun_config['o_timeout_visit'] == '600')
+ $db->query('UPDATE '.$db->prefix.'config SET conf_value = \'1800\' WHERE conf_name = \'o_timeout_visit\'') or error('Unable to update visit timeout config', __FILE__, __LINE__, $db->error());
+
+ // Remove obsolete g_post_polls permission from groups table
+ $db->drop_field('groups', 'g_post_polls');
+
+ // Make room for multiple moderator groups
+ if (!$db->field_exists('groups', 'g_moderator'))
+ {
+ // Add g_moderator column to groups table
+ $db->add_field('groups', 'g_moderator', 'TINYINT(1)', false, 0, 'g_user_title') or error('Unable to add g_moderator field', __FILE__, __LINE__, $db->error());
+
+ // Give the moderator group moderator privileges
+ $db->query('UPDATE '.$db->prefix.'groups SET g_moderator = 1 WHERE g_id = 2') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error());
+ }
+
+ // Replace obsolete p_mod_edit_users config setting with new per-group permission
+ if (array_key_exists('p_mod_edit_users', $pun_config))
+ {
+ $db->query('DELETE FROM '.$db->prefix.'config WHERE conf_name = \'p_mod_edit_users\'') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error());
+
+ $db->add_field('groups', 'g_mod_edit_users', 'TINYINT(1)', false, 0, 'g_moderator') or error('Unable to add g_mod_edit_users field', __FILE__, __LINE__, $db->error());
+
+ $db->query('UPDATE '.$db->prefix.'groups SET g_mod_edit_users = '.$pun_config['p_mod_edit_users'].' WHERE g_moderator = 1') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error());
+ }
+
+ // Replace obsolete p_mod_rename_users config setting with new per-group permission
+ if (array_key_exists('p_mod_rename_users', $pun_config))
+ {
+ $db->query('DELETE FROM '.$db->prefix.'config WHERE conf_name = \'p_mod_rename_users\'') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error());
+
+ $db->add_field('groups', 'g_mod_rename_users', 'TINYINT(1)', false, 0, 'g_mod_edit_users') or error('Unable to add g_mod_rename_users field', __FILE__, __LINE__, $db->error());
+
+ $db->query('UPDATE '.$db->prefix.'groups SET g_mod_rename_users = '.$pun_config['p_mod_rename_users'].' WHERE g_moderator = 1') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error());
+ }
+
+ // Replace obsolete p_mod_change_passwords config setting with new per-group permission
+ if (array_key_exists('p_mod_change_passwords', $pun_config))
+ {
+ $db->query('DELETE FROM '.$db->prefix.'config WHERE conf_name = \'p_mod_change_passwords\'') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error());
+
+ $db->add_field('groups', 'g_mod_change_passwords', 'TINYINT(1)', false, 0, 'g_mod_rename_users') or error('Unable to add g_mod_change_passwords field', __FILE__, __LINE__, $db->error());
+
+ $db->query('UPDATE '.$db->prefix.'groups SET g_mod_change_passwords = '.$pun_config['p_mod_change_passwords'].' WHERE g_moderator = 1') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error());
+ }
+
+ // Replace obsolete p_mod_ban_users config setting with new per-group permission
+ if (array_key_exists('p_mod_ban_users', $pun_config))
+ {
+ $db->query('DELETE FROM '.$db->prefix.'config WHERE conf_name = \'p_mod_ban_users\'') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error());
+
+ $db->add_field('groups', 'g_mod_ban_users', 'TINYINT(1)', false, 0, 'g_mod_change_passwords') or error('Unable to add g_mod_ban_users field', __FILE__, __LINE__, $db->error());
+
+ $db->query('UPDATE '.$db->prefix.'groups SET g_mod_ban_users = '.$pun_config['p_mod_ban_users'].' WHERE g_moderator = 1') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error());
+ }
+
+ // We need to add a unique index to avoid users having multiple rows in the online table
+ if (!$db->index_exists('online', 'user_id_ident_idx'))
+ {
+ $db->truncate_table('online') or error('Unable to clear online table', __FILE__, __LINE__, $db->error());
+
+ if ($mysql)
+ $db->add_index('online', 'user_id_ident_idx', array('user_id', 'ident(25)'), true) or error('Unable to add user_id_ident_idx index', __FILE__, __LINE__, $db->error());
+ else
+ $db->add_index('online', 'user_id_ident_idx', array('user_id', 'ident'), true) or error('Unable to add user_id_ident_idx index', __FILE__, __LINE__, $db->error());
+ }
+
+ // Remove the redundant user_id_idx on the online table
+ $db->drop_index('online', 'user_id_idx') or error('Unable to drop user_id_idx index', __FILE__, __LINE__, $db->error());
+
+ // Add an index to ident on the online table
+ if ($mysql)
+ $db->add_index('online', 'ident_idx', array('ident(25)')) or error('Unable to add ident_idx index', __FILE__, __LINE__, $db->error());
+ else
+ $db->add_index('online', 'ident_idx', array('ident')) or error('Unable to add ident_idx index', __FILE__, __LINE__, $db->error());
+
+ // Add an index to logged in the online table
+ $db->add_index('online', 'logged_idx', array('logged')) or error('Unable to add logged_idx index', __FILE__, __LINE__, $db->error());
+
+ // Add an index to last_post in the topics table
+ $db->add_index('topics', 'last_post_idx', array('last_post')) or error('Unable to add last_post_idx index', __FILE__, __LINE__, $db->error());
+
+ // Add an index to username on the bans table
+ if ($mysql)
+ $db->add_index('bans', 'username_idx', array('username(25)')) or error('Unable to add username_idx index', __FILE__, __LINE__, $db->error());
+ else
+ $db->add_index('bans', 'username_idx', array('username')) or error('Unable to add username_idx index', __FILE__, __LINE__, $db->error());
+
+ // Change the username_idx on users to a unique index of max size 25
+ $db->drop_index('users', 'username_idx') or error('Unable to drop old username_idx index', __FILE__, __LINE__, $db->error());
+ $field = $mysql ? 'username(25)' : 'username';
+
+ // Attempt to add a unique index. If the user doesn't use a transactional database this can fail due to multiple matching usernames in the
+ // users table. This is bad, but just giving up if it happens is even worse! If it fails just add a regular non-unique index.
+ if (!$db->add_index('users', 'username_idx', array($field), true))
+ $db->add_index('users', 'username_idx', array($field)) or error('Unable to add username_idx field', __FILE__, __LINE__, $db->error());
+
+ // Add g_view_users column to groups table
+ $db->add_field('groups', 'g_view_users', 'TINYINT(1)', false, 1, 'g_read_board') or error('Unable to add g_view_users field', __FILE__, __LINE__, $db->error());
+
+ // Add the last_email_sent column to the users table and the g_send_email and
+ // g_email_flood columns to the groups table
+ $db->add_field('users', 'last_email_sent', 'INT(10) UNSIGNED', true, null, 'last_search') or error('Unable to add last_email_sent field', __FILE__, __LINE__, $db->error());
+ $db->add_field('groups', 'g_send_email', 'TINYINT(1)', false, 1, 'g_search_users') or error('Unable to add g_send_email field', __FILE__, __LINE__, $db->error());
+ $db->add_field('groups', 'g_email_flood', 'SMALLINT(6)', false, 60, 'g_search_flood') or error('Unable to add g_email_flood field', __FILE__, __LINE__, $db->error());
+
+ // Add the last_report_sent column to the users table and the g_report_flood
+ // column to the groups table
+ $db->add_field('users', 'last_report_sent', 'INT(10) UNSIGNED', true, null, 'last_email_sent') or error('Unable to add last_report_sent field', __FILE__, __LINE__, $db->error());
+ $db->add_field('groups', 'g_report_flood', 'SMALLINT(6)', false, 60, 'g_email_flood') or error('Unable to add g_report_flood field', __FILE__, __LINE__, $db->error());
+
+ // Set non-default g_send_email, g_flood_email and g_flood_report values properly
+ $db->query('UPDATE '.$db->prefix.'groups SET g_send_email = 0 WHERE g_id = 3') or error('Unable to update group email permissions', __FILE__, __LINE__, $db->error());
+ $db->query('UPDATE '.$db->prefix.'groups SET g_email_flood = 0, g_report_flood = 0 WHERE g_id IN (1,2,3)') or error('Unable to update group email permissions', __FILE__, __LINE__, $db->error());
+
+ // Add the auto notify/subscription option to the users table
+ $db->add_field('users', 'auto_notify', 'TINYINT(1)', false, 0, 'notify_with_post') or error('Unable to add auto_notify field', __FILE__, __LINE__, $db->error());
+
+ // Add the first_post_id column to the topics table
+ if (!$db->field_exists('topics', 'first_post_id'))
+ {
+ $db->add_field('topics', 'first_post_id', 'INT(10) UNSIGNED', false, 0, 'posted') or error('Unable to add first_post_id field', __FILE__, __LINE__, $db->error());
+ $db->add_index('topics', 'first_post_id_idx', array('first_post_id')) or error('Unable to add first_post_id_idx index', __FILE__, __LINE__, $db->error());
+
+ // Now that we've added the column and indexed it, we need to give it correct data
+ $result = $db->query('SELECT MIN(id) AS first_post, topic_id FROM '.$db->prefix.'posts GROUP BY topic_id') or error('Unable to fetch first_post_id', __FILE__, __LINE__, $db->error());
+
+ while ($cur_post = $db->fetch_assoc($result))
+ $db->query('UPDATE '.$db->prefix.'topics SET first_post_id = '.$cur_post['first_post'].' WHERE id = '.$cur_post['topic_id']) or error('Unable to update first_post_id', __FILE__, __LINE__, $db->error());
+ }
+
+ // Move any users with the old unverified status to their new group
+ $db->query('UPDATE '.$db->prefix.'users SET group_id=0 WHERE group_id=32000') or error('Unable to move unverified users', __FILE__, __LINE__, $db->error());
+
+ // Add the ban_creator column to the bans table
+ $db->add_field('bans', 'ban_creator', 'INT(10) UNSIGNED', false, 0) or error('Unable to add ban_creator field', __FILE__, __LINE__, $db->error());
+
+ // Add the time/date format settings to the user table
+ $db->add_field('users', 'time_format', 'TINYINT(1)', false, 0, 'dst') or error('Unable to add time_format field', __FILE__, __LINE__, $db->error());
+ $db->add_field('users', 'date_format', 'TINYINT(1)', false, 0, 'dst') or error('Unable to add date_format field', __FILE__, __LINE__, $db->error());
+
+ // Change the search_data column to mediumtext
+ $db->alter_field('search_cache', 'search_data', 'MEDIUMTEXT', true) or error('Unable to alter search_data field', __FILE__, __LINE__, $db->error());
+
+ // Add the group promotion columns to the groups table
+ $db->add_field('groups', 'g_promote_min_posts', 'INT(10) UNSIGNED', false, 0, 'g_user_title') or error('Unable to add g_promote_min_posts field', __FILE__, __LINE__, $db->error());
+ $db->add_field('groups', 'g_promote_next_group', 'INT(10) UNSIGNED', false, 0, 'g_promote_min_posts') or error('Unable to add g_promote_next_group field', __FILE__, __LINE__, $db->error());
+
+ // Add a field for the per-group permission to post links
+ $db->add_field('groups', 'g_post_links', 'TINYINT(1)', false, 1, 'g_delete_topics') or error('Unable to add per-group permission to post links', __FILE__, __LINE__, $db->error());
+
+ // Add a field for the per-group permission to promote users to the next auto-promote group
+ $db->add_field('groups', 'g_mod_promote_users', 'TINYINT(1)', false, 0, 'g_mod_ban_users') or error('Unable to add per-group permission to promote users', __FILE__, __LINE__, $db->error());
+
+ // In case we had the fulltext search extension installed (1.3-legacy), remove it
+ $db->drop_index('topics', 'subject_idx') or error('Unable to drop subject_idx index', __FILE__, __LINE__, $db->error());
+ $db->drop_index('posts', 'message_idx') or error('Unable to drop message_idx index', __FILE__, __LINE__, $db->error());
+ // In case we had the fulltext search mod installed (1.2), remove it
+ $db->drop_index('topics', 'subject_fulltext_search') or error('Unable to drop subject_fulltext_search index', __FILE__, __LINE__, $db->error());
+ $db->drop_index('posts', 'message_fulltext_search') or error('Unable to drop message_fulltext_search index', __FILE__, __LINE__, $db->error());
+
+ // If the search_cache table has been dropped by the fulltext search extension, recreate it
+ if (!$db->table_exists('search_cache'))
+ {
+ $schema = array(
+ 'FIELDS' => array(
+ 'id' => array(
+ 'datatype' => 'INT(10) UNSIGNED',
+ 'allow_null' => false,
+ 'default' => '0'
+ ),
+ 'ident' => array(
+ 'datatype' => 'VARCHAR(200)',
+ 'allow_null' => false,
+ 'default' => '\'\''
+ ),
+ 'search_data' => array(
+ 'datatype' => 'MEDIUMTEXT',
+ 'allow_null' => true
+ )
+ ),
+ 'PRIMARY KEY' => array('id'),
+ 'INDEXES' => array(
+ 'ident_idx' => array('ident')
+ )
+ );
+
+ if ($db_type == 'mysql' || $db_type == 'mysqli' || $db_type == 'mysql_innodb' || $db_type == 'mysqli_innodb')
+ $schema['INDEXES']['ident_idx'] = array('ident(8)');
+
+ $db->create_table('search_cache', $schema);
+ }
+
+ // If the search_matches table has been dropped by the fulltext search extension, recreate it
+ if (!$db->table_exists('search_matches'))
+ {
+ $schema = array(
+ 'FIELDS' => array(
+ 'post_id' => array(
+ 'datatype' => 'INT(10) UNSIGNED',
+ 'allow_null' => false,
+ 'default' => '0'
+ ),
+ 'word_id' => array(
+ 'datatype' => 'INT(10) UNSIGNED',
+ 'allow_null' => false,
+ 'default' => '0'
+ ),
+ 'subject_match' => array(
+ 'datatype' => 'TINYINT(1)',
+ 'allow_null' => false,
+ 'default' => '0'
+ )
+ ),
+ 'INDEXES' => array(
+ 'word_id_idx' => array('word_id'),
+ 'post_id_idx' => array('post_id')
+ )
+ );
+
+ $db->create_table('search_matches', $schema);
+ }
+
+ // If the search_words table has been dropped by the fulltext search extension, recreate it
+ if (!$db->table_exists('search_words'))
+ {
+ $schema = array(
+ 'FIELDS' => array(
+ 'id' => array(
+ 'datatype' => 'SERIAL',
+ 'allow_null' => false
+ ),
+ 'word' => array(
+ 'datatype' => 'VARCHAR(20)',
+ 'allow_null' => false,
+ 'default' => '\'\'',
+ 'collation' => 'bin'
+ )
+ ),
+ 'PRIMARY KEY' => array('word'),
+ 'INDEXES' => array(
+ 'id_idx' => array('id')
+ )
+ );
+
+ if ($db_type == 'sqlite')
+ {
+ $schema['PRIMARY KEY'] = array('id');
+ $schema['UNIQUE KEYS'] = array('word_idx' => array('word'));
+ }
+
+ $db->create_table('search_words', $schema);
+ }
+
+ // Rename the subscription table
+ $db->rename_table('subscriptions', 'topic_subscriptions');
+
+ // if we don't have the forum_subscriptions table, create it
+ if (!$db->table_exists('forum_subscriptions'))
+ {
+ $schema = array(
+ 'FIELDS' => array(
+ 'user_id' => array(
+ 'datatype' => 'INT(10) UNSIGNED',
+ 'allow_null' => false,
+ 'default' => '0'
+ ),
+ 'forum_id' => array(
+ 'datatype' => 'INT(10) UNSIGNED',
+ 'allow_null' => false,
+ 'default' => '0'
+ )
+ ),
+ 'PRIMARY KEY' => array('user_id', 'forum_id')
+ );
+
+ $db->create_table('forum_subscriptions', $schema) or error('Unable to create forum subscriptions table', __FILE__, __LINE__, $db->error());
+ }
+
+ // Insert new config option o_forum_subscriptions
+ if (!array_key_exists('o_forum_subscriptions', $pun_config))
+ $db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_forum_subscriptions\', \'1\')') or error('Unable to insert config value \'o_forum_subscriptions\'', __FILE__, __LINE__, $db->error());
+
+ // Rename config option o_subscriptions to o_topic_subscriptions
+ if (!array_key_exists('o_topic_subscriptions', $pun_config))
+ $db->query('UPDATE '.$db->prefix.'config SET conf_name=\'o_topic_subscriptions\' WHERE conf_name=\'o_subscriptions\'') or error('Unable to rename config value \'o_subscriptions\'', __FILE__, __LINE__, $db->error());
+
+ // Change the default style if the old doesn't exist anymore
+ if ($pun_config['o_default_style'] != $default_style)
+ $db->query('UPDATE '.$db->prefix.'config SET conf_value = \''.$db->escape($default_style).'\' WHERE conf_name = \'o_default_style\'') or error('Unable to update default style config', __FILE__, __LINE__, $db->error());
+
+ // For MySQL(i) without InnoDB, change the engine of the online table (for performance reasons)
+ if ($db_type == 'mysql' || $db_type == 'mysqli')
+ $db->query('ALTER TABLE '.$db->prefix.'online ENGINE = MyISAM') or error('Unable to change engine type of online table to MyISAM', __FILE__, __LINE__, $db->error());
+
+ // Remove config option o_ranks
+ if (array_key_exists('o_ranks', $pun_config))
+ $db->query('DELETE FROM '.$db->prefix.'config WHERE conf_name=\'o_ranks\'') or error('Unable to remove config value \'o_ranks\'', __FILE__, __LINE__, $db->error());
+
+ // Remove the ranks table
+ if ($db->table_exists('ranks'))
+ $db->drop_table('ranks') or error('Unable to drop ranks table', __FILE__, __LINE__, $db->error());
+
+ // Should we do charset conversion or not?
+ if (strpos($cur_version, '1.2') === 0 && isset($_POST['convert_charset']))
+ $query_str = '?stage=conv_bans&req_old_charset='.$old_charset;
+
+ break;
+
+
+ // Convert bans
+ case 'conv_bans':
+ $query_str = '?stage=conv_categories&req_old_charset='.$old_charset;
+
+ function _conv_bans($cur_item, $old_charset)
+ {
+ global $lang_update;
+
+ echo sprintf($lang_update['Converting item'], $lang_update['ban'], $cur_item['id']).'<br />'."\n";
+
+ convert_to_utf8($cur_item['username'], $old_charset);
+ convert_to_utf8($cur_item['message'], $old_charset);
+
+ return $cur_item;
+ }
+
+ $end_at = convert_table_utf8($db->prefix.'bans', '_conv_bans', $old_charset, 'id', $start_at);
+
+ if ($end_at !== true)
+ $query_str = '?stage=conv_bans&req_old_charset='.$old_charset.'&start_at='.$end_at;
+
+ break;
+
+
+ // Convert categories
+ case 'conv_categories':
+ $query_str = '?stage=conv_censors&req_old_charset='.$old_charset;
+
+ echo sprintf($lang_update['Converting'], $lang_update['categories']).'<br />'."\n";
+
+ function _conv_categories($cur_item, $old_charset)
+ {
+ convert_to_utf8($cur_item['cat_name'], $old_charset);
+
+ return $cur_item;
+ }
+
+ convert_table_utf8($db->prefix.'categories', '_conv_categories', $old_charset, 'id');
+
+ break;
+
+
+ // Convert censor words
+ case 'conv_censors':
+ $query_str = '?stage=conv_config&req_old_charset='.$old_charset;
+
+ echo sprintf($lang_update['Converting'], $lang_update['censor words']).'<br />'."\n";
+
+ function _conv_censoring($cur_item, $old_charset)
+ {
+ convert_to_utf8($cur_item['search_for'], $old_charset);
+ convert_to_utf8($cur_item['replace_with'], $old_charset);
+
+ return $cur_item;
+ }
+
+ convert_table_utf8($db->prefix.'censoring', '_conv_censoring', $old_charset, 'id');
+
+ break;
+
+
+ // Convert config
+ case 'conv_config':
+ $query_str = '?stage=conv_forums&req_old_charset='.$old_charset;
+
+ echo sprintf($lang_update['Converting'], $lang_update['configuration']).'<br />'."\n";
+
+ function _conv_config($cur_item, $old_charset)
+ {
+ convert_to_utf8($cur_item['conf_value'], $old_charset);
+
+ return $cur_item;
+ }
+
+ convert_table_utf8($db->prefix.'config', '_conv_config', $old_charset, 'conf_name');
+
+ break;
+
+
+ // Convert forums
+ case 'conv_forums':
+ $query_str = '?stage=conv_perms&req_old_charset='.$old_charset;
+
+ echo sprintf($lang_update['Converting'], $lang_update['forums']).'<br />'."\n";
+
+ function _conv_forums($cur_item, $old_charset)
+ {
+ $moderators = ($cur_item['moderators'] != '') ? unserialize($cur_item['moderators']) : array();
+ $moderators_utf8 = array();
+ foreach ($moderators as $mod_username => $mod_user_id)
+ {
+ convert_to_utf8($mod_username, $old_charset);
+ $moderators_utf8[$mod_username] = $mod_user_id;
+ }
+
+ convert_to_utf8($cur_item['forum_name'], $old_charset);
+ convert_to_utf8($cur_item['forum_desc'], $old_charset);
+ convert_to_utf8($cur_item['last_poster'], $old_charset);
+
+ if (!empty($moderators_utf8))
+ $cur_item['moderators'] = serialize($moderators_utf8);
+
+ return $cur_item;
+ }
+
+ convert_table_utf8($db->prefix.'forums', '_conv_forums', $old_charset, 'id');
+
+ break;
+
+
+ // Convert forum permissions
+ case 'conv_perms':
+ $query_str = '?stage=conv_groups&req_old_charset='.$old_charset;
+
+ alter_table_utf8($db->prefix.'forum_perms');
+
+ break;
+
+
+ // Convert groups
+ case 'conv_groups':
+ $query_str = '?stage=conv_online&req_old_charset='.$old_charset;
+
+ echo sprintf($lang_update['Converting'], $lang_update['groups']).'<br />'."\n";
+
+ function _conv_groups($cur_item, $old_charset)
+ {
+ convert_to_utf8($cur_item['g_title'], $old_charset);
+ convert_to_utf8($cur_item['g_user_title'], $old_charset);
+
+ return $cur_item;
+ }
+
+ convert_table_utf8($db->prefix.'groups', '_conv_groups', $old_charset, 'g_id');
+
+ break;
+
+
+ // Convert online
+ case 'conv_online':
+ $query_str = '?stage=conv_posts&req_old_charset='.$old_charset;
+
+ // Truncate the table
+ $db->truncate_table('online') or error('Unable to empty online table', __FILE__, __LINE__, $db->error());
+
+ alter_table_utf8($db->prefix.'online');
+
+ break;
+
+
+ // Convert posts
+ case 'conv_posts':
+ $query_str = '?stage=conv_reports&req_old_charset='.$old_charset;
+
+ function _conv_posts($cur_item, $old_charset)
+ {
+ global $lang_update;
+
+ echo sprintf($lang_update['Converting item'], $lang_update['post'], $cur_item['id']).'<br />'."\n";
+
+ convert_to_utf8($cur_item['poster'], $old_charset);
+ convert_to_utf8($cur_item['message'], $old_charset);
+ convert_to_utf8($cur_item['edited_by'], $old_charset);
+
+ return $cur_item;
+ }
+
+ $end_at = convert_table_utf8($db->prefix.'posts', '_conv_posts', $old_charset, 'id', $start_at);
+
+ if ($end_at !== true)
+ $query_str = '?stage=conv_posts&req_old_charset='.$old_charset.'&start_at='.$end_at;
+
+ break;
+
+
+ // Convert reports
+ case 'conv_reports':
+ $query_str = '?stage=conv_search_cache&req_old_charset='.$old_charset;
+
+ function _conv_reports($cur_item, $old_charset)
+ {
+ global $lang_update;
+
+ echo sprintf($lang_update['Converting item'], $lang_update['report'], $cur_item['id']).'<br />'."\n";
+
+ convert_to_utf8($cur_item['message'], $old_charset);
+
+ return $cur_item;
+ }
+
+ $end_at = convert_table_utf8($db->prefix.'reports', '_conv_reports', $old_charset, 'id', $start_at);
+
+ if ($end_at !== true)
+ $query_str = '?stage=conv_reports&req_old_charset='.$old_charset.'&start_at='.$end_at;
+
+ break;
+
+
+ // Convert search cache
+ case 'conv_search_cache':
+ $query_str = '?stage=conv_search_matches&req_old_charset='.$old_charset;
+
+ // Truncate the table
+ $db->truncate_table('search_cache') or error('Unable to empty search cache table', __FILE__, __LINE__, $db->error());
+
+ alter_table_utf8($db->prefix.'search_cache');
+
+ break;
+
+
+ // Convert search matches
+ case 'conv_search_matches':
+ $query_str = '?stage=conv_search_words&req_old_charset='.$old_charset;
+
+ // Truncate the table
+ $db->truncate_table('search_matches') or error('Unable to empty search index match table', __FILE__, __LINE__, $db->error());
+
+ alter_table_utf8($db->prefix.'search_matches');
+
+ break;
+
+
+ // Convert search words
+ case 'conv_search_words':
+ $query_str = '?stage=conv_subscriptions&req_old_charset='.$old_charset;
+
+ // Truncate the table
+ $db->truncate_table('search_words') or error('Unable to empty search index words table', __FILE__, __LINE__, $db->error());
+
+ // Reset the sequence for the search words (not needed for SQLite)
+ switch ($db_type)
+ {
+ case 'mysql':
+ case 'mysqli':
+ case 'mysql_innodb':
+ case 'mysqli_innodb':
+ $db->query('ALTER TABLE '.$db->prefix.'search_words auto_increment=1') or error('Unable to update table auto_increment', __FILE__, __LINE__, $db->error());
+ break;
+
+ case 'pgsql';
+ $db->query('SELECT setval(\''.$db->prefix.'search_words_id_seq\', 1, false)') or error('Unable to update sequence', __FILE__, __LINE__, $db->error());
+ break;
+ }
+
+ alter_table_utf8($db->prefix.'search_words');
+
+ break;
+
+
+ // Convert subscriptions
+ case 'conv_subscriptions':
+ $query_str = '?stage=conv_topics&req_old_charset='.$old_charset;
+
+ // By this stage we should have already renamed the subscription table
+ alter_table_utf8($db->prefix.'topic_subscriptions');
+ alter_table_utf8($db->prefix.'forum_subscriptions'); // This should actually already be utf8, but for consistency...
+
+ break;
+
+
+ // Convert topics
+ case 'conv_topics':
+ $query_str = '?stage=conv_users&req_old_charset='.$old_charset;
+
+ function _conv_topics($cur_item, $old_charset)
+ {
+ global $lang_update;
+
+ echo sprintf($lang_update['Converting item'], $lang_update['topic'], $cur_item['id']).'<br />'."\n";
+
+ convert_to_utf8($cur_item['poster'], $old_charset);
+ convert_to_utf8($cur_item['subject'], $old_charset);
+ convert_to_utf8($cur_item['last_poster'], $old_charset);
+
+ return $cur_item;
+ }
+
+ $end_at = convert_table_utf8($db->prefix.'topics', '_conv_topics', $old_charset, 'id', $start_at);
+
+ if ($end_at !== true)
+ $query_str = '?stage=conv_topics&req_old_charset='.$old_charset.'&start_at='.$end_at;
+
+ break;
+
+
+ // Convert users
+ case 'conv_users':
+ $query_str = '?stage=preparse_posts';
+
+ if ($start_at == 0)
+ $_SESSION['dupe_users'] = array();
+
+ function _conv_users($cur_item, $old_charset)
+ {
+ global $lang_update;
+
+ echo sprintf($lang_update['Converting item'], $lang_update['user'], $cur_item['id']).'<br />'."\n";
+
+ convert_to_utf8($cur_item['username'], $old_charset);
+ convert_to_utf8($cur_item['title'], $old_charset);
+ convert_to_utf8($cur_item['realname'], $old_charset);
+ convert_to_utf8($cur_item['location'], $old_charset);
+ convert_to_utf8($cur_item['signature'], $old_charset);
+ convert_to_utf8($cur_item['admin_note'], $old_charset);
+
+ return $cur_item;
+ }
+
+ function _error_users($cur_user)
+ {
+ $_SESSION['dupe_users'][$cur_user['id']] = $cur_user;
+ }
+
+ $end_at = convert_table_utf8($db->prefix.'users', '_conv_users', $old_charset, 'id', $start_at, '_error_users');
+
+ if ($end_at !== true)
+ $query_str = '?stage=conv_users&req_old_charset='.$old_charset.'&start_at='.$end_at;
+ else if (!empty($_SESSION['dupe_users']))
+ $query_str = '?stage=conv_users_dupe';
+
+ break;
+
+
+ // Handle any duplicate users which occured due to conversion
+ case 'conv_users_dupe':
+ $query_str = '?stage=preparse_posts';
+
+ if (!$mysql || empty($_SESSION['dupe_users']))
+ break;
+
+ if (isset($_POST['form_sent']))
+ {
+ $errors = array();
+
+ require PUN_ROOT.'include/email.php';
+
+ foreach ($_SESSION['dupe_users'] as $id => $cur_user)
+ {
+ $errors[$id] = array();
+
+ $username = pun_trim($_POST['dupe_users'][$id]);
+
+ if (pun_strlen($username) < 2)
+ $errors[$id][] = $lang_update['Username too short error'];
+ else if (pun_strlen($username) > 25) // This usually doesn't happen since the form element only accepts 25 characters
+ $errors[$id][] = $lang_update['Username too long error'];
+ else if (!strcasecmp($username, 'Guest'))
+ $errors[$id][] = $lang_update['Username Guest reserved error'];
+ else if (preg_match('%[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}%', $username) || preg_match('%((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))%', $username))
+ $errors[$id][] = $lang_update['Username IP format error'];
+ else if ((strpos($username, '[') !== false || strpos($username, ']') !== false) && strpos($username, '\'') !== false && strpos($username, '"') !== false)
+ $errors[$id][] = $lang_update['Username bad characters error'];
+ else if (preg_match('%(?:\[/?(?:b|u|s|ins|del|em|i|h|colou?r|quote|code|img|url|email|list|\*)\]|\[(?:img|url|quote|list)=)%i', $username))
+ $errors[$id][] = $lang_update['Username BBCode error'];
+
+ $result = $db->query('SELECT username FROM '.$db->prefix.'users WHERE (UPPER(username)=UPPER(\''.$db->escape($username).'\') OR UPPER(username)=UPPER(\''.$db->escape(ucp_preg_replace('%[^\p{L}\p{N}]%u', '', $username)).'\')) AND id>1') or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
+
+ if ($db->num_rows($result))
+ {
+ $busy = $db->result($result);
+ $errors[$id][] = sprintf($lang_update['Username duplicate error'], pun_htmlspecialchars($busy));
+ }
+
+ if (empty($errors[$id]))
+ {
+ $old_username = $cur_user['username'];
+ $_SESSION['dupe_users'][$id]['username'] = $cur_user['username'] = $username;
+
+ $temp = array();
+ foreach ($cur_user as $idx => $value)
+ $temp[$idx] = is_null($value) ? 'NULL' : '\''.$db->escape($value).'\'';
+
+ // Insert the renamed user
+ $db->query('INSERT INTO '.$db->prefix.'users('.implode(',', array_keys($temp)).') VALUES ('.implode(',', array_values($temp)).')') or error('Unable to insert data to new table', __FILE__, __LINE__, $db->error());
+
+ // Renaming a user also affects a bunch of other stuff, lets fix that too...
+ $db->query('UPDATE '.$db->prefix.'posts SET poster=\''.$db->escape($username).'\' WHERE poster_id='.$id) or error('Unable to update posts', __FILE__, __LINE__, $db->error());
+
+ // TODO: The following must compare using collation utf8_bin otherwise we will accidently update posts/topics/etc belonging to both of the duplicate users, not just the one we renamed!
+ $db->query('UPDATE '.$db->prefix.'posts SET edited_by=\''.$db->escape($username).'\' WHERE edited_by=\''.$db->escape($old_username).'\' COLLATE utf8_bin') or error('Unable to update posts', __FILE__, __LINE__, $db->error());
+ $db->query('UPDATE '.$db->prefix.'topics SET poster=\''.$db->escape($username).'\' WHERE poster=\''.$db->escape($old_username).'\' COLLATE utf8_bin') or error('Unable to update topics', __FILE__, __LINE__, $db->error());
+ $db->query('UPDATE '.$db->prefix.'topics SET last_poster=\''.$db->escape($username).'\' WHERE last_poster=\''.$db->escape($old_username).'\' COLLATE utf8_bin') or error('Unable to update topics', __FILE__, __LINE__, $db->error());
+ $db->query('UPDATE '.$db->prefix.'forums SET last_poster=\''.$db->escape($username).'\' WHERE last_poster=\''.$db->escape($old_username).'\' COLLATE utf8_bin') or error('Unable to update forums', __FILE__, __LINE__, $db->error());
+ $db->query('UPDATE '.$db->prefix.'online SET ident=\''.$db->escape($username).'\' WHERE ident=\''.$db->escape($old_username).'\' COLLATE utf8_bin') or error('Unable to update online list', __FILE__, __LINE__, $db->error());
+
+ // If the user is a moderator or an administrator we have to update the moderator lists
+ $result = $db->query('SELECT g_moderator FROM '.$db->prefix.'groups WHERE g_id='.$cur_user['group_id']) or error('Unable to fetch group', __FILE__, __LINE__, $db->error());
+ $group_mod = $db->result($result);
+
+ if ($cur_user['group_id'] == PUN_ADMIN || $group_mod == '1')
+ {
+ $result = $db->query('SELECT id, moderators FROM '.$db->prefix.'forums') or error('Unable to fetch forum list', __FILE__, __LINE__, $db->error());
+
+ while ($cur_forum = $db->fetch_assoc($result))
+ {
+ $cur_moderators = ($cur_forum['moderators'] != '') ? unserialize($cur_forum['moderators']) : array();
+
+ if (in_array($id, $cur_moderators))
+ {
+ unset($cur_moderators[$old_username]);
+ $cur_moderators[$username] = $id;
+ uksort($cur_moderators, 'utf8_strcasecmp');
+
+ $db->query('UPDATE '.$db->prefix.'forums SET moderators=\''.$db->escape(serialize($cur_moderators)).'\' WHERE id='.$cur_forum['id']) or error('Unable to update forum', __FILE__, __LINE__, $db->error());
+ }
+ }
+ }
+
+ // Email the user alerting them of the change
+ if (file_exists(PUN_ROOT.'lang/'.$cur_user['language'].'/mail_templates/rename.tpl'))
+ $mail_tpl = trim(file_get_contents(PUN_ROOT.'lang/'.$cur_user['language'].'/mail_templates/rename.tpl'));
+ else if (file_exists(PUN_ROOT.'lang/'.$pun_config['o_default_lang'].'/mail_templates/rename.tpl'))
+ $mail_tpl = trim(file_get_contents(PUN_ROOT.'lang/'.$pun_config['o_default_lang'].'/mail_templates/rename.tpl'));
+ else
+ $mail_tpl = trim(file_get_contents(PUN_ROOT.'lang/English/mail_templates/rename.tpl'));
+
+ // The first row contains the subject
+ $first_crlf = strpos($mail_tpl, "\n");
+ $mail_subject = trim(substr($mail_tpl, 8, $first_crlf-8));
+ $mail_message = trim(substr($mail_tpl, $first_crlf));
+
+ $mail_subject = str_replace('<board_title>', $pun_config['o_board_title'], $mail_subject);
+ $mail_message = str_replace('<base_url>', get_base_url().'/', $mail_message);
+ $mail_message = str_replace('<old_username>', $old_username, $mail_message);
+ $mail_message = str_replace('<new_username>', $username, $mail_message);
+ $mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'], $mail_message);
+
+ pun_mail($cur_user['email'], $mail_subject, $mail_message);
+
+ unset($_SESSION['dupe_users'][$id]);
+ }
+ }
+ }
+
+ if (!empty($_SESSION['dupe_users']))
+ {
+ $query_str = '';
+
+?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php echo $lang_common['lang_identifier'] ?>" lang="<?php echo $lang_common['lang_identifier'] ?>" dir="<?php echo $lang_common['lang_direction'] ?>">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title><?php echo $lang_update['Update'] ?></title>
+<link rel="stylesheet" type="text/css" href="style/<?php echo $default_style ?>.css" />
+</head>
+<body>
+
+<div id="pundb_update" class="pun">
+<div class="top-box"><div><!-- Top Corners --></div></div>
+<div class="punwrap">
+
+<div class="blockform">
+ <h2><span><?php echo $lang_update['Error converting users'] ?></span></h2>
+ <div class="box">
+ <form method="post" action="db_update.php?stage=conv_users_dupe&amp;uid=<?php echo $uid ?>">
+ <input type="hidden" name="form_sent" value="1" />
+ <div class="inform">
+ <div class="forminfo">
+ <p style="font-size: 1.1em"><?php echo $lang_update['Error info 1'] ?></p>
+ <p style="font-size: 1.1em"><?php echo $lang_update['Error info 2'] ?></p>
+ </div>
+ </div>
+<?php
+
+ foreach ($_SESSION['dupe_users'] as $id => $cur_user)
+ {
+
+?>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo pun_htmlspecialchars($cur_user['username']); ?></legend>
+ <div class="infldset">
+ <label class="required"><strong><?php echo $lang_update['New username'] ?> <span><?php echo $lang_update['Required'] ?></span></strong><br /><input type="text" name="<?php echo 'dupe_users['.$id.']'; ?>" value="<?php if (isset($_POST['dupe_users'][$id])) echo pun_htmlspecialchars($_POST['dupe_users'][$id]); ?>" size="25" maxlength="25" /><br /></label>
+ </div>
+ </fieldset>
+<?php if (!empty($errors[$id])): ?> <div class="forminfo error-info">
+ <h3><?php echo $lang_update['Correct errors'] ?></h3>
+ <ul class="error-list">
+<?php
+
+foreach ($errors[$id] as $cur_error)
+ echo "\t\t\t\t\t\t".'<li><strong>'.$cur_error.'</strong></li>'."\n";
+?>
+ </ul>
+ </div>
+<?php endif; ?> </div>
+<?php
+
+ }
+
+?>
+ <p class="buttons"><input type="submit" name="rename" value="<?php echo $lang_update['Rename users'] ?>" /></p>
+ </form>
+ </div>
+</div>
+
+</div>
+<div class="end-box"><div><!-- Bottom Corners --></div></div>
+</div>
+
+</body>
+</html>
+<?php
+
+ }
+
+ break;
+
+
+ // Preparse posts
+ case 'preparse_posts':
+ $query_str = '?stage=preparse_sigs';
+
+ // If we don't need to parse the posts, skip this stage
+ if (isset($pun_config['o_parser_revision']) && $pun_config['o_parser_revision'] >= UPDATE_TO_PARSER_REVISION)
+ break;
+
+ require PUN_ROOT.'include/parser.php';
+
+ // Fetch posts to process this cycle
+ $result = $db->query('SELECT id, message FROM '.$db->prefix.'posts WHERE id > '.$start_at.' ORDER BY id ASC LIMIT '.PER_PAGE) or error('Unable to fetch posts', __FILE__, __LINE__, $db->error());
+
+ $temp = array();
+ $end_at = 0;
+ while ($cur_item = $db->fetch_assoc($result))
+ {
+ echo sprintf($lang_update['Preparsing item'], $lang_update['post'], $cur_item['id']).'<br />'."\n";
+ $db->query('UPDATE '.$db->prefix.'posts SET message = \''.$db->escape(preparse_bbcode($cur_item['message'], $temp)).'\' WHERE id = '.$cur_item['id']) or error('Unable to update post', __FILE__, __LINE__, $db->error());
+
+ $end_at = $cur_item['id'];
+ }
+
+ // Check if there is more work to do
+ if ($end_at > 0)
+ {
+ $result = $db->query('SELECT 1 FROM '.$db->prefix.'posts WHERE id > '.$end_at.' ORDER BY id ASC LIMIT 1') or error('Unable to fetch next ID', __FILE__, __LINE__, $db->error());
+
+ if ($db->num_rows($result) > 0)
+ $query_str = '?stage=preparse_posts&start_at='.$end_at;
+ }
+
+ break;
+
+
+ // Preparse signatures
+ case 'preparse_sigs':
+ $query_str = '?stage=rebuild_idx';
+
+ // If we don't need to parse the sigs, skip this stage
+ if (isset($pun_config['o_parser_revision']) && $pun_config['o_parser_revision'] >= UPDATE_TO_PARSER_REVISION)
+ break;
+
+ require PUN_ROOT.'include/parser.php';
+
+ // Fetch users to process this cycle
+ $result = $db->query('SELECT id, signature FROM '.$db->prefix.'users WHERE id > '.$start_at.' ORDER BY id ASC LIMIT '.PER_PAGE) or error('Unable to fetch users', __FILE__, __LINE__, $db->error());
+
+ $temp = array();
+ $end_at = 0;
+ while ($cur_item = $db->fetch_assoc($result))
+ {
+ echo sprintf($lang_update['Preparsing item'], $lang_update['signature'], $cur_item['id']).'<br />'."\n";
+ $db->query('UPDATE '.$db->prefix.'users SET signature = \''.$db->escape(preparse_bbcode($cur_item['signature'], $temp, true)).'\' WHERE id = '.$cur_item['id']) or error('Unable to update user', __FILE__, __LINE__, $db->error());
+
+ $end_at = $cur_item['id'];
+ }
+
+ // Check if there is more work to do
+ if ($end_at > 0)
+ {
+ $result = $db->query('SELECT 1 FROM '.$db->prefix.'users WHERE id > '.$end_at.' ORDER BY id ASC LIMIT 1') or error('Unable to fetch next ID', __FILE__, __LINE__, $db->error());
+ if ($db->num_rows($result) > 0)
+ $query_str = '?stage=preparse_sigs&start_at='.$end_at;
+ }
+
+ break;
+
+
+ // Rebuild the search index
+ case 'rebuild_idx':
+ $query_str = '?stage=finish';
+
+ // If we don't need to update the search index, skip this stage
+ if (isset($pun_config['o_searchindex_revision']) && $pun_config['o_searchindex_revision'] >= UPDATE_TO_SI_REVISION)
+ break;
+
+ if ($start_at == 0)
+ {
+ // Truncate the tables just in-case we didn't already (if we are coming directly here without converting the tables)
+ $db->truncate_table('search_cache') or error('Unable to empty search cache table', __FILE__, __LINE__, $db->error());
+ $db->truncate_table('search_matches') or error('Unable to empty search index match table', __FILE__, __LINE__, $db->error());
+ $db->truncate_table('search_words') or error('Unable to empty search index words table', __FILE__, __LINE__, $db->error());
+
+ // Reset the sequence for the search words (not needed for SQLite)
+ switch ($db_type)
+ {
+ case 'mysql':
+ case 'mysqli':
+ case 'mysql_innodb':
+ case 'mysqli_innodb':
+ $db->query('ALTER TABLE '.$db->prefix.'search_words auto_increment=1') or error('Unable to update table auto_increment', __FILE__, __LINE__, $db->error());
+ break;
+
+ case 'pgsql';
+ $db->query('SELECT setval(\''.$db->prefix.'search_words_id_seq\', 1, false)') or error('Unable to update sequence', __FILE__, __LINE__, $db->error());
+ break;
+ }
+ }
+
+ require PUN_ROOT.'include/search_idx.php';
+
+ // Fetch posts to process this cycle
+ $result = $db->query('SELECT p.id, p.message, t.subject, t.first_post_id FROM '.$db->prefix.'posts AS p INNER JOIN '.$db->prefix.'topics AS t ON t.id=p.topic_id WHERE p.id > '.$start_at.' ORDER BY p.id ASC LIMIT '.PER_PAGE) or error('Unable to fetch posts', __FILE__, __LINE__, $db->error());
+
+ $end_at = 0;
+ while ($cur_item = $db->fetch_assoc($result))
+ {
+ echo sprintf($lang_update['Rebuilding index item'], $lang_update['post'], $cur_item['id']).'<br />'."\n";
+
+ if ($cur_item['id'] == $cur_item['first_post_id'])
+ update_search_index('post', $cur_item['id'], $cur_item['message'], $cur_item['subject']);
+ else
+ update_search_index('post', $cur_item['id'], $cur_item['message']);
+
+ $end_at = $cur_item['id'];
+ }
+
+ // Check if there is more work to do
+ if ($end_at > 0)
+ {
+ $result = $db->query('SELECT 1 FROM '.$db->prefix.'posts WHERE id > '.$end_at.' ORDER BY id ASC LIMIT 1') or error('Unable to fetch next ID', __FILE__, __LINE__, $db->error());
+
+ if ($db->num_rows($result) > 0)
+ $query_str = '?stage=rebuild_idx&start_at='.$end_at;
+ }
+
+ break;
+
+
+ // Show results page
+ case 'finish':
+ // We update the version number
+ $db->query('UPDATE '.$db->prefix.'config SET conf_value = \''.UPDATE_TO.'\' WHERE conf_name = \'o_cur_version\'') or error('Unable to update version', __FILE__, __LINE__, $db->error());
+
+ // And the database revision number
+ $db->query('UPDATE '.$db->prefix.'config SET conf_value = \''.UPDATE_TO_DB_REVISION.'\' WHERE conf_name = \'o_database_revision\'') or error('Unable to update database revision number', __FILE__, __LINE__, $db->error());
+
+ // And the search index revision number
+ $db->query('UPDATE '.$db->prefix.'config SET conf_value = \''.UPDATE_TO_SI_REVISION.'\' WHERE conf_name = \'o_searchindex_revision\'') or error('Unable to update search index revision number', __FILE__, __LINE__, $db->error());
+
+ // And the parser revision number
+ $db->query('UPDATE '.$db->prefix.'config SET conf_value = \''.UPDATE_TO_PARSER_REVISION.'\' WHERE conf_name = \'o_parser_revision\'') or error('Unable to update parser revision number', __FILE__, __LINE__, $db->error());
+
+ // Check the default language still exists!
+ if (!file_exists(PUN_ROOT.'lang/'.$pun_config['o_default_lang'].'/common.php'))
+ $db->query('UPDATE '.$db->prefix.'config SET conf_value = \'English\' WHERE conf_name = \'o_default_lang\'') or error('Unable to update default language', __FILE__, __LINE__, $db->error());
+
+ // Check the default style still exists!
+ if (!file_exists(PUN_ROOT.'style/'.$pun_config['o_default_style'].'.css'))
+ $db->query('UPDATE '.$db->prefix.'config SET conf_value = \'Air\' WHERE conf_name = \'o_default_style\'') or error('Unable to update default style', __FILE__, __LINE__, $db->error());
+
+ // This feels like a good time to synchronize the forums
+ $result = $db->query('SELECT id FROM '.$db->prefix.'forums') or error('Unable to fetch forum IDs', __FILE__, __LINE__, $db->error());
+
+ while ($row = $db->fetch_row($result))
+ update_forum($row[0]);
+
+ // Empty the PHP cache
+ forum_clear_cache();
+
+ // Delete the update lock file
+ @unlink(FORUM_CACHE_DIR.'db_update.lock');
+
+?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php echo $lang_common['lang_identifier'] ?>" lang="<?php echo $lang_common['lang_identifier'] ?>" dir="<?php echo $lang_common['lang_direction'] ?>">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title><?php echo $lang_update['Update'] ?></title>
+<link rel="stylesheet" type="text/css" href="style/<?php echo $default_style ?>.css" />
+</head>
+<body>
+
+<div id="pundb_update" class="pun">
+<div class="top-box"><div><!-- Top Corners --></div></div>
+<div class="punwrap">
+
+<div class="blockform">
+ <h2><span><?php echo $lang_update['Update'] ?></span></h2>
+ <div class="box">
+ <div class="fakeform">
+ <div class="inform">
+ <div class="forminfo">
+ <p style="font-size: 1.1em"><?php printf($lang_update['Successfully updated'], sprintf('<a href="index.php">%s</a>', $lang_update['go to index'])) ?></p>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+
+</div>
+<div class="end-box"><div><!-- Bottom Corners --></div></div>
+</div>
+
+</body>
+</html>
+<?php
+
+ break;
+}
+
+$db->end_transaction();
+$db->close();
+
+if ($query_str != '')
+ exit('<meta http-equiv="refresh" content="0;url=db_update.php'.$query_str.'&uid='.$uid.'" /><hr /><p>'.sprintf($lang_update['Automatic redirect failed'], '<a href="db_update.php'.$query_str.'&uid='.$uid.'">'.$lang_update['Click here'].'</a>').'</p>');
diff --git a/delete.php b/delete.php
new file mode 100644
index 0000000..e253bb4
--- /dev/null
+++ b/delete.php
@@ -0,0 +1,140 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+define('PUN_ROOT', dirname(__FILE__).'/');
+require PUN_ROOT.'include/common.php';
+
+
+if ($pun_user['g_read_board'] == '0')
+ message($lang_common['No view'], false, '403 Forbidden');
+
+
+$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
+if ($id < 1)
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+// Fetch some info about the post, the topic and the forum
+$result = $db->query('SELECT f.id AS fid, f.forum_name, f.moderators, f.redirect_url, fp.post_replies, fp.post_topics, t.id AS tid, t.subject, t.first_post_id, t.closed, p.posted, p.poster, p.poster_id, p.message, p.hide_smilies FROM '.$db->prefix.'posts AS p INNER JOIN '.$db->prefix.'topics AS t ON t.id=p.topic_id INNER JOIN '.$db->prefix.'forums AS f ON f.id=t.forum_id LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND p.id='.$id) or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
+if (!$db->num_rows($result))
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+$cur_post = $db->fetch_assoc($result);
+
+if ($pun_config['o_censoring'] == '1')
+ $cur_post['subject'] = censor_words($cur_post['subject']);
+
+// Sort out who the moderators are and if we are currently a moderator (or an admin)
+$mods_array = ($cur_post['moderators'] != '') ? unserialize($cur_post['moderators']) : array();
+$is_admmod = ($pun_user['g_id'] == PUN_ADMIN || ($pun_user['g_moderator'] == '1' && array_key_exists($pun_user['username'], $mods_array))) ? true : false;
+
+$is_topic_post = ($id == $cur_post['first_post_id']) ? true : false;
+
+// Do we have permission to edit this post?
+if (($pun_user['g_delete_posts'] == '0' ||
+ ($pun_user['g_delete_topics'] == '0' && $is_topic_post) ||
+ $cur_post['poster_id'] != $pun_user['id'] ||
+ $cur_post['closed'] == '1') &&
+ !$is_admmod)
+ message($lang_common['No permission'], false, '403 Forbidden');
+
+if ($is_admmod && $pun_user['g_id'] != PUN_ADMIN && in_array($cur_post['poster_id'], get_admin_ids()))
+ message($lang_common['No permission'], false, '403 Forbidden');
+
+// Load the delete.php language file
+require PUN_ROOT.'lang/'.$pun_user['language'].'/delete.php';
+
+
+if (isset($_POST['delete']))
+{
+ // Make sure they got here from the site
+ confirm_referrer('delete.php');
+
+ require PUN_ROOT.'include/search_idx.php';
+
+ if ($is_topic_post)
+ {
+ // Delete the topic and all of its posts
+ delete_topic($cur_post['tid']);
+ update_forum($cur_post['fid']);
+
+ redirect('viewforum.php?id='.$cur_post['fid'], $lang_delete['Topic del redirect']);
+ }
+ else
+ {
+ // Delete just this one post
+ delete_post($id, $cur_post['tid']);
+ update_forum($cur_post['fid']);
+
+ // Redirect towards the previous post
+ $result = $db->query('SELECT id FROM '.$db->prefix.'posts WHERE topic_id='.$cur_post['tid'].' AND id < '.$id.' ORDER BY id DESC LIMIT 1') or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
+ $post_id = $db->result($result);
+
+ redirect('viewtopic.php?pid='.$post_id.'#p'.$post_id, $lang_delete['Post del redirect']);
+ }
+}
+
+
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_delete['Delete post']);
+define ('PUN_ACTIVE_PAGE', 'index');
+require PUN_ROOT.'header.php';
+
+require PUN_ROOT.'include/parser.php';
+$cur_post['message'] = parse_message($cur_post['message'], $cur_post['hide_smilies']);
+
+?>
+<div class="linkst">
+ <div class="inbox">
+ <ul class="crumbs">
+ <li><a href="index.php"><?php echo $lang_common['Index'] ?></a></li>
+ <li><span>»&#160;</span><a href="viewforum.php?id=<?php echo $cur_post['fid'] ?>"><?php echo pun_htmlspecialchars($cur_post['forum_name']) ?></a></li>
+ <li><span>»&#160;</span><a href="viewtopic.php?pid=<?php echo $id ?>#p<?php echo $id ?>"><?php echo pun_htmlspecialchars($cur_post['subject']) ?></a></li>
+ <li><span>»&#160;</span><strong><?php echo $lang_delete['Delete post'] ?></strong></li>
+ </ul>
+ </div>
+</div>
+
+<div class="blockform">
+ <h2><span><?php echo $lang_delete['Delete post'] ?></span></h2>
+ <div class="box">
+ <form method="post" action="delete.php?id=<?php echo $id ?>">
+ <div class="inform">
+ <div class="forminfo">
+ <h3><span><?php printf($is_topic_post ? $lang_delete['Topic by'] : $lang_delete['Reply by'], '<strong>'.pun_htmlspecialchars($cur_post['poster']).'</strong>', format_time($cur_post['posted'])) ?></span></h3>
+ <p><?php echo ($is_topic_post) ? '<strong>'.$lang_delete['Topic warning'].'</strong>' : '<strong>'.$lang_delete['Warning'].'</strong>' ?><br /><?php echo $lang_delete['Delete info'] ?></p>
+ </div>
+ </div>
+ <p class="buttons"><input type="submit" name="delete" value="<?php echo $lang_delete['Delete'] ?>" /> <a href="javascript:history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
+ </form>
+ </div>
+</div>
+
+<div id="postreview">
+ <div class="blockpost">
+ <div class="box">
+ <div class="inbox">
+ <div class="postbody">
+ <div class="postleft">
+ <dl>
+ <dt><strong><?php echo pun_htmlspecialchars($cur_post['poster']) ?></strong></dt>
+ <dd><span><?php echo format_time($cur_post['posted']) ?></span></dd>
+ </dl>
+ </div>
+ <div class="postright">
+ <div class="postmsg">
+ <?php echo $cur_post['message']."\n" ?>
+ </div>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+</div>
+<?php
+
+require PUN_ROOT.'footer.php';
diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
new file mode 100644
index 0000000..f799bd6
--- /dev/null
+++ b/docker/docker-compose.yml
@@ -0,0 +1,30 @@
+version: "3.3"
+
+volumes:
+ db-socket:
+ db-data:
+
+services:
+ app:
+ build: php
+ working_dir: /app
+ command: php -S 0.0.0.0:${PORT:-8080} -t /app
+ user: http
+ ports:
+ - "${PORT:-8080}:${PORT:-8080}"
+ volumes:
+ - ../:/app
+ - db-socket:/run/mysqld
+ tmpfs:
+ - /app/cache
+ depends_on:
+ - db
+
+ db:
+ build: mariadb
+ command: mysqld
+ user: mysql
+ network_mode: none
+ volumes:
+ - db-data:/var/lib/mysql
+ - db-socket:/run/mysqld
diff --git a/docker/mariadb/Dockerfile b/docker/mariadb/Dockerfile
new file mode 100644
index 0000000..b11b9a0
--- /dev/null
+++ b/docker/mariadb/Dockerfile
@@ -0,0 +1,4 @@
+FROM archlinux/base
+
+RUN pacman -Syu --noconfirm mariadb
+RUN mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql --auth-root-authentication-method=normal
diff --git a/docker/php/Dockerfile b/docker/php/Dockerfile
new file mode 100644
index 0000000..90d82e3
--- /dev/null
+++ b/docker/php/Dockerfile
@@ -0,0 +1,4 @@
+FROM archlinux/base
+
+RUN pacman -Syu --noconfirm php php-apcu php-apcu-bc
+ADD etc/ /etc
diff --git a/docker/php/etc/php/conf.d/extensions.ini b/docker/php/etc/php/conf.d/extensions.ini
new file mode 100644
index 0000000..fa6402f
--- /dev/null
+++ b/docker/php/etc/php/conf.d/extensions.ini
@@ -0,0 +1,4 @@
+[PHP]
+extension=mysqli.so
+extension=apcu.so
+extension=apc.so
diff --git a/docker/restart b/docker/restart
new file mode 100755
index 0000000..06c6aa5
--- /dev/null
+++ b/docker/restart
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+
+pushd $(dirname $BASH_SOURCE)
+
+./stop
+./start
diff --git a/docker/start b/docker/start
new file mode 100755
index 0000000..921b80f
--- /dev/null
+++ b/docker/start
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+pushd $(dirname $BASH_SOURCE)
+
+if [[ -n "$(docker-compose ps -q)" ]]; then
+ echo "Service already running" >&2
+ exit 1
+fi
+
+docker-compose up --build -d
+docker-compose exec db mysqladmin -uroot --wait=10 ping
+docker-compose exec db mysqladmin -uroot create fluxbb
diff --git a/docker/stop b/docker/stop
new file mode 100755
index 0000000..732c654
--- /dev/null
+++ b/docker/stop
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+pushd $(dirname $BASH_SOURCE)
+
+docker-compose down -v
diff --git a/edit.php b/edit.php
new file mode 100644
index 0000000..5aba54d
--- /dev/null
+++ b/edit.php
@@ -0,0 +1,293 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+define('PUN_ROOT', dirname(__FILE__).'/');
+require PUN_ROOT.'include/common.php';
+
+
+if ($pun_user['g_read_board'] == '0')
+ message($lang_common['No view'], false, '403 Forbidden');
+
+
+$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
+if ($id < 1)
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+// Fetch some info about the post, the topic and the forum
+$result = $db->query('SELECT f.id AS fid, f.forum_name, f.moderators, f.redirect_url, fp.post_replies, fp.post_topics, t.id AS tid, t.subject, t.posted, t.first_post_id, t.sticky, t.closed, p.poster, p.poster_id, p.message, p.hide_smilies FROM '.$db->prefix.'posts AS p INNER JOIN '.$db->prefix.'topics AS t ON t.id=p.topic_id INNER JOIN '.$db->prefix.'forums AS f ON f.id=t.forum_id LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND p.id='.$id) or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
+if (!$db->num_rows($result))
+ message($lang_common['Bad request'], false, '404 Not Found');
+
+$cur_post = $db->fetch_assoc($result);
+
+// Sort out who the moderators are and if we are currently a moderator (or an admin)
+$mods_array = ($cur_post['moderators'] != '') ? unserialize($cur_post['moderators']) : array();
+$is_admmod = ($pun_user['g_id'] == PUN_ADMIN || ($pun_user['g_moderator'] == '1' && array_key_exists($pun_user['username'], $mods_array))) ? true : false;
+
+$can_edit_subject = $id == $cur_post['first_post_id'];
+
+if ($pun_config['o_censoring'] == '1')
+{
+ $cur_post['subject'] = censor_words($cur_post['subject']);
+ $cur_post['message'] = censor_words($cur_post['message']);
+}
+
+// Do we have permission to edit this post?
+if (($pun_user['g_edit_posts'] == '0' ||
+ $cur_post['poster_id'] != $pun_user['id'] ||
+ $cur_post['closed'] == '1') &&
+ !$is_admmod)
+ message($lang_common['No permission'], false, '403 Forbidden');
+
+if ($is_admmod && $pun_user['g_id'] != PUN_ADMIN && in_array($cur_post['poster_id'], get_admin_ids()))
+ message($lang_common['No permission'], false, '403 Forbidden');
+
+// Load the post.php language file
+require PUN_ROOT.'lang/'.$pun_user['language'].'/post.php';
+
+// Start with a clean slate
+$errors = array();
+
+
+if (isset($_POST['form_sent']))
+{
+ // Make sure they got here from the site
+ confirm_referrer('edit.php');
+
+ // If it's a topic it must contain a subject
+ if ($can_edit_subject)
+ {
+ $subject = pun_trim($_POST['req_subject']);
+
+ if ($pun_config['o_censoring'] == '1')
+ $censored_subject = pun_trim(censor_words($subject));
+
+ if ($subject == '')
+ $errors[] = $lang_post['No subject'];
+ else if ($pun_config['o_censoring'] == '1' && $censored_subject == '')
+ $errors[] = $lang_post['No subject after censoring'];
+ else if (pun_strlen($subject) > 70)
+ $errors[] = $lang_post['Too long subject'];
+ else if ($pun_config['p_subject_all_caps'] == '0' && is_all_uppercase($subject) && !$pun_user['is_admmod'])
+ $errors[] = $lang_post['All caps subject'];
+ else if ($pun_user['g_post_links'] != '1' && preg_match('%(?:h\s*t|f)\s*t\s*p\s*(?:s\s*)?:\s*/\s*/%', $subject))
+ $errors[] = $lang_common['BBCode error tag url not allowed'];
+ }
+
+ // Clean up message from POST
+ $message = pun_linebreaks(pun_trim($_POST['req_message']));
+
+ // Here we use strlen() not pun_strlen() as we want to limit the post to PUN_MAX_POSTSIZE bytes, not characters
+ if (strlen($message) > PUN_MAX_POSTSIZE)
+ $errors[] = sprintf($lang_post['Too long message'], forum_number_format(PUN_MAX_POSTSIZE));
+ else if ($pun_config['p_message_all_caps'] == '0' && is_all_uppercase($message) && !$pun_user['is_admmod'])
+ $errors[] = $lang_post['All caps message'];
+
+ // Validate BBCode syntax
+ if ($pun_config['p_message_bbcode'] == '1')
+ {
+ require PUN_ROOT.'include/parser.php';
+ $message = preparse_bbcode($message, $errors);
+ }
+
+ if (empty($errors))
+ {
+ if ($message == '')
+ $errors[] = $lang_post['No message'];
+ else if ($pun_config['o_censoring'] == '1')
+ {
+ // Censor message to see if that causes problems
+ $censored_message = pun_trim(censor_words($message));
+
+ if ($censored_message == '')
+ $errors[] = $lang_post['No message after censoring'];
+ }
+ }
+
+ $hide_smilies = isset($_POST['hide_smilies']) ? '1' : '0';
+ $stick_topic = isset($_POST['stick_topic']) ? '1' : '0';
+ if (!$is_admmod)
+ $stick_topic = $cur_post['sticky'];
+
+ // Replace four-byte characters (MySQL cannot handle them)
+ $message = strip_bad_multibyte_chars($message);
+
+ // Did everything go according to plan?
+ if (empty($errors) && !isset($_POST['preview']))
+ {
+ $edited_sql = (!isset($_POST['silent']) || !$is_admmod) ? ', edited='.time().', edited_by=\''.$db->escape($pun_user['username']).'\'' : '';
+
+ require PUN_ROOT.'include/search_idx.php';
+
+ if ($can_edit_subject)
+ {
+ // Update the topic and any redirect topics
+ $db->query('UPDATE '.$db->prefix.'topics SET subject=\''.$db->escape($subject).'\', sticky='.$stick_topic.' WHERE id='.$cur_post['tid'].' OR moved_to='.$cur_post['tid']) or error('Unable to update topic', __FILE__, __LINE__, $db->error());
+
+ // We changed the subject, so we need to take that into account when we update the search words
+ update_search_index('edit', $id, $message, $subject);
+ }
+ else
+ update_search_index('edit', $id, $message);
+
+ // Update the post
+ $db->query('UPDATE '.$db->prefix.'posts SET message=\''.$db->escape($message).'\', hide_smilies='.$hide_smilies.$edited_sql.' WHERE id='.$id) or error('Unable to update post', __FILE__, __LINE__, $db->error());
+
+ redirect('viewtopic.php?pid='.$id.'#p'.$id, $lang_post['Edit redirect']);
+ }
+}
+
+
+
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_post['Edit post']);
+$required_fields = array('req_subject' => $lang_common['Subject'], 'req_message' => $lang_common['Message']);
+$focus_element = array('edit', 'req_message');
+define('PUN_ACTIVE_PAGE', 'index');
+require PUN_ROOT.'header.php';
+
+$cur_index = 1;
+
+?>
+<div class="linkst">
+ <div class="inbox">
+ <ul class="crumbs">
+ <li><a href="index.php"><?php echo $lang_common['Index'] ?></a></li>
+ <li><span>»&#160;</span><a href="viewforum.php?id=<?php echo $cur_post['fid'] ?>"><?php echo pun_htmlspecialchars($cur_post['forum_name']) ?></a></li>
+ <li><span>»&#160;</span><a href="viewtopic.php?id=<?php echo $cur_post['tid'] ?>"><?php echo pun_htmlspecialchars($cur_post['subject']) ?></a></li>
+ <li><span>»&#160;</span><strong><?php echo $lang_post['Edit post'] ?></strong></li>
+ </ul>
+ </div>
+</div>
+
+<?php
+
+// If there are errors, we display them
+if (!empty($errors))
+{
+
+?>
+<div id="posterror" class="block">
+ <h2><span><?php echo $lang_post['Post errors'] ?></span></h2>
+ <div class="box">
+ <div class="inbox error-info">
+ <p><?php echo $lang_post['Post errors info'] ?></p>
+ <ul class="error-list">
+<?php
+
+ foreach ($errors as $cur_error)
+ echo "\t\t\t\t".'<li><strong>'.$cur_error.'</strong></li>'."\n";
+?>
+ </ul>
+ </div>
+ </div>
+</div>
+
+<?php
+
+}
+else if (isset($_POST['preview']))
+{
+ require_once PUN_ROOT.'include/parser.php';
+ $preview_message = parse_message($message, $hide_smilies);
+
+?>
+<div id="postpreview" class="blockpost">
+ <h2><span><?php echo $lang_post['Post preview'] ?></span></h2>
+ <div class="box">
+ <div class="inbox">
+ <div class="postbody">
+ <div class="postright">
+ <div class="postmsg">
+ <?php echo $preview_message."\n" ?>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+
+<?php
+
+}
+
+?>
+<div id="editform" class="blockform">
+ <h2><span><?php echo $lang_post['Edit post'] ?></span></h2>
+ <div class="box">
+ <form id="edit" method="post" action="edit.php?id=<?php echo $id ?>&amp;action=edit" onsubmit="return process_form(this)">
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_post['Edit post legend'] ?></legend>
+ <input type="hidden" name="form_sent" value="1" />
+ <div class="infldset txtarea">
+<?php if ($can_edit_subject): ?> <label class="required"><strong><?php echo $lang_common['Subject'] ?> <span><?php echo $lang_common['Required'] ?></span></strong><br />
+ <input class="longinput" type="text" name="req_subject" size="80" maxlength="70" tabindex="<?php echo $cur_index++ ?>" value="<?php echo pun_htmlspecialchars(isset($_POST['req_subject']) ? $_POST['req_subject'] : $cur_post['subject']) ?>" /><br /></label>
+<?php endif; ?> <label class="required"><strong><?php echo $lang_common['Message'] ?> <span><?php echo $lang_common['Required'] ?></span></strong><br />
+ <textarea name="req_message" rows="20" cols="95" tabindex="<?php echo $cur_index++ ?>"><?php echo pun_htmlspecialchars(isset($_POST['req_message']) ? $message : $cur_post['message']) ?></textarea><br /></label>
+ <ul class="bblinks">
+ <li><span><a href="help.php#bbcode" onclick="window.open(this.href); return false;"><?php echo $lang_common['BBCode'] ?></a> <?php echo ($pun_config['p_message_bbcode'] == '1') ? $lang_common['on'] : $lang_common['off']; ?></span></li>
+ <li><span><a href="help.php#url" onclick="window.open(this.href); return false;"><?php echo $lang_common['url tag'] ?></a> <?php echo ($pun_config['p_message_bbcode'] == '1' && $pun_user['g_post_links'] == '1') ? $lang_common['on'] : $lang_common['off']; ?></span></li>
+ <li><span><a href="help.php#img" onclick="window.open(this.href); return false;"><?php echo $lang_common['img tag'] ?></a> <?php echo ($pun_config['p_message_bbcode'] == '1' && $pun_config['p_message_img_tag'] == '1') ? $lang_common['on'] : $lang_common['off']; ?></span></li>
+ <li><span><a href="help.php#smilies" onclick="window.open(this.href); return false;"><?php echo $lang_common['Smilies'] ?></a> <?php echo ($pun_config['o_smilies'] == '1') ? $lang_common['on'] : $lang_common['off']; ?></span></li>
+ </ul>
+ </div>
+ </fieldset>
+<?php
+
+$checkboxes = array();
+if ($can_edit_subject && $is_admmod)
+{
+ if (isset($_POST['stick_topic']) || !isset($_POST['form_sent']) && $cur_post['sticky'] == '1')
+ $checkboxes[] = '<label><input type="checkbox" name="stick_topic" value="1" checked="checked" tabindex="'.($cur_index++).'" />'.$lang_common['Stick topic'].'<br /></label>';
+ else
+ $checkboxes[] = '<label><input type="checkbox" name="stick_topic" value="1" tabindex="'.($cur_index++).'" />'.$lang_common['Stick topic'].'<br /></label>';
+}
+
+if ($pun_config['o_smilies'] == '1')
+{
+ if (isset($_POST['hide_smilies']) || !isset($_POST['form_sent']) && $cur_post['hide_smilies'] == '1')
+ $checkboxes[] = '<label><input type="checkbox" name="hide_smilies" value="1" checked="checked" tabindex="'.($cur_index++).'" />'.$lang_post['Hide smilies'].'<br /></label>';
+ else
+ $checkboxes[] = '<label><input type="checkbox" name="hide_smilies" value="1" tabindex="'.($cur_index++).'" />'.$lang_post['Hide smilies'].'<br /></label>';
+}
+
+if ($is_admmod)
+{
+ if (isset($_POST['silent']) || !isset($_POST['form_sent']))
+ $checkboxes[] = '<label><input type="checkbox" name="silent" value="1" tabindex="'.($cur_index++).'" checked="checked" />'.$lang_post['Silent edit'].'<br /></label>';
+ else
+ $checkboxes[] = '<label><input type="checkbox" name="silent" value="1" tabindex="'.($cur_index++).'" />'.$lang_post['Silent edit'].'<br /></label>';
+}
+
+if (!empty($checkboxes))
+{
+
+?>
+ </div>
+ <div class="inform">
+ <fieldset>
+ <legend><?php echo $lang_common['Options'] ?></legend>
+ <div class="infldset">
+ <div class="rbox">
+ <?php echo implode("\n\t\t\t\t\t\t\t", $checkboxes)."\n" ?>
+ </div>
+ </div>
+ </fieldset>
+<?php
+
+ }
+
+?>
+ </div>
+ <p class="buttons"><input type="submit" name="submit" value="<?php echo $lang_common['Submit'] ?>" tabindex="<?php echo $cur_index++ ?>" accesskey="s" /> <input type="submit" name="preview" value="<?php echo $lang_post['Preview'] ?>" tabindex="<?php echo $cur_index++ ?>" accesskey="p" /> <a href="javascript:history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
+ </form>
+ </div>
+</div>
+<?php
+
+require PUN_ROOT.'footer.php';
diff --git a/extern.php b/extern.php
new file mode 100644
index 0000000..d43574b
--- /dev/null
+++ b/extern.php
@@ -0,0 +1,547 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+/*-----------------------------------------------------------------------------
+
+ INSTRUCTIONS
+
+ This script is used to include information about your board from
+ pages outside the forums and to syndicate news about recent
+ discussions via RSS/Atom/XML. The script can display a list of
+ recent discussions, a list of active users or a collection of
+ general board statistics. The script can be called directly via
+ an URL, from a PHP include command or through the use of Server
+ Side Includes (SSI).
+
+ The scripts behaviour is controlled via variables supplied in the
+ URL to the script. The different variables are: action (what to
+ do), show (how many items to display), fid (the ID or IDs of
+ the forum(s) to poll for topics), nfid (the ID or IDs of forums
+ that should be excluded), tid (the ID of the topic from which to
+ display posts) and type (output as HTML or RSS). The only
+ mandatory variable is action. Possible/default values are:
+
+ action: feed - show most recent topics/posts (HTML or RSS)
+ online - show users online (HTML)
+ online_full - as above, but includes a full list (HTML)
+ stats - show board statistics (HTML)
+
+ type: rss - output as RSS 2.0
+ atom - output as Atom 1.0
+ xml - output as XML
+ html - output as HTML (<li>'s)
+
+ fid: One or more forum IDs (comma-separated). If ignored,
+ topics from all readable forums will be pulled.
+
+ nfid: One or more forum IDs (comma-separated) that are to be
+ excluded. E.g. the ID of a a test forum.
+
+ tid: A topic ID from which to show posts. If a tid is supplied,
+ fid and nfid are ignored.
+
+ show: Any integer value between 1 and 50. The default is 15.
+
+ order: last_post - show topics ordered by when they were last
+ posted in, giving information about the reply.
+ posted - show topics ordered by when they were first
+ posted, giving information about the original post.
+
+-----------------------------------------------------------------------------*/
+
+define('PUN_QUIET_VISIT', 1);
+
+if (!defined('PUN_ROOT'))
+ define('PUN_ROOT', dirname(__FILE__).'/');
+require PUN_ROOT.'include/common.php';
+
+// The length at which topic subjects will be truncated (for HTML output)
+if (!defined('FORUM_EXTERN_MAX_SUBJECT_LENGTH'))
+ define('FORUM_EXTERN_MAX_SUBJECT_LENGTH', 30);
+
+// If we're a guest and we've sent a username/pass, we can try to authenticate using those details
+if ($pun_user['is_guest'] && isset($_SERVER['PHP_AUTH_USER']))
+ authenticate_user($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
+
+if ($pun_user['g_read_board'] == '0')
+{
+ http_authenticate_user();
+ exit($lang_common['No view']);
+}
+
+$action = isset($_GET['action']) ? strtolower($_GET['action']) : 'feed';
+
+// Handle a couple old formats, from FluxBB 1.2
+switch ($action)
+{
+ case 'active':
+ $action = 'feed';
+ $_GET['order'] = 'last_post';
+ break;
+
+ case 'new':
+ $action = 'feed';
+ $_GET['order'] = 'posted';
+ break;
+}
+
+//
+// Sends the proper headers for Basic HTTP Authentication
+//
+function http_authenticate_user()
+{
+ global $pun_config, $pun_user;
+
+ if (!$pun_user['is_guest'])
+ return;
+
+ header('WWW-Authenticate: Basic realm="'.$pun_config['o_board_title'].' External Syndication"');
+ header('HTTP/1.0 401 Unauthorized');
+}
+
+
+//
+// Output $feed as RSS 2.0
+//
+function output_rss($feed)
+{
+ global $lang_common, $pun_config;
+
+ // Send XML/no cache headers
+ header('Content-Type: application/xml; charset=utf-8');
+ header('Expires: '.gmdate('D, d M Y H:i:s').' GMT');
+ header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+ header('Pragma: public');
+
+ echo '<?xml version="1.0" encoding="utf-8"?>'."\n";
+ echo '<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">'."\n";
+ echo "\t".'<channel>'."\n";
+ echo "\t\t".'<atom:link href="'.pun_htmlspecialchars(get_current_url()).'" rel="self" type="application/rss+xml" />'."\n";
+ echo "\t\t".'<title><![CDATA['.escape_cdata($feed['title']).']]></title>'."\n";
+ echo "\t\t".'<link>'.pun_htmlspecialchars($feed['link']).'</link>'."\n";
+ echo "\t\t".'<description><![CDATA['.escape_cdata($feed['description']).']]></description>'."\n";
+ echo "\t\t".'<lastBuildDate>'.gmdate('r', count($feed['items']) ? $feed['items'][0]['pubdate'] : time()).'</lastBuildDate>'."\n";
+
+ if ($pun_config['o_show_version'] == '1')
+ echo "\t\t".'<generator>FluxBB '.$pun_config['o_cur_version'].'</generator>'."\n";
+ else
+ echo "\t\t".'<generator>FluxBB</generator>'."\n";
+
+ foreach ($feed['items'] as $item)
+ {
+ echo "\t\t".'<item>'."\n";
+ echo "\t\t\t".'<title><![CDATA['.escape_cdata($item['title']).']]></title>'."\n";
+ echo "\t\t\t".'<link>'.pun_htmlspecialchars($item['link']).'</link>'."\n";
+ echo "\t\t\t".'<description><![CDATA['.escape_cdata($item['description']).']]></description>'."\n";
+ echo "\t\t\t".'<author><![CDATA['.(isset($item['author']['email']) ? escape_cdata($item['author']['email']) : 'dummy@example.com').' ('.escape_cdata($item['author']['name']).')]]></author>'."\n";
+ echo "\t\t\t".'<pubDate>'.gmdate('r', $item['pubdate']).'</pubDate>'."\n";
+ echo "\t\t\t".'<guid>'.pun_htmlspecialchars($item['link']).'</guid>'."\n";
+
+ echo "\t\t".'</item>'."\n";
+ }
+
+ echo "\t".'</channel>'."\n";
+ echo '</rss>'."\n";
+}
+
+
+//
+// Output $feed as Atom 1.0
+//
+function output_atom($feed)
+{
+ global $lang_common, $pun_config;
+
+ // Send XML/no cache headers
+ header('Content-Type: application/atom+xml; charset=utf-8');
+ header('Expires: '.gmdate('D, d M Y H:i:s').' GMT');
+ header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+ header('Pragma: public');
+
+ echo '<?xml version="1.0" encoding="utf-8"?>'."\n";
+ echo '<feed xmlns="http://www.w3.org/2005/Atom">'."\n";
+
+ echo "\t".'<title type="html"><![CDATA['.escape_cdata($feed['title']).']]></title>'."\n";
+ echo "\t".'<link rel="self" href="'.pun_htmlspecialchars(get_current_url()).'"/>'."\n";
+ echo "\t".'<link href="'.pun_htmlspecialchars($feed['link']).'"/>'."\n";
+ echo "\t".'<updated>'.gmdate('Y-m-d\TH:i:s\Z', count($feed['items']) ? $feed['items'][0]['pubdate'] : time()).'</updated>'."\n";
+
+ if ($pun_config['o_show_version'] == '1')
+ echo "\t".'<generator version="'.$pun_config['o_cur_version'].'">FluxBB</generator>'."\n";
+ else
+ echo "\t".'<generator>FluxBB</generator>'."\n";
+
+ echo "\t".'<id>'.pun_htmlspecialchars($feed['link']).'</id>'."\n";
+
+ $content_tag = ($feed['type'] == 'posts') ? 'content' : 'summary';
+
+ foreach ($feed['items'] as $item)
+ {
+ echo "\t".'<entry>'."\n";
+ echo "\t\t".'<title type="html"><![CDATA['.escape_cdata($item['title']).']]></title>'."\n";
+ echo "\t\t".'<link rel="alternate" href="'.pun_htmlspecialchars($item['link']).'"/>'."\n";
+ echo "\t\t".'<'.$content_tag.' type="html"><![CDATA['.escape_cdata($item['description']).']]></'.$content_tag.'>'."\n";
+ echo "\t\t".'<author>'."\n";
+ echo "\t\t\t".'<name><![CDATA['.escape_cdata($item['author']['name']).']]></name>'."\n";
+
+ if (isset($item['author']['email']))
+ echo "\t\t\t".'<email><![CDATA['.escape_cdata($item['author']['email']).']]></email>'."\n";
+
+ if (isset($item['author']['uri']))
+ echo "\t\t\t".'<uri>'.pun_htmlspecialchars($item['author']['uri']).'</uri>'."\n";
+
+ echo "\t\t".'</author>'."\n";
+ echo "\t\t".'<updated>'.gmdate('Y-m-d\TH:i:s\Z', $item['pubdate']).'</updated>'."\n";
+
+ echo "\t\t".'<id>'.pun_htmlspecialchars($item['link']).'</id>'."\n";
+ echo "\t".'</entry>'."\n";
+ }
+
+ echo '</feed>'."\n";
+}
+
+
+//
+// Output $feed as XML
+//
+function output_xml($feed)
+{
+ global $lang_common, $pun_config;
+
+ // Send XML/no cache headers
+ header('Content-Type: application/xml; charset=utf-8');
+ header('Expires: '.gmdate('D, d M Y H:i:s').' GMT');
+ header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+ header('Pragma: public');
+
+ echo '<?xml version="1.0" encoding="utf-8"?>'."\n";
+ echo '<source>'."\n";
+ echo "\t".'<url>'.pun_htmlspecialchars($feed['link']).'</url>'."\n";
+
+ $forum_tag = ($feed['type'] == 'posts') ? 'post' : 'topic';
+
+ foreach ($feed['items'] as $item)
+ {
+ echo "\t".'<'.$forum_tag.' id="'.$item['id'].'">'."\n";
+
+ echo "\t\t".'<title><![CDATA['.escape_cdata($item['title']).']]></title>'."\n";
+ echo "\t\t".'<link>'.pun_htmlspecialchars($item['link']).'</link>'."\n";
+ echo "\t\t".'<content><![CDATA['.escape_cdata($item['description']).']]></content>'."\n";
+ echo "\t\t".'<author>'."\n";
+ echo "\t\t\t".'<name><![CDATA['.escape_cdata($item['author']['name']).']]></name>'."\n";
+
+ if (isset($item['author']['email']))
+ echo "\t\t\t".'<email><![CDATA['.escape_cdata($item['author']['email']).']]></email>'."\n";
+
+ if (isset($item['author']['uri']))
+ echo "\t\t\t".'<uri>'.pun_htmlspecialchars($item['author']['uri']).'</uri>'."\n";
+
+ echo "\t\t".'</author>'."\n";
+ echo "\t\t".'<posted>'.gmdate('r', $item['pubdate']).'</posted>'."\n";
+
+ echo "\t".'</'.$forum_tag.'>'."\n";
+ }
+
+ echo '</source>'."\n";
+}
+
+
+//
+// Output $feed as HTML (using <li> tags)
+//
+function output_html($feed)
+{
+
+ // Send the Content-type header in case the web server is setup to send something else
+ header('Content-type: text/html; charset=utf-8');
+ header('Expires: '.gmdate('D, d M Y H:i:s').' GMT');
+ header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+ header('Pragma: public');
+
+ foreach ($feed['items'] as $item)
+ {
+ if (utf8_strlen($item['title']) > FORUM_EXTERN_MAX_SUBJECT_LENGTH)
+ $subject_truncated = pun_htmlspecialchars(pun_trim(utf8_substr($item['title'], 0, (FORUM_EXTERN_MAX_SUBJECT_LENGTH - 5)))).' …';
+ else
+ $subject_truncated = pun_htmlspecialchars($item['title']);
+
+ echo '<li><a href="'.pun_htmlspecialchars($item['link']).'" title="'.pun_htmlspecialchars($item['title']).'">'.$subject_truncated.'</a></li>'."\n";
+ }
+}
+
+// Show recent discussions
+if ($action == 'feed')
+{
+ require PUN_ROOT.'include/parser.php';
+
+ // Determine what type of feed to output
+ $type = isset($_GET['type']) ? strtolower($_GET['type']) : 'html';
+ if (!in_array($type, array('html', 'rss', 'atom', 'xml')))
+ $type = 'html';
+
+ $show = isset($_GET['show']) ? intval($_GET['show']) : 15;
+ if ($show < 1 || $show > 50)
+ $show = 15;
+
+ // Was a topic ID supplied?
+ if (isset($_GET['tid']))
+ {
+ $tid = intval($_GET['tid']);
+
+ // Fetch topic subject
+ $result = $db->query('SELECT t.subject, t.first_post_id FROM '.$db->prefix.'topics AS t LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=t.forum_id AND fp.group_id='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND t.moved_to IS NULL AND t.id='.$tid) or error('Unable to fetch topic info', __FILE__, __LINE__, $db->error());
+ if (!$db->num_rows($result))
+ {
+ http_authenticate_user();
+ exit($lang_common['Bad request']);
+ }
+
+ $cur_topic = $db->fetch_assoc($result);
+
+ if ($pun_config['o_censoring'] == '1')
+ $cur_topic['subject'] = censor_words($cur_topic['subject']);
+
+ // Setup the feed
+ $feed = array(
+ 'title' => $pun_config['o_board_title'].$lang_common['Title separator'].$cur_topic['subject'],
+ 'link' => get_base_url(true).'/viewtopic.php?id='.$tid,
+ 'description' => sprintf($lang_common['RSS description topic'], $cur_topic['subject']),
+ 'items' => array(),
+ 'type' => 'posts'
+ );
+
+ // Fetch $show posts
+ $result = $db->query('SELECT p.id, p.poster, p.message, p.hide_smilies, p.posted, p.poster_id, u.email_setting, u.email, p.poster_email FROM '.$db->prefix.'posts AS p INNER JOIN '.$db->prefix.'users AS u ON u.id=p.poster_id WHERE p.topic_id='.$tid.' ORDER BY p.posted DESC LIMIT '.$show) or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
+ while ($cur_post = $db->fetch_assoc($result))
+ {
+ $cur_post['message'] = parse_message($cur_post['message'], $cur_post['hide_smilies']);
+
+ $item = array(
+ 'id' => $cur_post['id'],
+ 'title' => $cur_topic['first_post_id'] == $cur_post['id'] ? $cur_topic['subject'] : $lang_common['RSS reply'].$cur_topic['subject'],
+ 'link' => get_base_url(true).'/viewtopic.php?pid='.$cur_post['id'].'#p'.$cur_post['id'],
+ 'description' => $cur_post['message'],
+ 'author' => array(
+ 'name' => $cur_post['poster'],
+ ),
+ 'pubdate' => $cur_post['posted']
+ );
+
+ if ($cur_post['poster_id'] > 1)
+ {
+ if ($cur_post['email_setting'] == '0' && !$pun_user['is_guest'])
+ $item['author']['email'] = $cur_post['email'];
+
+ $item['author']['uri'] = get_base_url(true).'/profile.php?id='.$cur_post['poster_id'];
+ }
+ else if ($cur_post['poster_email'] != '' && !$pun_user['is_guest'])
+ $item['author']['email'] = $cur_post['poster_email'];
+
+ $feed['items'][] = $item;
+ }
+
+ $output_func = 'output_'.$type;
+ $output_func($feed);
+ }
+ else
+ {
+ $order_posted = isset($_GET['order']) && strtolower($_GET['order']) == 'posted';
+ $forum_name = '';
+ $forum_sql = '';
+
+ // Were any forum IDs supplied?
+ if (isset($_GET['fid']) && is_scalar($_GET['fid']) && $_GET['fid'] != '')
+ {
+ $fids = explode(',', pun_trim($_GET['fid']));
+ $fids = array_map('intval', $fids);
+
+ if (!empty($fids))
+ $forum_sql .= ' AND t.forum_id IN('.implode(',', $fids).')';
+
+ if (count($fids) == 1)
+ {
+ // Fetch forum name
+ $result = $db->query('SELECT f.forum_name FROM '.$db->prefix.'forums AS f LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND f.id='.$fids[0]) or error('Unable to fetch forum name', __FILE__, __LINE__, $db->error());
+ if ($db->num_rows($result))
+ $forum_name = $lang_common['Title separator'].$db->result($result);
+ }
+ }
+
+ // Any forum IDs to exclude?
+ if (isset($_GET['nfid']) && is_scalar($_GET['nfid']) && $_GET['nfid'] != '')
+ {
+ $nfids = explode(',', pun_trim($_GET['nfid']));
+ $nfids = array_map('intval', $nfids);
+
+ if (!empty($nfids))
+ $forum_sql .= ' AND t.forum_id NOT IN('.implode(',', $nfids).')';
+ }
+
+ // Only attempt to cache if caching is enabled and we have all or a single forum
+ if ($pun_config['o_feed_ttl'] > 0 && ($forum_sql == '' || ($forum_name != '' && !isset($_GET['nfid']))))
+ $cache_id = 'feed'.sha1($pun_user['g_id'].'|'.$lang_common['lang_identifier'].'|'.($order_posted ? '1' : '0').($forum_name == '' ? '' : '|'.$fids[0]));
+
+ // Load cached feed
+ if (isset($cache_id) && file_exists(FORUM_CACHE_DIR.'cache_'.$cache_id.'.php'))
+ include FORUM_CACHE_DIR.'cache_'.$cache_id.'.php';
+
+ $now = time();
+ if (!isset($feed) || $cache_expire < $now)
+ {
+ // Setup the feed
+ $feed = array(
+ 'title' => $pun_config['o_board_title'].$forum_name,
+ 'link' => '/index.php',
+ 'description' => sprintf($lang_common['RSS description'], $pun_config['o_board_title']),
+ 'items' => array(),
+ 'type' => 'topics'
+ );
+
+ // Fetch $show topics
+ $result = $db->query('SELECT t.id, t.poster, t.subject, t.posted, t.last_post, t.last_poster, p.message, p.hide_smilies, u.email_setting, u.email, p.poster_id, p.poster_email FROM '.$db->prefix.'topics AS t INNER JOIN '.$db->prefix.'posts AS p ON p.id='.($order_posted ? 't.first_post_id' : 't.last_post_id').' INNER JOIN '.$db->prefix.'users AS u ON u.id=p.poster_id LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=t.forum_id AND fp.group_id='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND t.moved_to IS NULL'.$forum_sql.' ORDER BY '.($order_posted ? 't.posted' : 't.last_post').' DESC LIMIT '.(isset($cache_id) ? 50 : $show)) or error('Unable to fetch topic info', __FILE__, __LINE__, $db->error());
+ while ($cur_topic = $db->fetch_assoc($result))
+ {
+ if ($pun_config['o_censoring'] == '1')
+ $cur_topic['subject'] = censor_words($cur_topic['subject']);
+
+ $cur_topic['message'] = parse_message($cur_topic['message'], $cur_topic['hide_smilies']);
+
+ $item = array(
+ 'id' => $cur_topic['id'],
+ 'title' => $cur_topic['subject'],
+ 'link' => '/viewtopic.php?id='.$cur_topic['id'].($order_posted ? '' : '&action=new'),
+ 'description' => $cur_topic['message'],
+ 'author' => array(
+ 'name' => $order_posted ? $cur_topic['poster'] : $cur_topic['last_poster']
+ ),
+ 'pubdate' => $order_posted ? $cur_topic['posted'] : $cur_topic['last_post']
+ );
+
+ if ($cur_topic['poster_id'] > 1)
+ {
+ if ($cur_topic['email_setting'] == '0' && !$pun_user['is_guest'])
+ $item['author']['email'] = $cur_topic['email'];
+
+ $item['author']['uri'] = '/profile.php?id='.$cur_topic['poster_id'];
+ }
+ else if ($cur_topic['poster_email'] != '' && !$pun_user['is_guest'])
+ $item['author']['email'] = $cur_topic['poster_email'];
+
+ $feed['items'][] = $item;
+ }
+
+ // Output feed as PHP code
+ if (isset($cache_id))
+ {
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ $content = '<?php'."\n\n".'$feed = '.var_export($feed, true).';'."\n\n".'$cache_expire = '.($now + ($pun_config['o_feed_ttl'] * 60)).';'."\n\n".'?>';
+ fluxbb_write_cache_file('cache_'.$cache_id.'.php', $content);
+ }
+ }
+
+ // If we only want to show a few items but due to caching we have too many
+ if (count($feed['items']) > $show)
+ $feed['items'] = array_slice($feed['items'], 0, $show);
+
+ // Prepend the current base URL onto some links. Done after caching to handle http/https correctly
+ $feed['link'] = get_base_url(true).$feed['link'];
+
+ foreach ($feed['items'] as $key => $item)
+ {
+ $feed['items'][$key]['link'] = get_base_url(true).$item['link'];
+
+ if (isset($item['author']['uri']))
+ $feed['items'][$key]['author']['uri'] = get_base_url(true).$item['author']['uri'];
+ }
+
+ $output_func = 'output_'.$type;
+ $output_func($feed);
+ }
+
+ exit;
+}
+
+// Show users online
+else if ($action == 'online' || $action == 'online_full')
+{
+ // Load the index.php language file
+ require PUN_ROOT.'lang/'.$pun_config['o_default_lang'].'/index.php';
+
+ // Fetch users online info and generate strings for output
+ $num_guests = $num_users = 0;
+ $users = array();
+
+ $result = $db->query('SELECT user_id, ident FROM '.$db->prefix.'online WHERE idle=0 ORDER BY ident', true) or error('Unable to fetch online list', __FILE__, __LINE__, $db->error());
+
+ while ($pun_user_online = $db->fetch_assoc($result))
+ {
+ if ($pun_user_online['user_id'] > 1)
+ {
+ $users[] = ($pun_user['g_view_users'] == '1') ? '<a href="'.pun_htmlspecialchars(get_base_url(true)).'/profile.php?id='.$pun_user_online['user_id'].'">'.pun_htmlspecialchars($pun_user_online['ident']).'</a>' : pun_htmlspecialchars($pun_user_online['ident']);
+ ++$num_users;
+ }
+ else
+ ++$num_guests;
+ }
+
+ // Send the Content-type header in case the web server is setup to send something else
+ header('Content-type: text/html; charset=utf-8');
+ header('Expires: '.gmdate('D, d M Y H:i:s').' GMT');
+ header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+ header('Pragma: public');
+
+ echo sprintf($lang_index['Guests online'], forum_number_format($num_guests)).'<br />'."\n";
+
+ if ($action == 'online_full' && !empty($users))
+ echo sprintf($lang_index['Users online'], implode(', ', $users)).'<br />'."\n";
+ else
+ echo sprintf($lang_index['Users online'], forum_number_format($num_users)).'<br />'."\n";
+
+ exit;
+}
+
+// Show board statistics
+else if ($action == 'stats')
+{
+ // Load the index.php language file
+ require PUN_ROOT.'lang/'.$pun_config['o_default_lang'].'/index.php';
+
+ // Collect some statistics from the database
+ if (file_exists(FORUM_CACHE_DIR.'cache_users_info.php'))
+ include FORUM_CACHE_DIR.'cache_users_info.php';
+
+ if (!defined('PUN_USERS_INFO_LOADED'))
+ {
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_users_info_cache();
+ require FORUM_CACHE_DIR.'cache_users_info.php';
+ }
+
+ $result = $db->query('SELECT SUM(num_topics), SUM(num_posts) FROM '.$db->prefix.'forums') or error('Unable to fetch topic/post count', __FILE__, __LINE__, $db->error());
+ list($stats['total_topics'], $stats['total_posts']) = $db->fetch_row($result);
+
+ // Send the Content-type header in case the web server is setup to send something else
+ header('Content-type: text/html; charset=utf-8');
+ header('Expires: '.gmdate('D, d M Y H:i:s').' GMT');
+ header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+ header('Pragma: public');
+
+ echo sprintf($lang_index['No of users'], forum_number_format($stats['total_users'])).'<br />'."\n";
+ echo sprintf($lang_index['Newest user'], (($pun_user['g_view_users'] == '1') ? '<a href="'.pun_htmlspecialchars(get_base_url(true)).'/profile.php?id='.$stats['last_user']['id'].'">'.pun_htmlspecialchars($stats['last_user']['username']).'</a>' : pun_htmlspecialchars($stats['last_user']['username']))).'<br />'."\n";
+ echo sprintf($lang_index['No of topics'], forum_number_format($stats['total_topics'])).'<br />'."\n";
+ echo sprintf($lang_index['No of posts'], forum_number_format($stats['total_posts'])).'<br />'."\n";
+
+ exit;
+}
+
+// If we end up here, the script was called with some wacky parameters
+exit($lang_common['Bad request']);
diff --git a/favicon.ico b/favicon.ico
new file mode 120000
index 0000000..179ce47
--- /dev/null
+++ b/favicon.ico
@@ -0,0 +1 @@
+style/ArchLinux/favicon.ico \ No newline at end of file
diff --git a/footer.php b/footer.php
new file mode 100644
index 0000000..ad666cf
--- /dev/null
+++ b/footer.php
@@ -0,0 +1,165 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Make sure no one attempts to run this script "directly"
+if (!defined('PUN'))
+ exit;
+
+$tpl_temp = trim(ob_get_contents());
+$tpl_main = str_replace('<pun_main>', $tpl_temp, $tpl_main);
+ob_end_clean();
+// END SUBST - <pun_main>
+
+
+// START SUBST - <pun_footer>
+ob_start();
+
+?>
+<div id="brdfooter" class="block">
+ <h2><span><?php echo $lang_common['Board footer'] ?></span></h2>
+ <div class="box">
+<?php
+
+if (isset($footer_style) && ($footer_style == 'viewforum' || $footer_style == 'viewtopic') && $is_admmod)
+{
+ echo "\t\t".'<div id="modcontrols" class="inbox">'."\n";
+
+ $token_url = '&amp;csrf_token='.pun_csrf_token();
+
+ if ($footer_style == 'viewforum')
+ {
+ echo "\t\t\t".'<dl>'."\n";
+ echo "\t\t\t\t".'<dt><strong>'.$lang_forum['Mod controls'].'</strong></dt>'."\n";
+ echo "\t\t\t\t".'<dd><span><a href="moderate.php?fid='.$forum_id.'&amp;p='.$p.'">'.$lang_common['Moderate forum'].'</a></span></dd>'."\n";
+ echo "\t\t\t".'</dl>'."\n";
+ }
+ else if ($footer_style == 'viewtopic')
+ {
+ echo "\t\t\t".'<dl>'."\n";
+ echo "\t\t\t\t".'<dt><strong>'.$lang_topic['Mod controls'].'</strong></dt>'."\n";
+ echo "\t\t\t\t".'<dd><span><a href="moderate.php?fid='.$forum_id.'&amp;tid='.$id.'&amp;p='.$p.'">'.$lang_common['Moderate topic'].'</a>'.($num_pages > 1 ? ' (<a href="moderate.php?fid='.$forum_id.'&amp;tid='.$id.'&amp;action=all">'.$lang_common['All'].'</a>)' : '').'</span></dd>'."\n";
+ echo "\t\t\t\t".'<dd><span><a href="moderate.php?fid='.$forum_id.'&amp;move_topics='.$id.'">'.$lang_common['Move topic'].'</a></span></dd>'."\n";
+
+ if ($cur_topic['closed'] == '1')
+ echo "\t\t\t\t".'<dd><span><a href="moderate.php?fid='.$forum_id.'&amp;open='.$id.$token_url.'">'.$lang_common['Open topic'].'</a></span></dd>'."\n";
+ else
+ echo "\t\t\t\t".'<dd><span><a href="moderate.php?fid='.$forum_id.'&amp;close='.$id.$token_url.'">'.$lang_common['Close topic'].'</a></span></dd>'."\n";
+
+ if ($cur_topic['sticky'] == '1')
+ echo "\t\t\t\t".'<dd><span><a href="moderate.php?fid='.$forum_id.'&amp;unstick='.$id.$token_url.'">'.$lang_common['Unstick topic'].'</a></span></dd>'."\n";
+ else
+ echo "\t\t\t\t".'<dd><span><a href="moderate.php?fid='.$forum_id.'&amp;stick='.$id.$token_url.'">'.$lang_common['Stick topic'].'</a></span></dd>'."\n";
+
+ echo "\t\t\t".'</dl>'."\n";
+ }
+
+ echo "\t\t\t".'<div class="clearer"></div>'."\n\t\t".'</div>'."\n";
+}
+
+?>
+ <div id="brdfooternav" class="inbox">
+<?php
+
+echo "\t\t\t".'<div class="conl">'."\n";
+
+// Display the "Jump to" drop list
+if ($pun_config['o_quickjump'] == '1')
+{
+ // Load cached quick jump
+ if (file_exists(FORUM_CACHE_DIR.'cache_quickjump_'.$pun_user['g_id'].'.php'))
+ include FORUM_CACHE_DIR.'cache_quickjump_'.$pun_user['g_id'].'.php';
+
+ if (!defined('PUN_QJ_LOADED'))
+ {
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_quickjump_cache($pun_user['g_id']);
+ require FORUM_CACHE_DIR.'cache_quickjump_'.$pun_user['g_id'].'.php';
+ }
+}
+
+echo "\t\t\t".'</div>'."\n";
+
+?>
+ <div class="conr">
+<?php
+
+// If no footer style has been specified, we use the default (only copyright/debug info)
+$footer_style = isset($footer_style) ? $footer_style : NULL;
+
+if ($footer_style == 'index')
+{
+ if ($pun_config['o_feed_type'] == '1')
+ echo "\t\t\t\t".'<p id="feedlinks"><span class="rss"><a href="extern.php?action=feed&amp;type=rss">'.$lang_common['RSS active topics feed'].'</a></span></p>'."\n";
+ else if ($pun_config['o_feed_type'] == '2')
+ echo "\t\t\t\t".'<p id="feedlinks"><span class="atom"><a href="extern.php?action=feed&amp;type=atom">'.$lang_common['Atom active topics feed'].'</a></span></p>'."\n";
+}
+else if ($footer_style == 'viewforum')
+{
+ if ($pun_config['o_feed_type'] == '1')
+ echo "\t\t\t\t".'<p id="feedlinks"><span class="rss"><a href="extern.php?action=feed&amp;fid='.$forum_id.'&amp;type=rss">'.$lang_common['RSS forum feed'].'</a></span></p>'."\n";
+ else if ($pun_config['o_feed_type'] == '2')
+ echo "\t\t\t\t".'<p id="feedlinks"><span class="atom"><a href="extern.php?action=feed&amp;fid='.$forum_id.'&amp;type=atom">'.$lang_common['Atom forum feed'].'</a></span></p>'."\n";
+}
+else if ($footer_style == 'viewtopic')
+{
+ if ($pun_config['o_feed_type'] == '1')
+ echo "\t\t\t\t".'<p id="feedlinks"><span class="rss"><a href="extern.php?action=feed&amp;tid='.$id.'&amp;type=rss">'.$lang_common['RSS topic feed'].'</a></span></p>'."\n";
+ else if ($pun_config['o_feed_type'] == '2')
+ echo "\t\t\t\t".'<p id="feedlinks"><span class="atom"><a href="extern.php?action=feed&amp;tid='.$id.'&amp;type=atom">'.$lang_common['Atom topic feed'].'</a></span></p>'."\n";
+}
+
+?>
+ <p id="poweredby"><?php printf($lang_common['Powered by'], '<a href="http://fluxbb.org/">FluxBB</a>'.(($pun_config['o_show_version'] == '1') ? ' '.$pun_config['o_cur_version'] : '')) ?></p>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ </div>
+</div>
+<?php
+
+// Display debug info (if enabled/defined)
+if (defined('PUN_DEBUG'))
+{
+ echo '<p id="debugtime">[ ';
+
+ // Calculate script generation time
+ $time_diff = sprintf('%.3f', get_microtime() - $pun_start);
+ echo sprintf($lang_common['Querytime'], $time_diff, $db->get_num_queries());
+
+ if (function_exists('memory_get_usage'))
+ {
+ echo ' - '.sprintf($lang_common['Memory usage'], file_size(memory_get_usage()));
+
+ if (function_exists('memory_get_peak_usage'))
+ echo ' '.sprintf($lang_common['Peak usage'], file_size(memory_get_peak_usage()));
+ }
+
+ echo ' ]</p>'."\n";
+}
+
+
+// End the transaction
+$db->end_transaction();
+
+// Display executed queries (if enabled)
+if (defined('PUN_SHOW_QUERIES'))
+ display_saved_queries();
+
+$tpl_temp = trim(ob_get_contents());
+$tpl_main = str_replace('<pun_footer>', $tpl_temp, $tpl_main);
+ob_end_clean();
+// END SUBST - <pun_footer>
+
+
+// Close the db connection (and free up any result data)
+$db->close();
+
+// Spit out the page
+exit($tpl_main);
diff --git a/header.php b/header.php
new file mode 100644
index 0000000..b579ada
--- /dev/null
+++ b/header.php
@@ -0,0 +1,332 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Make sure no one attempts to run this script "directly"
+if (!defined('PUN'))
+ exit;
+
+// Send no-cache headers
+header('Expires: Thu, 21 Jul 1977 07:30:00 GMT'); // When yours truly first set eyes on this world! :)
+header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
+header('Cache-Control: post-check=0, pre-check=0', false);
+header('Pragma: no-cache'); // For HTTP/1.0 compatibility
+
+// Send the Content-type header in case the web server is setup to send something else
+header('Content-type: text/html; charset=utf-8');
+
+// Prevent site from being embedded in a frame unless FORUM_FRAME_OPTIONS is set
+// to a valid X-Frame-Options header value or false
+if (defined('FORUM_FRAME_OPTIONS'))
+{
+ if (preg_match('/^(?:allow-from|deny|sameorigin)/i', FORUM_FRAME_OPTIONS))
+ header('X-Frame-Options: '.FORUM_FRAME_OPTIONS);
+}
+else
+ header('X-Frame-Options: deny');
+
+// Load the template
+if (defined('PUN_ADMIN_CONSOLE'))
+ $tpl_file = 'admin.tpl';
+else if (defined('PUN_HELP'))
+ $tpl_file = 'help.tpl';
+else
+ $tpl_file = 'main.tpl';
+
+if (file_exists(PUN_ROOT.'style/'.$pun_user['style'].'/'.$tpl_file))
+{
+ $tpl_file = PUN_ROOT.'style/'.$pun_user['style'].'/'.$tpl_file;
+ $tpl_inc_dir = PUN_ROOT.'style/'.$pun_user['style'].'/';
+}
+else
+{
+ $tpl_file = PUN_ROOT.'include/template/'.$tpl_file;
+ $tpl_inc_dir = PUN_ROOT.'include/user/';
+}
+
+$tpl_main = file_get_contents($tpl_file);
+
+// START SUBST - <pun_include "*">
+preg_match_all('%<pun_include "([^"]+)">%i', $tpl_main, $pun_includes, PREG_SET_ORDER);
+
+foreach ($pun_includes as $cur_include)
+{
+ ob_start();
+
+ $file_info = pathinfo($cur_include[1]);
+
+ if (!in_array($file_info['extension'], array('php', 'php4', 'php5', 'inc', 'html', 'txt'))) // Allow some extensions
+ error(sprintf($lang_common['Pun include extension'], pun_htmlspecialchars($cur_include[0]), basename($tpl_file), pun_htmlspecialchars($file_info['extension'])));
+
+ if (strpos($file_info['dirname'], '..') !== false) // Don't allow directory traversal
+ error(sprintf($lang_common['Pun include directory'], pun_htmlspecialchars($cur_include[0]), basename($tpl_file)));
+
+ // Allow for overriding user includes, too.
+ if (file_exists($tpl_inc_dir.$cur_include[1]))
+ require $tpl_inc_dir.$cur_include[1];
+ else if (file_exists(PUN_ROOT.'include/user/'.$cur_include[1]))
+ require PUN_ROOT.'include/user/'.$cur_include[1];
+ else
+ error(sprintf($lang_common['Pun include error'], pun_htmlspecialchars($cur_include[0]), basename($tpl_file)));
+
+ $tpl_temp = ob_get_contents();
+ $tpl_main = str_replace($cur_include[0], $tpl_temp, $tpl_main);
+ ob_end_clean();
+}
+// END SUBST - <pun_include "*">
+
+
+// START SUBST - <pun_language>
+$tpl_main = str_replace('<pun_language>', $lang_common['lang_identifier'], $tpl_main);
+// END SUBST - <pun_language>
+
+
+// START SUBST - <pun_content_direction>
+$tpl_main = str_replace('<pun_content_direction>', $lang_common['lang_direction'], $tpl_main);
+// END SUBST - <pun_content_direction>
+
+
+// START SUBST - <pun_head>
+ob_start();
+
+// Define $p if it's not set to avoid a PHP notice
+$p = isset($p) ? $p : null;
+
+// Is this a page that we want search index spiders to index?
+if (!defined('PUN_ALLOW_INDEX'))
+ echo '<meta name="ROBOTS" content="NOINDEX, FOLLOW" />'."\n";
+
+?>
+<title><?php echo generate_page_title($page_title, $p) ?></title>
+<link rel="stylesheet" type="text/css" href="style/<?php echo $pun_user['style'].'.css' ?>" />
+<?php
+
+if (defined('PUN_ADMIN_CONSOLE'))
+{
+ if (file_exists(PUN_ROOT.'style/'.$pun_user['style'].'/base_admin.css'))
+ echo '<link rel="stylesheet" type="text/css" href="style/'.$pun_user['style'].'/base_admin.css" />'."\n";
+ else
+ echo '<link rel="stylesheet" type="text/css" href="style/imports/base_admin.css" />'."\n";
+}
+
+if (isset($required_fields))
+{
+ // Output JavaScript to validate form (make sure required fields are filled out)
+
+?>
+<script type="text/javascript">
+/* <![CDATA[ */
+function process_form(the_form)
+{
+ var required_fields = {
+<?php
+ // Output a JavaScript object with localised field names
+ $tpl_temp = count($required_fields);
+ foreach ($required_fields as $elem_orig => $elem_trans)
+ {
+ echo "\t\t\"".$elem_orig.'": "'.addslashes(str_replace('&#160;', ' ', $elem_trans));
+ if (--$tpl_temp) echo "\",\n";
+ else echo "\"\n\t};\n";
+ }
+?>
+ if (document.all || document.getElementById)
+ {
+ for (var i = 0; i < the_form.length; ++i)
+ {
+ var elem = the_form.elements[i];
+ if (elem.name && required_fields[elem.name] && !elem.value && elem.type && (/^(?:text(?:area)?|password|file)$/i.test(elem.type)))
+ {
+ alert('"' + required_fields[elem.name] + '" <?php echo $lang_common['required field'] ?>');
+ elem.focus();
+ return false;
+ }
+ }
+ }
+ return true;
+}
+/* ]]> */
+</script>
+<?php
+
+}
+
+if (!empty($page_head))
+ echo implode("\n", $page_head)."\n";
+
+$tpl_temp = trim(ob_get_contents());
+$tpl_main = str_replace('<pun_head>', $tpl_temp, $tpl_main);
+ob_end_clean();
+// END SUBST - <pun_head>
+
+
+// START SUBST - <body>
+if (isset($focus_element))
+{
+ $tpl_main = str_replace('<body onload="', '<body onload="document.getElementById(\''.$focus_element[0].'\').elements[\''.$focus_element[1].'\'].focus();', $tpl_main);
+ $tpl_main = str_replace('<body>', '<body onload="document.getElementById(\''.$focus_element[0].'\').elements[\''.$focus_element[1].'\'].focus()">', $tpl_main);
+}
+// END SUBST - <body>
+
+
+// START SUBST - <pun_page>
+$tpl_main = str_replace('<pun_page>', htmlspecialchars(basename($_SERVER['SCRIPT_NAME'], '.php')), $tpl_main);
+// END SUBST - <pun_page>
+
+
+// START SUBST - <pun_title>
+$tpl_main = str_replace('<pun_title>', '<h1><a href="index.php">'.pun_htmlspecialchars($pun_config['o_board_title']).'</a></h1>', $tpl_main);
+// END SUBST - <pun_title>
+
+
+// START SUBST - <pun_desc>
+$tpl_main = str_replace('<pun_desc>', '<div id="brddesc">'.$pun_config['o_board_desc'].'</div>', $tpl_main);
+// END SUBST - <pun_desc>
+
+
+// START SUBST - <pun_navlinks>
+$links = array();
+
+// Index should always be displayed
+$links[] = '<li id="navindex"'.((PUN_ACTIVE_PAGE == 'index') ? ' class="isactive"' : '').'><a href="index.php">'.$lang_common['Index'].'</a></li>';
+
+if ($pun_user['g_read_board'] == '1' && $pun_user['g_view_users'] == '1')
+ $links[] = '<li id="navuserlist"'.((PUN_ACTIVE_PAGE == 'userlist') ? ' class="isactive"' : '').'><a href="userlist.php">'.$lang_common['User list'].'</a></li>';
+
+if ($pun_config['o_rules'] == '1' && (!$pun_user['is_guest'] || $pun_user['g_read_board'] == '1' || $pun_config['o_regs_allow'] == '1'))
+ $links[] = '<li id="navrules"'.((PUN_ACTIVE_PAGE == 'rules') ? ' class="isactive"' : '').'><a href="misc.php?action=rules">'.$lang_common['Rules'].'</a></li>';
+
+if ($pun_user['g_read_board'] == '1' && $pun_user['g_search'] == '1')
+ $links[] = '<li id="navsearch"'.((PUN_ACTIVE_PAGE == 'search') ? ' class="isactive"' : '').'><a href="search.php">'.$lang_common['Search'].'</a></li>';
+
+if ($pun_user['is_guest'])
+{
+ $links[] = '<li id="navregister"'.((PUN_ACTIVE_PAGE == 'register') ? ' class="isactive"' : '').'><a href="register.php">'.$lang_common['Register'].'</a></li>';
+ $links[] = '<li id="navlogin"'.((PUN_ACTIVE_PAGE == 'login') ? ' class="isactive"' : '').'><a href="login.php">'.$lang_common['Login'].'</a></li>';
+}
+else
+{
+ $links[] = '<li id="navprofile"'.((PUN_ACTIVE_PAGE == 'profile') ? ' class="isactive"' : '').'><a href="profile.php?id='.$pun_user['id'].'">'.$lang_common['Profile'].'</a></li>';
+
+ if ($pun_user['is_admmod'])
+ $links[] = '<li id="navadmin"'.((PUN_ACTIVE_PAGE == 'admin') ? ' class="isactive"' : '').'><a href="admin_index.php">'.$lang_common['Admin'].'</a></li>';
+
+ $links[] = '<li id="navlogout"><a href="login.php?action=out&amp;id='.$pun_user['id'].'&amp;csrf_token='.pun_csrf_token().'">'.$lang_common['Logout'].'</a></li>';
+}
+
+// Are there any additional navlinks we should insert into the array before imploding it?
+if ($pun_user['g_read_board'] == '1' && $pun_config['o_additional_navlinks'] != '')
+{
+ if (preg_match_all('%([0-9]+)\s*=\s*(.*?)\n%s', $pun_config['o_additional_navlinks']."\n", $extra_links))
+ {
+ // Insert any additional links into the $links array (at the correct index)
+ $num_links = count($extra_links[1]);
+ for ($i = 0; $i < $num_links; ++$i)
+ array_splice($links, $extra_links[1][$i], 0, array('<li id="navextra'.($i + 1).'">'.$extra_links[2][$i].'</li>'));
+ }
+}
+
+$tpl_temp = '<div id="brdmenu" class="inbox">'."\n\t\t\t".'<ul>'."\n\t\t\t\t".implode("\n\t\t\t\t", $links)."\n\t\t\t".'</ul>'."\n\t\t".'</div>';
+$tpl_main = str_replace('<pun_navlinks>', $tpl_temp, $tpl_main);
+// END SUBST - <pun_navlinks>
+
+
+// START SUBST - <pun_status>
+$page_statusinfo = $page_topicsearches = array();
+
+if ($pun_user['is_guest'])
+ $page_statusinfo = '<p class="conl">'.$lang_common['Not logged in'].'</p>';
+else
+{
+ $page_statusinfo[] = '<li><span>'.$lang_common['Logged in as'].' <strong>'.pun_htmlspecialchars($pun_user['username']).'</strong></span></li>';
+ $page_statusinfo[] = '<li><span>'.sprintf($lang_common['Last visit'], format_time($pun_user['last_visit'])).'</span></li>';
+
+ if ($pun_user['is_admmod'])
+ {
+ if ($pun_config['o_report_method'] == '0' || $pun_config['o_report_method'] == '2')
+ {
+ $result_header = $db->query('SELECT 1 FROM '.$db->prefix.'reports WHERE zapped IS NULL') or error('Unable to fetch reports info', __FILE__, __LINE__, $db->error());
+
+ if ($db->result($result_header))
+ $page_statusinfo[] = '<li class="reportlink"><span><strong><a href="admin_reports.php">'.$lang_common['New reports'].'</a></strong></span></li>';
+ }
+
+ if ($pun_config['o_maintenance'] == '1')
+ $page_statusinfo[] = '<li class="maintenancelink"><span><strong><a href="admin_options.php#maintenance">'.$lang_common['Maintenance mode enabled'].'</a></strong></span></li>';
+ }
+
+ if ($pun_user['g_read_board'] == '1' && $pun_user['g_search'] == '1')
+ {
+ $page_topicsearches[] = '<a href="search.php?action=show_replies" title="'.$lang_common['Show posted topics'].'">'.$lang_common['Posted topics'].'</a>';
+ $page_topicsearches[] = '<a href="search.php?action=show_new" title="'.$lang_common['Show new posts'].'">'.$lang_common['New posts header'].'</a>';
+ }
+}
+
+// Quick searches
+if ($pun_user['g_read_board'] == '1' && $pun_user['g_search'] == '1')
+{
+ $page_topicsearches[] = '<a href="search.php?action=show_recent" title="'.$lang_common['Show active topics'].'">'.$lang_common['Active topics'].'</a>';
+ $page_topicsearches[] = '<a href="search.php?action=show_unanswered" title="'.$lang_common['Show unanswered topics'].'">'.$lang_common['Unanswered topics'].'</a>';
+}
+
+
+// Generate all that jazz
+$tpl_temp = '<div id="brdwelcome" class="inbox">';
+
+// The status information
+if (is_array($page_statusinfo))
+{
+ $tpl_temp .= "\n\t\t\t".'<ul class="conl">';
+ $tpl_temp .= "\n\t\t\t\t".implode("\n\t\t\t\t", $page_statusinfo);
+ $tpl_temp .= "\n\t\t\t".'</ul>';
+}
+else
+ $tpl_temp .= "\n\t\t\t".$page_statusinfo;
+
+// Generate quicklinks
+if (!empty($page_topicsearches))
+{
+ $tpl_temp .= "\n\t\t\t".'<ul class="conr">';
+ $tpl_temp .= "\n\t\t\t\t".'<li><span>'.$lang_common['Topic searches'].' '.implode(' | ', $page_topicsearches).'</span></li>';
+ $tpl_temp .= "\n\t\t\t".'</ul>';
+}
+
+$tpl_temp .= "\n\t\t\t".'<div class="clearer"></div>'."\n\t\t".'</div>';
+
+$tpl_main = str_replace('<pun_status>', $tpl_temp, $tpl_main);
+// END SUBST - <pun_status>
+
+
+// START SUBST - <pun_announcement>
+if ($pun_user['g_read_board'] == '1' && $pun_config['o_announcement'] == '1')
+{
+ ob_start();
+
+?>
+<div id="announce" class="block">
+ <div class="hd"><h2><span><?php echo $lang_common['Announcement'] ?></span></h2></div>
+ <div class="box">
+ <div id="announce-block" class="inbox">
+ <div class="usercontent"><?php echo $pun_config['o_announcement_message'] ?></div>
+ </div>
+ </div>
+</div>
+<?php
+
+ $tpl_temp = trim(ob_get_contents());
+ $tpl_main = str_replace('<pun_announcement>', $tpl_temp, $tpl_main);
+ ob_end_clean();
+}
+else
+ $tpl_main = str_replace('<pun_announcement>', '', $tpl_main);
+// END SUBST - <pun_announcement>
+
+
+// START SUBST - <pun_main>
+ob_start();
+
+
+define('PUN_HEADER', 1);
diff --git a/help.php b/help.php
new file mode 100644
index 0000000..7ab702c
--- /dev/null
+++ b/help.php
@@ -0,0 +1,154 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Tell header.php to use the help template
+define('PUN_HELP', 1);
+
+define('PUN_ROOT', dirname(__FILE__).'/');
+require PUN_ROOT.'include/common.php';
+
+
+if ($pun_user['g_read_board'] == '0')
+ message($lang_common['No view'], false, '403 Forbidden');
+
+
+// Load the help.php language file
+require PUN_ROOT.'lang/'.$pun_user['language'].'/help.php';
+
+
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_help['Help']);
+define('PUN_ACTIVE_PAGE', 'help');
+require PUN_ROOT.'header.php';
+
+?>
+<h2><span><?php echo $lang_help['BBCode'] ?></span></h2>
+<div class="box">
+ <div class="inbox">
+ <p><a name="bbcode"></a><?php echo $lang_help['BBCode info 1'] ?></p>
+ <p><?php echo $lang_help['BBCode info 2'] ?></p>
+ </div>
+</div>
+<h2><span><?php echo $lang_help['Text style'] ?></span></h2>
+<div class="box">
+ <div class="inbox">
+ <p><?php echo $lang_help['Text style info'] ?></p>
+ <p><code>[b]<?php echo $lang_help['Bold text'] ?>[/b]</code> <?php echo $lang_help['produces'] ?> <samp><strong><?php echo $lang_help['Bold text'] ?></strong></samp></p>
+ <p><code>[u]<?php echo $lang_help['Underlined text'] ?>[/u]</code> <?php echo $lang_help['produces'] ?> <samp><span class="bbu"><?php echo $lang_help['Underlined text'] ?></span></samp></p>
+ <p><code>[i]<?php echo $lang_help['Italic text'] ?>[/i]</code> <?php echo $lang_help['produces'] ?> <samp><em><?php echo $lang_help['Italic text'] ?></em></samp></p>
+ <p><code>[s]<?php echo $lang_help['Strike-through text'] ?>[/s]</code> <?php echo $lang_help['produces'] ?> <samp><span class="bbs"><?php echo $lang_help['Strike-through text'] ?></span></samp></p>
+ <p><code>[del]<?php echo $lang_help['Deleted text'] ?>[/del]</code> <?php echo $lang_help['produces'] ?> <samp><del><?php echo $lang_help['Deleted text'] ?></del></samp></p>
+ <p><code>[ins]<?php echo $lang_help['Inserted text'] ?>[/ins]</code> <?php echo $lang_help['produces'] ?> <samp><ins><?php echo $lang_help['Inserted text'] ?></ins></samp></p>
+ <p><code>[em]<?php echo $lang_help['Emphasised text'] ?>[/em]</code> <?php echo $lang_help['produces'] ?> <samp><em><?php echo $lang_help['Emphasised text'] ?></em></samp></p>
+ <p><code>[color=#FF0000]<?php echo $lang_help['Red text'] ?>[/color]</code> <?php echo $lang_help['produces'] ?> <samp><span style="color: #ff0000"><?php echo $lang_help['Red text'] ?></span></samp></p>
+ <p><code>[color=blue]<?php echo $lang_help['Blue text'] ?>[/color]</code> <?php echo $lang_help['produces'] ?> <samp><span style="color: blue"><?php echo $lang_help['Blue text'] ?></span></samp></p>
+ <p><code>[h]<?php echo $lang_help['Heading text'] ?>[/h]</code> <?php echo $lang_help['produces'] ?></p> <div class="postmsg"><h5><?php echo $lang_help['Heading text'] ?></h5></div>
+ </div>
+</div>
+<h2><span><?php echo $lang_help['Links and images'] ?></span></h2>
+<div class="box">
+ <div class="inbox">
+ <p><?php echo $lang_help['Links info'] ?></p>
+ <p><a name="url"></a><code>[url=<?php echo pun_htmlspecialchars(get_base_url(true).'/') ?>]<?php echo pun_htmlspecialchars($pun_config['o_board_title']) ?>[/url]</code> <?php echo $lang_help['produces'] ?> <samp><a href="<?php echo pun_htmlspecialchars(get_base_url(true).'/') ?>"><?php echo pun_htmlspecialchars($pun_config['o_board_title']) ?></a></samp></p>
+ <p><code>[url]<?php echo pun_htmlspecialchars(get_base_url(true).'/') ?>[/url]</code> <?php echo $lang_help['produces'] ?> <samp><a href="<?php echo pun_htmlspecialchars(get_base_url(true).'/') ?>"><?php echo pun_htmlspecialchars(get_base_url(true).'/') ?></a></samp></p>
+ <p><code>[url=/help.php]<?php echo $lang_help['This help page'] ?>[/url]</code> <?php echo $lang_help['produces'] ?> <samp><a href="<?php echo pun_htmlspecialchars(get_base_url(true).'/help.php') ?>"><?php echo $lang_help['This help page'] ?></a></samp></p>
+ <p><code>[email]myname@example.com[/email]</code> <?php echo $lang_help['produces'] ?> <samp><a href="mailto:myname@example.com">myname@example.com</a></samp></p>
+ <p><code>[email=myname@example.com]<?php echo $lang_help['My email address'] ?>[/email]</code> <?php echo $lang_help['produces'] ?> <samp><a href="mailto:myname@example.com"><?php echo $lang_help['My email address'] ?></a></samp></p>
+ <p><code>[topic=1]<?php echo $lang_help['Test topic'] ?>[/topic]</code> <?php echo $lang_help['produces'] ?> <samp><a href="<?php echo pun_htmlspecialchars(get_base_url(true).'/viewtopic.php?id=1') ?>"><?php echo $lang_help['Test topic'] ?></a></samp></p>
+ <p><code>[topic]1[/topic]</code> <?php echo $lang_help['produces'] ?> <samp><a href="<?php echo pun_htmlspecialchars(get_base_url(true).'/viewtopic.php?id=1') ?>"><?php echo pun_htmlspecialchars(get_base_url(true).'/viewtopic.php?id=1') ?></a></samp></p>
+ <p><code>[post=1]<?php echo $lang_help['Test post'] ?>[/post]</code> <?php echo $lang_help['produces'] ?> <samp><a href="<?php echo pun_htmlspecialchars(get_base_url(true).'/viewtopic.php?pid=1#p1') ?>"><?php echo $lang_help['Test post'] ?></a></samp></p>
+ <p><code>[post]1[/post]</code> <?php echo $lang_help['produces'] ?> <samp><a href="<?php echo pun_htmlspecialchars(get_base_url(true).'/viewtopic.php?pid=1#p1') ?>"><?php echo pun_htmlspecialchars(get_base_url(true).'/viewtopic.php?pid=1#p1') ?></a></samp></p>
+ <p><code>[forum=1]<?php echo $lang_help['Test forum'] ?>[/forum]</code> <?php echo $lang_help['produces'] ?> <samp><a href="<?php echo pun_htmlspecialchars(get_base_url(true).'/viewforum.php?id=1') ?>"><?php echo $lang_help['Test forum'] ?></a></samp></p>
+ <p><code>[forum]1[/forum]</code> <?php echo $lang_help['produces'] ?> <samp><a href="<?php echo pun_htmlspecialchars(get_base_url(true).'/viewforum.php?id=1') ?>"><?php echo pun_htmlspecialchars(get_base_url(true).'/viewforum.php?id=1') ?></a></samp></p>
+ <p><code>[user=2]<?php echo $lang_help['Test user'] ?>[/user]</code> <?php echo $lang_help['produces'] ?> <samp><a href="<?php echo pun_htmlspecialchars(get_base_url(true).'/profile.php?id=2') ?>"><?php echo $lang_help['Test user'] ?></a></samp></p>
+ <p><code>[user]2[/user]</code> <?php echo $lang_help['produces'] ?> <samp><a href="<?php echo pun_htmlspecialchars(get_base_url(true).'/profile.php?id=2') ?>"><?php echo pun_htmlspecialchars(get_base_url(true).'/profile.php?id=2') ?></a></samp></p>
+ </div>
+ <div class="inbox">
+ <p><a name="img"></a><?php echo $lang_help['Images info'] ?></p>
+ <p><code>[img=<?php echo $lang_help['FluxBB bbcode test'] ?>]<?php echo pun_htmlspecialchars(get_base_url(true)) ?>/img/test.png[/img]</code> <?php echo $lang_help['produces'] ?> <samp><img style="height: 21px" src="<?php echo pun_htmlspecialchars(get_base_url(true)) ?>/img/test.png" alt="<?php echo $lang_help['FluxBB bbcode test'] ?>" /></samp></p>
+ </div>
+</div>
+<h2><span><?php echo $lang_help['Quotes'] ?></span></h2>
+<div class="box">
+ <div class="inbox">
+ <p><?php echo $lang_help['Quotes info'] ?></p>
+ <p><code>[quote=James]<?php echo $lang_help['Quote text'] ?>[/quote]</code></p>
+ <p><?php echo $lang_help['produces quote box'] ?></p>
+ <div class="postmsg">
+ <div class="quotebox"><cite>James <?php echo $lang_common['wrote'] ?></cite><blockquote><div><p><?php echo $lang_help['Quote text'] ?></p></div></blockquote></div>
+ </div>
+ <p><?php echo $lang_help['Quotes info 2'] ?></p>
+ <p><code>[quote]<?php echo $lang_help['Quote text'] ?>[/quote]</code></p>
+ <p><?php echo $lang_help['produces quote box'] ?></p>
+ <div class="postmsg">
+ <div class="quotebox"><blockquote><div><p><?php echo $lang_help['Quote text'] ?></p></div></blockquote></div>
+ </div>
+ <p><?php echo $lang_help['quote note'] ?></p>
+ </div>
+</div>
+<h2><span><?php echo $lang_help['Code'] ?></span></h2>
+<div class="box">
+ <div class="inbox">
+ <p><?php echo $lang_help['Code info'] ?></p>
+ <p><code>[code]<?php echo $lang_help['Code text'] ?>[/code]</code></p>
+ <p><?php echo $lang_help['produces code box'] ?></p>
+ <div class="postmsg">
+ <div class="codebox"><pre><code><?php echo $lang_help['Code text'] ?></code></pre></div>
+ </div>
+ </div>
+</div>
+<h2><span><?php echo $lang_help['Lists'] ?></span></h2>
+<div class="box">
+ <div class="inbox">
+ <p><a name="lists"></a><?php echo $lang_help['List info'] ?></p>
+ <p><code>[list][*]<?php echo $lang_help['List text 1'] ?>[/*][*]<?php echo $lang_help['List text 2'] ?>[/*][*]<?php echo $lang_help['List text 3'] ?>[/*][/list]</code>
+ <br /><span><?php echo $lang_help['produces list'] ?></span></p>
+ <div class="postmsg">
+ <ul><li><p><?php echo $lang_help['List text 1'] ?></p></li><li><p><?php echo $lang_help['List text 2'] ?></p></li><li><p><?php echo $lang_help['List text 3'] ?></p></li></ul>
+ </div>
+ <p><code>[list=1][*]<?php echo $lang_help['List text 1'] ?>[/*][*]<?php echo $lang_help['List text 2'] ?>[/*][*]<?php echo $lang_help['List text 3'] ?>[/*][/list]</code>
+ <br /><span><?php echo $lang_help['produces decimal list'] ?></span></p>
+ <div class="postmsg">
+ <ol class="decimal"><li><p><?php echo $lang_help['List text 1'] ?></p></li><li><p><?php echo $lang_help['List text 2'] ?></p></li><li><p><?php echo $lang_help['List text 3'] ?></p></li></ol>
+ </div>
+ <p><code>[list=a][*]<?php echo $lang_help['List text 1'] ?>[/*][*]<?php echo $lang_help['List text 2'] ?>[/*][*]<?php echo $lang_help['List text 3'] ?>[/*][/list]</code>
+ <br /><span><?php echo $lang_help['produces alpha list'] ?></span></p>
+ <div class="postmsg">
+ <ol class="alpha"><li><p><?php echo $lang_help['List text 1'] ?></p></li><li><p><?php echo $lang_help['List text 2'] ?></p></li><li><p><?php echo $lang_help['List text 3'] ?></p></li></ol>
+ </div>
+ </div>
+</div>
+<h2><span><?php echo $lang_help['Nested tags'] ?></span></h2>
+<div class="box">
+ <div class="inbox">
+ <p><?php echo $lang_help['Nested tags info'] ?></p>
+ <p><code>[b][u]<?php echo $lang_help['Bold, underlined text'] ?>[/u][/b]</code> <?php echo $lang_help['produces'] ?> <samp><strong><span class="bbu"><?php echo $lang_help['Bold, underlined text'] ?></span></strong></samp></p>
+ </div>
+</div>
+<h2><span><?php echo $lang_help['Smilies'] ?></span></h2>
+<div class="box">
+ <div class="inbox">
+ <p><a name="smilies"></a><?php echo $lang_help['Smilies info'] ?></p>
+<?php
+
+// Display the smiley set
+require PUN_ROOT.'include/parser.php';
+
+$smiley_groups = array();
+
+foreach ($smilies as $smiley_text => $smiley_img)
+ $smiley_groups[$smiley_img][] = $smiley_text;
+
+foreach ($smiley_groups as $smiley_img => $smiley_texts)
+ echo "\t\t".'<p><code>'.implode('</code> '.$lang_common['and'].' <code>', $smiley_texts).'</code> <span>'.$lang_help['produces'].'</span> <samp><img src="'.pun_htmlspecialchars(get_base_url(true)).'/img/smilies/'.$smiley_img.'" width="15" height="15" alt="'.$smiley_texts[0].'" /></samp></p>'."\n";
+
+?>
+ </div>
+</div>
+<?php
+
+require PUN_ROOT.'footer.php';
diff --git a/img/avatars/index.html b/img/avatars/index.html
new file mode 100644
index 0000000..89337b2
--- /dev/null
+++ b/img/avatars/index.html
@@ -0,0 +1 @@
+<html><head><title>.</title></head><body>.</body></html>
diff --git a/img/index.html b/img/index.html
new file mode 100644
index 0000000..89337b2
--- /dev/null
+++ b/img/index.html
@@ -0,0 +1 @@
+<html><head><title>.</title></head><body>.</body></html>
diff --git a/img/smilies/big_smile.png b/img/smilies/big_smile.png
new file mode 100644
index 0000000..1c4ea81
--- /dev/null
+++ b/img/smilies/big_smile.png
Binary files differ
diff --git a/img/smilies/cool.png b/img/smilies/cool.png
new file mode 100644
index 0000000..54ec46f
--- /dev/null
+++ b/img/smilies/cool.png
Binary files differ
diff --git a/img/smilies/hmm.png b/img/smilies/hmm.png
new file mode 100644
index 0000000..47b87b9
--- /dev/null
+++ b/img/smilies/hmm.png
Binary files differ
diff --git a/img/smilies/index.html b/img/smilies/index.html
new file mode 100644
index 0000000..89337b2
--- /dev/null
+++ b/img/smilies/index.html
@@ -0,0 +1 @@
+<html><head><title>.</title></head><body>.</body></html>
diff --git a/img/smilies/lol.png b/img/smilies/lol.png
new file mode 100644
index 0000000..bad0718
--- /dev/null
+++ b/img/smilies/lol.png
Binary files differ
diff --git a/img/smilies/mad.png b/img/smilies/mad.png
new file mode 100644
index 0000000..d8ffcc6
--- /dev/null
+++ b/img/smilies/mad.png
Binary files differ
diff --git a/img/smilies/neutral.png b/img/smilies/neutral.png
new file mode 100644
index 0000000..a2e4cb8
--- /dev/null
+++ b/img/smilies/neutral.png
Binary files differ
diff --git a/img/smilies/roll.png b/img/smilies/roll.png
new file mode 100644
index 0000000..1c3bc7e
--- /dev/null
+++ b/img/smilies/roll.png
Binary files differ
diff --git a/img/smilies/sad.png b/img/smilies/sad.png
new file mode 100644
index 0000000..b6a0899
--- /dev/null
+++ b/img/smilies/sad.png
Binary files differ
diff --git a/img/smilies/smile.png b/img/smilies/smile.png
new file mode 100644
index 0000000..77099a0
--- /dev/null
+++ b/img/smilies/smile.png
Binary files differ
diff --git a/img/smilies/tongue.png b/img/smilies/tongue.png
new file mode 100644
index 0000000..397b98a
--- /dev/null
+++ b/img/smilies/tongue.png
Binary files differ
diff --git a/img/smilies/wink.png b/img/smilies/wink.png
new file mode 100644
index 0000000..fbc40af
--- /dev/null
+++ b/img/smilies/wink.png
Binary files differ
diff --git a/img/smilies/yikes.png b/img/smilies/yikes.png
new file mode 100644
index 0000000..ddb055f
--- /dev/null
+++ b/img/smilies/yikes.png
Binary files differ
diff --git a/img/test.png b/img/test.png
new file mode 100644
index 0000000..4241f08
--- /dev/null
+++ b/img/test.png
Binary files differ
diff --git a/include/addons.php b/include/addons.php
new file mode 100644
index 0000000..8a0ff48
--- /dev/null
+++ b/include/addons.php
@@ -0,0 +1,84 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Make sure no one attempts to run this script "directly"
+if (!defined('PUN'))
+ exit;
+
+
+/**
+ * Class flux_addon_manager
+ *
+ * This class is responsible for loading the addons and storing their hook listeners.
+ */
+class flux_addon_manager
+{
+ var $hooks = array();
+
+ var $loaded = false;
+
+ function load()
+ {
+ $this->loaded = true;
+
+ $d = dir(PUN_ROOT.'addons');
+ if (!$d) return;
+
+ while (($addon_file = $d->read()) !== false)
+ {
+ if (!is_dir(PUN_ROOT.'addons/'.$addon_file) && preg_match('%(\w+)\.php$%', $addon_file))
+ {
+ $addon_name = 'addon_'.substr($addon_file, 0, -4);
+
+ include PUN_ROOT.'addons/'.$addon_file;
+ $addon = new $addon_name;
+
+ $addon->register($this);
+ }
+ }
+ $d->close();
+ }
+
+ function bind($hook, $callback)
+ {
+ if (!isset($this->hooks[$hook]))
+ $this->hooks[$hook] = array();
+
+ if (is_callable($callback))
+ $this->hooks[$hook][] = $callback;
+ }
+
+ function hook($name)
+ {
+ if (!$this->loaded)
+ $this->load();
+
+ $callbacks = isset($this->hooks[$name]) ? $this->hooks[$name] : array();
+
+ // Execute every registered callback for this hook
+ foreach ($callbacks as $callback)
+ {
+ list($addon, $method) = $callback;
+ $addon->$method();
+ }
+ }
+}
+
+
+/**
+ * Class flux_addon
+ *
+ * This class can be extended to provide addon functionality.
+ * Subclasses should implement the register method which will be called so that they have a chance to register possible
+ * listeners for all hooks.
+ */
+class flux_addon
+{
+ function register($manager)
+ { }
+}
diff --git a/include/cache.php b/include/cache.php
new file mode 100644
index 0000000..c1947ae
--- /dev/null
+++ b/include/cache.php
@@ -0,0 +1,263 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Make sure no one attempts to run this script "directly"
+if (!defined('PUN'))
+ exit;
+
+
+//
+// Generate the config cache PHP script
+//
+function generate_config_cache()
+{
+ global $db;
+
+ // Get the forum config from the DB
+ $result = $db->query('SELECT * FROM '.$db->prefix.'config', true) or error('Unable to fetch forum config', __FILE__, __LINE__, $db->error());
+
+ $output = array();
+ while ($cur_config_item = $db->fetch_row($result))
+ $output[$cur_config_item[0]] = $cur_config_item[1];
+
+ // Output config as PHP code
+ $content = '<?php'."\n\n".'define(\'PUN_CONFIG_LOADED\', 1);'."\n\n".'$pun_config = '.var_export($output, true).';'."\n\n".'?>';
+ fluxbb_write_cache_file('cache_config.php', $content);
+}
+
+
+//
+// Generate the bans cache PHP script
+//
+function generate_bans_cache()
+{
+ global $db;
+
+ // Get the ban list from the DB
+ $result = $db->query('SELECT * FROM '.$db->prefix.'bans', true) or error('Unable to fetch ban list', __FILE__, __LINE__, $db->error());
+
+ $output = array();
+ while ($cur_ban = $db->fetch_assoc($result))
+ $output[] = $cur_ban;
+
+ // Output ban list as PHP code
+ $content = '<?php'."\n\n".'define(\'PUN_BANS_LOADED\', 1);'."\n\n".'$pun_bans = '.var_export($output, true).';'."\n\n".'?>';
+ fluxbb_write_cache_file('cache_bans.php', $content);
+}
+
+
+//
+// Generate quick jump cache PHP scripts
+//
+function generate_quickjump_cache($group_id = false)
+{
+ global $db, $lang_common;
+
+ $groups = array();
+
+ // If a group_id was supplied, we generate the quick jump cache for that group only
+ if ($group_id !== false)
+ {
+ // Is this group even allowed to read forums?
+ $result = $db->query('SELECT g_read_board FROM '.$db->prefix.'groups WHERE g_id='.$group_id) or error('Unable to fetch user group read permission', __FILE__, __LINE__, $db->error());
+ $read_board = $db->result($result);
+
+ $groups[$group_id] = $read_board;
+ }
+ else
+ {
+ // A group_id was not supplied, so we generate the quick jump cache for all groups
+ $result = $db->query('SELECT g_id, g_read_board FROM '.$db->prefix.'groups') or error('Unable to fetch user group list', __FILE__, __LINE__, $db->error());
+
+ while ($row = $db->fetch_row($result))
+ $groups[$row[0]] = $row[1];
+ }
+
+ // Loop through the groups in $groups and output the cache for each of them
+ foreach ($groups as $group_id => $read_board)
+ {
+ // Output quick jump as PHP code
+ $output = '<?php'."\n\n".'if (!defined(\'PUN\')) exit;'."\n".'define(\'PUN_QJ_LOADED\', 1);'."\n".'$forum_id = isset($forum_id) ? $forum_id : 0;'."\n\n".'?>';
+
+ if ($read_board == '1')
+ {
+ $result = $db->query('SELECT c.id AS cid, c.cat_name, f.id AS fid, f.forum_name, f.redirect_url FROM '.$db->prefix.'categories AS c INNER JOIN '.$db->prefix.'forums AS f ON c.id=f.cat_id LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id='.$group_id.') WHERE fp.read_forum IS NULL OR fp.read_forum=1 ORDER BY c.disp_position, c.id, f.disp_position') or error('Unable to fetch category/forum list', __FILE__, __LINE__, $db->error());
+
+ if ($db->num_rows($result))
+ {
+ $output .= "\t\t\t\t".'<form id="qjump" method="get" action="viewforum.php">'."\n\t\t\t\t\t".'<div><label><span><?php echo $lang_common[\'Jump to\'] ?>'.'<br /></span>'."\n\t\t\t\t\t".'<select name="id" onchange="window.location=(\'viewforum.php?id=\'+this.options[this.selectedIndex].value)">'."\n";
+
+ $cur_category = 0;
+ while ($cur_forum = $db->fetch_assoc($result))
+ {
+ if ($cur_forum['cid'] != $cur_category) // A new category since last iteration?
+ {
+ if ($cur_category)
+ $output .= "\t\t\t\t\t\t".'</optgroup>'."\n";
+
+ $output .= "\t\t\t\t\t\t".'<optgroup label="'.pun_htmlspecialchars($cur_forum['cat_name']).'">'."\n";
+ $cur_category = $cur_forum['cid'];
+ }
+
+ $redirect_tag = ($cur_forum['redirect_url'] != '') ? ' &gt;&gt;&gt;' : '';
+ $output .= "\t\t\t\t\t\t\t".'<option value="'.$cur_forum['fid'].'"<?php echo ($forum_id == '.$cur_forum['fid'].') ? \' selected="selected"\' : \'\' ?>>'.pun_htmlspecialchars($cur_forum['forum_name']).$redirect_tag.'</option>'."\n";
+ }
+
+ $output .= "\t\t\t\t\t\t".'</optgroup>'."\n\t\t\t\t\t".'</select></label>'."\n\t\t\t\t\t".'<input type="submit" value="<?php echo $lang_common[\'Go\'] ?>" accesskey="g" />'."\n\t\t\t\t\t".'</div>'."\n\t\t\t\t".'</form>'."\n";
+ }
+ }
+
+ fluxbb_write_cache_file('cache_quickjump_'.$group_id.'.php', $output);
+ }
+}
+
+
+//
+// Generate the censoring cache PHP script
+//
+function generate_censoring_cache()
+{
+ global $db;
+
+ $result = $db->query('SELECT search_for, replace_with FROM '.$db->prefix.'censoring') or error('Unable to fetch censoring list', __FILE__, __LINE__, $db->error());
+ $num_words = $db->num_rows($result);
+
+ $search_for = $replace_with = array();
+ for ($i = 0; $i < $num_words; $i++)
+ {
+ list($search_for[$i], $replace_with[$i]) = $db->fetch_row($result);
+ $search_for[$i] = '%(?<=[^\p{L}\p{N}])('.str_replace('\*', '[\p{L}\p{N}]*?', preg_quote($search_for[$i], '%')).')(?=[^\p{L}\p{N}])%iu';
+ }
+
+ // Output censored words as PHP code
+ $content = '<?php'."\n\n".'define(\'PUN_CENSOR_LOADED\', 1);'."\n\n".'$search_for = '.var_export($search_for, true).';'."\n\n".'$replace_with = '.var_export($replace_with, true).';'."\n\n".'?>';
+ fluxbb_write_cache_file('cache_censoring.php', $content);
+}
+
+
+//
+// Generate the stopwords cache PHP script
+//
+function generate_stopwords_cache()
+{
+ $stopwords = array();
+
+ $d = dir(PUN_ROOT.'lang');
+ while (($entry = $d->read()) !== false)
+ {
+ if ($entry{0} == '.')
+ continue;
+
+ if (is_dir(PUN_ROOT.'lang/'.$entry) && file_exists(PUN_ROOT.'lang/'.$entry.'/stopwords.txt'))
+ $stopwords = array_merge($stopwords, file(PUN_ROOT.'lang/'.$entry.'/stopwords.txt'));
+ }
+ $d->close();
+
+ // Tidy up and filter the stopwords
+ $stopwords = array_map('pun_trim', $stopwords);
+ $stopwords = array_filter($stopwords);
+
+ // Output stopwords as PHP code
+ $content = '<?php'."\n\n".'$cache_id = \''.generate_stopwords_cache_id().'\';'."\n".'if ($cache_id != generate_stopwords_cache_id()) return;'."\n\n".'define(\'PUN_STOPWORDS_LOADED\', 1);'."\n\n".'$stopwords = '.var_export($stopwords, true).';'."\n\n".'?>';
+ fluxbb_write_cache_file('cache_stopwords.php', $content);
+}
+
+
+//
+// Load some information about the latest registered users
+//
+function generate_users_info_cache()
+{
+ global $db;
+
+ $stats = array();
+
+ $result = $db->query('SELECT COUNT(id)-1 FROM '.$db->prefix.'users WHERE group_id!='.PUN_UNVERIFIED) or error('Unable to fetch total user count', __FILE__, __LINE__, $db->error());
+ $stats['total_users'] = $db->result($result);
+
+ $result = $db->query('SELECT id, username FROM '.$db->prefix.'users WHERE group_id!='.PUN_UNVERIFIED.' ORDER BY registered DESC LIMIT 1') or error('Unable to fetch newest registered user', __FILE__, __LINE__, $db->error());
+ $stats['last_user'] = $db->fetch_assoc($result);
+
+ // Output users info as PHP code
+ $content = '<?php'."\n\n".'define(\'PUN_USERS_INFO_LOADED\', 1);'."\n\n".'$stats = '.var_export($stats, true).';'."\n\n".'?>';
+ fluxbb_write_cache_file('cache_users_info.php', $content);
+}
+
+
+//
+// Generate the admins cache PHP script
+//
+function generate_admins_cache()
+{
+ global $db;
+
+ // Get admins from the DB
+ $result = $db->query('SELECT id FROM '.$db->prefix.'users WHERE group_id='.PUN_ADMIN) or error('Unable to fetch users info', __FILE__, __LINE__, $db->error());
+
+ $output = array();
+ while ($row = $db->fetch_row($result))
+ $output[] = $row[0];
+
+ // Output admin list as PHP code
+ $content = '<?php'."\n\n".'define(\'PUN_ADMINS_LOADED\', 1);'."\n\n".'$pun_admins = '.var_export($output, true).';'."\n\n".'?>';
+ fluxbb_write_cache_file('cache_admins.php', $content);
+}
+
+
+//
+// Safely write out a cache file.
+//
+function fluxbb_write_cache_file($file, $content)
+{
+ $fh = @fopen(FORUM_CACHE_DIR.$file, 'wb');
+ if (!$fh)
+ error('Unable to write cache file '.pun_htmlspecialchars($file).' to cache directory. Please make sure PHP has write access to the directory \''.pun_htmlspecialchars(FORUM_CACHE_DIR).'\'', __FILE__, __LINE__);
+
+ flock($fh, LOCK_EX);
+ ftruncate($fh, 0);
+
+ fwrite($fh, $content);
+
+ flock($fh, LOCK_UN);
+ fclose($fh);
+
+ fluxbb_invalidate_cached_file(FORUM_CACHE_DIR.$file);
+}
+
+
+//
+// Delete all feed caches
+//
+function clear_feed_cache()
+{
+ $d = dir(FORUM_CACHE_DIR);
+ while (($entry = $d->read()) !== false)
+ {
+ if (substr($entry, 0, 10) == 'cache_feed' && substr($entry, -4) == '.php')
+ {
+ @unlink(FORUM_CACHE_DIR.$entry);
+ fluxbb_invalidate_cached_file(FORUM_CACHE_DIR.$entry);
+ }
+ }
+ $d->close();
+}
+
+
+//
+// Invalidate updated php files that are cached by an opcache
+//
+function fluxbb_invalidate_cached_file($file)
+{
+ if (function_exists('opcache_invalidate'))
+ opcache_invalidate($file, true);
+ elseif (function_exists('apc_delete_file'))
+ @apc_delete_file($file);
+}
+
+
+define('FORUM_CACHE_FUNCTIONS_LOADED', true);
diff --git a/include/common.php b/include/common.php
new file mode 100644
index 0000000..ad34b5e
--- /dev/null
+++ b/include/common.php
@@ -0,0 +1,209 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+if (!defined('PUN_ROOT'))
+ exit('The constant PUN_ROOT must be defined and point to a valid FluxBB installation root directory.');
+
+// Define the version and database revision that this code was written for
+define('FORUM_VERSION', '1.5.11');
+
+define('FORUM_DB_REVISION', 21);
+define('FORUM_SI_REVISION', 2);
+define('FORUM_PARSER_REVISION', 2);
+
+// Block prefetch requests
+if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch')
+{
+ header('HTTP/1.1 403 Prefetching Forbidden');
+
+ // Send no-cache headers
+ header('Expires: Thu, 21 Jul 1977 07:30:00 GMT'); // When yours truly first set eyes on this world! :)
+ header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
+ header('Cache-Control: post-check=0, pre-check=0', false);
+ header('Pragma: no-cache'); // For HTTP/1.0 compatibility
+
+ exit;
+}
+
+// Attempt to load the configuration file config.php
+if (file_exists(PUN_ROOT.'config.php'))
+ require PUN_ROOT.'config.php';
+
+// If we have the 1.3-legacy constant defined, define the proper 1.4 constant so we don't get an incorrect "need to install" message
+if (defined('FORUM'))
+ define('PUN', FORUM);
+
+// If PUN isn't defined, config.php is missing or corrupt
+if (!defined('PUN'))
+{
+ header('Location: install.php');
+ exit;
+}
+
+// Load the functions script
+require PUN_ROOT.'include/functions.php';
+
+// Load addon functionality
+require PUN_ROOT.'include/addons.php';
+
+// Load UTF-8 functions
+require PUN_ROOT.'include/utf8/utf8.php';
+
+// Strip out "bad" UTF-8 characters
+forum_remove_bad_characters();
+
+// Reverse the effect of register_globals
+forum_unregister_globals();
+
+// The addon manager is responsible for storing the hook listeners and communicating with the addons
+$flux_addons = new flux_addon_manager();
+
+// Record the start time (will be used to calculate the generation time for the page)
+$pun_start = get_microtime();
+
+// Seed the random number generator for systems where this does not happen automatically
+mt_srand();
+
+// Make sure PHP reports all errors except E_NOTICE. FluxBB supports E_ALL, but a lot of scripts it may interact with, do not
+// We set this in php.ini
+//error_reporting(E_ALL ^ E_NOTICE);
+
+// Force POSIX locale (to prevent functions such as strtolower() from messing up UTF-8 strings)
+setlocale(LC_CTYPE, 'C');
+
+// Turn off magic_quotes_runtime
+if (get_magic_quotes_runtime())
+ set_magic_quotes_runtime(0);
+
+// Strip slashes from GET/POST/COOKIE/REQUEST/FILES (if magic_quotes_gpc is enabled)
+if (!defined('FORUM_DISABLE_STRIPSLASHES') && get_magic_quotes_gpc())
+{
+ function stripslashes_array($array)
+ {
+ return is_array($array) ? array_map('stripslashes_array', $array) : stripslashes($array);
+ }
+
+ $_GET = stripslashes_array($_GET);
+ $_POST = stripslashes_array($_POST);
+ $_COOKIE = stripslashes_array($_COOKIE);
+ $_REQUEST = stripslashes_array($_REQUEST);
+ if (is_array($_FILES))
+ {
+ // Don't strip valid slashes from tmp_name path on Windows
+ foreach ($_FILES AS $key => $value)
+ $_FILES[$key]['tmp_name'] = str_replace('\\', '\\\\', $value['tmp_name']);
+ $_FILES = stripslashes_array($_FILES);
+ }
+}
+
+// If a cookie name is not specified in config.php, we use the default (pun_cookie)
+if (empty($cookie_name))
+ $cookie_name = 'pun_cookie';
+
+// If the cache directory is not specified, we use the default setting
+if (!defined('FORUM_CACHE_DIR'))
+ define('FORUM_CACHE_DIR', PUN_ROOT.'cache/');
+
+// Define a few commonly used constants
+define('PUN_UNVERIFIED', 0);
+define('PUN_ADMIN', 1);
+define('PUN_MOD', 2);
+define('PUN_GUEST', 3);
+define('PUN_MEMBER', 4);
+
+// Load DB abstraction layer and connect
+require PUN_ROOT.'include/dblayer/common_db.php';
+
+// Start a transaction
+$db->start_transaction();
+
+// Load cached config
+if (file_exists(FORUM_CACHE_DIR.'cache_config.php'))
+ include FORUM_CACHE_DIR.'cache_config.php';
+
+if (!defined('PUN_CONFIG_LOADED'))
+{
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_config_cache();
+ require FORUM_CACHE_DIR.'cache_config.php';
+}
+
+// Verify that we are running the proper database schema revision
+if (!isset($pun_config['o_database_revision']) || $pun_config['o_database_revision'] < FORUM_DB_REVISION ||
+ !isset($pun_config['o_searchindex_revision']) || $pun_config['o_searchindex_revision'] < FORUM_SI_REVISION ||
+ !isset($pun_config['o_parser_revision']) || $pun_config['o_parser_revision'] < FORUM_PARSER_REVISION ||
+ version_compare($pun_config['o_cur_version'], FORUM_VERSION, '<'))
+{
+ header('Location: db_update.php');
+ exit;
+}
+
+// Enable output buffering
+if (!defined('PUN_DISABLE_BUFFERING'))
+{
+ // Should we use gzip output compression?
+ if ($pun_config['o_gzip'] && extension_loaded('zlib'))
+ ob_start('ob_gzhandler');
+ else
+ ob_start();
+}
+
+// Define standard date/time formats
+$forum_time_formats = array($pun_config['o_time_format'], 'H:i:s', 'H:i', 'g:i:s a', 'g:i a');
+$forum_date_formats = array($pun_config['o_date_format'], 'Y-m-d', 'Y-d-m', 'd-m-Y', 'm-d-Y', 'M j Y', 'jS M Y');
+
+// Check/update/set cookie and fetch user info
+$pun_user = array();
+check_cookie($pun_user);
+
+// Attempt to load the common language file
+if (file_exists(PUN_ROOT.'lang/'.$pun_user['language'].'/common.php'))
+ include PUN_ROOT.'lang/'.$pun_user['language'].'/common.php';
+else
+ error('There is no valid language pack \''.pun_htmlspecialchars($pun_user['language']).'\' installed. Please reinstall a language of that name');
+
+// Check if we are to display a maintenance message
+if ($pun_config['o_maintenance'] && $pun_user['g_id'] > PUN_ADMIN && !defined('PUN_TURN_OFF_MAINT'))
+ maintenance_message();
+
+// Load cached bans
+if (file_exists(FORUM_CACHE_DIR.'cache_bans.php'))
+ include FORUM_CACHE_DIR.'cache_bans.php';
+
+if (!defined('PUN_BANS_LOADED'))
+{
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_bans_cache();
+ require FORUM_CACHE_DIR.'cache_bans.php';
+}
+
+// Check if current user is banned
+check_bans();
+
+// Update online list
+update_users_online();
+
+// Check to see if we logged in without a cookie being set
+if ($pun_user['is_guest'] && isset($_GET['login']))
+ message($lang_common['No cookie']);
+
+// The maximum size of a post, in bytes, since the field is now MEDIUMTEXT this allows ~16MB but lets cap at 1MB...
+if (!defined('PUN_MAX_POSTSIZE'))
+ define('PUN_MAX_POSTSIZE', 1048576);
+
+if (!defined('PUN_SEARCH_MIN_WORD'))
+ define('PUN_SEARCH_MIN_WORD', 3);
+if (!defined('PUN_SEARCH_MAX_WORD'))
+ define('PUN_SEARCH_MAX_WORD', 20);
+
+if (!defined('FORUM_MAX_COOKIE_SIZE'))
+ define('FORUM_MAX_COOKIE_SIZE', 4048);
diff --git a/include/common_admin.php b/include/common_admin.php
new file mode 100644
index 0000000..bb6ce50
--- /dev/null
+++ b/include/common_admin.php
@@ -0,0 +1,174 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Make sure no one attempts to run this script "directly"
+if (!defined('PUN'))
+ exit;
+
+// Make sure we have a usable language pack for admin.
+if (file_exists(PUN_ROOT.'lang/'.$pun_user['language'].'/admin_common.php'))
+ $admin_language = $pun_user['language'];
+else if (file_exists(PUN_ROOT.'lang/'.$pun_config['o_default_lang'].'/admin_common.php'))
+ $admin_language = $pun_config['o_default_lang'];
+else
+ $admin_language = 'English';
+
+// Attempt to load the admin_common language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_common.php';
+
+//
+// Fetch a list of available admin plugins
+//
+function forum_list_plugins($is_admin)
+{
+ $plugins = array();
+
+ $d = dir(PUN_ROOT.'plugins');
+ if (!$d) return $plugins;
+
+ while (($entry = $d->read()) !== false)
+ {
+ if (!is_dir(PUN_ROOT.'plugins/'.$entry) && preg_match('%^AM?P_(\w+)\.php$%i', $entry))
+ {
+ $prefix = substr($entry, 0, strpos($entry, '_'));
+
+ if ($prefix == 'AMP' || ($is_admin && $prefix == 'AP'))
+ $plugins[$entry] = substr($entry, strlen($prefix) + 1, -4);
+ }
+ }
+ $d->close();
+
+ natcasesort($plugins);
+
+ return $plugins;
+}
+
+
+//
+// Display the admin navigation menu
+//
+function generate_admin_menu($page = '')
+{
+ global $pun_config, $pun_user, $lang_admin_common;
+
+ $is_admin = $pun_user['g_id'] == PUN_ADMIN ? true : false;
+
+?>
+<div id="adminconsole" class="block2col">
+ <div id="adminmenu" class="blockmenu">
+ <h2><span><?php echo $lang_admin_common['Moderator menu'] ?></span></h2>
+ <div class="box">
+ <div class="inbox">
+ <ul>
+ <li<?php if ($page == 'index') echo ' class="isactive"'; ?>><a href="admin_index.php"><?php echo $lang_admin_common['Index'] ?></a></li>
+ <li<?php if ($page == 'users') echo ' class="isactive"'; ?>><a href="admin_users.php"><?php echo $lang_admin_common['Users'] ?></a></li>
+<?php if ($is_admin || $pun_user['g_mod_ban_users'] == '1'): ?> <li<?php if ($page == 'bans') echo ' class="isactive"'; ?>><a href="admin_bans.php"><?php echo $lang_admin_common['Bans'] ?></a></li>
+<?php endif; if ($is_admin || $pun_config['o_report_method'] == '0' || $pun_config['o_report_method'] == '2'): ?> <li<?php if ($page == 'reports') echo ' class="isactive"'; ?>><a href="admin_reports.php"><?php echo $lang_admin_common['Reports'] ?></a></li>
+<?php endif; ?> </ul>
+ </div>
+ </div>
+<?php
+
+ if ($is_admin)
+ {
+
+?>
+ <h2 class="block2"><span><?php echo $lang_admin_common['Admin menu'] ?></span></h2>
+ <div class="box">
+ <div class="inbox">
+ <ul>
+ <li<?php if ($page == 'options') echo ' class="isactive"'; ?>><a href="admin_options.php"><?php echo $lang_admin_common['Options'] ?></a></li>
+ <li<?php if ($page == 'permissions') echo ' class="isactive"'; ?>><a href="admin_permissions.php"><?php echo $lang_admin_common['Permissions'] ?></a></li>
+ <li<?php if ($page == 'categories') echo ' class="isactive"'; ?>><a href="admin_categories.php"><?php echo $lang_admin_common['Categories'] ?></a></li>
+ <li<?php if ($page == 'forums') echo ' class="isactive"'; ?>><a href="admin_forums.php"><?php echo $lang_admin_common['Forums'] ?></a></li>
+ <li<?php if ($page == 'groups') echo ' class="isactive"'; ?>><a href="admin_groups.php"><?php echo $lang_admin_common['User groups'] ?></a></li>
+ <li<?php if ($page == 'censoring') echo ' class="isactive"'; ?>><a href="admin_censoring.php"><?php echo $lang_admin_common['Censoring'] ?></a></li>
+ <li<?php if ($page == 'maintenance') echo ' class="isactive"'; ?>><a href="admin_maintenance.php"><?php echo $lang_admin_common['Maintenance'] ?></a></li>
+ </ul>
+ </div>
+ </div>
+<?php
+
+ }
+
+ // See if there are any plugins
+ $plugins = forum_list_plugins($is_admin);
+
+ // Did we find any plugins?
+ if (!empty($plugins))
+ {
+
+?>
+ <h2 class="block2"><span><?php echo $lang_admin_common['Plugins menu'] ?></span></h2>
+ <div class="box">
+ <div class="inbox">
+ <ul>
+<?php
+
+ foreach ($plugins as $plugin_name => $plugin)
+ echo "\t\t\t\t\t".'<li'.(($page == $plugin_name) ? ' class="isactive"' : '').'><a href="admin_loader.php?plugin='.$plugin_name.'">'.str_replace('_', ' ', $plugin).'</a></li>'."\n";
+
+?>
+ </ul>
+ </div>
+ </div>
+<?php
+
+ }
+
+?>
+ </div>
+
+<?php
+
+}
+
+
+//
+// Delete topics from $forum_id that are "older than" $prune_date (if $prune_sticky is 1, sticky topics will also be deleted)
+//
+function prune($forum_id, $prune_sticky, $prune_date)
+{
+ global $db;
+
+ $extra_sql = ($prune_date != -1) ? ' AND last_post<'.$prune_date : '';
+
+ if (!$prune_sticky)
+ $extra_sql .= ' AND sticky=\'0\'';
+
+ // Fetch topics to prune
+ $result = $db->query('SELECT id FROM '.$db->prefix.'topics WHERE forum_id='.$forum_id.$extra_sql, true) or error('Unable to fetch topics', __FILE__, __LINE__, $db->error());
+
+ $topic_ids = '';
+ while ($row = $db->fetch_row($result))
+ $topic_ids .= (($topic_ids != '') ? ',' : '').$row[0];
+
+ if ($topic_ids != '')
+ {
+ // Fetch posts to prune
+ $result = $db->query('SELECT id FROM '.$db->prefix.'posts WHERE topic_id IN('.$topic_ids.')', true) or error('Unable to fetch posts', __FILE__, __LINE__, $db->error());
+
+ $post_ids = '';
+ while ($row = $db->fetch_row($result))
+ $post_ids .= (($post_ids != '') ? ',' : '').$row[0];
+
+ if ($post_ids != '')
+ {
+ // Delete topics
+ $db->query('DELETE FROM '.$db->prefix.'topics WHERE id IN('.$topic_ids.')') or error('Unable to prune topics', __FILE__, __LINE__, $db->error());
+ // Delete subscriptions
+ $db->query('DELETE FROM '.$db->prefix.'topic_subscriptions WHERE topic_id IN('.$topic_ids.')') or error('Unable to prune subscriptions', __FILE__, __LINE__, $db->error());
+ // Delete posts
+ $db->query('DELETE FROM '.$db->prefix.'posts WHERE id IN('.$post_ids.')') or error('Unable to prune posts', __FILE__, __LINE__, $db->error());
+
+ // We removed a bunch of posts, so now we have to update the search index
+ require_once PUN_ROOT.'include/search_idx.php';
+ strip_search_index($post_ids);
+ }
+ }
+}
diff --git a/include/dblayer/common_db.php b/include/dblayer/common_db.php
new file mode 100644
index 0000000..5b9e67e
--- /dev/null
+++ b/include/dblayer/common_db.php
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Make sure no one attempts to run this script "directly"
+if (!defined('PUN'))
+ exit;
+
+
+// Load the appropriate DB layer class
+switch ($db_type)
+{
+ case 'mysql':
+ require_once PUN_ROOT.'include/dblayer/mysql.php';
+ break;
+
+ case 'mysql_innodb':
+ require_once PUN_ROOT.'include/dblayer/mysql_innodb.php';
+ break;
+
+ case 'mysqli':
+ require_once PUN_ROOT.'include/dblayer/mysqli.php';
+ break;
+
+ case 'mysqli_innodb':
+ require_once PUN_ROOT.'include/dblayer/mysqli_innodb.php';
+ break;
+
+ case 'pgsql':
+ require_once PUN_ROOT.'include/dblayer/pgsql.php';
+ break;
+
+ case 'sqlite':
+ require_once PUN_ROOT.'include/dblayer/sqlite.php';
+ break;
+
+ default:
+ error('\''.$db_type.'\' is not a valid database type. Please check settings in config.php.', __FILE__, __LINE__);
+ break;
+}
+
+
+// Create the database adapter object (and open/connect to/select db)
+$db = new DBLayer($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect);
diff --git a/include/dblayer/index.html b/include/dblayer/index.html
new file mode 100644
index 0000000..89337b2
--- /dev/null
+++ b/include/dblayer/index.html
@@ -0,0 +1 @@
+<html><head><title>.</title></head><body>.</body></html>
diff --git a/include/dblayer/mysql.php b/include/dblayer/mysql.php
new file mode 100644
index 0000000..1b36648
--- /dev/null
+++ b/include/dblayer/mysql.php
@@ -0,0 +1,378 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Make sure we have built in support for MySQL
+if (!function_exists('mysql_connect'))
+ exit('This PHP environment doesn\'t have MySQL support built in. MySQL support is required if you want to use a MySQL database to run this forum. Consult the PHP documentation for further assistance.');
+
+
+class DBLayer
+{
+ var $prefix;
+ var $link_id;
+ var $query_result;
+
+ var $saved_queries = array();
+ var $num_queries = 0;
+
+ var $error_no = false;
+ var $error_msg = 'Unknown';
+
+ var $datatype_transformations = array(
+ '%^SERIAL$%' => 'INT(10) UNSIGNED AUTO_INCREMENT'
+ );
+
+
+ function __construct($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect)
+ {
+ $this->prefix = $db_prefix;
+
+ if ($p_connect)
+ $this->link_id = @mysql_pconnect($db_host, $db_username, $db_password);
+ else
+ $this->link_id = @mysql_connect($db_host, $db_username, $db_password);
+
+ if ($this->link_id)
+ {
+ if (!@mysql_select_db($db_name, $this->link_id))
+ error('Unable to select database. MySQL reported: '.mysql_error(), __FILE__, __LINE__);
+ }
+ else
+ error('Unable to connect to MySQL server. MySQL reported: '.mysql_error(), __FILE__, __LINE__);
+
+ // Setup the client-server character set (UTF-8)
+ if (!defined('FORUM_NO_SET_NAMES'))
+ $this->set_names('utf8');
+
+ return $this->link_id;
+ }
+
+
+ function DBLayer($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect)
+ {
+ $this->__construct($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect);
+ }
+
+
+ function start_transaction()
+ {
+ return;
+ }
+
+
+ function end_transaction()
+ {
+ return;
+ }
+
+
+ function query($sql, $unbuffered = false)
+ {
+ if (defined('PUN_SHOW_QUERIES'))
+ $q_start = get_microtime();
+
+ if ($unbuffered)
+ $this->query_result = @mysql_unbuffered_query($sql, $this->link_id);
+ else
+ $this->query_result = @mysql_query($sql, $this->link_id);
+
+ if ($this->query_result)
+ {
+ if (defined('PUN_SHOW_QUERIES'))
+ $this->saved_queries[] = array($sql, sprintf('%.5F', get_microtime() - $q_start));
+
+ ++$this->num_queries;
+
+ return $this->query_result;
+ }
+ else
+ {
+ if (defined('PUN_SHOW_QUERIES'))
+ $this->saved_queries[] = array($sql, 0);
+
+ $this->error_no = @mysql_errno($this->link_id);
+ $this->error_msg = @mysql_error($this->link_id);
+
+ return false;
+ }
+ }
+
+
+ function result($query_id = 0, $row = 0, $col = 0)
+ {
+ return ($query_id) ? @mysql_result($query_id, $row, $col) : false;
+ }
+
+
+ function fetch_assoc($query_id = 0)
+ {
+ return ($query_id) ? @mysql_fetch_assoc($query_id) : false;
+ }
+
+
+ function fetch_row($query_id = 0)
+ {
+ return ($query_id) ? @mysql_fetch_row($query_id) : false;
+ }
+
+
+ function num_rows($query_id = 0)
+ {
+ return ($query_id) ? @mysql_num_rows($query_id) : false;
+ }
+
+
+ function affected_rows()
+ {
+ return ($this->link_id) ? @mysql_affected_rows($this->link_id) : false;
+ }
+
+
+ function insert_id()
+ {
+ return ($this->link_id) ? @mysql_insert_id($this->link_id) : false;
+ }
+
+
+ function get_num_queries()
+ {
+ return $this->num_queries;
+ }
+
+
+ function get_saved_queries()
+ {
+ return $this->saved_queries;
+ }
+
+
+ function free_result($query_id = false)
+ {
+ return ($query_id) ? @mysql_free_result($query_id) : false;
+ }
+
+
+ function escape($str)
+ {
+ if (is_array($str))
+ return '';
+ else if (function_exists('mysql_real_escape_string'))
+ return mysql_real_escape_string($str, $this->link_id);
+ else
+ return mysql_escape_string($str);
+ }
+
+
+ function error()
+ {
+ $result['error_sql'] = @current(@end($this->saved_queries));
+ $result['error_no'] = $this->error_no;
+ $result['error_msg'] = $this->error_msg;
+
+ return $result;
+ }
+
+
+ function close()
+ {
+ if ($this->link_id)
+ {
+ if (is_resource($this->query_result))
+ @mysql_free_result($this->query_result);
+
+ return @mysql_close($this->link_id);
+ }
+ else
+ return false;
+ }
+
+ function get_names()
+ {
+ $result = $this->query('SHOW VARIABLES LIKE \'character_set_connection\'');
+ return $this->result($result, 0, 1);
+ }
+
+
+ function set_names($names)
+ {
+ return $this->query('SET NAMES \''.$this->escape($names).'\'');
+ }
+
+
+ function get_version()
+ {
+ $result = $this->query('SELECT VERSION()');
+
+ return array(
+ 'name' => 'MySQL Standard',
+ 'version' => preg_replace('%^([^-]+).*$%', '\\1', $this->result($result))
+ );
+ }
+
+
+ function table_exists($table_name, $no_prefix = false)
+ {
+ $result = $this->query('SHOW TABLES LIKE \''.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'\'');
+ return $this->num_rows($result) > 0;
+ }
+
+
+ function field_exists($table_name, $field_name, $no_prefix = false)
+ {
+ $result = $this->query('SHOW COLUMNS FROM '.($no_prefix ? '' : $this->prefix).$table_name.' LIKE \''.$this->escape($field_name).'\'');
+ return $this->num_rows($result) > 0;
+ }
+
+
+ function index_exists($table_name, $index_name, $no_prefix = false)
+ {
+ $exists = false;
+
+ $result = $this->query('SHOW INDEX FROM '.($no_prefix ? '' : $this->prefix).$table_name);
+ while ($cur_index = $this->fetch_assoc($result))
+ {
+ if (strtolower($cur_index['Key_name']) == strtolower(($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name))
+ {
+ $exists = true;
+ break;
+ }
+ }
+
+ return $exists;
+ }
+
+
+ function create_table($table_name, $schema, $no_prefix = false)
+ {
+ if ($this->table_exists($table_name, $no_prefix))
+ return true;
+
+ $query = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name." (\n";
+
+ // Go through every schema element and add it to the query
+ foreach ($schema['FIELDS'] as $field_name => $field_data)
+ {
+ $field_data['datatype'] = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_data['datatype']);
+
+ $query .= $field_name.' '.$field_data['datatype'];
+
+ if (isset($field_data['collation']))
+ $query .= 'CHARACTER SET utf8 COLLATE utf8_'.$field_data['collation'];
+
+ if (!$field_data['allow_null'])
+ $query .= ' NOT NULL';
+
+ if (isset($field_data['default']))
+ $query .= ' DEFAULT '.$field_data['default'];
+
+ $query .= ",\n";
+ }
+
+ // If we have a primary key, add it
+ if (isset($schema['PRIMARY KEY']))
+ $query .= 'PRIMARY KEY ('.implode(',', $schema['PRIMARY KEY']).'),'."\n";
+
+ // Add unique keys
+ if (isset($schema['UNIQUE KEYS']))
+ {
+ foreach ($schema['UNIQUE KEYS'] as $key_name => $key_fields)
+ $query .= 'UNIQUE KEY '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$key_name.'('.implode(',', $key_fields).'),'."\n";
+ }
+
+ // Add indexes
+ if (isset($schema['INDEXES']))
+ {
+ foreach ($schema['INDEXES'] as $index_name => $index_fields)
+ $query .= 'KEY '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.'('.implode(',', $index_fields).'),'."\n";
+ }
+
+ // We remove the last two characters (a newline and a comma) and add on the ending
+ $query = substr($query, 0, strlen($query) - 2)."\n".') ENGINE = '.(isset($schema['ENGINE']) ? $schema['ENGINE'] : 'MyISAM').' CHARACTER SET utf8';
+
+ return $this->query($query) ? true : false;
+ }
+
+
+ function drop_table($table_name, $no_prefix = false)
+ {
+ if (!$this->table_exists($table_name, $no_prefix))
+ return true;
+
+ return $this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
+ }
+
+
+ function rename_table($old_table, $new_table, $no_prefix = false)
+ {
+ // If the new table exists and the old one doesn't, then we're happy
+ if ($this->table_exists($new_table, $no_prefix) && !$this->table_exists($old_table, $no_prefix))
+ return true;
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$old_table.' RENAME TO '.($no_prefix ? '' : $this->prefix).$new_table) ? true : false;
+ }
+
+
+ function add_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
+ {
+ if ($this->field_exists($table_name, $field_name, $no_prefix))
+ return true;
+
+ $field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
+
+ if (!is_null($default_value) && !is_int($default_value) && !is_float($default_value))
+ $default_value = '\''.$this->escape($default_value).'\'';
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.$field_name.' '.$field_type.($allow_null ? '' : ' NOT NULL').(!is_null($default_value) ? ' DEFAULT '.$default_value : '').(!is_null($after_field) ? ' AFTER '.$after_field : '')) ? true : false;
+ }
+
+
+ function alter_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
+ {
+ if (!$this->field_exists($table_name, $field_name, $no_prefix))
+ return true;
+
+ $field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
+
+ if (!is_null($default_value) && !is_int($default_value) && !is_float($default_value))
+ $default_value = '\''.$this->escape($default_value).'\'';
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' MODIFY '.$field_name.' '.$field_type.($allow_null ? '' : ' NOT NULL').(!is_null($default_value) ? ' DEFAULT '.$default_value : '').(!is_null($after_field) ? ' AFTER '.$after_field : '')) ? true : false;
+ }
+
+
+ function drop_field($table_name, $field_name, $no_prefix = false)
+ {
+ if (!$this->field_exists($table_name, $field_name, $no_prefix))
+ return true;
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP '.$field_name) ? true : false;
+ }
+
+
+ function add_index($table_name, $index_name, $index_fields, $unique = false, $no_prefix = false)
+ {
+ if ($this->index_exists($table_name, $index_name, $no_prefix))
+ return true;
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ('.implode(',', $index_fields).')') ? true : false;
+ }
+
+
+ function drop_index($table_name, $index_name, $no_prefix = false)
+ {
+ if (!$this->index_exists($table_name, $index_name, $no_prefix))
+ return true;
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) ? true : false;
+ }
+
+ function truncate_table($table_name, $no_prefix = false)
+ {
+ return $this->query('TRUNCATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
+ }
+}
diff --git a/include/dblayer/mysql_innodb.php b/include/dblayer/mysql_innodb.php
new file mode 100644
index 0000000..d284f67
--- /dev/null
+++ b/include/dblayer/mysql_innodb.php
@@ -0,0 +1,392 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Make sure we have built in support for MySQL
+if (!function_exists('mysql_connect'))
+ exit('This PHP environment doesn\'t have MySQL support built in. MySQL support is required if you want to use a MySQL database to run this forum. Consult the PHP documentation for further assistance.');
+
+
+class DBLayer
+{
+ var $prefix;
+ var $link_id;
+ var $query_result;
+ var $in_transaction = 0;
+
+ var $saved_queries = array();
+ var $num_queries = 0;
+
+ var $error_no = false;
+ var $error_msg = 'Unknown';
+
+ var $datatype_transformations = array(
+ '%^SERIAL$%' => 'INT(10) UNSIGNED AUTO_INCREMENT'
+ );
+
+
+ function __construct($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect)
+ {
+ $this->prefix = $db_prefix;
+
+ if ($p_connect)
+ $this->link_id = @mysql_pconnect($db_host, $db_username, $db_password);
+ else
+ $this->link_id = @mysql_connect($db_host, $db_username, $db_password);
+
+ if ($this->link_id)
+ {
+ if (!@mysql_select_db($db_name, $this->link_id))
+ error('Unable to select database. MySQL reported: '.mysql_error(), __FILE__, __LINE__);
+ }
+ else
+ error('Unable to connect to MySQL server. MySQL reported: '.mysql_error(), __FILE__, __LINE__);
+
+ // Setup the client-server character set (UTF-8)
+ if (!defined('FORUM_NO_SET_NAMES'))
+ $this->set_names('utf8');
+
+ return $this->link_id;
+ }
+
+
+ function DBLayer($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect)
+ {
+ $this->__construct($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect);
+ }
+
+
+ function start_transaction()
+ {
+ ++$this->in_transaction;
+
+ mysql_query('START TRANSACTION', $this->link_id);
+ return;
+ }
+
+
+ function end_transaction()
+ {
+ --$this->in_transaction;
+
+ mysql_query('COMMIT', $this->link_id);
+ return;
+ }
+
+
+ function query($sql, $unbuffered = false)
+ {
+ if (defined('PUN_SHOW_QUERIES'))
+ $q_start = get_microtime();
+
+ if ($unbuffered)
+ $this->query_result = @mysql_unbuffered_query($sql, $this->link_id);
+ else
+ $this->query_result = @mysql_query($sql, $this->link_id);
+
+ if ($this->query_result)
+ {
+ if (defined('PUN_SHOW_QUERIES'))
+ $this->saved_queries[] = array($sql, sprintf('%.5F', get_microtime() - $q_start));
+
+ ++$this->num_queries;
+
+ return $this->query_result;
+ }
+ else
+ {
+ if (defined('PUN_SHOW_QUERIES'))
+ $this->saved_queries[] = array($sql, 0);
+
+ $this->error_no = @mysql_errno($this->link_id);
+ $this->error_msg = @mysql_error($this->link_id);
+
+ // Rollback transaction
+ if ($this->in_transaction)
+ mysql_query('ROLLBACK', $this->link_id);
+
+ --$this->in_transaction;
+
+ return false;
+ }
+ }
+
+
+ function result($query_id = 0, $row = 0, $col = 0)
+ {
+ return ($query_id) ? @mysql_result($query_id, $row, $col) : false;
+ }
+
+
+ function fetch_assoc($query_id = 0)
+ {
+ return ($query_id) ? @mysql_fetch_assoc($query_id) : false;
+ }
+
+
+ function fetch_row($query_id = 0)
+ {
+ return ($query_id) ? @mysql_fetch_row($query_id) : false;
+ }
+
+
+ function num_rows($query_id = 0)
+ {
+ return ($query_id) ? @mysql_num_rows($query_id) : false;
+ }
+
+
+ function affected_rows()
+ {
+ return ($this->link_id) ? @mysql_affected_rows($this->link_id) : false;
+ }
+
+
+ function insert_id()
+ {
+ return ($this->link_id) ? @mysql_insert_id($this->link_id) : false;
+ }
+
+
+ function get_num_queries()
+ {
+ return $this->num_queries;
+ }
+
+
+ function get_saved_queries()
+ {
+ return $this->saved_queries;
+ }
+
+
+ function free_result($query_id = false)
+ {
+ return ($query_id) ? @mysql_free_result($query_id) : false;
+ }
+
+
+ function escape($str)
+ {
+ if (is_array($str))
+ return '';
+ else if (function_exists('mysql_real_escape_string'))
+ return mysql_real_escape_string($str, $this->link_id);
+ else
+ return mysql_escape_string($str);
+ }
+
+
+ function error()
+ {
+ $result['error_sql'] = @current(@end($this->saved_queries));
+ $result['error_no'] = $this->error_no;
+ $result['error_msg'] = $this->error_msg;
+
+ return $result;
+ }
+
+
+ function close()
+ {
+ if ($this->link_id)
+ {
+ if (is_resource($this->query_result))
+ @mysql_free_result($this->query_result);
+
+ return @mysql_close($this->link_id);
+ }
+ else
+ return false;
+ }
+
+
+ function get_names()
+ {
+ $result = $this->query('SHOW VARIABLES LIKE \'character_set_connection\'');
+ return $this->result($result, 0, 1);
+ }
+
+
+ function set_names($names)
+ {
+ return $this->query('SET NAMES \''.$this->escape($names).'\'');
+ }
+
+
+ function get_version()
+ {
+ $result = $this->query('SELECT VERSION()');
+
+ return array(
+ 'name' => 'MySQL Standard (InnoDB)',
+ 'version' => preg_replace('%^([^-]+).*$%', '\\1', $this->result($result))
+ );
+ }
+
+
+ function table_exists($table_name, $no_prefix = false)
+ {
+ $result = $this->query('SHOW TABLES LIKE \''.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'\'');
+ return $this->num_rows($result) > 0;
+ }
+
+
+ function field_exists($table_name, $field_name, $no_prefix = false)
+ {
+ $result = $this->query('SHOW COLUMNS FROM '.($no_prefix ? '' : $this->prefix).$table_name.' LIKE \''.$this->escape($field_name).'\'');
+ return $this->num_rows($result) > 0;
+ }
+
+
+ function index_exists($table_name, $index_name, $no_prefix = false)
+ {
+ $exists = false;
+
+ $result = $this->query('SHOW INDEX FROM '.($no_prefix ? '' : $this->prefix).$table_name);
+ while ($cur_index = $this->fetch_assoc($result))
+ {
+ if (strtolower($cur_index['Key_name']) == strtolower(($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name))
+ {
+ $exists = true;
+ break;
+ }
+ }
+
+ return $exists;
+ }
+
+
+ function create_table($table_name, $schema, $no_prefix = false)
+ {
+ if ($this->table_exists($table_name, $no_prefix))
+ return true;
+
+ $query = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name." (\n";
+
+ // Go through every schema element and add it to the query
+ foreach ($schema['FIELDS'] as $field_name => $field_data)
+ {
+ $field_data['datatype'] = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_data['datatype']);
+
+ $query .= $field_name.' '.$field_data['datatype'];
+
+ if (isset($field_data['collation']))
+ $query .= 'CHARACTER SET utf8 COLLATE utf8_'.$field_data['collation'];
+
+ if (!$field_data['allow_null'])
+ $query .= ' NOT NULL';
+
+ if (isset($field_data['default']))
+ $query .= ' DEFAULT '.$field_data['default'];
+
+ $query .= ",\n";
+ }
+
+ // If we have a primary key, add it
+ if (isset($schema['PRIMARY KEY']))
+ $query .= 'PRIMARY KEY ('.implode(',', $schema['PRIMARY KEY']).'),'."\n";
+
+ // Add unique keys
+ if (isset($schema['UNIQUE KEYS']))
+ {
+ foreach ($schema['UNIQUE KEYS'] as $key_name => $key_fields)
+ $query .= 'UNIQUE KEY '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$key_name.'('.implode(',', $key_fields).'),'."\n";
+ }
+
+ // Add indexes
+ if (isset($schema['INDEXES']))
+ {
+ foreach ($schema['INDEXES'] as $index_name => $index_fields)
+ $query .= 'KEY '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.'('.implode(',', $index_fields).'),'."\n";
+ }
+
+ // We remove the last two characters (a newline and a comma) and add on the ending
+ $query = substr($query, 0, strlen($query) - 2)."\n".') ENGINE = '.(isset($schema['ENGINE']) ? $schema['ENGINE'] : 'InnoDB').' CHARACTER SET utf8';
+
+ return $this->query($query) ? true : false;
+ }
+
+
+ function drop_table($table_name, $no_prefix = false)
+ {
+ if (!$this->table_exists($table_name, $no_prefix))
+ return true;
+
+ return $this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
+ }
+
+
+ function rename_table($old_table, $new_table, $no_prefix = false)
+ {
+ // If the new table exists and the old one doesn't, then we're happy
+ if ($this->table_exists($new_table, $no_prefix) && !$this->table_exists($old_table, $no_prefix))
+ return true;
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$old_table.' RENAME TO '.($no_prefix ? '' : $this->prefix).$new_table) ? true : false;
+ }
+
+
+ function add_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
+ {
+ if ($this->field_exists($table_name, $field_name, $no_prefix))
+ return true;
+
+ $field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
+
+ if (!is_null($default_value) && !is_int($default_value) && !is_float($default_value))
+ $default_value = '\''.$this->escape($default_value).'\'';
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.$field_name.' '.$field_type.($allow_null ? '' : ' NOT NULL').(!is_null($default_value) ? ' DEFAULT '.$default_value : '').(!is_null($after_field) ? ' AFTER '.$after_field : '')) ? true : false;
+ }
+
+
+ function alter_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
+ {
+ if (!$this->field_exists($table_name, $field_name, $no_prefix))
+ return true;
+
+ $field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
+
+ if (!is_null($default_value) && !is_int($default_value) && !is_float($default_value))
+ $default_value = '\''.$this->escape($default_value).'\'';
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' MODIFY '.$field_name.' '.$field_type.($allow_null ? '' : ' NOT NULL').(!is_null($default_value) ? ' DEFAULT '.$default_value : '').(!is_null($after_field) ? ' AFTER '.$after_field : '')) ? true : false;
+ }
+
+
+ function drop_field($table_name, $field_name, $no_prefix = false)
+ {
+ if (!$this->field_exists($table_name, $field_name, $no_prefix))
+ return true;
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP '.$field_name) ? true : false;
+ }
+
+
+ function add_index($table_name, $index_name, $index_fields, $unique = false, $no_prefix = false)
+ {
+ if ($this->index_exists($table_name, $index_name, $no_prefix))
+ return true;
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ('.implode(',', $index_fields).')') ? true : false;
+ }
+
+
+ function drop_index($table_name, $index_name, $no_prefix = false)
+ {
+ if (!$this->index_exists($table_name, $index_name, $no_prefix))
+ return true;
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) ? true : false;
+ }
+
+ function truncate_table($table_name, $no_prefix = false)
+ {
+ return $this->query('TRUNCATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
+ }
+}
diff --git a/include/dblayer/mysqli.php b/include/dblayer/mysqli.php
new file mode 100644
index 0000000..05ae599
--- /dev/null
+++ b/include/dblayer/mysqli.php
@@ -0,0 +1,385 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Make sure we have built in support for MySQL
+if (!function_exists('mysqli_connect'))
+ exit('This PHP environment doesn\'t have Improved MySQL (mysqli) support built in. Improved MySQL support is required if you want to use a MySQL 4.1 (or later) database to run this forum. Consult the PHP documentation for further assistance.');
+
+
+class DBLayer
+{
+ var $prefix;
+ var $link_id;
+ var $query_result;
+
+ var $saved_queries = array();
+ var $num_queries = 0;
+
+ var $error_no = false;
+ var $error_msg = 'Unknown';
+
+ var $datatype_transformations = array(
+ '%^SERIAL$%' => 'INT(10) UNSIGNED AUTO_INCREMENT'
+ );
+
+
+ function __construct($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect)
+ {
+ $this->prefix = $db_prefix;
+
+ // Was a custom port supplied with $db_host?
+ if (strpos($db_host, ':') !== false)
+ list($db_host, $db_port) = explode(':', $db_host);
+
+ // Persistent connection in MySQLi are only available in PHP 5.3 and later releases
+ $p_connect = $p_connect && version_compare(PHP_VERSION, '5.3.0', '>=') ? 'p:' : '';
+
+ if (isset($db_port))
+ $this->link_id = @mysqli_connect($p_connect.$db_host, $db_username, $db_password, $db_name, $db_port);
+ else
+ $this->link_id = @mysqli_connect($p_connect.$db_host, $db_username, $db_password, $db_name);
+
+ if (!$this->link_id)
+ error('Unable to connect to MySQL and select database. MySQL reported: '.mysqli_connect_error(), __FILE__, __LINE__);
+
+ // Setup the client-server character set (UTF-8)
+ if (!defined('FORUM_NO_SET_NAMES'))
+ $this->set_names('utf8');
+
+ return $this->link_id;
+ }
+
+
+ function DBLayer($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect)
+ {
+ $this->__construct($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect);
+ }
+
+
+ function start_transaction()
+ {
+ return;
+ }
+
+
+ function end_transaction()
+ {
+ return;
+ }
+
+
+ function query($sql, $unbuffered = false)
+ {
+ if (defined('PUN_SHOW_QUERIES'))
+ $q_start = get_microtime();
+
+ $this->query_result = @mysqli_query($this->link_id, $sql);
+
+ if ($this->query_result)
+ {
+ if (defined('PUN_SHOW_QUERIES'))
+ $this->saved_queries[] = array($sql, sprintf('%.5F', get_microtime() - $q_start));
+
+ ++$this->num_queries;
+
+ return $this->query_result;
+ }
+ else
+ {
+ if (defined('PUN_SHOW_QUERIES'))
+ $this->saved_queries[] = array($sql, 0);
+
+ $this->error_no = @mysqli_errno($this->link_id);
+ $this->error_msg = @mysqli_error($this->link_id);
+
+ return false;
+ }
+ }
+
+
+ function result($query_id = 0, $row = 0, $col = 0)
+ {
+ if ($query_id)
+ {
+ if ($row !== 0 && @mysqli_data_seek($query_id, $row) === false)
+ return false;
+
+ $cur_row = @mysqli_fetch_row($query_id);
+ if ($cur_row === false)
+ return false;
+
+ return $cur_row[$col];
+ }
+ else
+ return false;
+ }
+
+
+ function fetch_assoc($query_id = 0)
+ {
+ return ($query_id) ? @mysqli_fetch_assoc($query_id) : false;
+ }
+
+
+ function fetch_row($query_id = 0)
+ {
+ return ($query_id) ? @mysqli_fetch_row($query_id) : false;
+ }
+
+
+ function num_rows($query_id = 0)
+ {
+ return ($query_id) ? @mysqli_num_rows($query_id) : false;
+ }
+
+
+ function affected_rows()
+ {
+ return ($this->link_id) ? @mysqli_affected_rows($this->link_id) : false;
+ }
+
+
+ function insert_id()
+ {
+ return ($this->link_id) ? @mysqli_insert_id($this->link_id) : false;
+ }
+
+
+ function get_num_queries()
+ {
+ return $this->num_queries;
+ }
+
+
+ function get_saved_queries()
+ {
+ return $this->saved_queries;
+ }
+
+
+ function free_result($query_id = false)
+ {
+ return ($query_id) ? @mysqli_free_result($query_id) : false;
+ }
+
+
+ function escape($str)
+ {
+ return is_array($str) ? '' : mysqli_real_escape_string($this->link_id, $str);
+ }
+
+
+ function error()
+ {
+ $result['error_sql'] = @current(@end($this->saved_queries));
+ $result['error_no'] = $this->error_no;
+ $result['error_msg'] = $this->error_msg;
+
+ return $result;
+ }
+
+
+ function close()
+ {
+ if ($this->link_id)
+ {
+ if ($this->query_result instanceof mysqli_result)
+ @mysqli_free_result($this->query_result);
+
+ return @mysqli_close($this->link_id);
+ }
+ else
+ return false;
+ }
+
+
+ function get_names()
+ {
+ $result = $this->query('SHOW VARIABLES LIKE \'character_set_connection\'');
+ return $this->result($result, 0, 1);
+ }
+
+
+ function set_names($names)
+ {
+ return $this->query('SET NAMES \''.$this->escape($names).'\'');
+ }
+
+
+ function get_version()
+ {
+ $result = $this->query('SELECT VERSION()');
+
+ return array(
+ 'name' => 'MySQL Improved',
+ 'version' => preg_replace('%^([^-]+).*$%', '\\1', $this->result($result))
+ );
+ }
+
+
+ function table_exists($table_name, $no_prefix = false)
+ {
+ $result = $this->query('SHOW TABLES LIKE \''.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'\'');
+ return $this->num_rows($result) > 0;
+ }
+
+
+ function field_exists($table_name, $field_name, $no_prefix = false)
+ {
+ $result = $this->query('SHOW COLUMNS FROM '.($no_prefix ? '' : $this->prefix).$table_name.' LIKE \''.$this->escape($field_name).'\'');
+ return $this->num_rows($result) > 0;
+ }
+
+
+ function index_exists($table_name, $index_name, $no_prefix = false)
+ {
+ $exists = false;
+
+ $result = $this->query('SHOW INDEX FROM '.($no_prefix ? '' : $this->prefix).$table_name);
+ while ($cur_index = $this->fetch_assoc($result))
+ {
+ if (strtolower($cur_index['Key_name']) == strtolower(($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name))
+ {
+ $exists = true;
+ break;
+ }
+ }
+
+ return $exists;
+ }
+
+
+ function create_table($table_name, $schema, $no_prefix = false)
+ {
+ if ($this->table_exists($table_name, $no_prefix))
+ return true;
+
+ $query = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name." (\n";
+
+ // Go through every schema element and add it to the query
+ foreach ($schema['FIELDS'] as $field_name => $field_data)
+ {
+ $field_data['datatype'] = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_data['datatype']);
+
+ $query .= $field_name.' '.$field_data['datatype'];
+
+ if (isset($field_data['collation']))
+ $query .= 'CHARACTER SET utf8 COLLATE utf8_'.$field_data['collation'];
+
+ if (!$field_data['allow_null'])
+ $query .= ' NOT NULL';
+
+ if (isset($field_data['default']))
+ $query .= ' DEFAULT '.$field_data['default'];
+
+ $query .= ",\n";
+ }
+
+ // If we have a primary key, add it
+ if (isset($schema['PRIMARY KEY']))
+ $query .= 'PRIMARY KEY ('.implode(',', $schema['PRIMARY KEY']).'),'."\n";
+
+ // Add unique keys
+ if (isset($schema['UNIQUE KEYS']))
+ {
+ foreach ($schema['UNIQUE KEYS'] as $key_name => $key_fields)
+ $query .= 'UNIQUE KEY '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$key_name.'('.implode(',', $key_fields).'),'."\n";
+ }
+
+ // Add indexes
+ if (isset($schema['INDEXES']))
+ {
+ foreach ($schema['INDEXES'] as $index_name => $index_fields)
+ $query .= 'KEY '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.'('.implode(',', $index_fields).'),'."\n";
+ }
+
+ // We remove the last two characters (a newline and a comma) and add on the ending
+ $query = substr($query, 0, strlen($query) - 2)."\n".') ENGINE = '.(isset($schema['ENGINE']) ? $schema['ENGINE'] : 'MyISAM').' CHARACTER SET utf8';
+
+ return $this->query($query) ? true : false;
+ }
+
+
+ function drop_table($table_name, $no_prefix = false)
+ {
+ if (!$this->table_exists($table_name, $no_prefix))
+ return true;
+
+ return $this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
+ }
+
+
+ function rename_table($old_table, $new_table, $no_prefix = false)
+ {
+ // If the new table exists and the old one doesn't, then we're happy
+ if ($this->table_exists($new_table, $no_prefix) && !$this->table_exists($old_table, $no_prefix))
+ return true;
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$old_table.' RENAME TO '.($no_prefix ? '' : $this->prefix).$new_table) ? true : false;
+ }
+
+
+ function add_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
+ {
+ if ($this->field_exists($table_name, $field_name, $no_prefix))
+ return true;
+
+ $field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
+
+ if (!is_null($default_value) && !is_int($default_value) && !is_float($default_value))
+ $default_value = '\''.$this->escape($default_value).'\'';
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.$field_name.' '.$field_type.($allow_null ? '' : ' NOT NULL').(!is_null($default_value) ? ' DEFAULT '.$default_value : '').(!is_null($after_field) ? ' AFTER '.$after_field : '')) ? true : false;
+ }
+
+
+ function alter_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
+ {
+ if (!$this->field_exists($table_name, $field_name, $no_prefix))
+ return true;
+
+ $field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
+
+ if (!is_null($default_value) && !is_int($default_value) && !is_float($default_value))
+ $default_value = '\''.$this->escape($default_value).'\'';
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' MODIFY '.$field_name.' '.$field_type.($allow_null ? '' : ' NOT NULL').(!is_null($default_value) ? ' DEFAULT '.$default_value : '').(!is_null($after_field) ? ' AFTER '.$after_field : '')) ? true : false;
+ }
+
+
+ function drop_field($table_name, $field_name, $no_prefix = false)
+ {
+ if (!$this->field_exists($table_name, $field_name, $no_prefix))
+ return true;
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP '.$field_name) ? true : false;
+ }
+
+
+ function add_index($table_name, $index_name, $index_fields, $unique = false, $no_prefix = false)
+ {
+ if ($this->index_exists($table_name, $index_name, $no_prefix))
+ return true;
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ('.implode(',', $index_fields).')') ? true : false;
+ }
+
+
+ function drop_index($table_name, $index_name, $no_prefix = false)
+ {
+ if (!$this->index_exists($table_name, $index_name, $no_prefix))
+ return true;
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) ? true : false;
+ }
+
+ function truncate_table($table_name, $no_prefix = false)
+ {
+ return $this->query('TRUNCATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
+ }
+}
diff --git a/include/dblayer/mysqli_innodb.php b/include/dblayer/mysqli_innodb.php
new file mode 100644
index 0000000..f132276
--- /dev/null
+++ b/include/dblayer/mysqli_innodb.php
@@ -0,0 +1,398 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Make sure we have built in support for MySQL
+if (!function_exists('mysqli_connect'))
+ exit('This PHP environment doesn\'t have Improved MySQL (mysqli) support built in. Improved MySQL support is required if you want to use a MySQL 4.1 (or later) database to run this forum. Consult the PHP documentation for further assistance.');
+
+
+class DBLayer
+{
+ var $prefix;
+ var $link_id;
+ var $query_result;
+
+ var $saved_queries = array();
+ var $num_queries = 0;
+ var $in_transaction = 0;
+
+ var $error_no = false;
+ var $error_msg = 'Unknown';
+
+ var $datatype_transformations = array(
+ '%^SERIAL$%' => 'INT(10) UNSIGNED AUTO_INCREMENT'
+ );
+
+
+ function __construct($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect)
+ {
+ $this->prefix = $db_prefix;
+
+ // Was a custom port supplied with $db_host?
+ if (strpos($db_host, ':') !== false)
+ list($db_host, $db_port) = explode(':', $db_host);
+
+ // Persistent connection in MySQLi are only available in PHP 5.3 and later releases
+ $p_connect = $p_connect && version_compare(PHP_VERSION, '5.3.0', '>=') ? 'p:' : '';
+
+ if (isset($db_port))
+ $this->link_id = @mysqli_connect($p_connect.$db_host, $db_username, $db_password, $db_name, $db_port);
+ else
+ $this->link_id = @mysqli_connect($p_connect.$db_host, $db_username, $db_password, $db_name);
+
+ if (!$this->link_id)
+ error('Unable to connect to MySQL and select database. MySQL reported: '.mysqli_connect_error(), __FILE__, __LINE__);
+
+ // Setup the client-server character set (UTF-8)
+ if (!defined('FORUM_NO_SET_NAMES'))
+ $this->set_names('utf8');
+
+ return $this->link_id;
+ }
+
+
+ function DBLayer($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect)
+ {
+ $this->__construct($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect);
+ }
+
+
+ function start_transaction()
+ {
+ ++$this->in_transaction;
+
+ mysqli_query($this->link_id, 'START TRANSACTION');
+ return;
+ }
+
+
+ function end_transaction()
+ {
+ --$this->in_transaction;
+
+ mysqli_query($this->link_id, 'COMMIT');
+ return;
+ }
+
+
+ function query($sql, $unbuffered = false)
+ {
+ if (defined('PUN_SHOW_QUERIES'))
+ $q_start = get_microtime();
+
+ $this->query_result = @mysqli_query($this->link_id, $sql);
+
+ if ($this->query_result)
+ {
+ if (defined('PUN_SHOW_QUERIES'))
+ $this->saved_queries[] = array($sql, sprintf('%.5F', get_microtime() - $q_start));
+
+ ++$this->num_queries;
+
+ return $this->query_result;
+ }
+ else
+ {
+ if (defined('PUN_SHOW_QUERIES'))
+ $this->saved_queries[] = array($sql, 0);
+
+ $this->error_no = @mysqli_errno($this->link_id);
+ $this->error_msg = @mysqli_error($this->link_id);
+
+ // Rollback transaction
+ if ($this->in_transaction)
+ mysqli_query($this->link_id, 'ROLLBACK');
+
+ --$this->in_transaction;
+
+ return false;
+ }
+ }
+
+
+ function result($query_id = 0, $row = 0, $col = 0)
+ {
+ if ($query_id)
+ {
+ if ($row !== 0 && @mysqli_data_seek($query_id, $row) === false)
+ return false;
+
+ $cur_row = @mysqli_fetch_row($query_id);
+ if ($cur_row === false)
+ return false;
+
+ return $cur_row[$col];
+ }
+ else
+ return false;
+ }
+
+
+ function fetch_assoc($query_id = 0)
+ {
+ return ($query_id) ? @mysqli_fetch_assoc($query_id) : false;
+ }
+
+
+ function fetch_row($query_id = 0)
+ {
+ return ($query_id) ? @mysqli_fetch_row($query_id) : false;
+ }
+
+
+ function num_rows($query_id = 0)
+ {
+ return ($query_id) ? @mysqli_num_rows($query_id) : false;
+ }
+
+
+ function affected_rows()
+ {
+ return ($this->link_id) ? @mysqli_affected_rows($this->link_id) : false;
+ }
+
+
+ function insert_id()
+ {
+ return ($this->link_id) ? @mysqli_insert_id($this->link_id) : false;
+ }
+
+
+ function get_num_queries()
+ {
+ return $this->num_queries;
+ }
+
+
+ function get_saved_queries()
+ {
+ return $this->saved_queries;
+ }
+
+
+ function free_result($query_id = false)
+ {
+ return ($query_id) ? @mysqli_free_result($query_id) : false;
+ }
+
+
+ function escape($str)
+ {
+ return is_array($str) ? '' : mysqli_real_escape_string($this->link_id, $str);
+ }
+
+
+ function error()
+ {
+ $result['error_sql'] = @current(@end($this->saved_queries));
+ $result['error_no'] = $this->error_no;
+ $result['error_msg'] = $this->error_msg;
+
+ return $result;
+ }
+
+
+ function close()
+ {
+ if ($this->link_id)
+ {
+ if ($this->query_result instanceof mysqli_result)
+ @mysqli_free_result($this->query_result);
+
+ return @mysqli_close($this->link_id);
+ }
+ else
+ return false;
+ }
+
+
+ function get_names()
+ {
+ $result = $this->query('SHOW VARIABLES LIKE \'character_set_connection\'');
+ return $this->result($result, 0, 1);
+ }
+
+
+ function set_names($names)
+ {
+ return $this->query('SET NAMES \''.$this->escape($names).'\'');
+ }
+
+
+ function get_version()
+ {
+ $result = $this->query('SELECT VERSION()');
+
+ return array(
+ 'name' => 'MySQL Improved (InnoDB)',
+ 'version' => preg_replace('%^([^-]+).*$%', '\\1', $this->result($result))
+ );
+ }
+
+
+ function table_exists($table_name, $no_prefix = false)
+ {
+ $result = $this->query('SHOW TABLES LIKE \''.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'\'');
+ return $this->num_rows($result) > 0;
+ }
+
+
+ function field_exists($table_name, $field_name, $no_prefix = false)
+ {
+ $result = $this->query('SHOW COLUMNS FROM '.($no_prefix ? '' : $this->prefix).$table_name.' LIKE \''.$this->escape($field_name).'\'');
+ return $this->num_rows($result) > 0;
+ }
+
+
+ function index_exists($table_name, $index_name, $no_prefix = false)
+ {
+ $exists = false;
+
+ $result = $this->query('SHOW INDEX FROM '.($no_prefix ? '' : $this->prefix).$table_name);
+ while ($cur_index = $this->fetch_assoc($result))
+ {
+ if (strtolower($cur_index['Key_name']) == strtolower(($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name))
+ {
+ $exists = true;
+ break;
+ }
+ }
+
+ return $exists;
+ }
+
+
+ function create_table($table_name, $schema, $no_prefix = false)
+ {
+ if ($this->table_exists($table_name, $no_prefix))
+ return true;
+
+ $query = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name." (\n";
+
+ // Go through every schema element and add it to the query
+ foreach ($schema['FIELDS'] as $field_name => $field_data)
+ {
+ $field_data['datatype'] = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_data['datatype']);
+
+ $query .= $field_name.' '.$field_data['datatype'];
+
+ if (isset($field_data['collation']))
+ $query .= 'CHARACTER SET utf8 COLLATE utf8_'.$field_data['collation'];
+
+ if (!$field_data['allow_null'])
+ $query .= ' NOT NULL';
+
+ if (isset($field_data['default']))
+ $query .= ' DEFAULT '.$field_data['default'];
+
+ $query .= ",\n";
+ }
+
+ // If we have a primary key, add it
+ if (isset($schema['PRIMARY KEY']))
+ $query .= 'PRIMARY KEY ('.implode(',', $schema['PRIMARY KEY']).'),'."\n";
+
+ // Add unique keys
+ if (isset($schema['UNIQUE KEYS']))
+ {
+ foreach ($schema['UNIQUE KEYS'] as $key_name => $key_fields)
+ $query .= 'UNIQUE KEY '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$key_name.'('.implode(',', $key_fields).'),'."\n";
+ }
+
+ // Add indexes
+ if (isset($schema['INDEXES']))
+ {
+ foreach ($schema['INDEXES'] as $index_name => $index_fields)
+ $query .= 'KEY '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.'('.implode(',', $index_fields).'),'."\n";
+ }
+
+ // We remove the last two characters (a newline and a comma) and add on the ending
+ $query = substr($query, 0, strlen($query) - 2)."\n".') ENGINE = '.(isset($schema['ENGINE']) ? $schema['ENGINE'] : 'InnoDB').' CHARACTER SET utf8';
+
+ return $this->query($query) ? true : false;
+ }
+
+
+ function drop_table($table_name, $no_prefix = false)
+ {
+ if (!$this->table_exists($table_name, $no_prefix))
+ return true;
+
+ return $this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
+ }
+
+
+ function rename_table($old_table, $new_table, $no_prefix = false)
+ {
+ // If the new table exists and the old one doesn't, then we're happy
+ if ($this->table_exists($new_table, $no_prefix) && !$this->table_exists($old_table, $no_prefix))
+ return true;
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$old_table.' RENAME TO '.($no_prefix ? '' : $this->prefix).$new_table) ? true : false;
+ }
+
+
+ function add_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
+ {
+ if ($this->field_exists($table_name, $field_name, $no_prefix))
+ return true;
+
+ $field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
+
+ if (!is_null($default_value) && !is_int($default_value) && !is_float($default_value))
+ $default_value = '\''.$this->escape($default_value).'\'';
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.$field_name.' '.$field_type.($allow_null ? '' : ' NOT NULL').(!is_null($default_value) ? ' DEFAULT '.$default_value : '').(!is_null($after_field) ? ' AFTER '.$after_field : '')) ? true : false;
+ }
+
+
+ function alter_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
+ {
+ if (!$this->field_exists($table_name, $field_name, $no_prefix))
+ return true;
+
+ $field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
+
+ if (!is_null($default_value) && !is_int($default_value) && !is_float($default_value))
+ $default_value = '\''.$this->escape($default_value).'\'';
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' MODIFY '.$field_name.' '.$field_type.($allow_null ? '' : ' NOT NULL').(!is_null($default_value) ? ' DEFAULT '.$default_value : '').(!is_null($after_field) ? ' AFTER '.$after_field : '')) ? true : false;
+ }
+
+
+ function drop_field($table_name, $field_name, $no_prefix = false)
+ {
+ if (!$this->field_exists($table_name, $field_name, $no_prefix))
+ return true;
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP '.$field_name) ? true : false;
+ }
+
+
+ function add_index($table_name, $index_name, $index_fields, $unique = false, $no_prefix = false)
+ {
+ if ($this->index_exists($table_name, $index_name, $no_prefix))
+ return true;
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ('.implode(',', $index_fields).')') ? true : false;
+ }
+
+
+ function drop_index($table_name, $index_name, $no_prefix = false)
+ {
+ if (!$this->index_exists($table_name, $index_name, $no_prefix))
+ return true;
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) ? true : false;
+ }
+
+ function truncate_table($table_name, $no_prefix = false)
+ {
+ return $this->query('TRUNCATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
+ }
+}
diff --git a/include/dblayer/pgsql.php b/include/dblayer/pgsql.php
new file mode 100644
index 0000000..8d13ad9
--- /dev/null
+++ b/include/dblayer/pgsql.php
@@ -0,0 +1,442 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Make sure we have built in support for PostgreSQL
+if (!function_exists('pg_connect'))
+ exit('This PHP environment doesn\'t have PostgreSQL support built in. PostgreSQL support is required if you want to use a PostgreSQL database to run this forum. Consult the PHP documentation for further assistance.');
+
+
+class DBLayer
+{
+ var $prefix;
+ var $link_id;
+ var $query_result;
+ var $last_query_text = array();
+ var $in_transaction = 0;
+
+ var $saved_queries = array();
+ var $num_queries = 0;
+
+ var $error_no = false;
+ var $error_msg = 'Unknown';
+
+ var $datatype_transformations = array(
+ '%^(TINY|SMALL)INT( )?(\\([0-9]+\\))?( )?(UNSIGNED)?$%i' => 'SMALLINT',
+ '%^(MEDIUM)?INT( )?(\\([0-9]+\\))?( )?(UNSIGNED)?$%i' => 'INTEGER',
+ '%^BIGINT( )?(\\([0-9]+\\))?( )?(UNSIGNED)?$%i' => 'BIGINT',
+ '%^(TINY|MEDIUM|LONG)?TEXT$%i' => 'TEXT',
+ '%^DOUBLE( )?(\\([0-9,]+\\))?( )?(UNSIGNED)?$%i' => 'DOUBLE PRECISION',
+ '%^FLOAT( )?(\\([0-9]+\\))?( )?(UNSIGNED)?$%i' => 'REAL'
+ );
+
+
+ function __construct($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect)
+ {
+ $this->prefix = $db_prefix;
+
+ if ($db_host)
+ {
+ if (strpos($db_host, ':') !== false)
+ {
+ list($db_host, $dbport) = explode(':', $db_host);
+ $connect_str[] = 'host='.$db_host.' port='.$dbport;
+ }
+ else
+ $connect_str[] = 'host='.$db_host;
+ }
+
+ if ($db_name)
+ $connect_str[] = 'dbname='.$db_name;
+
+ if ($db_username)
+ $connect_str[] = 'user='.$db_username;
+
+ if ($db_password)
+ $connect_str[] = 'password='.$db_password;
+
+ if ($p_connect)
+ $this->link_id = @pg_pconnect(implode(' ', $connect_str));
+ else
+ $this->link_id = @pg_connect(implode(' ', $connect_str));
+
+ if (!$this->link_id)
+ error('Unable to connect to PostgreSQL server', __FILE__, __LINE__);
+
+ // Setup the client-server character set (UTF-8)
+ if (!defined('FORUM_NO_SET_NAMES'))
+ $this->set_names('utf8');
+
+ return $this->link_id;
+ }
+
+
+ function DBLayer($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect)
+ {
+ $this->__construct($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect);
+ }
+
+
+ function start_transaction()
+ {
+ ++$this->in_transaction;
+
+ return (@pg_query($this->link_id, 'BEGIN')) ? true : false;
+ }
+
+
+ function end_transaction()
+ {
+ --$this->in_transaction;
+
+ if (@pg_query($this->link_id, 'COMMIT'))
+ return true;
+ else
+ {
+ @pg_query($this->link_id, 'ROLLBACK');
+ return false;
+ }
+ }
+
+
+ function query($sql, $unbuffered = false) // $unbuffered is ignored since there is no pgsql_unbuffered_query()
+ {
+ if (strrpos($sql, 'LIMIT') !== false)
+ $sql = preg_replace('%LIMIT ([0-9]+),([ 0-9]+)%', 'LIMIT \\2 OFFSET \\1', $sql);
+
+ if (defined('PUN_SHOW_QUERIES'))
+ $q_start = get_microtime();
+
+ @pg_send_query($this->link_id, $sql);
+ $this->query_result = @pg_get_result($this->link_id);
+
+ if (pg_result_status($this->query_result) != PGSQL_FATAL_ERROR)
+ {
+ if (defined('PUN_SHOW_QUERIES'))
+ $this->saved_queries[] = array($sql, sprintf('%.5F', get_microtime() - $q_start));
+
+ ++$this->num_queries;
+
+ $this->last_query_text[intval($this->query_result)] = $sql;
+
+ return $this->query_result;
+ }
+ else
+ {
+ if (defined('PUN_SHOW_QUERIES'))
+ $this->saved_queries[] = array($sql, 0);
+
+ $this->error_no = false;
+ $this->error_msg = @pg_result_error($this->query_result);
+
+ if ($this->in_transaction)
+ @pg_query($this->link_id, 'ROLLBACK');
+
+ --$this->in_transaction;
+
+ return false;
+ }
+ }
+
+
+ function result($query_id = 0, $row = 0, $col = 0)
+ {
+ return ($query_id) ? @pg_fetch_result($query_id, $row, $col) : false;
+ }
+
+
+ function fetch_assoc($query_id = 0)
+ {
+ return ($query_id) ? @pg_fetch_assoc($query_id) : false;
+ }
+
+
+ function fetch_row($query_id = 0)
+ {
+ return ($query_id) ? @pg_fetch_row($query_id) : false;
+ }
+
+
+ function num_rows($query_id = 0)
+ {
+ return ($query_id) ? @pg_num_rows($query_id) : false;
+ }
+
+
+ function affected_rows()
+ {
+ return ($this->query_result) ? @pg_affected_rows($this->query_result) : false;
+ }
+
+
+ function insert_id()
+ {
+ $query_id = $this->query_result;
+
+ if ($query_id && $this->last_query_text[intval($query_id)] != '')
+ {
+ if (preg_match('%^INSERT INTO ([a-z0-9\_\-]+)%is', $this->last_query_text[intval($query_id)], $table_name))
+ {
+ // Hack (don't ask)
+ if (substr($table_name[1], -6) == 'groups')
+ $table_name[1] .= '_g';
+
+ $temp_q_id = @pg_query($this->link_id, 'SELECT currval(\''.$table_name[1].'_id_seq\')');
+ return ($temp_q_id) ? intval(@pg_fetch_result($temp_q_id, 0)) : false;
+ }
+ }
+
+ return false;
+ }
+
+
+ function get_num_queries()
+ {
+ return $this->num_queries;
+ }
+
+
+ function get_saved_queries()
+ {
+ return $this->saved_queries;
+ }
+
+
+ function free_result($query_id = false)
+ {
+ if (!$query_id)
+ $query_id = $this->query_result;
+
+ return ($query_id) ? @pg_free_result($query_id) : false;
+ }
+
+
+ function escape($str)
+ {
+ return is_array($str) ? '' : pg_escape_string($str);
+ }
+
+
+ function error()
+ {
+ $result['error_sql'] = @current(@end($this->saved_queries));
+ $result['error_no'] = $this->error_no;
+ $result['error_msg'] = $this->error_msg;
+
+ return $result;
+ }
+
+
+ function close()
+ {
+ if ($this->link_id)
+ {
+ if ($this->in_transaction)
+ {
+ if (defined('PUN_SHOW_QUERIES'))
+ $this->saved_queries[] = array('COMMIT', 0);
+
+ @pg_query($this->link_id, 'COMMIT');
+ }
+
+ if ($this->query_result)
+ @pg_free_result($this->query_result);
+
+ return @pg_close($this->link_id);
+ }
+ else
+ return false;
+ }
+
+
+ function get_names()
+ {
+ $result = $this->query('SHOW client_encoding');
+ return strtolower($this->result($result)); // MySQL returns lowercase so lets be consistent
+ }
+
+
+ function set_names($names)
+ {
+ return $this->query('SET NAMES \''.$this->escape($names).'\'');
+ }
+
+
+ function get_version()
+ {
+ $result = $this->query('SELECT VERSION()');
+
+ return array(
+ 'name' => 'PostgreSQL',
+ 'version' => preg_replace('%^[^0-9]+([^\s,-]+).*$%', '\\1', $this->result($result))
+ );
+ }
+
+
+ function table_exists($table_name, $no_prefix = false)
+ {
+ $result = $this->query('SELECT 1 FROM pg_class WHERE relname = \''.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'\'');
+ return $this->num_rows($result) > 0;
+ }
+
+
+ function field_exists($table_name, $field_name, $no_prefix = false)
+ {
+ $result = $this->query('SELECT 1 FROM pg_class c INNER JOIN pg_attribute a ON a.attrelid = c.oid WHERE c.relname = \''.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'\' AND a.attname = \''.$this->escape($field_name).'\'');
+ return $this->num_rows($result) > 0;
+ }
+
+
+ function index_exists($table_name, $index_name, $no_prefix = false)
+ {
+ $result = $this->query('SELECT 1 FROM pg_index i INNER JOIN pg_class c1 ON c1.oid = i.indrelid INNER JOIN pg_class c2 ON c2.oid = i.indexrelid WHERE c1.relname = \''.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'\' AND c2.relname = \''.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_'.$this->escape($index_name).'\'');
+ return $this->num_rows($result) > 0;
+ }
+
+
+ function create_table($table_name, $schema, $no_prefix = false)
+ {
+ if ($this->table_exists($table_name, $no_prefix))
+ return true;
+
+ $query = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name." (\n";
+
+ // Go through every schema element and add it to the query
+ foreach ($schema['FIELDS'] as $field_name => $field_data)
+ {
+ $field_data['datatype'] = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_data['datatype']);
+
+ $query .= $field_name.' '.$field_data['datatype'];
+
+ // The SERIAL datatype is a special case where we don't need to say not null
+ if (!$field_data['allow_null'] && $field_data['datatype'] != 'SERIAL')
+ $query .= ' NOT NULL';
+
+ if (isset($field_data['default']))
+ $query .= ' DEFAULT '.$field_data['default'];
+
+ $query .= ",\n";
+ }
+
+ // If we have a primary key, add it
+ if (isset($schema['PRIMARY KEY']))
+ $query .= 'PRIMARY KEY ('.implode(',', $schema['PRIMARY KEY']).'),'."\n";
+
+ // Add unique keys
+ if (isset($schema['UNIQUE KEYS']))
+ {
+ foreach ($schema['UNIQUE KEYS'] as $key_name => $key_fields)
+ $query .= 'UNIQUE ('.implode(',', $key_fields).'),'."\n";
+ }
+
+ // We remove the last two characters (a newline and a comma) and add on the ending
+ $query = substr($query, 0, strlen($query) - 2)."\n".')';
+
+ $result = $this->query($query) ? true : false;
+
+ // Add indexes
+ if (isset($schema['INDEXES']))
+ {
+ foreach ($schema['INDEXES'] as $index_name => $index_fields)
+ $result &= $this->add_index($table_name, $index_name, $index_fields, false, $no_prefix);
+ }
+
+ return $result;
+ }
+
+
+ function drop_table($table_name, $no_prefix = false)
+ {
+ if (!$this->table_exists($table_name, $no_prefix))
+ return true;
+
+ return $this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
+ }
+
+
+ function rename_table($old_table, $new_table, $no_prefix = false)
+ {
+ // If the new table exists and the old one doesn't, then we're happy
+ if ($this->table_exists($new_table, $no_prefix) && !$this->table_exists($old_table, $no_prefix))
+ return true;
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$old_table.' RENAME TO '.($no_prefix ? '' : $this->prefix).$new_table) ? true : false;
+ }
+
+
+ function add_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
+ {
+ if ($this->field_exists($table_name, $field_name, $no_prefix))
+ return true;
+
+ $field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
+
+ $result = $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.$field_name.' '.$field_type) ? true : false;
+
+ if (!is_null($default_value))
+ {
+ if (!is_int($default_value) && !is_float($default_value))
+ $default_value = '\''.$this->escape($default_value).'\'';
+
+ $result &= $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ALTER '.$field_name.' SET DEFAULT '.$default_value) ? true : false;
+ $result &= $this->query('UPDATE '.($no_prefix ? '' : $this->prefix).$table_name.' SET '.$field_name.'='.$default_value) ? true : false;
+ }
+
+ if (!$allow_null)
+ $result &= $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ALTER '.$field_name.' SET NOT NULL') ? true : false;
+
+ return $result;
+ }
+
+
+ function alter_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
+ {
+ if (!$this->field_exists($table_name, $field_name, $no_prefix))
+ return true;
+
+ $field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
+
+ $result = $this->add_field($table_name, 'tmp_'.$field_name, $field_type, $allow_null, $default_value, $after_field, $no_prefix);
+ $result &= $this->query('UPDATE '.($no_prefix ? '' : $this->prefix).$table_name.' SET tmp_'.$field_name.' = '.$field_name) ? true : false;
+ $result &= $this->drop_field($table_name, $field_name, $no_prefix);
+ $result &= $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' RENAME COLUMN tmp_'.$field_name.' TO '.$field_name) ? true : false;
+
+ return $result;
+ }
+
+
+ function drop_field($table_name, $field_name, $no_prefix = false)
+ {
+ if (!$this->field_exists($table_name, $field_name, $no_prefix))
+ return true;
+
+ return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP '.$field_name) ? true : false;
+ }
+
+
+ function add_index($table_name, $index_name, $index_fields, $unique = false, $no_prefix = false)
+ {
+ if ($this->index_exists($table_name, $index_name, $no_prefix))
+ return true;
+
+ return $this->query('CREATE '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ON '.($no_prefix ? '' : $this->prefix).$table_name.'('.implode(',', $index_fields).')') ? true : false;
+ }
+
+
+ function drop_index($table_name, $index_name, $no_prefix = false)
+ {
+ if (!$this->index_exists($table_name, $index_name, $no_prefix))
+ return true;
+
+ return $this->query('DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) ? true : false;
+ }
+
+ function truncate_table($table_name, $no_prefix = false)
+ {
+ return $this->query('DELETE FROM '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
+ }
+}
diff --git a/include/dblayer/sqlite.php b/include/dblayer/sqlite.php
new file mode 100644
index 0000000..f9164fa
--- /dev/null
+++ b/include/dblayer/sqlite.php
@@ -0,0 +1,601 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Make sure we have built in support for SQLite
+if (!function_exists('sqlite_open'))
+ exit('This PHP environment doesn\'t have SQLite support built in. SQLite support is required if you want to use a SQLite database to run this forum. Consult the PHP documentation for further assistance.');
+
+
+class DBLayer
+{
+ var $prefix;
+ var $link_id;
+ var $query_result;
+ var $in_transaction = 0;
+
+ var $saved_queries = array();
+ var $num_queries = 0;
+
+ var $error_no = false;
+ var $error_msg = 'Unknown';
+
+ var $datatype_transformations = array(
+ '%^SERIAL$%' => 'INTEGER',
+ '%^(TINY|SMALL|MEDIUM|BIG)?INT( )?(\\([0-9]+\\))?( )?(UNSIGNED)?$%i' => 'INTEGER',
+ '%^(TINY|MEDIUM|LONG)?TEXT$%i' => 'TEXT'
+ );
+
+
+ function __construct($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect)
+ {
+ // Prepend $db_name with the path to the forum root directory
+ $db_name = PUN_ROOT.$db_name;
+
+ $this->prefix = $db_prefix;
+
+ if (!file_exists($db_name))
+ {
+ @touch($db_name);
+ @chmod($db_name, 0666);
+ if (!file_exists($db_name))
+ error('Unable to create new database \''.$db_name.'\'. Permission denied', __FILE__, __LINE__);
+ }
+
+ if (!is_readable($db_name))
+ error('Unable to open database \''.$db_name.'\' for reading. Permission denied', __FILE__, __LINE__);
+
+ if (!forum_is_writable($db_name))
+ error('Unable to open database \''.$db_name.'\' for writing. Permission denied', __FILE__, __LINE__);
+
+ if ($p_connect)
+ $this->link_id = @sqlite_popen($db_name, 0666, $sqlite_error);
+ else
+ $this->link_id = @sqlite_open($db_name, 0666, $sqlite_error);
+
+ if (!$this->link_id)
+ error('Unable to open database \''.$db_name.'\'. SQLite reported: '.$sqlite_error, __FILE__, __LINE__);
+ else
+ return $this->link_id;
+ }
+
+
+ function DBLayer($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect)
+ {
+ $this->__construct($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect);
+ }
+
+
+ function start_transaction()
+ {
+ ++$this->in_transaction;
+
+ return (@sqlite_query($this->link_id, 'BEGIN')) ? true : false;
+ }
+
+
+ function end_transaction()
+ {
+ --$this->in_transaction;
+
+ if (@sqlite_query($this->link_id, 'COMMIT'))
+ return true;
+ else
+ {
+ @sqlite_query($this->link_id, 'ROLLBACK');
+ return false;
+ }
+ }
+
+
+ function query($sql, $unbuffered = false)
+ {
+ if (defined('PUN_SHOW_QUERIES'))
+ $q_start = get_microtime();
+
+ if ($unbuffered)
+ $this->query_result = @sqlite_unbuffered_query($this->link_id, $sql);
+ else
+ $this->query_result = @sqlite_query($this->link_id, $sql);
+
+ if ($this->query_result)
+ {
+ if (defined('PUN_SHOW_QUERIES'))
+ $this->saved_queries[] = array($sql, sprintf('%.5F', get_microtime() - $q_start));
+
+ ++$this->num_queries;
+
+ return $this->query_result;
+ }
+ else
+ {
+ if (defined('PUN_SHOW_QUERIES'))
+ $this->saved_queries[] = array($sql, 0);
+
+ $this->error_no = @sqlite_last_error($this->link_id);
+ $this->error_msg = @sqlite_error_string($this->error_no);
+
+ if ($this->in_transaction)
+ @sqlite_query($this->link_id, 'ROLLBACK');
+
+ --$this->in_transaction;
+
+ return false;
+ }
+ }
+
+
+ function result($query_id = 0, $row = 0, $col = 0)
+ {
+ if ($query_id)
+ {
+ if ($row !== 0 && @sqlite_seek($query_id, $row) === false)
+ return false;
+
+ $cur_row = @sqlite_current($query_id);
+ if ($cur_row === false)
+ return false;
+
+ return $cur_row[$col];
+ }
+ else
+ return false;
+ }
+
+
+ function fetch_assoc($query_id = 0)
+ {
+ if ($query_id)
+ {
+ $cur_row = @sqlite_fetch_array($query_id, SQLITE_ASSOC);
+ if ($cur_row)
+ {
+ // Horrible hack to get rid of table names and table aliases from the array keys
+ foreach ($cur_row as $key => $value)
+ {
+ $dot_spot = strpos($key, '.');
+ if ($dot_spot !== false)
+ {
+ unset($cur_row[$key]);
+ $key = substr($key, $dot_spot+1);
+ $cur_row[$key] = $value;
+ }
+ }
+ }
+
+ return $cur_row;
+ }
+ else
+ return false;
+ }
+
+
+ function fetch_row($query_id = 0)
+ {
+ return ($query_id) ? @sqlite_fetch_array($query_id, SQLITE_NUM) : false;
+ }
+
+
+ function num_rows($query_id = 0)
+ {
+ return ($query_id) ? @sqlite_num_rows($query_id) : false;
+ }
+
+
+ function affected_rows()
+ {
+ return ($this->link_id) ? @sqlite_changes($this->link_id) : false;
+ }
+
+
+ function insert_id()
+ {
+ return ($this->link_id) ? @sqlite_last_insert_rowid($this->link_id) : false;
+ }
+
+
+ function get_num_queries()
+ {
+ return $this->num_queries;
+ }
+
+
+ function get_saved_queries()
+ {
+ return $this->saved_queries;
+ }
+
+
+ function free_result($query_id = false)
+ {
+ return true;
+ }
+
+
+ function escape($str)
+ {
+ return is_array($str) ? '' : sqlite_escape_string($str);
+ }
+
+
+ function error()
+ {
+ $result['error_sql'] = @current(@end($this->saved_queries));
+ $result['error_no'] = $this->error_no;
+ $result['error_msg'] = $this->error_msg;
+
+ return $result;
+ }
+
+
+ function close()
+ {
+ if ($this->link_id)
+ {
+ if ($this->in_transaction)
+ {
+ if (defined('PUN_SHOW_QUERIES'))
+ $this->saved_queries[] = array('COMMIT', 0);
+
+ @sqlite_query($this->link_id, 'COMMIT');
+ }
+
+ return @sqlite_close($this->link_id);
+ }
+ else
+ return false;
+ }
+
+
+ function get_names()
+ {
+ return '';
+ }
+
+
+ function set_names($names)
+ {
+ return true;
+ }
+
+
+ function get_version()
+ {
+ return array(
+ 'name' => 'SQLite',
+ 'version' => sqlite_libversion()
+ );
+ }
+
+
+ function table_exists($table_name, $no_prefix = false)
+ {
+ $result = $this->query('SELECT 1 FROM sqlite_master WHERE name = \''.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'\' AND type=\'table\'');
+ return $this->num_rows($result) > 0;
+ }
+
+
+ function field_exists($table_name, $field_name, $no_prefix = false)
+ {
+ $result = $this->query('SELECT sql FROM sqlite_master WHERE name = \''.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'\' AND type=\'table\'');
+ if (!$this->num_rows($result))
+ return false;
+
+ return preg_match('%[\r\n]'.preg_quote($field_name, '%').' %', $this->result($result));
+ }
+
+
+ function index_exists($table_name, $index_name, $no_prefix = false)
+ {
+ $result = $this->query('SELECT 1 FROM sqlite_master WHERE tbl_name = \''.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'\' AND name = \''.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_'.$this->escape($index_name).'\' AND type=\'index\'');
+ return $this->num_rows($result) > 0;
+ }
+
+
+ function create_table($table_name, $schema, $no_prefix = false)
+ {
+ if ($this->table_exists($table_name, $no_prefix))
+ return true;
+
+ $query = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name." (\n";
+
+ // Go through every schema element and add it to the query
+ foreach ($schema['FIELDS'] as $field_name => $field_data)
+ {
+ $field_data['datatype'] = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_data['datatype']);
+
+ $query .= $field_name.' '.$field_data['datatype'];
+
+ if (!$field_data['allow_null'])
+ $query .= ' NOT NULL';
+
+ if (isset($field_data['default']))
+ $query .= ' DEFAULT '.$field_data['default'];
+
+ $query .= ",\n";
+ }
+
+ // If we have a primary key, add it
+ if (isset($schema['PRIMARY KEY']))
+ $query .= 'PRIMARY KEY ('.implode(',', $schema['PRIMARY KEY']).'),'."\n";
+
+ // Add unique keys
+ if (isset($schema['UNIQUE KEYS']))
+ {
+ foreach ($schema['UNIQUE KEYS'] as $key_name => $key_fields)
+ $query .= 'UNIQUE ('.implode(',', $key_fields).'),'."\n";
+ }
+
+ // We remove the last two characters (a newline and a comma) and add on the ending
+ $query = substr($query, 0, strlen($query) - 2)."\n".')';
+
+ $result = $this->query($query) ? true : false;
+
+ // Add indexes
+ if (isset($schema['INDEXES']))
+ {
+ foreach ($schema['INDEXES'] as $index_name => $index_fields)
+ $result &= $this->add_index($table_name, $index_name, $index_fields, false, $no_prefix);
+ }
+
+ return $result;
+ }
+
+
+ function drop_table($table_name, $no_prefix = false)
+ {
+ if (!$this->table_exists($table_name, $no_prefix))
+ return true;
+
+ return $this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($table_name)) ? true : false;
+ }
+
+
+ function rename_table($old_table, $new_table, $no_prefix = false)
+ {
+ // If the old table does not exist
+ if (!$this->table_exists($old_table, $no_prefix))
+ return false;
+ // If the table names are the same
+ else if ($old_table == $new_table)
+ return true;
+ // If the new table already exists
+ else if ($this->table_exists($new_table, $no_prefix))
+ return false;
+
+ $table = $this->get_table_info($old_table, $no_prefix);
+
+ // Create new table
+ $query = str_replace('CREATE TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($old_table).' (', 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($new_table).' (', $table['sql']);
+ $result = $this->query($query) ? true : false;
+
+ // Recreate indexes
+ if (!empty($table['indices']))
+ {
+ foreach ($table['indices'] as $cur_index)
+ {
+ $query = str_replace('CREATE INDEX '.($no_prefix ? '' : $this->prefix).$this->escape($old_table), 'CREATE INDEX '.($no_prefix ? '' : $this->prefix).$this->escape($new_table), $cur_index);
+ $query = str_replace('ON '.($no_prefix ? '' : $this->prefix).$this->escape($old_table), 'ON '.($no_prefix ? '' : $this->prefix).$this->escape($new_table), $query);
+ $result &= $this->query($query) ? true : false;
+ }
+ }
+
+ // Copy content across
+ $result &= $this->query('INSERT INTO '.($no_prefix ? '' : $this->prefix).$this->escape($new_table).' SELECT * FROM '.($no_prefix ? '' : $this->prefix).$this->escape($old_table)) ? true : false;
+
+ // Drop the old table if the new one exists
+ if ($this->table_exists($new_table, $no_prefix))
+ $result &= $this->drop_table($old_table, $no_prefix);
+
+ return $result;
+ }
+
+
+ function get_table_info($table_name, $no_prefix = false)
+ {
+ // Grab table info
+ $result = $this->query('SELECT sql FROM sqlite_master WHERE tbl_name = \''.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'\' ORDER BY type DESC') or error('Unable to fetch table information', __FILE__, __LINE__, $this->error());
+ $num_rows = $this->num_rows($result);
+
+ if ($num_rows == 0)
+ return;
+
+ $table = array();
+ $table['indices'] = array();
+ while ($cur_index = $this->fetch_assoc($result))
+ {
+ if (empty($cur_index['sql']))
+ continue;
+
+ if (!isset($table['sql']))
+ $table['sql'] = $cur_index['sql'];
+ else
+ $table['indices'][] = $cur_index['sql'];
+ }
+
+ // Work out the columns in the table currently
+ $table_lines = explode("\n", $table['sql']);
+ $table['columns'] = array();
+ foreach ($table_lines as $table_line)
+ {
+ $table_line = trim($table_line, " \t\n\r,"); // trim spaces, tabs, newlines, and commas
+ if (substr($table_line, 0, 12) == 'CREATE TABLE')
+ continue;
+ else if (substr($table_line, 0, 11) == 'PRIMARY KEY')
+ $table['primary_key'] = $table_line;
+ else if (substr($table_line, 0, 6) == 'UNIQUE')
+ $table['unique'] = $table_line;
+ else if (substr($table_line, 0, strpos($table_line, ' ')) != '')
+ $table['columns'][substr($table_line, 0, strpos($table_line, ' '))] = trim(substr($table_line, strpos($table_line, ' ')));
+ }
+
+ return $table;
+ }
+
+
+ function add_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
+ {
+ if ($this->field_exists($table_name, $field_name, $no_prefix))
+ return true;
+
+ $table = $this->get_table_info($table_name, $no_prefix);
+
+ // Create temp table
+ $now = time();
+ $tmptable = str_replace('CREATE TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).' (', 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now.' (', $table['sql']);
+ $result = $this->query($tmptable) ? true : false;
+ $result &= $this->query('INSERT INTO '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now.' SELECT * FROM '.($no_prefix ? '' : $this->prefix).$this->escape($table_name)) ? true : false;
+
+ // Create new table sql
+ $field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
+ $query = $field_type;
+
+ if (!$allow_null)
+ $query .= ' NOT NULL';
+
+ if (is_string($default_value))
+ $default_value = '\''.$this->escape($default_value).'\'';
+
+ if (!is_null($default_value))
+ $query .= ' DEFAULT '.$default_value;
+
+ $old_columns = array_keys($table['columns']);
+
+ // Determine the proper offset
+ if (!is_null($after_field))
+ $offset = array_search($after_field, array_keys($table['columns']), true) + 1;
+ else
+ $offset = count($table['columns']);
+
+ // Out of bounds checks
+ if ($offset > count($table['columns']))
+ $offset = count($table['columns']);
+ else if ($offset < 0)
+ $offset = 0;
+
+ if (!is_null($field_name) && $field_name !== '')
+ $table['columns'] = array_merge(array_slice($table['columns'], 0, $offset), array($field_name => $query), array_slice($table['columns'], $offset));
+
+ $new_table = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).' (';
+
+ foreach ($table['columns'] as $cur_column => $column_details)
+ $new_table .= "\n".$cur_column.' '.$column_details.',';
+
+ if (isset($table['unique']))
+ $new_table .= "\n".$table['unique'].',';
+
+ if (isset($table['primary_key']))
+ $new_table .= "\n".$table['primary_key'].',';
+
+ $new_table = trim($new_table, ',')."\n".');';
+
+ // Drop old table
+ $result &= $this->drop_table($table_name, $no_prefix);
+
+ // Create new table
+ $result &= $this->query($new_table) ? true : false;
+
+ // Recreate indexes
+ if (!empty($table['indices']))
+ {
+ foreach ($table['indices'] as $cur_index)
+ $result &= $this->query($cur_index) ? true : false;
+ }
+
+ // Copy content back
+ $result &= $this->query('INSERT INTO '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).' ('.implode(', ', $old_columns).') SELECT * FROM '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now) ? true : false;
+
+ // Drop temp table
+ $result &= $this->drop_table($table_name.'_t'.$now, $no_prefix);
+
+ return $result;
+ }
+
+
+ function alter_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
+ {
+ // Unneeded for SQLite
+ return true;
+ }
+
+
+ function drop_field($table_name, $field_name, $no_prefix = false)
+ {
+ if (!$this->field_exists($table_name, $field_name, $no_prefix))
+ return true;
+
+ $table = $this->get_table_info($table_name, $no_prefix);
+
+ // Create temp table
+ $now = time();
+ $tmptable = str_replace('CREATE TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).' (', 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now.' (', $table['sql']);
+ $result = $this->query($tmptable) ? true : false;
+ $result &= $this->query('INSERT INTO '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now.' SELECT * FROM '.($no_prefix ? '' : $this->prefix).$this->escape($table_name)) ? true : false;
+
+ // Work out the columns we need to keep and the sql for the new table
+ unset($table['columns'][$field_name]);
+ $new_columns = array_keys($table['columns']);
+
+ $new_table = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).' (';
+
+ foreach ($table['columns'] as $cur_column => $column_details)
+ $new_table .= "\n".$cur_column.' '.$column_details.',';
+
+ if (isset($table['unique']))
+ $new_table .= "\n".$table['unique'].',';
+
+ if (isset($table['primary_key']))
+ $new_table .= "\n".$table['primary_key'].',';
+
+ $new_table = trim($new_table, ',')."\n".');';
+
+ // Drop old table
+ $result &= $this->drop_table($table_name, $no_prefix);
+
+ // Create new table
+ $result &= $this->query($new_table) ? true : false;
+
+ // Recreate indexes
+ if (!empty($table['indices']))
+ {
+ foreach ($table['indices'] as $cur_index)
+ if (!preg_match('%\('.preg_quote($field_name, '%').'\)%', $cur_index))
+ $result &= $this->query($cur_index) ? true : false;
+ }
+
+ // Copy content back
+ $result &= $this->query('INSERT INTO '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).' SELECT '.implode(', ', $new_columns).' FROM '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now) ? true : false;
+
+ // Drop temp table
+ $result &= $this->drop_table($table_name.'_t'.$now, $no_prefix);
+
+ return $result;
+ }
+
+
+ function add_index($table_name, $index_name, $index_fields, $unique = false, $no_prefix = false)
+ {
+ if ($this->index_exists($table_name, $index_name, $no_prefix))
+ return true;
+
+ return $this->query('CREATE '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ON '.($no_prefix ? '' : $this->prefix).$table_name.'('.implode(',', $index_fields).')') ? true : false;
+ }
+
+
+ function drop_index($table_name, $index_name, $no_prefix = false)
+ {
+ if (!$this->index_exists($table_name, $index_name, $no_prefix))
+ return true;
+
+ return $this->query('DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) ? true : false;
+ }
+
+ function truncate_table($table_name, $no_prefix = false)
+ {
+ return $this->query('DELETE FROM '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
+ }
+}
diff --git a/include/email.php b/include/email.php
new file mode 100644
index 0000000..b66b584
--- /dev/null
+++ b/include/email.php
@@ -0,0 +1,364 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+// Make sure no one attempts to run this script "directly"
+if (!defined('PUN'))
+ exit;
+
+// Define line breaks in mail headers; possible values can be PHP_EOL, "\r\n", "\n" or "\r"
+if (!defined('FORUM_EOL'))
+ define('FORUM_EOL', PHP_EOL);
+
+require PUN_ROOT.'include/utf8/utils/ascii.php';
+
+//
+// Validate an email address
+//
+function is_valid_email($email)
+{
+ if (strlen($email) > 80)
+ return false;
+
+ return preg_match('%^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|("[^"]+"))@((\[\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\])|(([a-zA-Z\d\-]+\.)+[a-zA-Z]{2,}))$%', $email);
+}
+
+
+//
+// Check if $email is banned
+//
+function is_banned_email($email)
+{
+ global $pun_bans;
+
+ foreach ($pun_bans as $cur_ban)
+ {
+ if ($cur_ban['email'] != '' &&
+ ($email == $cur_ban['email'] ||
+ (strpos($cur_ban['email'], '@') === false && stristr($email, '@'.$cur_ban['email']))))
+ return true;
+ }
+
+ return false;
+}
+
+
+//
+// Only encode with base64, if there is at least one unicode character in the string
+//
+function encode_mail_text($str)
+{
+ if (utf8_is_ascii($str))
+ return $str;
+
+ return '=?UTF-8?B?'.base64_encode($str).'?=';
+}
+
+
+//
+// Make a post email safe
+//
+function bbcode2email($text, $wrap_length = 72)
+{
+ static $base_url;
+
+ if (!isset($base_url))
+ $base_url = get_base_url();
+
+ $text = pun_trim($text, "\t\n ");
+
+ $shortcut_urls = array(
+ 'topic' => '/viewtopic.php?id=$1',
+ 'post' => '/viewtopic.php?pid=$1#p$1',
+ 'forum' => '/viewforum.php?id=$1',
+ 'user' => '/profile.php?id=$1',
+ );
+
+ // Split code blocks and text so BBcode in codeblocks won't be touched
+ list($code, $text) = extract_blocks($text, '[code]', '[/code]');
+
+ // Strip all bbcodes, except the quote, url, img, email, code and list items bbcodes
+ $text = preg_replace(array(
+ '%\[/?(?!(?:quote|url|topic|post|user|forum|img|email|code|list|\*))[a-z]+(?:=[^\]]+)?\]%i',
+ '%\n\[/?list(?:=[^\]]+)?\]%i' // A separate regex for the list tags to get rid of some whitespace
+ ), '', $text);
+
+ // Match the deepest nested bbcode
+ // An adapted example from Mastering Regular Expressions
+ $match_quote_regex = '%
+ \[(quote|\*|url|img|email|topic|post|user|forum)(?:=([^\]]+))?\]
+ (
+ (?>[^\[]*)
+ (?>
+ (?!\[/?\1(?:=[^\]]+)?\])
+ \[
+ [^\[]*
+ )*
+ )
+ \[/\1\]
+ %ix';
+
+ $url_index = 1;
+ $url_stack = array();
+ while (preg_match($match_quote_regex, $text, $matches))
+ {
+ // Quotes
+ if ($matches[1] == 'quote')
+ {
+ // Put '>' or '> ' at the start of a line
+ $replacement = preg_replace(
+ array('%^(?=\>)%m', '%^(?!\>)%m'),
+ array('>', '> '),
+ $matches[2].":\n".$matches[3]);
+ }
+
+ // List items
+ elseif ($matches[1] == '*')
+ {
+ $replacement = ' * '.$matches[3];
+ }
+
+ // URLs and emails
+ elseif (in_array($matches[1], array('url', 'email')))
+ {
+ if (!empty($matches[2]))
+ {
+ $replacement = '['.$matches[3].']['.$url_index.']';
+ $url_stack[$url_index] = $matches[2];
+ $url_index++;
+ }
+ else
+ $replacement = '['.$matches[3].']';
+ }
+
+ // Images
+ elseif ($matches[1] == 'img')
+ {
+ if (!empty($matches[2]))
+ $replacement = '['.$matches[2].']['.$url_index.']';
+ else
+ $replacement = '['.basename($matches[3]).']['.$url_index.']';
+
+ $url_stack[$url_index] = $matches[3];
+ $url_index++;
+ }
+
+ // Topic, post, forum and user URLs
+ elseif (in_array($matches[1], array('topic', 'post', 'forum', 'user')))
+ {
+ $url = isset($shortcut_urls[$matches[1]]) ? $base_url.$shortcut_urls[$matches[1]] : '';
+
+ if (!empty($matches[2]))
+ {
+ $replacement = '['.$matches[3].']['.$url_index.']';
+ $url_stack[$url_index] = str_replace('$1', $matches[2], $url);
+ $url_index++;
+ }
+ else
+ $replacement = '['.str_replace('$1', $matches[3], $url).']';
+ }
+
+ // Update the main text if there is a replacement
+ if (!is_null($replacement))
+ {
+ $text = str_replace($matches[0], $replacement, $text);
+ $replacement = null;
+ }
+ }
+
+ // Put code blocks and text together
+ if (isset($code))
+ {
+ $parts = explode("\1", $text);
+ $text = '';
+ foreach ($parts as $i => $part)
+ {
+ $text .= $part;
+ if (isset($code[$i]))
+ $text .= trim($code[$i], "\n\r");
+ }
+ }
+
+ // Put URLs at the bottom
+ if ($url_stack)
+ {
+ $text .= "\n\n";
+ foreach ($url_stack as $i => $url)
+ $text .= "\n".' ['.$i.']: '.$url;
+ }
+
+ // Wrap lines if $wrap_length is higher than -1
+ if ($wrap_length > -1)
+ {
+ // Split all lines and wrap them individually
+ $parts = explode("\n", $text);
+ foreach ($parts as $k => $part)
+ {
+ preg_match('%^(>+ )?(.*)%', $part, $matches);
+ $parts[$k] = wordwrap($matches[1].$matches[2], $wrap_length -
+ strlen($matches[1]), "\n".$matches[1]);
+ }
+
+ return implode("\n", $parts);
+ }
+ else
+ return $text;
+}
+
+
+//
+// Wrapper for PHP's mail()
+//
+function pun_mail($to, $subject, $message, $reply_to_email = '', $reply_to_name = '')
+{
+ global $pun_config, $lang_common;
+
+ // Use \r\n for SMTP servers, the system's line ending for local mailers
+ $smtp = $pun_config['o_smtp_host'] != '';
+ $EOL = $smtp ? "\r\n" : FORUM_EOL;
+
+ // Default sender/return address
+ $from_name = sprintf($lang_common['Mailer'], $pun_config['o_board_title']);
+ $from_email = $pun_config['o_webmaster_email'];
+
+ // Do a little spring cleaning
+ $to = pun_trim(preg_replace('%[\n\r]+%s', '', $to));
+ $subject = pun_trim(preg_replace('%[\n\r]+%s', '', $subject));
+ $from_email = pun_trim(preg_replace('%[\n\r:]+%s', '', $from_email));
+ $from_name = pun_trim(preg_replace('%[\n\r:]+%s', '', str_replace('"', '', $from_name)));
+ $reply_to_email = pun_trim(preg_replace('%[\n\r:]+%s', '', $reply_to_email));
+ $reply_to_name = pun_trim(preg_replace('%[\n\r:]+%s', '', str_replace('"', '', $reply_to_name)));
+
+ // Set up some headers to take advantage of UTF-8
+ $from = '"'.encode_mail_text($from_name).'" <'.$from_email.'>';
+ $subject = encode_mail_text($subject);
+
+ $headers = 'From: '.$from.$EOL.'Date: '.gmdate('r').$EOL.'MIME-Version: 1.0'.$EOL.'Content-transfer-encoding: 8bit'.$EOL.'Content-type: text/plain; charset=utf-8'.$EOL.'X-Mailer: FluxBB Mailer';
+
+ // If we specified a reply-to email, we deal with it here
+ if (!empty($reply_to_email))
+ {
+ $reply_to = '"'.encode_mail_text($reply_to_name).'" <'.$reply_to_email.'>';
+
+ $headers .= $EOL.'Reply-To: '.$reply_to;
+ }
+
+ // Make sure all linebreaks are LF in message (and strip out any NULL bytes)
+ $message = str_replace("\0", '', pun_linebreaks($message));
+ $message = str_replace("\n", $EOL, $message);
+
+ $mailer = $smtp ? 'smtp_mail' : 'mail';
+ $mailer($to, $subject, $message, $headers);
+}
+
+
+//
+// This function was originally a part of the phpBB Group forum software phpBB2 (http://www.phpbb.com)
+// They deserve all the credit for writing it. I made small modifications for it to suit PunBB and its coding standards
+//
+function server_parse($socket, $expected_response)
+{
+ $server_response = '';
+ while (substr($server_response, 3, 1) != ' ')
+ {
+ if (!($server_response = fgets($socket, 256)))
+ error('Couldn\'t get mail server response codes. Please contact the forum administrator.', __FILE__, __LINE__);
+ }
+
+ if (!(substr($server_response, 0, 3) == $expected_response))
+ error('Unable to send email. Please contact the forum administrator with the following error message reported by the SMTP server: "'.$server_response.'"', __FILE__, __LINE__);
+}
+
+
+//
+// This function was originally a part of the phpBB Group forum software phpBB2 (http://www.phpbb.com)
+// They deserve all the credit for writing it. I made small modifications for it to suit PunBB and its coding standards.
+//
+function smtp_mail($to, $subject, $message, $headers = '')
+{
+ global $pun_config;
+ static $local_host;
+
+ $recipients = explode(',', $to);
+
+ // Sanitize the message
+ $message = str_replace("\r\n.", "\r\n..", $message);
+ $message = (substr($message, 0, 1) == '.' ? '.'.$message : $message);
+
+ // Are we using port 25 or a custom port?
+ if (strpos($pun_config['o_smtp_host'], ':') !== false)
+ list($smtp_host, $smtp_port) = explode(':', $pun_config['o_smtp_host']);
+ else
+ {
+ $smtp_host = $pun_config['o_smtp_host'];
+ $smtp_port = 25;
+ }
+
+ if ($pun_config['o_smtp_ssl'] == '1')
+ $smtp_host = 'ssl://'.$smtp_host;
+
+ if (!($socket = fsockopen($smtp_host, $smtp_port, $errno, $errstr, 15)))
+ error('Could not connect to smtp host "'.$pun_config['o_smtp_host'].'" ('.$errno.') ('.$errstr.')', __FILE__, __LINE__);
+
+ server_parse($socket, '220');
+
+ if (!isset($local_host))
+ {
+ // Here we try to determine the *real* hostname (reverse DNS entry preferably)
+ $local_host = php_uname('n');
+
+ // Able to resolve name to IP
+ if (($local_addr = @gethostbyname($local_host)) !== $local_host)
+ {
+ // Able to resolve IP back to name
+ if (($local_name = @gethostbyaddr($local_addr)) !== $local_addr)
+ $local_host = $local_name;
+ }
+ }
+
+ if ($pun_config['o_smtp_user'] != '' && $pun_config['o_smtp_pass'] != '')
+ {
+ fwrite($socket, 'EHLO '.$local_host."\r\n");
+ server_parse($socket, '250');
+
+ fwrite($socket, 'AUTH LOGIN'."\r\n");
+ server_parse($socket, '334');
+
+ fwrite($socket, base64_encode($pun_config['o_smtp_user'])."\r\n");
+ server_parse($socket, '334');
+
+ fwrite($socket, base64_encode($pun_config['o_smtp_pass'])."\r\n");
+ server_parse($socket, '235');
+ }
+ else
+ {
+ fwrite($socket, 'HELO '.$local_host."\r\n");
+ server_parse($socket, '250');
+ }
+
+ fwrite($socket, 'MAIL FROM: <'.$pun_config['o_webmaster_email'].'>'."\r\n");
+ server_parse($socket, '250');
+
+ foreach ($recipients as $email)
+ {
+ fwrite($socket, 'RCPT TO: <'.$email.'>'."\r\n");
+ server_parse($socket, '250');
+ }
+
+ fwrite($socket, 'DATA'."\r\n");
+ server_parse($socket, '354');
+
+ fwrite($socket, 'Subject: '.$subject."\r\n".'To: <'.implode('>, <', $recipients).'>'."\r\n".$headers."\r\n\r\n".$message."\r\n");
+
+ fwrite($socket, '.'."\r\n");
+ server_parse($socket, '250');
+
+ fwrite($socket, 'QUIT'."\r\n");
+ fclose($socket);
+
+ return true;
+}
diff --git a/include/functions.php b/include/functions.php
new file mode 100644
index 0000000..ace2934
--- /dev/null
+++ b/include/functions.php
@@ -0,0 +1,2227 @@
+<?php
+
+/**
+ * Copyright (C) 2008-2012 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
+
+
+
+//
+// Return current timestamp (with microseconds) as a float
+//
+function get_microtime()
+{
+ list($usec, $sec) = explode(' ', microtime());
+ return ((float)$usec + (float)$sec);
+}
+
+//
+// Cookie stuff!
+//
+function check_cookie(&$pun_user)
+{
+ global $db, $db_type, $pun_config, $cookie_name, $cookie_seed;
+
+ $now = time();
+
+ // If the cookie is set and it matches the correct pattern, then read the values from it
+ if (isset($_COOKIE[$cookie_name]) && preg_match('%^(\d+)\|([0-9a-fA-F]+)\|(\d+)\|([0-9a-fA-F]+)$%', $_COOKIE[$cookie_name], $matches))
+ {
+ $cookie = array(
+ 'user_id' => intval($matches[1]),
+ 'password_hash' => $matches[2],
+ 'expiration_time' => intval($matches[3]),
+ 'cookie_hash' => $matches[4],
+ );
+ }
+
+ // If it has a non-guest user, and hasn't expired
+ if (isset($cookie) && $cookie['user_id'] > 1 && $cookie['expiration_time'] > $now)
+ {
+ // If the cookie has been tampered with
+ $is_authorized = pun_hash_equals(forum_hmac($cookie['user_id'].'|'.$cookie['expiration_time'], $cookie_seed.'_cookie_hash'), $cookie['cookie_hash']);
+ if (!$is_authorized)
+ {
+ $expire = $now + 31536000; // The cookie expires after a year
+ pun_setcookie(1, pun_hash(uniqid(rand(), true)), $expire);
+ set_default_user();
+
+ return;
+ }
+
+ // Check if there's a user with the user ID and password hash from the cookie
+ $result = $db->query('SELECT u.*, g.*, o.logged, o.idle FROM '.$db->prefix.'users AS u INNER JOIN '.$db->prefix.'groups AS g ON u.group_id=g.g_id LEFT JOIN '.$db->prefix.'online AS o ON o.user_id=u.id WHERE u.id='.intval($cookie['user_id'])) or error('Unable to fetch user information', __FILE__, __LINE__, $db->error());
+ $pun_user = $db->fetch_assoc($result);
+
+ // If user authorisation failed
+ $is_authorized = pun_hash_equals(forum_hmac($pun_user['password'], $cookie_seed.'_password_hash'), $cookie['password_hash']);
+ if (!isset($pun_user['id']) || !$is_authorized)
+ {
+ $expire = $now + 31536000; // The cookie expires after a year
+ pun_setcookie(1, pun_hash(uniqid(rand(), true)), $expire);
+ set_default_user();
+
+ return;
+ }
+
+ // Send a new, updated cookie with a new expiration timestamp
+ $expire = ($cookie['expiration_time'] > $now + $pun_config['o_timeout_visit']) ? $now + 1209600 : $now + $pun_config['o_timeout_visit'];
+ pun_setcookie($pun_user['id'], $pun_user['password'], $expire);
+
+ // Set a default language if the user selected language no longer exists
+ if (!file_exists(PUN_ROOT.'lang/'.$pun_user['language']))
+ $pun_user['language'] = $pun_config['o_default_lang'];
+
+ // Set a default style if the user selected style no longer exists
+ if (!file_exists(PUN_ROOT.'style/'.$pun_user['style'].'.css'))
+ $pun_user['style'] = $pun_config['o_default_style'];
+
+ if (!$pun_user['disp_topics'])
+ $pun_user['disp_topics'] = $pun_config['o_disp_topics_default'];
+ if (!$pun_user['disp_posts'])
+ $pun_user['disp_posts'] = $pun_config['o_disp_posts_default'];
+
+ // Define this if you want this visit to affect the online list and the users last visit data
+ if (!defined('PUN_QUIET_VISIT'))
+ {
+ // Update the online list
+ if (!$pun_user['logged'])
+ {
+ $pun_user['logged'] = $now;
+
+ // With MySQL/MySQLi/SQLite, REPLACE INTO avoids a user having two rows in the online table
+ switch ($db_type)
+ {
+ case 'mysql':
+ case 'mysqli':
+ case 'mysql_innodb':
+ case 'mysqli_innodb':
+ case 'sqlite':
+ $db->query('REPLACE INTO '.$db->prefix.'online (user_id, ident, logged) VALUES('.$pun_user['id'].', \''.$db->escape($pun_user['username']).'\', '.$pun_user['logged'].')') or error('Unable to insert into online list', __FILE__, __LINE__, $db->error());
+ break;
+
+ default:
+ $db->query('INSERT INTO '.$db->prefix.'online (user_id, ident, logged) SELECT '.$pun_user['id'].', \''.$db->escape($pun_user['username']).'\', '.$pun_user['logged'].' WHERE NOT EXISTS (SELECT 1 FROM '.$db->prefix.'online WHERE user_id='.$pun_user['id'].')') or error('Unable to insert into online list', __FILE__, __LINE__, $db->error());
+ break;
+ }
+
+ // Reset tracked topics
+ set_tracked_topics(null);
+ }
+ else
+ {
+ // Special case: We've timed out, but no other user has browsed the forums since we timed out
+ if ($pun_user['logged'] < ($now-$pun_config['o_timeout_visit']))
+ {
+ $db->query('UPDATE '.$db->prefix.'users SET last_visit='.$pun_user['logged'].' WHERE id='.$pun_user['id']) or error('Unable to update user visit data', __FILE__, __LINE__, $db->error());
+ $pun_user['last_visit'] = $pun_user['logged'];
+ }
+
+ $idle_sql = ($pun_user['idle'] == '1') ? ', idle=0' : '';
+ $db->query('UPDATE '.$db->prefix.'online SET logged='.$now.$idle_sql.' WHERE user_id='.$pun_user['id']) or error('Unable to update online list', __FILE__, __LINE__, $db->error());
+
+ // Update tracked topics with the current expire time
+ if (isset($_COOKIE[$cookie_name.'_track']))
+ forum_setcookie($cookie_name.'_track', $_COOKIE[$cookie_name.'_track'], $now + $pun_config['o_timeout_visit']);
+ }
+ }
+ else
+ {
+ if (!$pun_user['logged'])
+ $pun_user['logged'] = $pun_user['last_visit'];
+ }
+
+ $pun_user['is_guest'] = false;
+ $pun_user['is_admmod'] = $pun_user['g_id'] == PUN_ADMIN || $pun_user['g_moderator'] == '1';
+ }
+ else
+ set_default_user();
+}
+
+
+//
+// Converts the CDATA end sequence ]]> into ]]&gt;
+//
+function escape_cdata($str)
+{
+ return str_replace(']]>', ']]&gt;', $str);
+}
+
+
+//
+// Authenticates the provided username and password against the user database
+// $user can be either a user ID (integer) or a username (string)
+// $password can be either a plaintext password or a password hash including salt ($password_is_hash must be set accordingly)
+//
+function authenticate_user($user, $password, $password_is_hash = false)
+{
+ global $db, $pun_user;
+
+ // Check if there's a user matching $user and $password
+ $result = $db->query('SELECT u.*, g.*, o.logged, o.idle FROM '.$db->prefix.'users AS u INNER JOIN '.$db->prefix.'groups AS g ON g.g_id=u.group_id LEFT JOIN '.$db->prefix.'online AS o ON o.user_id=u.id WHERE '.(is_int($user) ? 'u.id='.intval($user) : 'u.username=\''.$db->escape($user).'\'')) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
+ $pun_user = $db->fetch_assoc($result);
+
+ $is_password_authorized = pun_hash_equals($password, $pun_user['password']);
+ $is_hash_authorized = pun_hash_equals(pun_hash($password), $pun_user['password']);
+
+ if (!isset($pun_user['id']) ||
+ ($password_is_hash && !$is_password_authorized ||
+ (!$password_is_hash && !$is_hash_authorized)))
+ set_default_user();
+ else
+ $pun_user['is_guest'] = false;
+}
+
+
+//
+// Try to determine the current URL
+//
+function get_current_url($max_length = 0)
+{
+ $protocol = get_current_protocol();
+ $port = (isset($_SERVER['SERVER_PORT']) && (($_SERVER['SERVER_PORT'] != '80' && $protocol == 'http') || ($_SERVER['SERVER_PORT'] != '443' && $protocol == 'https')) && strpos($_SERVER['HTTP_HOST'], ':') === false) ? ':'.$_SERVER['SERVER_PORT'] : '';
+
+ $url = urldecode($protocol.'://'.$_SERVER['HTTP_HOST'].$port.$_SERVER['REQUEST_URI']);
+
+ if (strlen($url) <= $max_length || $max_length == 0)
+ return $url;
+
+ // We can't find a short enough url
+ return null;
+}
+
+
+//
+// Fetch the current protocol in use - http or https
+//
+function get_current_protocol()
+{
+ $protocol = 'http';
+
+ // Check if the server is claiming to using HTTPS
+ if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off')
+ $protocol = 'https';
+
+ // If we are behind a reverse proxy try to decide which protocol it is using
+ if (defined('FORUM_BEHIND_REVERSE_PROXY'))
+ {
+ // Check if we are behind a Microsoft based reverse proxy
+ if (!empty($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) != 'off')
+ $protocol = 'https';
+
+ // Check if we're behind a "proper" reverse proxy, and what protocol it's using
+ if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']))
+ $protocol = strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']);
+ }
+
+ return $protocol;
+}
+
+
+//
+// Fetch the base_url, optionally support HTTPS and HTTP
+//
+function get_base_url($support_https = false)
+{
+ global $pun_config;
+ static $base_url;
+
+ if (!$support_https)
+ return $pun_config['o_base_url'];
+
+ if (!isset($base_url))
+ {
+ // Make sure we are using the correct protocol
+ $base_url = str_replace(array('http://', 'https://'), get_current_protocol().'://', $pun_config['o_base_url']);
+ }
+
+ return $base_url;
+}
+
+
+//
+// Fetch admin IDs
+//
+function get_admin_ids()
+{
+ if (file_exists(FORUM_CACHE_DIR.'cache_admins.php'))
+ include FORUM_CACHE_DIR.'cache_admins.php';
+
+ if (!defined('PUN_ADMINS_LOADED'))
+ {
+ if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+ require PUN_ROOT.'include/cache.php';
+
+ generate_admins_cache();
+ require FORUM_CACHE_DIR.'cache_admins.php';
+ }
+
+ return $pun_admins;
+}
+
+
+//
+// Fill $pun_user with default values (for guests)
+//
+function set_default_user()
+{
+ global $db, $db_type, $pun_user, $pun_config;
+
+ $remote_addr = get_remote_address();
+
+ // Fetch guest user
+ $result = $db->query('SELECT u.*, g.*, o.logged, o.last_post, o.last_search FROM '.$db->prefix.'users AS u INNER JOIN '.$db->prefix.'groups AS g ON u.group_id=g.g_id LEFT JOIN '.$db->prefix.'online AS o ON o.ident=\''.$db->escape($remote_addr).'\' WHERE u.id=1') or error('Unable to fetch guest information', __FILE__, __LINE__, $db->error());
+ if (!$db->num_rows($result))
+ exit('Unable to fetch guest information. Your database must contain both a guest user and a guest user group.');
+
+ $pun_user = $db->fetch_assoc($result);
+
+ // Update online list
+ if (!$pun_user['logged'])
+ {
+ $pun_user['logged'] = time();
+
+ // With MySQL/MySQLi/SQLite, REPLACE INTO avoids a user having two rows in the online table
+ switch ($db_type)
+ {
+ case 'mysql':
+ case 'mysqli':
+ case 'mysql_innodb':
+ case 'mysqli_innodb':
+ case 'sqlite':
+ $db->query('REPLACE INTO '.$db->prefix.'online (user_id, ident, logged) VALUES(1, \''.$db->escape($remote_addr).'\', '.$pun_user['logged'].')') or error('Unable to insert into online list', __FILE__, __LINE__, $db->error());
+ break;
+
+ default:
+ $db->query('INSERT INTO '.$db->prefix.'online (user_id, ident, logged) SELECT 1, \''.$db->escape($remote_addr).'\', '.$pun_user['logged'].' WHERE NOT EXISTS (SELECT 1 FROM '.$db->prefix.'online WHERE ident=\''.$db->escape($remote_addr).'\')') or error('Unable to insert into online list', __FILE__, __LINE__, $db->error());
+ break;
+ }
+ }
+ else
+ $db->query('UPDATE '.$db->prefix.'online SET logged='.time().' WHERE ident=\''.$db->escape($remote_addr).'\'') or error('Unable to update online list', __FILE__, __LINE__, $db->error());
+
+ $pun_user['disp_topics'] = $pun_config['o_disp_topics_default'];
+ $pun_user['disp_posts'] = $pun_config['o_disp_posts_default'];
+ $pun_user['timezone'] = $pun_config['o_default_timezone'];
+ $pun_user['dst'] = $pun_config['o_default_dst'];
+ $pun_user['language'] = $pun_config['o_default_lang'];
+ $pun_user['style'] = $pun_config['o_default_style'];
+ $pun_user['is_guest'] = true;
+ $pun_user['is_admmod'] = false;
+}
+
+
+//
+// SHA1 HMAC with PHP 4 fallback
+//
+function forum_hmac($data, $key, $raw_output = false)
+{
+ if (function_exists('hash_hmac'))
+ return hash_hmac('sha1', $data, $key, $raw_output);
+
+ // If key size more than blocksize then we hash it once
+ if (strlen($key) > 64)
+ $key = pack('H*', sha1($key)); // we have to use raw output here to match the standard
+
+ // Ensure we're padded to exactly one block boundary
+ $key = str_pad($key, 64, chr(0x00));
+
+ $hmac_opad = str_repeat(chr(0x5C), 64);
+ $hmac_ipad = str_repeat(chr(0x36), 64);
+
+ // Do inner and outer padding
+ for ($i = 0;$i < 64;$i++) {
+ $hmac_opad[$i] = $hmac_opad[$i] ^ $key[$i];
+ $hmac_ipad[$i] = $hmac_ipad[$i] ^ $key[$i];
+ }
+
+ // Finally, calculate the HMAC