diff options
author | Andreas Baumann <mail@andreasbaumann.cc> | 2019-11-17 20:57:39 +0100 |
---|---|---|
committer | Andreas Baumann <mail@andreasbaumann.cc> | 2019-11-17 20:57:39 +0100 |
commit | 3b06ee0d381dc1be5f40ca98ad4278046d869d21 (patch) | |
tree | d31e79fc57d882b8267f40c3434480bb58a3ca73 | |
download | fluxbb-master.tar.xz |
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/ +*~ @@ -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=&'.implode('&', $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>» </span><a href="admin_bans.php"><?php echo $lang_admin_common['Bans'] ?></a></li>
+ <li><span>» </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']) : ' ' ?></td>
+ <td class="tc2"><?php echo ($ban_data['email'] != '') ? pun_htmlspecialchars($ban_data['email']) : ' ' ?></td>
+ <td class="tc3"><?php echo ($ban_data['ip'] != '') ? pun_htmlspecialchars($ban_data['ip']) : ' ' ?></td>
+ <td class="tc4"><?php echo $expire ?></td>
+ <td class="tc5"><?php echo ($ban_data['message'] != '') ? pun_htmlspecialchars($ban_data['message']) : ' ' ?></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>» </span><a href="admin_bans.php"><?php echo $lang_admin_common['Bans'] ?></a></li>
+ <li><span>» </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>   <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'].'" /> <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"> </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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" /> <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" />  <?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" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong></label> + <label class="conl"><input type="radio" name="prune_sticky" value="0" /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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" /> <?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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <?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"' ?> /> <?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"' ?> /> <?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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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"' ?> /> <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>» <a href="viewtopic.php?id='.$cur_report['topic_id'].'">'.pun_htmlspecialchars($cur_report['subject']).'</a></span>' : '<span>» '.$lang_admin_reports['Deleted'].'</span>'; + $post = str_replace("\n", '<br />', pun_htmlspecialchars($cur_report['message'])); + $post_id = ($cur_report['pid'] != '') ? '<span>» <a href="viewtopic.php?pid='.$cur_report['pid'].'#p'.$cur_report['pid'].'">'.sprintf($lang_admin_reports['Post ID'], $cur_report['pid']).'</a></span>' : '<span>» '.$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>» <a href="viewtopic.php?id='.$cur_report['topic_id'].'">'.pun_htmlspecialchars($cur_report['subject']).'</a></span>' : '<span>» '.$lang_admin_reports['Deleted'].'</span>'; + $post = str_replace("\n", '<br />', pun_htmlspecialchars($cur_report['message'])); + $post_id = ($cur_report['pid'] != '') ? '<span>» <a href="viewtopic.php?pid='.$cur_report['pid'].'#p'.$cur_report['pid'].'">'.sprintf($lang_admin_reports['Post ID'], $cur_report['pid']).'</a></span>' : '<span>» '.$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>» </span><a href="admin_users.php"><?php echo $lang_admin_common['Users'] ?></a></li> + <li><span>» </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>» </span><a href="admin_users.php"><?php echo $lang_admin_common['Users'] ?></a></li> + <li><span>» </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>» </span><a href="admin_users.php"><?php echo $lang_admin_common['Users'] ?></a></li> + <li><span>» </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&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']) : ' ' ?></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"> </td> + <td class="tc3"><?php echo $lang_admin_users['Results guest'] ?></td> + <td class="tc4"> </td> + <td class="tc5"> </td> + <td class="tcr"> </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>» </span><a href="admin_users.php"><?php echo $lang_admin_common['Users'] ?></a></li> + <li><span>» </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" /> <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" /> <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=&'.implode('&', $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>» </span><a href="admin_users.php"><?php echo $lang_admin_common['Users'] ?></a></li> + <li><span>» </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&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']) : ' ' ?></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>» </span><a href="admin_users.php"><?php echo $lang_admin_common['Users'] ?></a></li> + <li><span>» </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>   <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('    ', '  ', '  '); + $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&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>» </span><a href="viewforum.php?id=<?php echo $cur_post['fid'] ?>"><?php echo pun_htmlspecialchars($cur_post['forum_name']) ?></a></li> + <li><span>» </span><a href="viewtopic.php?pid=<?php echo $id ?>#p<?php echo $id ?>"><?php echo pun_htmlspecialchars($cur_post['subject']) ?></a></li> + <li><span>» </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>» </span><a href="viewforum.php?id=<?php echo $cur_post['fid'] ?>"><?php echo pun_htmlspecialchars($cur_post['forum_name']) ?></a></li> + <li><span>» </span><a href="viewtopic.php?id=<?php echo $cur_post['tid'] ?>"><?php echo pun_htmlspecialchars($cur_post['subject']) ?></a></li> + <li><span>» </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 ?>&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 = '&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.'&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.'&tid='.$id.'&p='.$p.'">'.$lang_common['Moderate topic'].'</a>'.($num_pages > 1 ? ' (<a href="moderate.php?fid='.$forum_id.'&tid='.$id.'&action=all">'.$lang_common['All'].'</a>)' : '').'</span></dd>'."\n"; + echo "\t\t\t\t".'<dd><span><a href="moderate.php?fid='.$forum_id.'&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.'&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.'&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.'&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.'&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&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&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&fid='.$forum_id.'&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&fid='.$forum_id.'&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&tid='.$id.'&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&tid='.$id.'&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(' ', ' ', $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&id='.$pun_user['id'].'&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 Binary files differnew file mode 100644 index 0000000..1c4ea81 --- /dev/null +++ b/img/smilies/big_smile.png diff --git a/img/smilies/cool.png b/img/smilies/cool.png Binary files differnew file mode 100644 index 0000000..54ec46f --- /dev/null +++ b/img/smilies/cool.png diff --git a/img/smilies/hmm.png b/img/smilies/hmm.png Binary files differnew file mode 100644 index 0000000..47b87b9 --- /dev/null +++ b/img/smilies/hmm.png 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 Binary files differnew file mode 100644 index 0000000..bad0718 --- /dev/null +++ b/img/smilies/lol.png diff --git a/img/smilies/mad.png b/img/smilies/mad.png Binary files differnew file mode 100644 index 0000000..d8ffcc6 --- /dev/null +++ b/img/smilies/mad.png diff --git a/img/smilies/neutral.png b/img/smilies/neutral.png Binary files differnew file mode 100644 index 0000000..a2e4cb8 --- /dev/null +++ b/img/smilies/neutral.png diff --git a/img/smilies/roll.png b/img/smilies/roll.png Binary files differnew file mode 100644 index 0000000..1c3bc7e --- /dev/null +++ b/img/smilies/roll.png diff --git a/img/smilies/sad.png b/img/smilies/sad.png Binary files differnew file mode 100644 index 0000000..b6a0899 --- /dev/null +++ b/img/smilies/sad.png diff --git a/img/smilies/smile.png b/img/smilies/smile.png Binary files differnew file mode 100644 index 0000000..77099a0 --- /dev/null +++ b/img/smilies/smile.png diff --git a/img/smilies/tongue.png b/img/smilies/tongue.png Binary files differnew file mode 100644 index 0000000..397b98a --- /dev/null +++ b/img/smilies/tongue.png diff --git a/img/smilies/wink.png b/img/smilies/wink.png Binary files differnew file mode 100644 index 0000000..fbc40af --- /dev/null +++ b/img/smilies/wink.png diff --git a/img/smilies/yikes.png b/img/smilies/yikes.png Binary files differnew file mode 100644 index 0000000..ddb055f --- /dev/null +++ b/img/smilies/yikes.png diff --git a/img/test.png b/img/test.png Binary files differnew file mode 100644 index 0000000..4241f08 --- /dev/null +++ b/img/test.png 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'] != '') ? ' >>>' : ''; + $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 ]]> +// +function escape_cdata($str) +{ + return str_replace(']]>', ']]>', $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) |