diff --git a/500.shtml b/500.shtml new file mode 100644 index 0000000..d6db1bc --- /dev/null +++ b/500.shtml @@ -0,0 +1,25 @@ + + + + + + +系统崩溃了…… + + + + + +

系统崩溃了……

+

+

『奇怪的事情发生了……』

+

『请等待我们查出问题所在后进行维修。』

+

特此通告。  By 冴月麟

\ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d511905 --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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. + + + Copyright (C) + + 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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. + + , 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 Lesser General +Public License instead of this License. diff --git a/OTHER/README_s2kx.txt b/OTHER/README_s2kx.txt new file mode 100644 index 0000000..612821f --- /dev/null +++ b/OTHER/README_s2kx.txt @@ -0,0 +1,14 @@ +===== Serissa to Kusaba X 0.8 Conversion Script ===== + +=== How to use === + +1. Copy s2xk.php and s2kx.sql to the folder containing config.php on your server. +2. Run s2kx.php. +3. Download the full version Kusaba X from http://kusabax.org +4. Make a backup of your current config.php +5. Extract the files that you downloaded where you want them installed. Overwrite everything. +6. If everything went right, congratulations! You are now running Kusaba X 0.8! + +== When upgrading to Kusaba X 0.9 == + +7. Once converted, you will need to run the upgrade scripts to upgrade from Kusaba X 0.8 to Kusabax 0.9. These scripts are located in the OTHER directory. \ No newline at end of file diff --git a/OTHER/install-mysql.php b/OTHER/install-mysql.php new file mode 100644 index 0000000..d023cce --- /dev/null +++ b/OTHER/install-mysql.php @@ -0,0 +1,146 @@ + + + + + + +MySQL Batch File Importing Script + + + + + +

MySQL Batch File Importing Script

+ +

+ + +WARNING!

+The purpose of this script is to quickly and easily run the commands contained within the kusaba SQL file, and is +to be used if you are installing the script for the first time or want to recreate the tables, for whatever reason.
+Running this script will delete any related tables and their data (including the admin files). I offer this script as-is and cannot be held +responsible for any damages caused or accidental loss of data incurred as a result of running this script.
+Before running this script, make sure that:
+
    +
  • -> You have set up the database connection and that it is working
  • +
  • -> You have created the database
  • +
  • -> You have created the database user and set up the config file appropriately
  • +
+
+
+ By clicking this check box I agree that the author of this script cannot be held responsible for my own stupidity if something goes wrong.


+ +
+ +".KU_DBPREFIX.$tablename." already exists in the database! Drop it, and re run this script."); + } + } + // Lets open the file for reading! :) + echo '

SQL Batch File Processing

'; + echo 'Locating \'kusaba_freshinstall.mysql.sql\'... '; + if (file_exists('kusaba_freshinstall.mysql.sql') && (filesize('kusaba_freshinstall.mysql.sql') > 0)) { + echo 'found.
'; + $sqlfile = fopen('kusaba_freshinstall.mysql.sql', 'r'); + echo 'File opened.
'; + $readdata = fread($sqlfile, filesize('kusaba_freshinstall.mysql.sql')); + $readdata = str_replace('PREFIX_',KU_DBPREFIX,$readdata); + fclose($sqlfile); + echo 'Contents read.
'; + }else{ + echo 'error. '; + die('An error occured. kusaba_freshinstall.mysql.sql does not exist in this directory or it is 0 bytes big :( Barring that, do you have read permissions for the directory?'); + } + + $tc_db->Execute("ALTER DATABASE `" . KU_DBDATABASE . "` CHARACTER SET utf8 COLLATE utf8_general_ci"); + + // Explodes the array + $sqlarray = explode("\n", $readdata); + + // Loops through the array and deletes the non-SQL bits in the file, which is basically the '--' lines and the lines with no content + foreach ($sqlarray as $key => $sqldata) { + if (strstr($sqldata, '--') || strlen($sqldata) == 0){ + unset($sqlarray[$key]); + } + } + // Here we are imploding everything together again... + $readdata = implode('',$sqlarray); + + // ...then exploding it again. At this point we will have an array where each key's value is a one of the CREATE statements + $sqlarray = explode(';',$readdata); + echo 'File contents have been formatted for use with mysql_query.
'; + // Lets drop any existing tables in the database + $listoftables = $tc_db->GetAll("show tables from ".KU_DBDATABASE.""); + + echo '

Table Creation

'; + // Lets now loop through the array and create each table + foreach ($sqlarray as $sqldata) { + + if (strlen($sqldata) !== 0) { // As the array was exploded on ';', the last ';' caused a blank element to be created as there was no data after it :p + // The following three lines retrieve the table name of the table from the sql command. It's dynamic so it doesn't matter how many tables need to be created + // As long as each CREATE TABLE statement stays in the format CREATE TABLE `table` then this part will work. + $pos1 = strpos($sqldata, '`'); + $pos2 = strpos($sqldata, '`', $pos1 + 1); + $tablename = substr($sqldata, $pos1+1, ($pos2-$pos1)-1); + echo "Attempting to create table '$tablename'... "; + if($tc_db->Execute($sqldata)) { + echo "success.
"; + } else { + echo "failed. Enable debugging by setting KU_DEBUG to true to see this error.
"; + die ("Table creation failed. Please rerun this script again or attempt to fix the problem if you know how to solve it."); + } + } + } + // All done :) + echo '
SQL commands have finished. If all is well, proceed to the installation file but don\'t forget to delete this file!'; +} + +function mysql_table_exists($database, $tableName) +{ + global $tc_db; + $tables = array(); + $tablesResults = $tc_db->GetAll("SHOW TABLES FROM `$database`;"); + foreach ($tablesResults AS $row) $tables[] = $row[0]; + return(in_array($tableName, $tables)); +} + +?> + + \ No newline at end of file diff --git a/OTHER/install-pgsql.php b/OTHER/install-pgsql.php new file mode 100644 index 0000000..b254333 --- /dev/null +++ b/OTHER/install-pgsql.php @@ -0,0 +1,147 @@ + + + + + + +PostgreSQL Batch File Importing Script + + + + + +

PostgreSQL Batch File Importing Script

+ +

+ + +WARNING!

+The purpose of this script is to quickly and easily run the commands contained within the kusaba SQL file, and is +to be used if you are installing the script for the first time or want to recreate the tables, for whatever reason.
+Running this script will delete any related tables and their data (including the admin files). I offer this script as-is and cannot be held +responsible for any damages caused or accidental loss of data incurred as a result of running this script.
+Before running this script, make sure that:
+
    +
  • -> You have set up the database connection and that it is working
  • +
  • -> You have created the database
  • +
  • -> You have created the database user and set up the config file appropriately
  • +
+
+
+ By clicking this check box I agree that the author of this script cannot be held responsible for my own stupidity if something goes wrong.


+ +
+ +".KU_DBPREFIX.$tablename." already exists in the database! Drop it, and re run this script."); + } + } + // Lets open the file for reading! :) + echo '

SQL Batch File Processing

'; + echo 'Locating \'kusaba_freshinstall.postgres.sql\'... '; + if (file_exists('kusaba_freshinstall.postgres.sql') && (filesize('kusaba_freshinstall.postgres.sql') > 0)) { + echo 'found.
'; + $sqlfile = fopen('kusaba_freshinstall.postgres.sql', 'r'); + echo 'File opened.
'; + $readdata = fread($sqlfile, filesize('kusaba_freshinstall.postgres.sql')); + $readdata = str_replace('PREFIX_',KU_DBPREFIX,$readdata); + fclose($sqlfile); + echo 'Contents read.
'; + }else{ + echo 'error. '; + die('An error occured. kusaba_freshinstall.postgres.sql does not exist in this directory or it is 0 bytes big :( Barring that, do you have read permissions for the directory?'); + } + + // Explodes the array + $sqlarray = explode("\n", $readdata); + + // Loops through the array and deletes the non-SQL bits in the file, which is basically the '--' lines and the lines with no content + foreach ($sqlarray as $key => $sqldata) { + if (strstr($sqldata, '--') || strlen($sqldata) == 0){ + unset($sqlarray[$key]); + } + } + // Here we are imploding everything together again... + $readdata = implode('',$sqlarray); + + // ...then exploding it again. At this point we will have an array where each key's value is a one of the CREATE statements + $sqlarray = explode(';',$readdata); + echo 'File contents have been formatted for use with pg_query.
'; + // Lets drop any existing tables in the database + $listoftables = $tc_db->GetAll("SELECT table_name FROM information_schema.tables WHERE table_schema='public' AND table_type='BASE TABLE'"); + + echo '

Table Creation

'; + // Lets now loop through the array and create each table + foreach ($sqlarray as $sqldata) { + + if (strlen($sqldata) !== 0) { // As the array was exploded on ';', the last ';' caused a blank element to be created as there was no data after it :p + // The following three lines retrieve the table name of the table from the sql command. It's dynamic so it doesn't matter how many tables need to be created + // As long as each CREATE TABLE statement stays in the format CREATE TABLE `table` then this part will work. + $sqldata = str_replace(":semicolon:", ";", $sqldata); + if (strpos($sqldata, "CREATE TABLE") !== false) { + preg_match("/CREATE TABLE (.*?) \(/", $sqldata, $tablename); + echo "Attempting to create table '{$tablename[1]}'... "; + } + else { + echo "Attempting to run query '".$sqldata."'... "; + } + if($tc_db->Execute($sqldata)) { + echo "success.
"; + } else { + echo "failed. Enable debugging by setting KU_DEBUG to true to see this error.
"; + die ("Table creation failed. Please rerun this script again or attempt to fix the problem if you know how to solve it."); + } + } + } + // All done :) + echo '
SQL commands have finished. If all is well, proceed to the installation file but don\'t forget to delete this file!'; +} + +function pgsql_table_exists($database, $tableName) { + global $tc_db; + $tables = array(); + $tablesResults = $tc_db->GetAll("SELECT table_name FROM information_schema.tables WHERE table_schema='public' AND table_type='BASE TABLE'"); + foreach ($tablesResults AS $row) $tables[] = $row[0]; + return(in_array($tableName, $tables)); +} + +?> + + diff --git a/OTHER/install-sqlite.php b/OTHER/install-sqlite.php new file mode 100644 index 0000000..a752918 --- /dev/null +++ b/OTHER/install-sqlite.php @@ -0,0 +1,150 @@ + + + + + + +SQLite Batch File Importing Script + + + + + +

SQLite Batch File Importing Script

+ +

+ + +WARNING!

+The purpose of this script is to quickly and easily run the commands contained within the kusaba SQL file, and is +to be used if you are installing the script for the first time or want to recreate the tables, for whatever reason.
+Running this script will delete any related tables and their data (including the admin files). I offer this script as-is and cannot be held +responsible for any damages caused or accidental loss of data incurred as a result of running this script.
+Before running this script, make sure that:
+
    +
  • -> You have set up the database connection and that it is working
  • +
  • -> You have created the database
  • +
  • -> You have created the database user and set up the config file appropriately
  • +
+
+
+ By clicking this check box I agree that the author of this script cannot be held responsible for my own stupidity if something goes wrong.


+ +
+ +".KU_DBPREFIX.$tablename." already exists in the database! Drop it, and re run this script."); + } + } + // Lets open the file for reading! :) + + echo '

SQL Batch File Processing

'; + echo 'Locating \'kusaba_freshinstall.sqlite.sql\'... '; + if (file_exists('kusaba_freshinstall.sqlite.sql') && (filesize('kusaba_freshinstall.sqlite.sql') > 0)) { + echo 'found.
'; + $sqlfile = fopen('kusaba_freshinstall.sqlite.sql', 'r'); + echo 'File opened.
'; + $readdata = fread($sqlfile, filesize('kusaba_freshinstall.sqlite.sql')); + $readdata = str_replace('PREFIX_',KU_DBPREFIX,$readdata); + fclose($sqlfile); + echo 'Contents read.
'; + }else{ + echo 'error. '; + die('An error occured. kusaba_freshinstall.sqlite.sql does not exist in this directory or it is 0 bytes big :( Barring that, do you have read permissions for the directory?'); + } + + + + // Explodes the array + $sqlarray = explode("\n", $readdata); + + // Loops through the array and deletes the non-SQL bits in the file, which is basically the '--' lines and the lines with no content + foreach ($sqlarray as $key => $sqldata) { + if (strstr($sqldata, '--') || strlen($sqldata) == 0){ + unset($sqlarray[$key]); + } + } + // Here we are imploding everything together again... + $readdata = implode('',$sqlarray); + + // ...then exploding it again. At this point we will have an array where each key's value is a one of the CREATE statements + $sqlarray = explode(';',$readdata); + echo 'File contents have been formatted for use with sqlite_query.
'; + // Lets drop any existing tables in the database + $listoftables = $tc_db->GetAll("SELECT name FROM sqlite_master WHERE type = 'table'"); + + echo '

Table Creation

'; + // Lets now loop through the array and create each table + foreach ($sqlarray as $sqldata) { + + if (strlen($sqldata) !== 0) { // As the array was exploded on ';', the last ';' caused a blank element to be created as there was no data after it :p + // The following three lines retrieve the table name of the table from the sql command. It's dynamic so it doesn't matter how many tables need to be created + // As long as each CREATE TABLE statement stays in the format CREATE TABLE `table` then this part will work. + $sqldata = str_replace(":semicolon:", ";", $sqldata); + if (strpos($sqldata, "CREATE TABLE") !== false) { + preg_match("/CREATE TABLE (.*?) \(/", $sqldata, $tablename); + echo "Attempting to create table '{$tablename[1]}'... "; + } + else { + echo "Attempting to run query '".$sqldata."'... "; + } + if($tc_db->Execute($sqldata)) { + echo "success.
"; + } else { + echo "failed. Enable debugging by setting KU_DEBUG to true to see this error.
"; + die ("Table creation failed. Please rerun this script again or attempt to fix the problem if you know how to solve it."); + } + } + } + // All done :) + echo '
SQL commands have finished. If all is well, proceed to the installation file but don\'t forget to delete this file!'; +} + +function sqlite_table_exists($database, $tableName) { + global $tc_db; + $tables = array(); + $tablesResults = $tc_db->GetAll("SELECT name FROM sqlite_master WHERE type = 'table'" ); + foreach ($tablesResults AS $row) $tables[] = $row[0]; + return(in_array($tableName, $tables)); +} + +?> + + \ No newline at end of file diff --git a/OTHER/install.php b/OTHER/install.php new file mode 100644 index 0000000..d7167c2 --- /dev/null +++ b/OTHER/install.php @@ -0,0 +1,120 @@ +GetAll("SHOW TABLES FROM `$database`;"); + foreach ($tablesResults AS $row) $tables[] = $row[0]; + return(in_array($tableName, $tables)); +} +function pgsql_table_exists($database, $tableName) { + global $tc_db; + $tables = array(); + $tablesResults = $tc_db->GetAll(" select table_name from information_schema.tables where table_schema='public' and table_type='BASE TABLE'"); + foreach ($tablesResults AS $row) $tables[] = $row[0]; + return(in_array($tableName, $tables)); +} + +function sqlite_table_exists($database, $tableName) { + global $tc_db; + $tables = array(); + $tablesResults = $tc_db->GetAll("SELECT name FROM sqlite_master WHERE type = 'table'" ); + foreach ($tablesResults AS $row) $tables[] = $row[0]; + return(in_array($tableName, $tables)); +} + +function CreateSalt() { + $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + $salt = ''; + + for ($i = 0; $i < 3; ++$i) { + $salt .= $chars[mt_rand(0, strlen($chars) - 1)]; + } + return $salt; +} + +?> + + + + +Kusaba X Installation + + + + + +

Kusaba X Installation

+ +Checking configuration file...'; +if (file_exists('config.php')) { + require 'config.php'; + require KU_ROOTDIR . 'inc/functions.php'; + if (KU_RANDOMSEED!="ENTER RANDOM LETTERS/NUMBERS HERE"&&KU_RANDOMSEED!="") { + echo 'Configuration appears correct.'; + echo '

Checking database...

'; + $reqiredtables = array("ads","announcements","banlist","bannedhashes","blotter","boards","board_filetypes","embeds","events","filetypes","front","loginattempts","modlog","module_settings","posts","reports","sections","staff","watchedthreads","wordfilter"); + foreach ($reqiredtables as $tablename) { + if (KU_DBTYPE == 'mysql' || KU_DBTYPE == 'mysqli') { + if (!mysql_table_exists(KU_DBDATABASE,KU_DBPREFIX.$tablename)) { + die("Couldn't find the table ".KU_DBPREFIX.$tablename." in the database. Please insert the mySQL dump."); + } + } + if (KU_DBTYPE == 'postgres7' || KU_DBTYPE == 'postgres8' || KU_DBTYPE == 'postgres') { + if (!pgsql_table_exists(KU_DBDATABASE,KU_DBPREFIX.$tablename)) { + die("Couldn't find the table ".KU_DBPREFIX.$tablename." in the database. Please insert the PostgreSQL dump."); + } + } + if (KU_DBTYPE == 'sqlite') { + if (!sqlite_table_exists(KU_DBDATABASE,KU_DBPREFIX.$tablename)) { + die("Couldn't find the table ".KU_DBPREFIX.$tablename." in the database. Please insert the SQLite dump."); + } + } + } + echo 'Database appears correct.'; + echo '

Inserting default administrator account...

'; + $result_exists = $tc_db->GetOne("SELECT COUNT(*) FROM `".KU_DBPREFIX."staff` WHERE `username` = 'admin'"); + if ($result_exists==0) { + $salt = CreateSalt(); + $result = $tc_db->Execute("INSERT INTO `".KU_DBPREFIX."staff` ( `username` , `salt`, `password` , `type` , `addedon` ) VALUES ( 'admin' , '".$salt."', '".md5("admin".$salt)."' , '1' , '".time()."' )"); + echo 'Account inserted.'; + $result = true; + } else { + echo 'There is already an administrator account inserted.'; + $result = true; + } + if ($result) { + require_once KU_ROOTDIR . 'inc/classes/menu.class.php'; + $menu_class = new Menu(); + $menu_class->Generate(); + echo '

Done!

Installation has finished! The default administrator account is admin with the password of admin.

Delete this and the install-mysql.php file from the server, then add some boards!'; + echo '


DELETE THIS AND install-mysql.php RIGHT NOW!

'; + } else { + echo 'Error inserting SQL. Please add $tc_db->debug = true; just before ?> in config.php to turn on debugging, and check the error message.'; + } + } else { + echo 'Please enter a random string into the KU_RANDOMSEED value.'; + } +} else { + echo 'Unable to locate config.php'; +} +?> + + + diff --git a/OTHER/kusaba_freshinstall.mysql.sql b/OTHER/kusaba_freshinstall.mysql.sql new file mode 100644 index 0000000..fc34a1e --- /dev/null +++ b/OTHER/kusaba_freshinstall.mysql.sql @@ -0,0 +1,371 @@ +-- -------------------------------------------------------- + +-- +-- Table structure for table `ads` +-- + +CREATE TABLE `PREFIX_ads` ( + `id` smallint(1) unsigned NOT NULL, + `position` varchar(3) NOT NULL, + `disp` tinyint(1) NOT NULL, + `boards` varchar(255) NOT NULL, + `code` text NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `announcements` +-- + +CREATE TABLE `PREFIX_announcements` ( + `id` int(10) unsigned NOT NULL auto_increment, + `parentid` int(10) unsigned NOT NULL default '0', + `subject` varchar(255) NOT NULL, + `postedat` int(20) NOT NULL, + `postedby` varchar(75) NOT NULL, + `message` text NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `banlist` +-- + +CREATE TABLE `PREFIX_banlist` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `type` tinyint(1) NOT NULL default '0', + `expired` tinyint(1) NOT NULL default '0', + `allowread` tinyint(1) NOT NULL default '1', + `ip` varchar(50) NOT NULL, + `ipmd5` char(32) NOT NULL, + `globalban` tinyint(1) NOT NULL default '0', + `boards` varchar(255) NOT NULL, + `by` varchar(75) NOT NULL, + `at` int(20) NOT NULL, + `until` int(20) NOT NULL, + `reason` text NOT NULL, + `staffnote` text NOT NULL, + `appeal` text, + `appealat` int(20) NOT NULL default '0', + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `bannedhashes` +-- + +CREATE TABLE `PREFIX_bannedhashes` ( + `id` int(10) NOT NULL auto_increment, + `md5` varchar(255) NOT NULL, + `bantime` int(10) NOT NULL default '0', + `description` text NOT NULL, + UNIQUE KEY `id` (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `blotter` +-- + +CREATE TABLE `PREFIX_blotter` ( + `id` smallint(5) unsigned NOT NULL auto_increment, + `important` tinyint(1) NOT NULL, + `at` int(20) NOT NULL, + `message` text NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `boards` +-- + +CREATE TABLE `PREFIX_boards` ( + `id` smallint(5) unsigned NOT NULL auto_increment, + `order` tinyint(5) NOT NULL default '0', + `name` varchar(75) collate utf8_unicode_ci NOT NULL default '', + `type` tinyint(1) NOT NULL default '0', + `start` int(10) UNSIGNED NOT NULL , + `uploadtype` tinyint(1) NOT NULL default '0', + `desc` varchar(75) collate utf8_unicode_ci NOT NULL default '', + `image` varchar(255) collate utf8_unicode_ci NOT NULL, + `section` tinyint(2) NOT NULL default '0', + `maximagesize` int(20) NOT NULL default '1024000', + `maxpages` int(20) NOT NULL default '11', + `maxage` int(20) NOT NULL default '0', + `markpage` tinyint(4) NOT NULL default '9', + `maxreplies` int(5) NOT NULL default '200', + `messagelength` int(10) NOT NULL default '8192', + `createdon` int(20) NOT NULL, + `locked` tinyint(1) NOT NULL default '0', + `includeheader` text collate utf8_unicode_ci NOT NULL, + `redirecttothread` tinyint(1) NOT NULL default '0', + `anonymous` varchar(255) collate utf8_unicode_ci NOT NULL default 'Anonymous', + `forcedanon` tinyint(1) NOT NULL default '0', + `embeds_allowed` varchar(255) NOT NULL default '', + `trial` tinyint(1) NOT NULL default '0', + `popular` tinyint(1) NOT NULL default '0', + `defaultstyle` varchar(50) character set latin1 NOT NULL default '', + `locale` varchar(30) character set latin1 NOT NULL default '', + `showid` tinyint(1) NOT NULL default '0', + `compactlist` tinyint(1) NOT NULL default '0', + `enablereporting` tinyint(1) NOT NULL default '1', + `enablecaptcha` tinyint(1) NOT NULL default '0', + `enablenofile` tinyint(1) NOT NULL default '0', + `enablearchiving` tinyint(1) NOT NULL default '0', + `enablecatalog` tinyint(1) NOT NULL default '1', + `loadbalanceurl` varchar(255) character set latin1 NOT NULL default '', + `loadbalancepassword` varchar(255) character set latin1 NOT NULL default '', + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `board_filetypes` +-- + +CREATE TABLE `PREFIX_board_filetypes` ( + `boardid` tinyint(5) NOT NULL default '0', + `typeid` mediumint(5) NOT NULL default '0' +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `embeds` +-- + +CREATE TABLE `PREFIX_embeds` ( + `id` tinyint(5) unsigned NOT NULL auto_increment, + `filetype` varchar(3) NOT NULL, + `name` varchar(255) NOT NULL, + `videourl` varchar(510) NOT NULL, + `width` tinyint(3) unsigned NOT NULL, + `height` tinyint(3) unsigned NOT NULL, + `code` text NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `events` +-- + +CREATE TABLE `PREFIX_events` ( + `name` varchar(255) NOT NULL, + `at` int(20) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `filetypes` +-- + +CREATE TABLE `PREFIX_filetypes` ( + `id` smallint(5) unsigned NOT NULL auto_increment, + `filetype` varchar(255) NOT NULL, + `mime` varchar(255) NOT NULL default '', + `image` varchar(255) NOT NULL default '', + `image_w` int(7) NOT NULL default '0', + `image_h` int(7) NOT NULL default '0', + `force_thumb` int(1) NOT NULL default '1', + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `front` +-- + +CREATE TABLE `PREFIX_front` ( + `id` smallint(5) unsigned NOT NULL auto_increment, + `page` smallint(1) unsigned NOT NULL default '0', + `order` smallint(5) unsigned NOT NULL default '0', + `subject` varchar(255) NOT NULL, + `message` text NOT NULL, + `timestamp` int(20) NOT NULL default '0', + `poster` varchar(75) NOT NULL, + `email` varchar(255) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `loginattempts` +-- + +CREATE TABLE `PREFIX_loginattempts` ( + `username` varchar(255) NOT NULL, + `ip` varchar(20) NOT NULL, + `timestamp` int(20) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `modlog` +-- + +CREATE TABLE `PREFIX_modlog` ( + `entry` text NOT NULL, + `user` varchar(255) NOT NULL, + `category` tinyint(2) NOT NULL default '0', + `timestamp` int(20) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `module_settings` +-- + +CREATE TABLE `PREFIX_module_settings` ( + `module` varchar(255) NOT NULL, + `key` varchar(255) NOT NULL, + `value` text character set utf8 collate utf8_unicode_ci NOT NULL, + `type` varchar(255) NOT NULL default 'string' +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `posts` +-- + +CREATE TABLE `PREFIX_posts` ( + `id` int(10) unsigned NOT NULL auto_increment, + `boardid` smallint(5) unsigned NOT NULL, + `parentid` int(10) unsigned NOT NULL default '0', + `name` varchar(255) NOT NULL, + `tripcode` varchar(30) NOT NULL, + `email` varchar(255) NOT NULL, + `subject` varchar(255) NOT NULL, + `message` text NOT NULL, + `password` varchar(255) NOT NULL, + `file` varchar(50) NOT NULL, + `file_md5` char(32) NOT NULL, + `file_type` varchar(20) NOT NULL, + `file_original` varchar(255) NOT NULL, + `file_size` int(20) NOT NULL default '0', + `file_size_formatted` varchar(75) NOT NULL, + `image_w` smallint(5) NOT NULL default '0', + `image_h` smallint(5) NOT NULL default '0', + `thumb_w` smallint(5) unsigned NOT NULL default '0', + `thumb_h` smallint(5) unsigned NOT NULL default '0', + `ip` varchar(75) NOT NULL, + `ipmd5` char(32) NOT NULL, + `tag` varchar(5) NOT NULL, + `timestamp` int(20) unsigned NOT NULL, + `stickied` tinyint(1) NOT NULL default '0', + `locked` tinyint(1) NOT NULL default '0', + `posterauthority` tinyint(1) NOT NULL default '0', + `reviewed` tinyint(1) unsigned NOT NULL default '0', + `deleted_timestamp` int(20) NOT NULL default '0', + `IS_DELETED` tinyint(1) NOT NULL default '0', + `bumped` int(20) unsigned NOT NULL default '0', + PRIMARY KEY (`boardid`,`id`), + KEY `parentid` (`parentid`), + KEY `bumped` (`bumped`), + KEY `file_md5` (`file_md5`), + KEY `stickied` (`stickied`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `reports` +-- + +CREATE TABLE `PREFIX_reports` ( + `id` smallint(5) unsigned NOT NULL auto_increment, + `cleared` tinyint(1) NOT NULL default '0', + `board` varchar(255) NOT NULL, + `postid` int(20) NOT NULL, + `when` int(20) NOT NULL, + `ip` varchar(75) NOT NULL, + `reason` varchar(255) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `sections` +-- + +CREATE TABLE `PREFIX_sections` ( + `id` smallint(5) unsigned NOT NULL auto_increment, + `order` tinyint(3) NOT NULL default '0', + `hidden` tinyint(1) NOT NULL default '0', + `name` varchar(255) NOT NULL default '0', + `abbreviation` varchar(10) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `staff` +-- + +CREATE TABLE `PREFIX_staff` ( + `id` smallint(5) unsigned NOT NULL auto_increment, + `username` varchar(255) NOT NULL, + `password` varchar(255) NOT NULL, + `salt` varchar(3) NOT NULL, + `type` tinyint(1) NOT NULL default '0', + `boards` text, + `addedon` int(20) NOT NULL, + `lastactive` int(20) NOT NULL default '0', + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `watchedthreads` +-- + +CREATE TABLE `PREFIX_watchedthreads` ( + `id` mediumint(8) unsigned NOT NULL auto_increment, + `threadid` int(20) NOT NULL, + `board` varchar(255) NOT NULL, + `ip` char(15) NOT NULL, + `lastsawreplyid` int(20) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `wordfilter` +-- + +CREATE TABLE `PREFIX_wordfilter` ( + `id` smallint(5) unsigned NOT NULL auto_increment, + `word` varchar(75) NOT NULL, + `replacedby` varchar(75) NOT NULL, + `boards` text NOT NULL, + `time` int(20) NOT NULL, + `regex` tinyint(1) NOT NULL default '0', + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + + + +INSERT INTO `PREFIX_ads` (`id`, `position`, `disp`, `boards`, `code`) VALUES (1, 'top', 0, '', 'Right Frame Top'), (2, 'bot', 0, '', 'Right Frame Bottom'); +INSERT INTO `PREFIX_filetypes` (`filetype`, `force_thumb`) VALUES ('jpg', 0), ('gif', 0), ('png', 0) ; +INSERT INTO `PREFIX_events` (`name`, `at`) VALUES ('pingback', 0), ('sitemap', 0); +INSERT INTO `PREFIX_embeds` (`filetype`, `name`, `videourl`, `width`, `height`, `code`) VALUES ('you', 'Youtube', 'http://www.youtube.com/watch?v=', 200, 164, ' '), ('goo', 'Google', 'http://video.google.com/videoplay?docid=', 200, 164, '') ; \ No newline at end of file diff --git a/OTHER/kusaba_freshinstall.postgres.sql b/OTHER/kusaba_freshinstall.postgres.sql new file mode 100644 index 0000000..003b1ef --- /dev/null +++ b/OTHER/kusaba_freshinstall.postgres.sql @@ -0,0 +1,386 @@ +-- -------------------------------------------------------- + +-- +-- Table structure for table ads +-- + +CREATE TABLE PREFIX_ads ( + id smallint NOT NULL, + position varchar(3) NOT NULL, + disp smallint NOT NULL, + boards varchar(255) NOT NULL, + code text NOT NULL +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table announcements +-- + +CREATE TABLE PREFIX_announcements ( + id serial, + parentid int NOT NULL default '0', + subject varchar(255) NOT NULL, + postedat int NOT NULL, + postedby varchar(75) NOT NULL, + message text NOT NULL, + PRIMARY KEY (id) +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table banlist +-- + +CREATE TABLE PREFIX_banlist ( + id serial, + type smallint NOT NULL default '0', + expired smallint NOT NULL default '0', + allowread smallint NOT NULL default '1', + ip varchar(50) NOT NULL, + ipmd5 char(32) NOT NULL, + globalban smallint NOT NULL default '0', + boards varchar(255) NOT NULL, + by varchar(75) NOT NULL, + at int NOT NULL, + until int NOT NULL, + reason text NOT NULL, + staffnote text NOT NULL, + appeal text NOT NULL default '', + appealat int NOT NULL default'0', + PRIMARY KEY (id) +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table bannedhashes +-- + +CREATE TABLE PREFIX_bannedhashes ( + id serial, + md5 varchar(255) NOT NULL, + bantime int, + description text NOT NULL, + UNIQUE (id) +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table blotter +-- + +CREATE TABLE PREFIX_blotter ( + id serial, + important smallint NOT NULL, + at int NOT NULL, + message text NOT NULL, + PRIMARY KEY (id) +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table boards +-- + +CREATE TABLE PREFIX_boards ( + id serial, + `order` smallint, + name varchar(75) NOT NULL default '', + type smallint NOT NULL default '0', + start int NOT NULL, + uploadtype smallint, + `desc` varchar(75) NOT NULL default '', + image varchar(255) NOT NULL, + section smallint NOT NULL default '0', + maximagesize int NOT NULL default '1024000', + maxpages int NOT NULL default '11', + maxage int NOT NULL default '0', + markpage smallint NOT NULL default '9', + maxreplies int NOT NULL default '200', + messagelength int NOT NULL default '8192', + createdon int NOT NULL, + locked smallint NOT NULL default '0', + includeheader text NOT NULL default '', + redirecttothread smallint NOT NULL default '0', + anonymous varchar(255) NOT NULL default 'Anonymous', + forcedanon smallint NOT NULL default '0', + embeds_allowed varchar(255) NOT NULL default '', + trial smallint NOT NULL default '0', + popular smallint NOT NULL default '0', + defaultstyle varchar(50) NOT NULL default '', + locale varchar(30) NOT NULL default '', + showid smallint NOT NULL default '0', + compactlist smallint NOT NULL default '0', + enablereporting smallint NOT NULL default '1', + enablecaptcha smallint NOT NULL default '0', + enablenofile smallint NOT NULL default '0', + enablearchiving smallint NOT NULL default '0', + enablecatalog smallint NOT NULL default '1', + loadbalanceurl varchar(255) NOT NULL default '', + loadbalancepassword varchar(255) NOT NULL default '', + PRIMARY KEY (id) +); + +-- +-- Table structure for table board_filetypes +-- + +CREATE TABLE PREFIX_board_filetypes ( + boardid smallint NOT NULL default '0', + typeid int NOT NULL default '0' +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table embeds +-- + +CREATE TABLE PREFIX_embeds ( + id serial, + filetype varchar(3) NOT NULL, + name varchar(255) NOT NULL, + videourl varchar(510) NOT NULL, + width smallint NOT NULL, + height smallint NOT NULL, + code text NOT NULL, + PRIMARY KEY (id) +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table events +-- + +CREATE TABLE PREFIX_events ( + name varchar(255) NOT NULL, + at int NOT NULL +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table filetypes +-- + +CREATE TABLE PREFIX_filetypes ( + id serial, + filetype varchar(255) NOT NULL, + mime varchar(255) NOT NULL default '', + image varchar(255) NOT NULL default '', + image_w int NOT NULL default '0', + image_h int NOT NULL default '0', + force_thumb int NOT NULL default '1', + PRIMARY KEY (id) +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table front +-- + +CREATE TABLE PREFIX_front ( + id serial, + page smallint NOT NULL default '0', + `order` smallint NOT NULL default '0', + subject varchar(255) NOT NULL, + message text NOT NULL, + timestamp int NOT NULL default '0', + poster varchar(75) NOT NULL default '', + email varchar(255) NOT NULL default '', + PRIMARY KEY (id) +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table loginattempts +-- + +CREATE TABLE PREFIX_loginattempts ( + username varchar(255) NOT NULL, + ip varchar(20) NOT NULL, + timestamp int NOT NULL +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table modlog +-- + +CREATE TABLE PREFIX_modlog ( + entry text NOT NULL, + `user` varchar(255) NOT NULL, + category smallint NOT NULL default '0', + timestamp int NOT NULL +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table module_settings +-- + +CREATE TABLE PREFIX_module_settings ( + module varchar(255) NOT NULL, + key varchar(255) NOT NULL, + value text NOT NULL, + type varchar(255) NOT NULL default 'string' +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table posts +-- + +CREATE TABLE PREFIX_posts ( + id int NOT NULL, + boardid smallint NOT NULL, + parentid int NOT NULL default '0', + name varchar(255) NOT NULL, + tripcode varchar(30) NOT NULL, + email varchar(255) NOT NULL, + subject varchar(255) NOT NULL, + message text NOT NULL, + password varchar(255) NOT NULL, + file varchar(50) NOT NULL, + file_md5 char(32) NOT NULL, + file_type varchar(20) NOT NULL, + file_original varchar(255) NOT NULL, + file_size int NOT NULL default '0', + file_size_formatted varchar(75) NOT NULL, + image_w smallint NOT NULL default '0', + image_h smallint NOT NULL default '0', + thumb_w smallint NOT NULL default '0', + thumb_h smallint NOT NULL default '0', + ip varchar(75) NOT NULL, + ipmd5 char(32) NOT NULL, + tag varchar(5) NOT NULL, + timestamp int NOT NULL, + stickied smallint NOT NULL default '0', + locked smallint NOT NULL default '0', + posterauthority smallint NOT NULL default '0', + reviewed smallint NOT NULL default '0', + deleted_timestamp int NOT NULL default '0', + IS_DELETED smallint NOT NULL default '0', + bumped int NOT NULL default '0', + PRIMARY KEY (boardid, id) +); + CREATE OR REPLACE FUNCTION posts_update() + RETURNS "trigger" AS + ' + BEGIN + PERFORM id FROM PREFIX_boards WHERE id = NEW.boardid FOR UPDATE:semicolon: + SELECT COALESCE(MAX(id),0) + 1 INTO NEW.id FROM PREFIX_posts WHERE boardid = NEW.boardid:semicolon: RETURN NEW:semicolon: + END + ' + LANGUAGE 'plpgsql'; + CREATE TRIGGER posts_trigger BEFORE INSERT on PREFIX_posts FOR EACH ROW EXECUTE PROCEDURE posts_update(); + CREATE INDEX parentid ON PREFIX_posts (parentid); + CREATE INDEX bumped ON PREFIX_posts (bumped); + CREATE INDEX file_md5 On PREFIX_posts (file_md5); + CREATE INDEX stickied ON PREFIX_posts (stickied); + +-- -------------------------------------------------------- + +-- +-- Table structure for table reports +-- + +CREATE TABLE PREFIX_reports ( + id serial, + cleared smallint NOT NULL default '0', + board varchar(255) NOT NULL, + postid int NOT NULL, + `when` int NOT NULL, + ip varchar(75) NOT NULL, + reason varchar(255) NOT NULL, + PRIMARY KEY (id) +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table sections +-- + +CREATE TABLE PREFIX_sections ( + id serial, + `order` smallint, + hidden smallint NOT NULL default '0', + name varchar(255) NOT NULL NOT NULL default '0', + abbreviation varchar(10) NOT NULL, + PRIMARY KEY (id) +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table staff +-- + +CREATE TABLE PREFIX_staff ( + id serial, + username varchar(255) NOT NULL, + password varchar(255) NOT NULL, + salt varchar(3) NOT NULL, + type smallint NOT NULL default '0', + boards text, + addedon int NOT NULL, + lastactive int NOT NULL default '0', + PRIMARY KEY (id) +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table watchedthreads +-- + +CREATE TABLE PREFIX_watchedthreads ( + id serial, + threadid int NOT NULL, + board varchar(255) NOT NULL, + ip char(15) NOT NULL, + lastsawreplyid int NOT NULL, + PRIMARY KEY (id) +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table wordfilter +-- + +CREATE TABLE PREFIX_wordfilter ( + id serial, + word varchar(75) NOT NULL, + replacedby varchar(75) NOT NULL, + boards text NOT NULL, + time int NOT NULL, + regex smallint NOT NULL default '0', + PRIMARY KEY (id) +); + + +CREATE OR REPLACE FUNCTION "if"(boolean, integer, integer) RETURNS integer AS + 'SELECT CASE WHEN $1 THEN $2 ELSE $3 END:semicolon:' + LANGUAGE 'sql'; +INSERT INTO `PREFIX_ads` (`id`, `position`, `disp`, `boards`, `code`) VALUES (1, 'top', 0, '', 'Right Frame Top'); +INSERT INTO `PREFIX_ads` (`id`, `position`, `disp`, `boards`, `code`) VALUES (2, 'bot', 0, '', 'Right Frame Bottom'); +INSERT INTO `PREFIX_filetypes` (`filetype`, `force_thumb`) VALUES ('jpg', 0); +INSERT INTO `PREFIX_filetypes` (`filetype`, `force_thumb`) VALUES ('gif', 0); +INSERT INTO `PREFIX_filetypes` (`filetype`, `force_thumb`) VALUES ('png', 0) ; +INSERT INTO `PREFIX_events` (`name`, `at`) VALUES ('pingback', 0); +INSERT INTO `PREFIX_events` (`name`, `at`) VALUES ('sitemap', 0); +INSERT INTO `PREFIX_embeds` (`filetype`, `name`, `videourl`, `width`, `height`, `code`) VALUES ('you', 'Youtube', 'http://www.youtube.com/watch?v=', 200, 164, ' '); +INSERT INTO `PREFIX_embeds` (`filetype`, `name`, `videourl`, `width`, `height`, `code`) VALUES ('goo', 'Google', 'http://video.google.com/videoplay?docid=', 200, 164, ''); diff --git a/OTHER/kusaba_freshinstall.sqlite.sql b/OTHER/kusaba_freshinstall.sqlite.sql new file mode 100644 index 0000000..fb24475 --- /dev/null +++ b/OTHER/kusaba_freshinstall.sqlite.sql @@ -0,0 +1,376 @@ +-- -------------------------------------------------------- + +-- +-- Table structure for table ads +-- + +CREATE TABLE PREFIX_ads ( + id smallint NOT NULL, + position varchar(3) NOT NULL, + disp smallint NOT NULL, + boards varchar(255) NOT NULL, + code text NOT NULL +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table announcements +-- + +CREATE TABLE PREFIX_announcements ( + id INTEGER PRIMARY KEY, + parentid int NOT NULL default '0', + subject varchar(255) NOT NULL, + postedat int NOT NULL, + postedby varchar(75) NOT NULL, + message text NOT NULL + +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table banlist +-- + +CREATE TABLE PREFIX_banlist ( + id INTEGER PRIMARY KEY, + type smallint NOT NULL default '0', + expired smallint NOT NULL default '0', + allowread smallint NOT NULL default '1', + ip varchar(50) NOT NULL, + ipmd5 char(32) NOT NULL, + globalban smallint NOT NULL default '0', + boards varchar(255) NOT NULL, + `by` varchar(75) NOT NULL, + at int NOT NULL, + until int NOT NULL, + reason text NOT NULL, + staffnote text NOT NULL, + appeal text NOT NULL default '', + appealat int NOT NULL default '0' + +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table bannedhashes +-- + +CREATE TABLE PREFIX_bannedhashes ( + id INTEGER PRIMARY KEY, + md5 varchar(255) NOT NULL, + bantime int, + description text NOT NULL, + UNIQUE (id) +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table blotter +-- + +CREATE TABLE PREFIX_blotter ( + id INTEGER PRIMARY KEY, + important smallint NOT NULL, + at int NOT NULL, + message text NOT NULL + +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table boards +-- + +CREATE TABLE PREFIX_boards ( + id INTEGER PRIMARY KEY, + `order` smallint, + name varchar(75) NOT NULL default '', + type smallint NOT NULL default '0', + start int NOT NULL, + uploadtype smallint, + `desc` varchar(75) NOT NULL default '', + image varchar(255) NOT NULL, + section smallint NOT NULL default '0', + maximagesize int NOT NULL default '1024000', + maxpages int NOT NULL default '11', + maxage int NOT NULL default '0', + markpage smallint NOT NULL default '9', + maxreplies int NOT NULL default '200', + messagelength int NOT NULL default '8192', + createdon int NOT NULL, + locked smallint NOT NULL default '0', + includeheader text NOT NULL default '', + redirecttothread smallint NOT NULL default '0', + anonymous varchar(255) NOT NULL default 'Anonymous', + forcedanon smallint NOT NULL default '0', + embeds_allowed varchar(255) NOT NULL default '', + trial smallint NOT NULL default '0', + popular smallint NOT NULL default '0', + defaultstyle varchar(50) NOT NULL default '', + locale varchar(30) NOT NULL default '', + showid smallint NOT NULL default '0', + compactlist smallint NOT NULL default '0', + enablereporting smallint NOT NULL default '1', + enablecaptcha smallint NOT NULL default '0', + enablenofile smallint NOT NULL default '0', + enablearchiving smallint NOT NULL default '0', + enablecatalog smallint NOT NULL default '1', + loadbalanceurl varchar(255) NOT NULL default '', + loadbalancepassword varchar(255) NOT NULL default '' + +); + +-- +-- Table structure for table board_filetypes +-- + +CREATE TABLE PREFIX_board_filetypes ( + boardid smallint NOT NULL default '0', + typeid int NOT NULL default '0' +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table embeds +-- + +CREATE TABLE PREFIX_embeds ( + id INTEGER PRIMARY KEY, + filetype varchar(3) NOT NULL, + name varchar(255) NOT NULL, + videourl varchar(510) NOT NULL, + width smallint NOT NULL, + height smallint NOT NULL, + code text NOT NULL +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table events +-- + +CREATE TABLE PREFIX_events ( + name varchar(255) NOT NULL, + at int NOT NULL +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table filetypes +-- + +CREATE TABLE PREFIX_filetypes ( + id INTEGER PRIMARY KEY, + filetype varchar(255) NOT NULL, + mime varchar(255) NOT NULL default '', + image varchar(255) NOT NULL default '', + image_w int NOT NULL default '0', + image_h int NOT NULL default '0', + force_thumb int NOT NULL default '1' + +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table front +-- + +CREATE TABLE PREFIX_front ( + id INTEGER PRIMARY KEY, + page smallint NOT NULL default '0', + `order` smallint NOT NULL default '0', + subject varchar(255) NOT NULL, + message text NOT NULL, + timestamp int NOT NULL DEFAULT '0', + poster varchar(75) NOT NULL DEFAULT '', + email varchar(255) NOT NULL DEFAULT '' + +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table loginattempts +-- + +CREATE TABLE PREFIX_loginattempts ( + username varchar(255) NOT NULL, + ip varchar(20) NOT NULL, + timestamp int NOT NULL +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table modlog +-- + +CREATE TABLE PREFIX_modlog ( + entry text NOT NULL, + `user` varchar(255) NOT NULL, + category smallint NOT NULL default '0', + timestamp int NOT NULL +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table module_settings +-- + +CREATE TABLE PREFIX_module_settings ( + module varchar(255) NOT NULL, + key varchar(255) NOT NULL, + value text NOT NULL, + type varchar(255) NOT NULL default 'string' +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table posts +-- + +CREATE TABLE PREFIX_posts ( + id int default '0' , + boardid smallint NOT NULL, + parentid int NOT NULL default '0', + name varchar(255) NOT NULL, + tripcode varchar(30) NOT NULL, + email varchar(255) NOT NULL, + subject varchar(255) NOT NULL, + message text NOT NULL, + password varchar(255) NOT NULL, + file varchar(50) NOT NULL, + file_md5 char(32) NOT NULL, + file_type varchar(20) NOT NULL, + file_original varchar(255) NOT NULL, + file_size int NOT NULL default '0', + file_size_formatted varchar(75) NOT NULL, + image_w smallint NOT NULL default '0', + image_h smallint NOT NULL default '0', + thumb_w smallint NOT NULL default '0', + thumb_h smallint NOT NULL default '0', + ip varchar(75) NOT NULL, + ipmd5 char(32) NOT NULL, + tag varchar(5) NOT NULL, + timestamp int NOT NULL, + stickied smallint NOT NULL default '0', + locked smallint NOT NULL default '0', + posterauthority smallint NOT NULL default '0', + reviewed smallint NOT NULL default '0', + deleted_timestamp int NOT NULL default '0', + IS_DELETED smallint NOT NULL default '0', + bumped int NOT NULL default '0', + PRIMARY KEY (boardid, id) +); + CREATE TRIGGER posts_trigger AFTER INSERT on PREFIX_posts + BEGIN + UPDATE PREFIX_posts SET id = (SELECT COALESCE(MAX(id),0) + 1 FROM PREFIX_posts WHERE boardid = NEW.boardid) WHERE rowid = last_insert_rowid():semicolon: + END; + CREATE INDEX parentid ON PREFIX_posts (parentid); + CREATE INDEX bumped ON PREFIX_posts (bumped); + CREATE INDEX file_md5 On PREFIX_posts (file_md5); + CREATE INDEX stickied ON PREFIX_posts (stickied); + +-- -------------------------------------------------------- + +-- +-- Table structure for table reports +-- + +CREATE TABLE PREFIX_reports ( + id INTEGER PRIMARY KEY, + cleared smallint NOT NULL default '0', + board varchar(255) NOT NULL, + postid int NOT NULL, + `when` int NOT NULL, + ip varchar(75) NOT NULL, + reason varchar(255) NOT NULL + +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table sections +-- + +CREATE TABLE PREFIX_sections ( + id INTEGER PRIMARY KEY, + `order` smallint, + hidden smallint NOT NULL default '0', + name varchar(255) NOT NULL NOT NULL default '0', + abbreviation varchar(10) NOT NULL + +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table staff +-- + +CREATE TABLE PREFIX_staff ( + id INTEGER PRIMARY KEY, + username varchar(255) NOT NULL, + password varchar(255) NOT NULL, + salt varchar(3) NOT NULL, + type smallint NOT NULL default '0', + boards text, + addedon int NOT NULL, + lastactive int NOT NULL default '0' + +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table watchedthreads +-- + +CREATE TABLE PREFIX_watchedthreads ( + id INTEGER PRIMARY KEY, + threadid int NOT NULL, + board varchar(255) NOT NULL, + ip char(15) NOT NULL, + lastsawreplyid int NOT NULL + +); + +-- -------------------------------------------------------- + +-- +-- Table structure for table wordfilter +-- + +CREATE TABLE PREFIX_wordfilter ( + id INTEGER PRIMARY KEY, + word varchar(75) NOT NULL, + replacedby varchar(75) NOT NULL, + boards text NOT NULL, + time int NOT NULL, + regex smallint NOT NULL default '0' + +); + + +INSERT INTO `PREFIX_ads` (`id`, `position`, `disp`, `boards`, `code`) VALUES (1, 'top', 0, '', 'Right Frame Top'); +INSERT INTO `PREFIX_ads` (`id`, `position`, `disp`, `boards`, `code`) VALUES (2, 'bot', 0, '', 'Right Frame Bottom'); +INSERT INTO `PREFIX_filetypes` (`filetype`, `force_thumb`) VALUES ('jpg', 0); +INSERT INTO `PREFIX_filetypes` (`filetype`, `force_thumb`) VALUES ('gif', 0); +INSERT INTO `PREFIX_filetypes` (`filetype`, `force_thumb`) VALUES ('png', 0) ; +INSERT INTO `PREFIX_events` (`name`, `at`) VALUES ('pingback', 0); +INSERT INTO `PREFIX_events` (`name`, `at`) VALUES ('sitemap', 0); +INSERT INTO `PREFIX_embeds` (`filetype`, `name`, `videourl`, `width`, `height`, `code`) VALUES ('you', 'Youtube', 'http://www.youtube.com/watch?v=', 200, 164, ' '); +INSERT INTO `PREFIX_embeds` (`filetype`, `name`, `videourl`, `width`, `height`, `code`) VALUES ('goo', 'Google', 'http://video.google.com/videoplay?docid=', 200, 164, ''); diff --git a/OTHER/kusabax_updatemysql.sql b/OTHER/kusabax_updatemysql.sql new file mode 100644 index 0000000..eaa4c05 --- /dev/null +++ b/OTHER/kusabax_updatemysql.sql @@ -0,0 +1,50 @@ +CREATE TABLE IF NOT EXISTS `PREFIX_front` ( + `id` smallint(5) unsigned NOT NULL auto_increment, + `page` smallint(1) unsigned NOT NULL default '0', + `order` smallint(5) unsigned NOT NULL default '0', + `subject` varchar(255) NOT NULL, + `message` text NOT NULL, + `timestamp` int(20) NOT NULL, + `poster` varchar(75) NOT NULL, + `email` varchar(255) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `PREFIX_posts` ( + `id` int(10) unsigned NOT NULL auto_increment, + `boardid` smallint(5) unsigned NOT NULL, + `parentid` int(10) unsigned NOT NULL default '0', + `name` varchar(255) NOT NULL, + `tripcode` varchar(30) NOT NULL, + `email` varchar(255) NOT NULL, + `subject` varchar(255) NOT NULL, + `message` text NOT NULL, + `password` varchar(255) NOT NULL, + `file` varchar(50) NOT NULL, + `file_md5` char(32) NOT NULL, + `file_type` varchar(20) NOT NULL, + `file_original` varchar(255) NOT NULL, + `file_size` int(20) NOT NULL default '0', + `file_size_formatted` varchar(75) NOT NULL, + `image_w` smallint(5) NOT NULL default '0', + `image_h` smallint(5) NOT NULL default '0', + `thumb_w` smallint(5) unsigned NOT NULL default '0', + `thumb_h` smallint(5) unsigned NOT NULL default '0', + `ip` varchar(75) NOT NULL, + `ipmd5` char(32) NOT NULL, + `tag` varchar(5) NOT NULL, + `timestamp_formatted` varchar(50) NOT NULL, + `timestamp` int(20) unsigned NOT NULL, + `stickied` tinyint(1) NOT NULL default '0', + `locked` tinyint(1) NOT NULL default '0', + `posterauthority` tinyint(1) NOT NULL default '0', + `reviewed` tinyint(1) unsigned NOT NULL default '0', + `deleted_timestamp` int(20) NOT NULL default '0', + `IS_DELETED` tinyint(1) NOT NULL default '0', + `bumped` int(20) unsigned NOT NULL default '0', + PRIMARY KEY (`boardid`,`id`), + KEY `parentid` (`parentid`), + KEY `bumped` (`bumped`), + KEY `file_md5` (`file_md5`), + KEY `stickied` (`stickied`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; \ No newline at end of file diff --git a/OTHER/load_receiver.php b/OTHER/load_receiver.php new file mode 100644 index 0000000..ef2a476 --- /dev/null +++ b/OTHER/load_receiver.php @@ -0,0 +1,192 @@ + KU_THUMBWIDTH || $imgh > KU_THUMBHEIGHT)) || ($_POST['isreply'] == '1' && ($imgw > KU_REPLYTHUMBWIDTH || $imgh > KU_REPLYTHUMBHEIGHT))) { + if ($_POST['isreply'] == '0') { + if (!@createThumbnail($target_file, $target_thumb, KU_THUMBWIDTH, KU_THUMBHEIGHT)) { + @unlink($target_file); + die('unable to thumbnail'); + } + } else { + if (!@createThumbnail($target_file, $target_thumb, KU_REPLYTHUMBWIDTH, KU_REPLYTHUMBHEIGHT)) { + @unlink($target_file); + die('unable to thumbnail'); + } + } + } else { + if (!@createThumbnail($target_file, $target_thumb, $imgw, $imgh)) { + @unlink($target_file); + die('unable to thumbnail'); + } + } + if (!@createThumbnail($target_file, $target_thumb_catalog, KU_CATTHUMBWIDTH, KU_CATTHUMBHEIGHT)) { + @unlink($target_file); + die('unable to thumbnail'); + } + + $imageDim_thumb = getimagesize($target_thumb); + $imgw_thumb = $imageDim_thumb[0]; + $imgh_thumb = $imageDim_thumb[1]; + + die(serialize(array('imgw_thumb' => $imgw_thumb, 'imgh_thumb' => $imgh_thumb))); + } + + die('success'); + } +} elseif ($_POST['type'] == 'delete') { + unlink('src/' . $_POST['filename'] . '.' . $_POST['filetype']); + unlink('thumb/' . $_POST['filename'] . 's.' . $_POST['filetype']); + unlink('thumb/' . $_POST['filename'] . 'c.' . $_POST['filetype']); + + die("\n" . 'finished'); +} + +/** + * @ignore + */ +function createThumbnail($name, $filename, $new_w, $new_h) { + $system=explode(".", $filename); + $system = array_reverse($system); + if (preg_match("/jpg|jpeg/", $system[0])) { + $src_img=imagecreatefromjpeg($name); + } else if (preg_match("/png/", $system[0])) { + $src_img=imagecreatefrompng($name); + } else if (preg_match("/gif/", $system[0])) { + $src_img=imagecreatefromgif($name); + } else { + return false; + } + + if (!$src_img) { + echo '
Unable to open the uploaded image for thumbnailing. Maybe its a different filetype, and has the wrong extension?'; + return false; + } + $old_x=imageSX($src_img); + $old_y=imageSY($src_img); + if ($old_x > $old_y) { + $percent = $new_w / $old_x; + } else { + $percent = $new_h / $old_y; + } + $thumb_w = round($old_x * $percent); + $thumb_h = round($old_y * $percent); + + $dst_img=ImageCreateTrueColor($thumb_w, $thumb_h); + fastimagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $thumb_w, $thumb_h, $old_x, $old_y); + + if (preg_match("/png/", $system[0])) { + if (!imagepng($dst_img, $filename)) { + echo 'unable to imagepng.'; + return false; + } + } else if (preg_match("/jpg|jpeg/", $system[0])) { + if (!imagejpeg($dst_img, $filename, 70)) { + echo 'unable to imagejpg.'; + return false; + } + } else if (preg_match("/gif/", $system[0])) { + if (!imagegif($dst_img, $filename)) { + echo 'unable to imagegif.'; + return false; + } + } + + imagedestroy($dst_img); + imagedestroy($src_img); + + return true; +} + +/* Author: Tim Eckel - Date: 12/17/04 - Project: FreeRingers.net - Freely distributable. */ +/** + * @ignore + */ +function fastimagecopyresampled(&$dst_image, &$src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h, $quality = 3) { + /* + Optional "quality" parameter (defaults is 3). Fractional values are allowed, for example 1.5. + 1 = Up to 600 times faster. Poor results, just uses imagecopyresized but removes black edges. + 2 = Up to 95 times faster. Images may appear too sharp, some people may prefer it. + 3 = Up to 60 times faster. Will give high quality smooth results very close to imagecopyresampled. + 4 = Up to 25 times faster. Almost identical to imagecopyresampled for most images. + 5 = No speedup. Just uses imagecopyresampled, highest quality but no advantage over imagecopyresampled. + */ + + if (empty($src_image) || empty($dst_image)) { return false; } + + if ($quality <= 1) { + $temp = imagecreatetruecolor ($dst_w + 1, $dst_h + 1); + imagecopyresized ($temp, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w + 1, $dst_h + 1, $src_w, $src_h); + imagecopyresized ($dst_image, $temp, 0, 0, 0, 0, $dst_w, $dst_h, $dst_w, $dst_h); + imagedestroy ($temp); + } elseif ($quality < 5 && (($dst_w * $quality) < $src_w || ($dst_h * $quality) < $src_h)) { + + $tmp_w = $dst_w * $quality; + $tmp_h = $dst_h * $quality; + $temp = imagecreatetruecolor ($tmp_w + 1, $tmp_h + 1); + + imagecopyresized ($temp, $src_image, $dst_x * $quality, $dst_y * $quality, $src_x, $src_y, $tmp_w + 1, $tmp_h + 1, $src_w, $src_h); + + imagecopyresampled ($dst_image, $temp, 0, 0, 0, 0, $dst_w, $dst_h, $tmp_w, $tmp_h); + + imagedestroy ($temp); + + } else { + imagecopyresampled ($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h); + } + + + return true; +} + +/** + * @ignore + */ +function mime_content_type_custom($f) { + return trim(exec('file -bi ' . escapeshellarg ($f ))); +} + +?> \ No newline at end of file diff --git a/OTHER/s2kx.php b/OTHER/s2kx.php new file mode 100644 index 0000000..27e943b --- /dev/null +++ b/OTHER/s2kx.php @@ -0,0 +1,144 @@ + + + + + +MySQL Batch File Importing Script + + + + + +

MySQL Batch File Importing Script

+ +

+ + +WARNING!

+The purpose of this script is to quickly and easily run the commands contained within the kusaba SQL file, and is +to be used if you are installing the script for the first time or want to recreate the tables, for whatever reason.
+Running this script will delete any related tables and their data (including the admin files). I offer this script as-is and cannot be held +responsible for any damages caused or accidental loss of data incurred as a result of running this script.
+Before running this script, make sure that:
+
    +
  • -> You have set up the database connection and that it is working
  • +
  • -> You have created the database
  • +
  • -> You have created the database user and set up the config file appropriately
  • +
+
+
+ By clicking this check box I agree that the author of this script cannot be held responsible for my own stupidity if something goes wrong.


+ +
+ +".KU_DBPREFIX.$tablename." already exists in the database! Drop it, and re run this script."); + // } + //} + // Lets open the file for reading! :) + echo '

SQL Batch File Processing

'; + echo 'Locating \'s2kx.sql\'... '; + if (file_exists('s2kx.sql') && (filesize('s2kx.sql') > 0)) { + echo 'found.
'; + $sqlfile = fopen('s2kx.sql', 'r'); + echo 'File opened.
'; + $readdata = fread($sqlfile, filesize('s2kx.sql')); + $readdata = str_replace('PREFIX_',KU_DBPREFIX,$readdata); + fclose($sqlfile); + echo 'Contents read.
'; + }else{ + echo 'Error. '; + die('An error occured. s2kx.sql does not exist in this directory or it is 0 bytes big :( Barring that, do you have read permissions for the directory?'); + } + + $tc_db->Execute("ALTER DATABASE `" . KU_DBDATABASE . "` CHARACTER SET utf8 COLLATE utf8_general_ci"); + + // Explodes the array + $sqlarray = explode("\n", $readdata); + + // Loops through the array and deletes the non-SQL bits in the file, which is basically the '--' lines and the lines with no content + foreach ($sqlarray as $key => $sqldata) { + if (strstr($sqldata, '--') || strlen($sqldata) == 0){ + unset($sqlarray[$key]); + } + } + // Here we are imploding everything together again... + $readdata = implode('',$sqlarray); + + // ...then exploding it again. At this point we will have an array where each key's value is a one of the CREATE statements + $sqlarray = explode(';',$readdata); + echo 'File contents have been formatted for use with mysql_query.
'; + // Lets drop any existing tables in the database + $listoftables = $tc_db->GetAll("show tables from ".KU_DBDATABASE.""); + + echo '

Table Creation

'; + // Lets now loop through the array and create each table + foreach ($sqlarray as $sqldata) { + + if (strlen($sqldata) !== 0) { // As the array was exploded on ';', the last ';' caused a blank element to be created as there was no data after it :p + // The following three lines retrieve the table name of the table from the sql command. It's dynamic so it doesn't matter how many tables need to be created + // As long as each CREATE TABLE statement stays in the format CREATE TABLE `table` then this part will work. + $pos1 = strpos($sqldata, '`'); + $pos2 = strpos($sqldata, '`', $pos1 + 1); + $tablename = substr($sqldata, $pos1+1, ($pos2-$pos1)-1); + echo "Attempting to create table '$tablename'... "; + if($tc_db->Execute($sqldata)) { + echo "success.
"; + } else { + echo "failed. Enable debugging by setting KU_DEBUG to true to see this error.
"; + die ("Table creation failed. Please rerun this script again or attempt to fix the problem if you know how to solve it."); + } + } + } + // All done :) + echo '
SQL commands have finished. If all is well, proceed to the installation file but don\'t forget to delete this file!'; +} + +function mysql_table_exists($database, $tableName) +{ + global $tc_db; + $tables = array(); + $tablesResults = $tc_db->GetAll("SHOW TABLES FROM `$database`;"); + foreach ($tablesResults AS $row) $tables[] = $row[0]; + return(in_array($tableName, $tables)); +} + +?> + + \ No newline at end of file diff --git a/OTHER/s2kx.sql b/OTHER/s2kx.sql new file mode 100644 index 0000000..2bae9a2 --- /dev/null +++ b/OTHER/s2kx.sql @@ -0,0 +1,99 @@ +-- -------------------------------------------------------- + +-- +-- Drop tables not used in Kusaba X. +-- + +DROP TABLE `PREFIX_announcements`; +DROP TABLE `PREFIX_faptcha_attempts`; +DROP TABLE `PREFIX_spamfilter`; +DROP TABLE `PREFIX_menu`; +ALTER TABLE `PREFIX_boards` DROP enablefaptcha; +ALTER TABLE `PREFIX_boards` DROP enableporn; +ALTER TABLE `PREFIX_staff` DROP suspended; +ALTER TABLE `PREFIX_staff` DROP access; +ALTER TABLE `PREFIX_banlist` CHANGE `note` `staffnote` TEXT; + + + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ads` +-- + +CREATE TABLE `PREFIX_ads` ( + `id` smallint(1) unsigned NOT NULL, + `position` varchar(3) NOT NULL, + `disp` tinyint(1) NOT NULL, + `boards` varchar(255) NOT NULL, + `code` text NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `announcements` +-- + +CREATE TABLE `PREFIX_announcements` ( + `id` int(10) unsigned NOT NULL auto_increment, + `parentid` int(10) unsigned NOT NULL default '0', + `subject` varchar(255) NOT NULL, + `postedat` int(20) NOT NULL, + `postedby` varchar(75) NOT NULL, + `message` text NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `embeds` +-- + +CREATE TABLE `PREFIX_embeds` ( + `id` tinyint(5) unsigned NOT NULL auto_increment, + `filetype` varchar(3) NOT NULL, + `name` varchar(255) NOT NULL, + `videourl` varchar(510) NOT NULL, + `width` tinyint(3) unsigned NOT NULL, + `height` tinyint(3) unsigned NOT NULL, + `code` text NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `faq` +-- + +CREATE TABLE `PREFIX_faq` ( + `id` smallint(5) unsigned NOT NULL auto_increment, + `order` smallint(5) unsigned NOT NULL, + `heading` varchar(255) NOT NULL, + `message` text NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `rules` +-- + +CREATE TABLE `PREFIX_rules` ( + `id` smallint(5) unsigned NOT NULL auto_increment, + `order` smallint(5) unsigned NOT NULL, + `heading` varchar(255) NOT NULL, + `message` text NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +ALTER TABLE `PREFIX_boards` CHANGE `maxpages` `maxpages` INT( 20 ) NOT NULL DEFAULT '11'; +ALTER TABLE `PREFIX_boards` CHANGE `maxpages` `maxpages` INT( 20 ) NOT NULL DEFAULT '11'; +INSERT INTO `PREFIX_ads` (`id`, `position`, `disp`, `boards`, `code`) VALUES (1, 'top', 0, '', 'Right Frame Top'), (2, 'bot', 0, '', 'Right Frame Bottom'); +INSERT INTO `PREFIX_embeds` (`filetype`, `name`, `videourl`, `width`, `height`, `code`) VALUES ('you', 'Youtube', 'http://www.youtube.com/watch?v=', 200, 164, ' '), ('goo', 'Google', 'http://video.google.com/videoplay?docid=', 200, 164, '') ; \ No newline at end of file diff --git a/OTHER/update-mysql.php b/OTHER/update-mysql.php new file mode 100644 index 0000000..36c3af9 --- /dev/null +++ b/OTHER/update-mysql.php @@ -0,0 +1,251 @@ + + + + + +MySQL Batch File Importing Script + + + + + +

MySQL Batch File Importing Script

+ +

+ + +WARNING!

+The purpose of this script is to quickly and easily run the commands contained within the kusaba SQL file, and is +to be used if you are installing the script for the first time or want to recreate the tables, for whatever reason.
+Running this script will delete any related tables and their data (including the admin files). I offer this script as-is and cannot be held +responsible for any damages caused or accidental loss of data incurred as a result of running this script.
+Before running this script, make sure that:
+
    +
  • -> You have set up the database connection and that it is working
  • +
  • -> You have created the database
  • +
  • -> You have created the database user and set up the config file appropriately
  • +
+
+
+Uncheck this box to convert posts to a single table without deleting the old tables. The old tables will not be deleted after being converted, but will remain completely unused.


+Uncheck this box to convert FAQ, Rules, and News to a single table without deleting the old tables. The old tables will not be deleted after being converted, but will remain completely unused.


+
+ By clicking this check box I agree that the author of this script cannot be held responsible for my own stupidity if something goes wrong.


+ +
+ +".KU_DBPREFIX.$tablename." already exists in the database! Drop it, and re run this script."); + } + }*/ + // Lets open the file for reading! :) + echo '

SQL Batch File Processing

'; + echo 'Locating \'kusabax_updatemysql.sql\'... '; + if (file_exists('kusabax_updatemysql.sql') && (filesize('kusabax_updatemysql.sql') > 0)) { + echo 'found.
'; + $sqlfile = fopen('kusabax_updatemysql.sql', 'r'); + echo 'File opened.
'; + $readdata = fread($sqlfile, filesize('kusabax_updatemysql.sql')); + $readdata = str_replace('PREFIX_',KU_DBPREFIX,$readdata); + fclose($sqlfile); + echo 'Contents read.
'; + }else{ + echo 'Error. '; + die('An error occured. kusabax_updatemysql.sql does not exist in this directory or it is 0 bytes big :( Barring that, do you have read permissions for the directory?'); + } + + $tc_db->Execute("ALTER DATABASE `" . KU_DBDATABASE . "` CHARACTER SET utf8 COLLATE utf8_general_ci"); + + // Explodes the array + $sqlarray = explode("\n", $readdata); + + // Loops through the array and deletes the non-SQL bits in the file, which is basically the '--' lines and the lines with no content + foreach ($sqlarray as $key => $sqldata) { + if (strstr($sqldata, '--') || strlen($sqldata) == 0){ + unset($sqlarray[$key]); + } + } + // Here we are imploding everything together again... + $readdata = implode('',$sqlarray); + + // ...then exploding it again. At this point we will have an array where each key's value is a one of the CREATE statements + $sqlarray = explode(';',$readdata); + echo 'File contents have been formatted for use with mysql_query.
'; + // Lets drop any existing tables in the database + $listoftables = $tc_db->GetAll("show tables from ".KU_DBDATABASE.""); + + echo '

Table Creation

'; + // Lets now loop through the array and create each table + foreach ($sqlarray as $sqldata) { + + if (strlen($sqldata) !== 0) { // As the array was exploded on ';', the last ';' caused a blank element to be created as there was no data after it :p + // The following three lines retrieve the table name of the table from the sql command. It's dynamic so it doesn't matter how many tables need to be created + // As long as each CREATE TABLE statement stays in the format CREATE TABLE `table` then this part will work. + $pos1 = strpos($sqldata, '`'); + $pos2 = strpos($sqldata, '`', $pos1 + 1); + $tablename = substr($sqldata, $pos1+1, ($pos2-$pos1)-1); + echo "Attempting to create table '$tablename'... "; + if($tc_db->Execute($sqldata)) { + echo "success.
"; + } else { + echo "failed. Enable debugging by setting KU_DEBUG to true to see this error.
"; + die ("Table creation failed. Please rerun this script again or attempt to fix the problem if you know how to solve it."); + } + } + } + add_column_if_not_exist("boards", "start", "int(10) UNSIGNED AFTER `type`"); + add_column_if_not_exist("reports", "reason", "VARCHAR(255)"); + add_column_if_not_exist("staff", "salt", "VARCHAR(3) AFTER `password`"); + add_column_if_not_exist("banlist", "appeal", "TEXT"); + add_column_if_not_exist("banlist", "staffnote", "text NOT NULL"); + add_column_if_not_exist("banlist", "expired", "tinyint(1) NOT NULL default '0'"); + add_column_if_not_exist("boards", "embeds_allowed", "VARCHAR(255) NOT NULL DEFAULT '' AFTER `forcedanon`"); + echo "Attempting to convert posts..."; + db_conversion(); + echo "done
"; + front_db_conversion(); + // All done :) + echo '
SQL commands have finished. If all is well, proceed to the installation file but don\'t forget to delete this file!'; +} + +function mysql_table_exists($database, $tableName) +{ + global $tc_db; + $tables = array(); + $tablesResults = $tc_db->GetAll("SHOW TABLES FROM `$database`;"); + foreach ($tablesResults AS $row) $tables[] = $row[0]; + return(in_array($tableName, $tables)); +} + +function add_column_if_not_exist($tableName, $columnName, $column_attr = "VARCHAR( 255 ) NULL" ){ + global $tc_db; + $exists = false; + $columns = $tc_db->GetAll("SHOW COLUMNS FROM `".KU_DBPREFIX."$tableName"); + foreach ($columns as $column) { + if($column['Field'] == $columnName){ + $exists = true; + break; + } + } + if(!$exists){ + $tc_db->Execute("ALTER TABLE `".KU_DBPREFIX."$tableName` ADD `$columnName` $column_attr"); + } +} + + +function db_conversion() +{ + global $tc_db; + $resultsboard = $tc_db->GetAll("SELECT HIGH_PRIORITY `id`, `name` FROM `" . KU_DBPREFIX . "boards` ORDER BY `name` ASC"); + + foreach ($resultsboard as $lineboard) { + echo "Converting board /".$lineboard['name']."/..."; + $posts_table = KU_DBPREFIX.'posts_'.$lineboard['name']; + $posts = $tc_db->GetOne('SELECT COUNT(*) FROM `' . $posts_table.'`'); + + $i=0; + while ($i <= $posts+1500) { + $boardid = $lineboard['id']; + $results = $tc_db->GetAssoc('SELECT * FROM `' . $posts_table.'` LIMIT '.$i.',1500'); + foreach($results AS $line) { + $query = 'INSERT INTO `'.KU_DBPREFIX.'posts` (`id`, `boardid`, `parentid`, `name`, `tripcode`, `email`, `subject`, `message`, `password`, `file`, `file_md5`, `file_type`, `file_original`, `file_size`, `file_size_formatted`, `image_w`, `image_h`, `thumb_w`, `thumb_h`, `ip`, `ipmd5`, `tag`, `timestamp_formatted`, `timestamp`, `stickied`, `locked`, `posterauthority`, `reviewed`, `deleted_timestamp`, `IS_DELETED`, `bumped`) VALUES + ( ' . $tc_db->qstr($line['id']) . ', \'' . $boardid . '\' ,' . $tc_db->qstr($line['parentid']) . ', ' . $tc_db->qstr($line['name']) . ', ' . $tc_db->qstr($line['tripcode']) . ', ' . $tc_db->qstr($line['email']) . ', ' . $tc_db->qstr($line['subject']) . ', ' . $tc_db->qstr($line['message']) . ', ' . $tc_db->qstr($line['password']) . ', ' . $tc_db->qstr($line['filename']) . ', ' . $tc_db->qstr($line['filemd5']) . ', ' .$tc_db->qstr($line['filetype']) . ', ' . $tc_db->qstr($line['filename_original']) . ', ' . $tc_db->qstr($line['filesize']) . ', ' . $tc_db->qstr($line['filesize_formatted']) . ', ' . $tc_db->qstr($line['image_w']) . ', ' . $tc_db->qstr($line['image_h']) . ', ' . $tc_db->qstr($line['thumb_w']) . ', ' . $tc_db->qstr($line['thumb_h']) . ', ' . $tc_db->qstr($line['ip']) . ', ' . $tc_db->qstr($line['ipmd5']) . ', ' . $tc_db->qstr($line['tag']) . ', '. $tc_db->qstr(date('y/m/d(D)H:i', $line['postedat'])) . ', ' . $tc_db->qstr($line['postedat']) . ', ' . $tc_db->qstr($line['stickied']) . ', ' . $tc_db->qstr($line['locked']) . ', ' . $tc_db->qstr($line['posterauthority']) . ', ' . $tc_db->qstr($line['reviewed']) . ', ' . $tc_db->qstr($line['deletedat']) . ', ' . $tc_db->qstr($line['IS_DELETED']) . ', ' . $tc_db->qstr($line['lastbumped']) . ')'; + $tc_db->Execute($query); + if (!mysql_error()) { + } else { + $error = mysql_error(); + $tc_db->Execute('TRUNCATE TABLE `'.KU_DBPREFIX.'posts`'); + die ("Conversion failed. Please rerun this script again or attempt to fix the problem if you know how to solve it.
+ Debugging info:
+ Query: ".$query."
+ Error: ".$error.""); + } + } + $i = $i+1500; + } + echo "done
"; + } + if (isset($_POST["removeposts"])) { + echo "Removing old posts tables..."; + foreach ($resultsboard as $lineboard) { + $posts_table = 'posts_'.$lineboard['name']; + $tc_db->Execute('DROP TABLE `' . $posts_table.'`'); + } + echo "done
"; + } +} + +function front_db_conversion() { + + global $tc_db; + + echo 'Updating News, FAQ, and Rules tables...
'; + $news = $tc_db->GetAll("SELECT * FROM `" . KU_DBPREFIX . "news`"); + $faq = $tc_db->GetAll("SELECT * FROM `" . KU_DBPREFIX . "faq` ORDER BY `order`"); + $rules = $tc_db->GetAll("SELECT * FROM `" . KU_DBPREFIX . "rules` ORDER BY `order`"); + + foreach ($news as $newspost) { + $tc_db->Execute("INSERT HIGH_PRIORITY INTO `" . KU_DBPREFIX . "front` ( `page`, `subject` , `message` , `timestamp` , `poster` , `email` ) VALUES ( '0', " . $tc_db->qstr($newspost['subject']) . " , " . $tc_db->qstr($newspost['message']) . " , " . $tc_db->qstr($newspost['postedat']) . " , " . $tc_db->qstr($newspost['postedby']) . " , " . $tc_db->qstr($newspost['postedemail']) . " )"); + } + echo 'Updated news table.
'; + + foreach ($faq as $faqpost) { + $tc_db->Execute("INSERT HIGH_PRIORITY INTO `" . KU_DBPREFIX . "front` ( `page`, `order`, `subject` , `message` ) VALUES ( '1', " . $tc_db->qstr($faqpost['order']) . " , " . $tc_db->qstr($faqpost['heading']) . " , " . $tc_db->qstr($faqpost['message']) . " )"); + } + echo 'Updated FAQ table.
'; + + foreach ($rules as $rulespost) { + $tc_db->Execute("INSERT HIGH_PRIORITY INTO `" . KU_DBPREFIX . "front` ( `page`, `order`, `subject` , `message` ) VALUES ( '2', " . $tc_db->qstr($rulespost['order']) . " , " . $tc_db->qstr($rulespost['heading']) . " , " . $tc_db->qstr($rulespost['message']) . " )"); + } + echo 'Updated rules table.
'; + + if (isset($_POST['removefront'])) { + echo 'Deleting unused front page tables...'; + $tc_db->Execute("DROP TABLE `" . KU_DBPREFIX . "news`"); + $tc_db->Execute("DROP TABLE `" . KU_DBPREFIX . "faq`"); + $tc_db->Execute("DROP TABLE `" . KU_DBPREFIX . "rules`"); + echo ' done
'; + } + echo 'Finished updating front tables.
'; +} + + +?> + + \ No newline at end of file diff --git a/PCHViewer123.jar b/PCHViewer123.jar new file mode 100644 index 0000000..39c3b52 Binary files /dev/null and b/PCHViewer123.jar differ diff --git a/README.md b/README.md index a627c59..16f48e8 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,49 @@ # x-233chan Kusaba X Fork with a translated Chinese frontend, powering a certain project starting with 2333 +匿名版系统Kusaba X的fork,增加以下特性: +- 中文前台 +- BBCode支持 +- 文字颜文字输入 +- 彩色饼干ID +- 音频上传(需要服务器支持,基于Flash播放器) + + +# 安装方法 # +Clone本repo后,用文本编辑器打开``config.php``,根据你的实际情况,修改其中的变量。 + +修改完毕保存后,将OTHER文件夹中的``install.php``, 对应你``config.php``中``KU_DBTYPE``变量的``install-dbtype.php``以及``kusaba_freshinstall.dbtype.sql``复制粘贴进根目录。 + +如果你使用虚拟主机,现在应该将全部内容上传到远端服务器上。 + +执行``/install.php``进行安装。 + +安装完毕后,删除前述的安装用文件以及``/OTHER``文件夹。 + +后台在``/manage.php``,默认用户名和密码均为``admin``,请记得修改。 + +以上 + +# 免责声明 # + +使用此代码产生的一切后果自负。 + +此程序的原作者为[Kusuba X制作组](https://github.com/Edaha)。 + +## 其他 ## + +里岛使用的波兰球现国别插件基于[这个repo](https://github.com/exclude/kusaba-int-module)。 + +文字颜文字列表来自于A岛。 + +``/assets``文件夹中图像的作者为Woody-Rinn。 + + +---------- +以下为原README文件内容 + +---------- +Installation Guide +http://kusabax.cultnet.net/wiki/installation_guide + +Other Info (Including Upgrading) +http://kusabax.cultnet.net/wiki/basics diff --git a/animation.php b/animation.php new file mode 100644 index 0000000..4128694 --- /dev/null +++ b/animation.php @@ -0,0 +1,89 @@ +GetAll("SELECT `image_w`, `image_h` FROM `" . KU_DBPREFIX . "posts` WHERE `file` = " . $tc_db->qstr($_GET['id']) . " LIMIT 1"); + + +// Checks to ensure valid $_GET input +$board = $tc_db->GetAll("SELECT `desc` FROM `" . KU_DBPREFIX . "boards WHERE `desc` = " . $tc_db->qstr($_GET['board']) . " LIMIT 1"); +if (count($board) < 1 || !is_numeric($_GET['id'])) { + die(); +} + +$width = $imagesize[0]['image_w']; +$height = $imagesize[0]['image_h']; + +?> + + + +View Animation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Java must be installed and enabled to use this applet. Please refer to our Java setup tutorial for more information.
+
+ + + \ No newline at end of file diff --git a/assets/401.jpg b/assets/401.jpg new file mode 100644 index 0000000..2668a8f Binary files /dev/null and b/assets/401.jpg differ diff --git a/assets/403.jpg b/assets/403.jpg new file mode 100644 index 0000000..68d67b3 Binary files /dev/null and b/assets/403.jpg differ diff --git a/assets/404.jpg b/assets/404.jpg new file mode 100644 index 0000000..a80447a Binary files /dev/null and b/assets/404.jpg differ diff --git a/assets/500.jpg b/assets/500.jpg new file mode 100644 index 0000000..c79f851 Binary files /dev/null and b/assets/500.jpg differ diff --git a/assets/503.jpg b/assets/503.jpg new file mode 100644 index 0000000..5c0cff5 Binary files /dev/null and b/assets/503.jpg differ diff --git a/assets/Thumbs.db b/assets/Thumbs.db new file mode 100644 index 0000000..6f4b6cd Binary files /dev/null and b/assets/Thumbs.db differ diff --git a/assets/_logo.png b/assets/_logo.png new file mode 100644 index 0000000..1b12d39 Binary files /dev/null and b/assets/_logo.png differ diff --git a/assets/front.css b/assets/front.css new file mode 100644 index 0000000..9742994 --- /dev/null +++ b/assets/front.css @@ -0,0 +1,163 @@ +html { + /*background-color: #C4C4C4;*/ + color: #333333; + font-family: "Trebuchet MS", "Tahoma", "Verdana", "Arial", sans-serif; + font-size: 13px; +} + +body { + width: 980px; + margin: 0 auto; + background-color: #F7F7F7; +} + +/** logo **/ + +.logo { + background: url('_logo.png') top left no-repeat; + width: 300px; + height: 120px; + margin: 0 auto; +} + +/** menu **/ + +.menu ul { + list-style: none; + margin: 0; + padding: 7px 0; + border-bottom: 1px solid #CCC; + font-weight: bold; + text-align: center; + white-space: nowrap; +} + +.menu ul li { + display: inline; + margin: 0 2px; +} + +.menu ul a { + text-decoration: none; + padding: 0 0 3px; + border-bottom: 4px solid #FFF; + color: #999; +} + +.menu ul a.active, .menu ul a:hover { + border-color: #888; + color: #555; +} + +/** boxies **/ + +.clear { + clear: both; +} + +.box { + background: #FFF; + border: 1px solid #919191; + margin: 15px 0 0 0; +} + +.box .box-title { + font-size: 18px; + background: #c0c0c0; + padding: 2px; +} + +/** boards **/ + +.boards ul { + float: left; + font-weight: bold; +} + +.boards ul li { + font-weight: normal; + list-style: none; +} + +/** noticias **/ + +.last-new .box-content { + padding: 0 5px; +} + +/** ultimas imagens **/ + +.last-images { + width: 49%; + float: left; +} + +.last-images .box-content { + height: 880px; + text-align: center; + overflow: auto; +} + +.last-images ul { + width: 100%; + margin: 0; + padding: 0; +} + +.last-images ul li { + background: #120; + list-style: none; + width: 280px; + height: auto; + margin: 10px auto; + padding: 10px; +} + +.last-images ul li img { + max-width: 250px; + max-height: 150px; +} + +/** Ultimos Posts **/ + +.last-post, +.popular-thread, +.stats { + float: right; + width: 49%; +} + +/** ban list **/ + +table { + margin: 15px 0 0 0; + border-collapse: collapse; + background: #fff; +} + +th { + background: #c0c0c0; +} + +table, th, td { + border: 1px solid black; + padding: 3px; +} + +/** footer **/ + +.footer { + text-align: center; + font-size: 12px; + margin-top: 5px; +} + +/** formatação **/ + +a { + color:#F60; +} + +a:hover { + color:#b34700; +} \ No newline at end of file diff --git a/banned.php b/banned.php new file mode 100644 index 0000000..6e891fd --- /dev/null +++ b/banned.php @@ -0,0 +1,55 @@ +GetAll("SELECT * FROM `".KU_DBPREFIX."banlist` WHERE `type` = '0' AND `ipmd5` = '" . md5($_SERVER['REMOTE_ADDR']) . "' AND `id` = " . $tc_db->qstr($_POST['banid']) . "LIMIT 1"); + if (count($results)>0) { + foreach($results AS $line) { + if ($line['appealat'] > 0 && $line['appealat'] < time()) { + $tc_db->Execute("UPDATE `".KU_DBPREFIX."banlist` SET `appealat` = '-1' , appeal = ".$tc_db->qstr($_POST['appealmessage'])." WHERE `id` = '" . $line['id'] . "'"); + + echo 'Your appeal has been sent and is pending review.'; + } else { + echo 'You may not appeal that ban at this time.'; + } + + die(); + } + } +} + +$bans_class->BanCheck($_SERVER['REMOTE_ADDR'], '', true); + +?> \ No newline at end of file diff --git a/blotter.php b/blotter.php new file mode 100644 index 0000000..ef4dd36 --- /dev/null +++ b/blotter.php @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/board.php b/board.php new file mode 100644 index 0000000..b536f37 --- /dev/null +++ b/board.php @@ -0,0 +1,473 @@ +GetOne("SELECT `name` FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($_POST['board']) . ""); + if (!empty($board_name)) { + $board_class = new Board($board_name); + if (!empty($board_class->board['locale'])) { + changeLocale($board_class->board['locale']); + } + } else { + do_redirect(KU_WEBPATH); + } +} else { + // A board being supplied is required for this script to function + do_redirect(KU_WEBPATH); +} + +// {{{ Expired ban removal, and then existing ban check on the current user + +$bans_class->BanCheck($_SERVER['REMOTE_ADDR'], $board_class->board['name']); + +// }}} + +$oekaki = $posting_class->CheckOekaki(); +$is_oekaki = empty($oekaki) ? false : true; +/* Ensure that UTF-8 is used on some of the post variables */ +$posting_class->UTF8Strings(); + +/* Check if the user sent a valid post (image for thread, image/message for reply, etc) */ +if ($posting_class->CheckValidPost($is_oekaki)) { + $tc_db->Execute("START TRANSACTION"); + $posting_class->CheckReplyTime(); + $posting_class->CheckNewThreadTime(); + $posting_class->CheckMessageLength(); + $posting_class->CheckCaptcha(); + $posting_class->CheckBannedHash(); + $posting_class->CheckBlacklistedText(); + $post_isreply = $posting_class->CheckIsReply(); + + $imagefile_name = isset($_FILES['imagefile']) ? $_FILES['imagefile']['name'] : ''; + + if ($post_isreply) { + list($thread_replies, $thread_locked, $thread_replyto) = $posting_class->GetThreadInfo($_POST['replythread']); + } else { + if ($board_class->board['type'] != 1 && (($board_class->board['uploadtype'] == '1' || $board_class->board['uploadtype'] == '2') && $board_class->board['embeds_allowed'] != '')) { + if (isset($_POST['embed'])) { + if ($_POST['embed'] == '') { + if (($board_class->board['uploadtype'] == '1' && $imagefile_name == '') || $board_class->board['uploadtype'] == '2') { + exitWithErrorPage('Please enter an embed ID.'); + } + } + } else { + exitWithErrorPage('Please enter an embed ID.'); + } + } + + $thread_replies = 0; + $thread_locked = 0; + $thread_replyto = 0; + } + + list($post_name, $post_email, $post_subject) = $posting_class->GetFields(); + $post_password = isset($_POST['postpassword']) ? $_POST['postpassword'] : ''; + + if ($board_class->board['type'] == 1) { + if ($post_isreply) { + $post_subject = ''; + } else { + $posting_class->CheckNotDuplicateSubject($post_subject); + } + } + + list($user_authority, $flags) = $posting_class->GetUserAuthority(); + + $post_fileused = false; + $post_autosticky = false; + $post_autolock = false; + $post_displaystaffstatus = false; + $file_is_special = false; + + if (isset($_POST['formatting'])) { + if ($_POST['formatting'] == 'aa') { + $_POST['message'] = '[aa]' . $_POST['message'] . '[/aa]'; + } + + if (isset($_POST['rememberformatting'])) { + setcookie('kuformatting', urldecode($_POST['formatting']), time() + 31556926, '/', KU_DOMAIN); + } + } + + $results = $tc_db->GetAll("SELECT id FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $board_class->board['id'] . " ORDER BY id DESC LIMIT 1"); + if (count($results) > 0) + $nextid = $results[0]['id'] + 1; + else + $nextid = 1; + $parse_class->id = $nextid; + + // If they are just a normal user, or vip... + if (isNormalUser($user_authority)) { + // If the thread is locked + if ($thread_locked == 1) { + // Don't let the user post + exitWithErrorPage(_gettext('Sorry, this thread is locked and can not be replied to.')); + } + + $post_message = $parse_class->ParsePost($_POST['message'], $board_class->board['name'], $board_class->board['type'], $thread_replyto, $board_class->board['id']); + // Or, if they are a moderator/administrator... + } else { + // If they checked the D checkbox, set the variable to tell the script to display their staff status (Admin/Mod) on the post during insertion + if (isset($_POST['displaystaffstatus'])) { + $post_displaystaffstatus = true; + } + + // If they checked the RH checkbox, set the variable to tell the script to insert the post as-is... + if (isset($_POST['rawhtml'])) { + $post_message = $_POST['message']; + // Otherwise, parse it as usual... + } else { + $post_message = $parse_class->ParsePost($_POST['message'], $board_class->board['name'], $board_class->board['type'], $thread_replyto, $board_class->board['id']); + } + + // If they checked the L checkbox, set the variable to tell the script to lock the post after insertion + if (isset($_POST['lockonpost'])) { + $post_autolock = true; + } + + // If they checked the S checkbox, set the variable to tell the script to sticky the post after insertion + if (isset($_POST['stickyonpost'])) { + $post_autosticky = true; + } + if (isset($_POST['usestaffname'])) { + $_POST['name'] = md5_decrypt($_POST['modpassword'], KU_RANDOMSEED); + $post_name = md5_decrypt($_POST['modpassword'], KU_RANDOMSEED); + } + } + + $posting_class->CheckBadUnicode($post_name, $post_email, $post_subject, $post_message); + + $post_tag = $posting_class->GetPostTag(); + + if ($post_isreply) { + if ($imagefile_name == '' && !$is_oekaki && $post_message == '') { + exitWithErrorPage(_gettext('An image, or message, is required for a reply.')); + } + } else { + if ($imagefile_name == '' && !$is_oekaki && ((!isset($_POST['nofile'])&&$board_class->board['enablenofile']==1) || $board_class->board['enablenofile']==0) && ($board_class->board['type'] == 0 || $board_class->board['type'] == 2 || $board_class->board['type'] == 3)) { + if (!isset($_POST['embed']) && $board_class->board['uploadtype'] != 1) { + exitWithErrorPage(_gettext('A file is required for a new thread. If embedding is allowed, either a file or embed ID is required.')); + } + } + } + + if (isset($_POST['nofile'])&&$board_class->board['enablenofile']==1) { + if ($post_message == '') { + exitWithErrorPage('A message is required to post without a file.'); + } + } + + if ($board_class->board['type'] == 1 && !$post_isreply && $post_subject == '') { + exitWithErrorPage('A subject is required to make a new thread.'); + } + + if ($board_class->board['locked'] == 0 || ($user_authority > 0 && $user_authority != 3)) { + require_once KU_ROOTDIR . 'inc/classes/upload.class.php'; + $upload_class = new Upload(); + if ($post_isreply) { + $upload_class->isreply = true; + } + + if ((!isset($_POST['nofile']) && $board_class->board['enablenofile'] == 1) || $board_class->board['enablenofile'] == 0) { + $upload_class->HandleUpload(); + } + + if ($board_class->board['forcedanon'] == '1') { + if ($user_authority == 0 || $user_authority == 3) { + $post_name = ''; + $post_subject = ''; + } + } + + $nameandtripcode = calculateNameAndTripcode($post_name); + if (is_array($nameandtripcode)) { + $name = $nameandtripcode[0]; + $tripcode = $nameandtripcode[1]; + } else { + $name = $post_name; + $tripcode = ''; + } + + $filetype_withoutdot = substr($upload_class->file_type, 1); + $post_passwordmd5 = ($post_password == '') ? '' : md5($post_password); + + if ($post_autosticky == true) { + if ($thread_replyto == 0) { + $sticky = 1; + } else { + $result = $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "posts` SET `stickied` = '1' WHERE `boardid` = " . $board_class->board['id'] . " AND `id` = '" . $thread_replyto . "'"); + $sticky = 0; + } + } else { + $sticky = 0; + } + + if ($post_autolock == true) { + if ($thread_replyto == 0) { + $lock = 1; + } else { + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "posts` SET `locked` = '1' WHERE `boardid` = " . $board_class->board['id'] . " AND `id` = '" . $thread_replyto . "'"); + $lock = 0; + } + } else { + $lock = 0; + } + + if (!$post_displaystaffstatus && $user_authority > 0 && $user_authority != 3) { + $user_authority_display = 0; + } elseif ($user_authority > 0) { + $user_authority_display = $user_authority; + } else { + $user_authority_display = 0; + } + + if ((file_exists(KU_BOARDSDIR . $board_class->board['name'] . '/src/' . $upload_class->file_name . $upload_class->file_type) && file_exists(KU_BOARDSDIR . $board_class->board['name'] . '/thumb/' . $upload_class->file_name . 's' . $upload_class->file_type)) || ($file_is_special && file_exists(KU_BOARDSDIR . $board_class->board['name'] . '/src/' . $upload_class->file_name . $upload_class->file_type)) || $post_fileused == false) { + $post = array(); + + $post['board'] = $board_class->board['name']; + $post['name'] = substr($name, 0, 74); + $post['name_save'] = true; + $post['tripcode'] = $tripcode; + $post['email'] = substr($post_email, 0, 74); + // First array is the converted form of the japanese characters meaning sage, second meaning age + $ords_email = unistr_to_ords($post_email); + if (strtolower($_POST['em']) != 'sage' && $ords_email != array(19979, 12370) && strtolower($_POST['em']) != 'age' && $ords_email != array(19978, 12370) && $_POST['em'] != 'return' && $_POST['em'] != 'noko') { + $post['email_save'] = true; + } else { + $post['email_save'] = false; + } + $post['subject'] = substr($post_subject, 0, 74); + $post['message'] = $post_message; + $post['tag'] = $post_tag; + + $post = hook_process('posting', $post); + + if ($is_oekaki) { + if (file_exists(KU_BOARDSDIR . $board_class->board['name'] . '/src/' . $upload_class->file_name . '.pch')) { + $post['message'] .= '
' . _gettext('View animation') . ''; + } + } + + if ($thread_replyto != '0') { + if ($post['message'] == '' && KU_NOMESSAGEREPLY != '') { + $post['message'] = KU_NOMESSAGEREPLY; + } + } else { + if ($post['message'] == '' && KU_NOMESSAGETHREAD != '') { + $post['message'] = KU_NOMESSAGETHREAD; + } + } + + $post_class = new Post(0, $board_class->board['name'], $board_class->board['id'], true); + $post_id = $post_class->Insert($thread_replyto, $post['name'], $post['tripcode'], $post['email'], $post['subject'], addslashes($post['message']), $upload_class->file_name, $upload_class->original_file_name, $filetype_withoutdot, $upload_class->file_md5, $upload_class->imgWidth, $upload_class->imgHeight, $upload_class->file_size, $upload_class->imgWidth_thumb, $upload_class->imgHeight_thumb, $post_passwordmd5, time(), time(), $_SERVER['REMOTE_ADDR'], $user_authority_display, $post['tag'], $sticky, $lock, $board_class->board['id']); + + if ($user_authority > 0 && $user_authority != 3) { + $modpost_message = 'Modposted #' . $post_id . ' in /'.$_POST['board'].'/ with flags: ' . $flags . '.'; + management_addlogentry($modpost_message, 1, md5_decrypt($_POST['modpassword'], KU_RANDOMSEED)); + } + + if ($post['name_save'] && isset($_POST['name'])) { + setcookie('name', urldecode($_POST['name']), time() + 31556926, '/', KU_DOMAIN); + } + + if ($post['email_save']) { + setcookie('email', urldecode($post['email']), time() + 31556926, '/', KU_DOMAIN); + } + + setcookie('postpassword', urldecode($_POST['postpassword']), time() + 31556926, '/'); + } else { + exitWithErrorPage(_gettext('Could not copy uploaded image.')); + } + + // If the user replied to a thread, and they weren't sage-ing it... + if ($thread_replyto != '0' && strtolower($_POST['em']) != 'sage' && unistr_to_ords($_POST['em']) != array(19979, 12370)) { + // And if the number of replies already in the thread are less than the maximum thread replies before perma-sage... + if ($thread_replies <= $board_class->board['maxreplies']) { + // Bump the thread + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "posts` SET `bumped` = '" . time() . "' WHERE `boardid` = " . $board_class->board['id'] . " AND `id` = '" . $thread_replyto . "'"); + } + } + + // If the user replied to a thread he is watching, update it so it doesn't count his reply as unread + if (KU_WATCHTHREADS && $thread_replyto != '0') { + $viewing_thread_is_watched = $tc_db->GetOne("SELECT COUNT(*) FROM `" . KU_DBPREFIX . "watchedthreads` WHERE `ip` = '" . $_SERVER['REMOTE_ADDR'] . "' AND `board` = '" . $board_class->board['name'] . "' AND `threadid` = '" . $thread_replyto . "'"); + if ($viewing_thread_is_watched > 0) { + $newestreplyid = $tc_db->GetOne('SELECT `id` FROM `'.KU_DBPREFIX.'posts` WHERE `boardid` = ' . $board_class->board['id'] . ' AND `IS_DELETED` = 0 AND `parentid` = '.$thread_replyto.' ORDER BY `id` DESC LIMIT 1'); + + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "watchedthreads` SET `lastsawreplyid` = " . $newestreplyid . " WHERE `ip` = '" . $_SERVER['REMOTE_ADDR'] . "' AND `board` = '" . $board_class->board['name'] . "' AND `threadid` = '" . $thread_replyto . "'"); + } + } + + $tc_db->Execute("COMMIT"); + + // Trim any threads which have been pushed past the limit, or exceed the maximum age limit + TrimToPageLimit($board_class->board); + + // Regenerate board pages + $board_class->RegeneratePages(); + if ($thread_replyto == '0') { + // Regenerate the thread + $board_class->RegenerateThreads($post_id); + } else { + // Regenerate the thread + $board_class->RegenerateThreads($thread_replyto); + } + } else { + exitWithErrorPage(_gettext('Sorry, this board is locked and can not be posted in.')); + } +} elseif ((isset($_POST['deletepost']) || isset($_POST['reportpost']) || isset($_POST['moddelete'])) && isset($_POST['post'])) { + $ismod = false; + // Initialize the post class + foreach ($_POST['post'] as $val) { + $post_class = new Post($val, $board_class->board['name'], $board_class->board['id']); + + if (isset($_POST['reportpost'])) { + // They clicked the Report button + if ($board_class->board['enablereporting'] == 1) { + $post_reported = $post_class->post['isreported']; + + if ($post_reported === 'cleared') { + echo _gettext('That post has been cleared as not requiring any deletion.') . '
'; + } elseif ($post_reported) { + echo _gettext('That post is already in the report list.') . '
'; + } else { + if ($post_class->Report()) { + echo _gettext('Post successfully reported.') . '
'; + } else { + echo _gettext('Unable to report post. Please go back and try again.') . '
'; + } + } + } else { + echo _gettext('This board does not allow post reporting.') . '
'; + } + } elseif (isset($_POST['postpassword']) || ( isset($_POST['moddelete']) && (require_once KU_ROOTDIR . 'inc/classes/manage.class.php') && Manage::CurrentUserIsModeratorOfBoard($board_class->board['name'], $_SESSION['manageusername']) && $ismod = true)) { + // They clicked the Delete button + if ($_POST['postpassword'] != '' || $ismod) { + if (md5($_POST['postpassword']) == $post_class->post['password'] || $ismod) { + if (isset($_POST['fileonly'])) { + if ($post_class->post['file'] != '' && $post_class->post['file'] != 'removed') { + $post_class->DeleteFile(); + $board_class->RegeneratePages(); + if ($post_class->post['parentid'] != 0) { + $board_class->RegenerateThreads($post_class->post['parentid']); + } + echo _gettext('Image successfully deleted from your post.') . '
'; + } else { + echo _gettext('Your post already doesn\'t have an image!') . '
'; + } + } else { + if ($post_class->Delete()) { + if ($post_class->post_parentid != '0') { + $board_class->RegenerateThreads($post_class->post['parentid']); + } + $board_class->RegeneratePages(); + echo _gettext('Post successfully deleted.') . '
'; + } else { + echo _gettext('There was an error in trying to delete your post') . '
'; + } + } + } else { + echo _gettext('Incorrect password.') . '
'; + } + } else { + do_redirect(KU_BOARDSPATH . '/' . $board_class->board['name'] . '/'); + } + } + } + do_redirect(KU_BOARDSPATH . '/' . $board_class->board['name'] . '/'); + die(); +} elseif (isset($_GET['postoek'])) { + $board_class->OekakiHeader($_GET['replyto'], $_GET['postoek']); + die(); +} else { + do_redirect(KU_BOARDSPATH . '/' . $board_class->board['name'] . '/'); +} + +if (KU_RSS) { + require_once KU_ROOTDIR . 'inc/classes/rss.class.php'; + $rss_class = new RSS(); + + print_page(KU_BOARDSDIR.$_POST['board'].'/rss.xml',$rss_class->GenerateRSS($_POST['board'], $board_class->board['id']),$_POST['board']); +} + +if ($board_class->board['redirecttothread'] == 1 || $_POST['em'] == 'return' || $_POST['em'] == 'noko') { + if ($thread_replyto == "0") { + do_redirect(KU_BOARDSPATH . '/' . $board_class->board['name'] . '/res/' . $post_id . '.html', true, $imagefile_name); + } else { + do_redirect(KU_BOARDSPATH . '/' . $board_class->board['name'] . '/res/' . $thread_replyto . '.html', true, $imagefile_name); + } +} else { + do_redirect(KU_BOARDSPATH . '/' . $board_class->board['name'] . '/', true, $imagefile_name); +} +?> \ No newline at end of file diff --git a/boards.html b/boards.html new file mode 100644 index 0000000..b6bd4e6 --- /dev/null +++ b/boards.html @@ -0,0 +1 @@ +[ edit this ] \ No newline at end of file diff --git a/captcha.php b/captcha.php new file mode 100644 index 0000000..2d071a4 --- /dev/null +++ b/captcha.php @@ -0,0 +1,133 @@ +rand_word($characters); + + /* font size will be 75% of the image height */ + $font_size = $height * 0.85; + $image = @imagecreate($width, $height) or die('Cannot initialize new GD image stream'); + /* set the colours */ + $background_color = imagecolorallocate($image, 255, 255, 255); + $text_color = imagecolorallocate($image, 35, 45, 100); + $noise_color = imagecolorallocate($image, 100, 120, 180); + /* generate random dots in background */ + if (@imagettfbbox($font_size, 0, $font, $code)) { + $ttf_supported = true; + for( $i=0; $i<($width*$height)/3; $i++ ) { + imagefilledellipse($image, mt_rand(0,$width), mt_rand(0,$height), 1, 1, $noise_color); + } + } else { + $ttf_supported = false; + for( $i=0; $i<($width*$height)/12; $i++ ) { + imagefilledellipse($image, mt_rand(0,$width), mt_rand(0,$height), 1, 1, $noise_color); + } + } + /* generate random lines in background */ + if ($ttf_supported) { + for( $i=0; $i<($width*$height)/150; $i++ ) { + imageline($image, mt_rand(0,$width), mt_rand(0,$height), mt_rand(0,$width), mt_rand(0,$height), $noise_color); + } + } + if ($ttf_supported) { + $textbox = imagettfbbox($font_size, 0, $font, $code); + $x = ($width - $textbox[4])/2; + $y = ($height - $textbox[5])/2; + imagettftext($image, $font_size, 0, $x, $y, $text_color, $font, $code); + } else { + $x = 4; + $y = 5; + imagestring($image, $font_ballback, $x, $y, $code, $text_color); + } + /* create textbox and add text*/ + $textbox = imagettfbbox($font_size, 0, $font, $code) or die('Error in imagettfbbox function'); + $x = ($width - $textbox[4])/2; + $y = ($height - $textbox[5])/2; + imagettftext($image, $font_size, 0, $x, $y, $text_color, $font, $code) or die('Error in imagettftext function'); + /*output captcha image to browser */ + header('Content-Type: image/jpeg'); + imagejpeg($image); + imagedestroy($image); + $_SESSION['security_code'] = $code; + } + +} + +$width = 90; +$height = 30; +$characters = 6; + +$font = KU_ROOTDIR . 'lib/fonts/monofont.ttf'; +$font_fallback = imageloadfont(KU_ROOTDIR . 'lib/fonts/captchafont.gdf'); + +$captcha = new CaptchaSecurityImages($width,$height,$characters,$font); + +?> \ No newline at end of file diff --git a/clear.gif b/clear.gif new file mode 100644 index 0000000..c95709f Binary files /dev/null and b/clear.gif differ diff --git a/config.php b/config.php new file mode 100644 index 0000000..d7bdf3a --- /dev/null +++ b/config.php @@ -0,0 +1,311 @@ +"网站口号,您为何要作死。"'; // Site slogan, set to nothing to disable its display + $cf['KU_HEADERURL'] = ''; // Full URL to the header image (or rotation script) to be displayed, can be left blank for no image + $cf['KU_IRC'] = ''; // IRC info, which will be displayed in the menu. Leave blank to remove it + $cf['KU_BANREASON'] = ''; // This is the default ban reason that will automatically fill in the ban reason box + + // Paths and URLs + // Main installation directory + $cf['KU_ROOTDIR'] = realpath(dirname(__FILE__))."/"; // Full system path of the folder containing kusaba.php, with trailing slash. The default value set here should be OK.. If you need to change it, you should already know what the full path is anyway. + $cf['KU_WEBFOLDER'] = '/'; // The path from the domain of the board to the folder which kusaba is in, including the trailing slash. Example: "http://www.yoursite.com/misc/kusaba/" would have a $cf['KU_WEBFOLDER'] of "/misc/kusaba/" + $cf['KU_WEBPATH'] = 'http://example.org'; // The path to the index folder of kusaba, without trailing slash. Example: http://www.yoursite.com + $cf['KU_DOMAIN'] = '.example.org'; // Used in cookies for the domain parameter. Should be a period and then the top level domain, which will allow the cookies to be set for all subdomains. For http://www.randomchan.org, the domain would be .randomchan.org; http://zachchan.freehost.com would be zach.freehost.com + + // Board subdomain/alternate directory (optional, change to enable) + // DO NOT CHANGE THESE IF YOU DO NOT KNOW WHAT YOU ARE DOING!! + $cf['KU_BOARDSDIR'] = $cf['KU_ROOTDIR']; + $cf['KU_BOARDSFOLDER'] = $cf['KU_WEBFOLDER']; + $cf['KU_BOARDSPATH'] = $cf['KU_WEBPATH']; + + // CGI subdomain/alternate directory (optional, change to enable) + // DO NOT CHANGE THESE IF YOU DO NOT KNOW WHAT YOU ARE DOING!! + $cf['KU_CGIDIR'] = $cf['KU_BOARDSDIR']; + $cf['KU_CGIFOLDER'] = $cf['KU_BOARDSFOLDER']; + $cf['KU_CGIPATH'] = $cf['KU_BOARDSPATH']; + + // Coralized URLs (optional, change to enable) + $cf['KU_WEBCORAL'] = ''; // Set to the coralized version of your webpath to enable. If not set to '', URLs which can safely be cached will be coralized, and will use the Coral Content Distribution Network. Example: http://www.kusaba.org becomes http://www.kusaba.org.nyud.net, http://www.crapchan.org/kusaba becomes http://www.crapchan.org.nyud.net/kusaba + $cf['KU_BOARDSCORAL'] = ''; + + // Templates + $cf['KU_TEMPLATEDIR'] = $cf['KU_ROOTDIR'] . 'dwoo/templates'; // Dwoo templates directory + $cf['KU_CACHEDTEMPLATEDIR'] = $cf['KU_ROOTDIR'] . 'dwoo/templates_c'; // Dwoo compiled templates directory. This folder MUST be writable (you may need to chmod it to 755). Set to '' to disable template caching + + // CSS styles + $cf['KU_STYLES'] = 'burichan:futaba'; // Styles which are available to be used for the boards, separated by colons, in lower case. These will be displayed next to [Home] [Manage] if KU_STYLESWIKUHER is set to true + $cf['KU_DEFAULTSTYLE'] = 'futaba'; // If Default is selected in the style list in board options, it will use this style. Should be lower case + $cf['KU_STYLESWITCHER'] = true; // Whether or not to display the different styles in a clickable switcher at the top of the board + $cf['KU_DROPSWITCHER'] = false; // Whether or not to use a dropdown style switcher. False is use plaintext switcher, true is dropdown. + + $cf['KU_TXTSTYLES'] = 'futatxt:buritxt'; // Styles which are available to be used for the boards, separated by colons, in lower case + $cf['KU_DEFAULTTXTSTYLE'] = 'futatxt'; // If Default is selected in the style list in board options, it will use this style. Should be lower case + $cf['KU_TXTSTYLESWITCHER'] = true; // Whether or not to display the different styles in a clickable switcher at the top of the board + + $cf['KU_MENUTYPE'] = 'normal'; // Type of display for the menu. normal will add the menu styles and such as it normally would, plain will not use the styles, and will look rather boring + $cf['KU_MENUSTYLES'] = 'futaba:burichan'; // Menu styles + $cf['KU_DEFAULTMENUSTYLE'] = 'futaba'; // Default menu style + $cf['KU_MENUSTYLESWITCHER'] = true; // Whether or not to display the different styles in a clickable switcher in the menu + + // Limitations + $cf['KU_NEWTHREADDELAY'] = 30; // Minimum time in seconds a user must wait before posting a new thread again + $cf['KU_REPLYDELAY'] = 7; // Minimum time in seconds a user must wait before posting a reply again + $cf['KU_LINELENGTH'] = 150; // Used when cutting long post messages on pages and placing the message too long notification + + // Image handling + $cf['KU_THUMBWIDTH'] = 200; // Maximum thumbnail width + $cf['KU_THUMBHEIGHT'] = 200; // Maximum thumbnail height + $cf['KU_REPLYTHUMBWIDTH'] = 125; // Maximum thumbnail width (reply) + $cf['KU_REPLYTHUMBHEIGHT'] = 125; // Maximum thumbnail height (reply) + $cf['KU_CATTHUMBWIDTH'] = 50; // Maximum thumbnail width (catalog) + $cf['KU_CATTHUMBHEIGHT'] = 50; // Maximum thumbnail height (catalog) + $cf['KU_THUMBMETHOD'] = 'gd'; // Method to use when thumbnailing images in jpg, gif, or png format. Options available: gd, imagemagick + $cf['KU_ANIMATEDTHUMBS'] = false; // Whether or not to allow animated thumbnails (only applies if using imagemagick) + + // Post handling + $cf['KU_NEWWINDOW'] = true; // When a user clicks a thumbnail, whether to open the link in a new window or not + $cf['KU_MAKELINKS'] = true; // Whether or not to turn http:// links into clickable links + $cf['KU_NOMESSAGETHREAD'] = '无本文'; // Text to set a message to if a thread is made with no text + $cf['KU_NOMESSAGEREPLY'] = '无本文'; // Text to set a message to if a reply is made with no text + + // Post display + $cf['KU_THREADS'] = 10; // Number of threads to display on a board page + $cf['KU_THREADSTXT'] = 15; // Number of threads to display on a text board front page + $cf['KU_REPLIES'] = 3; // Number of replies to display on a board page + $cf['KU_REPLIESSTICKY'] = 1; // Number of replies to display on a board page when a thread is stickied + $cf['KU_THUMBMSG'] = false; // Whether or not to display the "Thumbnail displayed, click image for full size." message on posts with images + $cf['KU_BANMSG'] = '
(用户因为此帖被塞了大雕)'; // The text to add at the end of a post if a ban is placed and "Add ban message" is checked + $cf['KU_TRADITIONALREAD'] = false; // Whether or not to use the traditional style for multi-quote urls. Traditional: read.php/board/thread/posts, Non-traditional: read.php?b=board&t=thread&p=posts + $cf['KU_YOUTUBEWIDTH'] = 200; // Width to display embedded YouTube videos + $cf['KU_YOUTUBEHEIGHT'] = 164; // Height to display embedded YouTube videos + + // Pages + $cf['KU_FIRSTPAGE'] = 'board.html'; // Filename of the first page of a board. Only change this if you are willing to maintain the .htaccess files for each board directory (they are created with a DirectoryIndex board.html, change them if you change this) + $cf['KU_DIRTITLE'] = false; // Whether or not to place the board directory in the board's title and at the top of the page. true would render as "/b/ - Random", false would render as "Random" + + // File tagging + $cf['KU_TAGS'] = array('一般' => 'J', + '动漫' => 'A', + '游戏' => 'G', + 'Loop' => 'L', + '其他' => '*'); // Used only in Upload imageboards. These are the tags which a user may choose to use as they are posting a file. If you wish to disable tagging on Upload imageboards, set this to '' + + // Special Tripcodes + //$cf['KU_TRIPS'] = array('#changeme' => 'changeme', + // '#changeme2' => 'changeme2'); // Special tripcodes which can have a predefined output. Do not include the initial ! in the output. Maximum length for the output is 30 characters. Set to array(); to disable + $cf['KU_TRIPS'] = array(); + // Extra features + $cf['KU_RSS'] = true; // Whether or not to enable the generation of rss for each board and modlog + $cf['KU_EXPAND'] = true; // Whether or not to add the expand button to threads viewed on board pages + $cf['KU_QUICKREPLY'] = true; // Whether or not to add quick reply links on posts + $cf['KU_WATCHTHREADS'] = true; // Whether or not to add thread watching capabilities + $cf['KU_FIRSTLAST'] = true; // Whether or not to generate extra files for the first 100 posts/last 50 posts + $cf['KU_BLOTTER'] = true; // Whether or not to enable the blotter feature + $cf['KU_SITEMAP'] = false; // Whether or not to enable automatic sitemap generation (you will still need to link the search engine sites to the sitemap.xml file) + $cf['KU_APPEAL'] = true; // Whether or not to enable the appeals system + + // Misc config + $cf['KU_MODLOGDAYS'] = 7; // Days to keep modlog entries before removing them + $cf['KU_RANDOMSEED'] = 'MIRAKURUKAGARINISTHEBESTADMINANYONEWHOOPPOSESWILLFACESALVATION'; // Type a bunch of random letters/numbers here, any large amount (35+ characters) will do + $cf['KU_STATICMENU'] = false; // Whether or not to generate the menu files as static files, instead of linking to menu.php. Enabling this will reduce load, however some users have had trouble with getting the files to generate + $cf['KU_GENERATEBOARDLIST'] = true; // Set to true to automatically make the board list which is displayed ad the top and bottom of the board pages, or false to use the boards.html file + + // Language / timezone / encoding + $cf['KU_LOCALE'] = 'zh'; // The locale of kusaba you would like to use. Locales available: en, de, et, es, fi, pl, nl, nb, ro, ru, it, ja + $cf['KU_CHARSET'] = 'UTF-8'; // The character encoding to mark the pages as. This must be the same in the .htaccess file (AddCharset charsethere .html and AddCharset charsethere .php) to function properly. Only UTF-8 and Shift_JIS have been tested + putenv('TZ=US/Pacific'); // The time zone which the server resides in + $cf['KU_DATEFORMAT'] = 'd/m/y(D)H:i'; + + // Debug + $cf['KU_DEBUG'] = false; // When enabled, debug information will be printed (Warning: all queries will be shown publicly) + + // Post-configuration actions, don't modify these + $cf['KU_VERSION'] = '0.9.3'; + $cf['KU_TAGS'] = serialize($cf['KU_TAGS']); + $cf['KU_TRIPS'] = serialize($cf['KU_TRIPS']); + $cf['KU_LINELENGTH'] = $cf['KU_LINELENGTH'] * 15; + + if (substr($cf['KU_WEBFOLDER'], -2) == '//') { $cf['KU_WEBFOLDER'] = substr($cf['KU_WEBFOLDER'], 0, -1); } + if (substr($cf['KU_BOARDSFOLDER'], -2) == '//') { $cf['KU_BOARDSFOLDER'] = substr($cf['KU_BOARDSFOLDER'], 0, -1); } + if (substr($cf['KU_CGIFOLDER'], -2) == '//') { $cf['KU_CGIFOLDER'] = substr($cf['KU_CGIFOLDER'], 0, -1); } + + $cf['KU_WEBPATH'] = trim($cf['KU_WEBPATH'], '/'); + $cf['KU_BOARDSPATH'] = trim($cf['KU_BOARDSPATH'], '/'); + $cf['KU_CGIPATH'] = trim($cf['KU_CGIPATH'], '/'); + + if ($cf['KU_APC']) { + apc_define_constants('config', $cf); + } + while (list($key, $value) = each($cf)) { + define($key, $value); + } + unset($cf); +} + +// DO NOT MODIFY BELOW THIS LINE UNLESS YOU KNOW WHAT YOU ARE DOING OR ELSE BAD THINGS MAY HAPPEN +$modules_loaded = array(); +$required = array(KU_ROOTDIR, KU_WEBFOLDER, KU_WEBPATH); +if (in_array('CHANGEME', $required) || in_array('', $required)){ + echo 'You must set KU_ROOTDIR, KU_WEBFOLDER, and KU_WEBPATH before installation will finish!'; + die(); +} +require KU_ROOTDIR . 'lib/gettext/gettext.inc.php'; +require KU_ROOTDIR . 'lib/adodb/adodb.inc.php'; + +// Gettext +_textdomain('kusaba'); +_setlocale(LC_ALL, KU_LOCALE); +_bindtextdomain('kusaba', KU_ROOTDIR . 'inc/lang'); +_bind_textdomain_codeset('kusaba', KU_CHARSET); + +// SQL database +if (!isset($tc_db) && !isset($preconfig_db_unnecessary)) { + $tc_db = &NewADOConnection(KU_DBTYPE); + if (KU_DBUSEPERSISTENT) { + $tc_db->PConnect(KU_DBHOST, KU_DBUSERNAME, KU_DBPASSWORD, KU_DBDATABASE) or die('SQL database connection error: ' . $tc_db->ErrorMsg()); + } else { + $tc_db->Connect(KU_DBHOST, KU_DBUSERNAME, KU_DBPASSWORD, KU_DBDATABASE) or die('SQL database connection error: ' . $tc_db->ErrorMsg()); + } + + // SQL debug + if (KU_DEBUG) { + $tc_db->debug = true; + } + + $results_events = $tc_db->GetAll("SELECT * FROM `" . KU_DBPREFIX . "events` WHERE `at` <= " . time()); + if (count($results_events) > 0) { + if ($tc_db->ErrorMsg() == '') { + foreach($results_events AS $line_events) { + if ($line_events['name'] == 'sitemap') { + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "events` SET `at` = " . (time() + 21600) . " WHERE `name` = 'sitemap'"); + if (KU_SITEMAP) { + $sitemap = '' . "\n" . + '' . "\n" . "\n"; + + $results = $tc_db->GetAll("SELECT `name`, `id` FROM `" . KU_DBPREFIX . "boards` ORDER BY `name` ASC"); + if (count($results) > 0) { + foreach($results AS $line) { + $sitemap .= ' ' . "\n" . + ' ' . KU_BOARDSPATH . '/' . $line['name'] . '/' . "\n" . + ' ' . date('Y-m-d') . '' . "\n" . + ' hourly' . "\n" . + ' ' . "\n"; + + $results2 = $tc_db->GetAll("SELECT `id`, `bumped` FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $line['id'] . " AND `parentid` = 0 AND `IS_DELETED` = 0 ORDER BY `bumped` DESC"); + if (count($results2) > 0) { + foreach($results2 AS $line2) { + $sitemap .= ' ' . "\n" . + ' ' . KU_BOARDSPATH . '/' . $line['name'] . '/res/' . $line2['id'] . '.html' . "\n" . + ' ' . date('Y-m-d', $line2['bumped']) . '' . "\n" . + ' hourly' . "\n" . + ' ' . "\n"; + } + } + } + } + + $sitemap .= ''; + + $fp = fopen(KU_BOARDSDIR . 'sitemap.xml', 'w'); + fwrite($fp, $sitemap); + fclose($fp); + + unset($sitemap, $fp); + } + } + } + } + + unset($results_events, $line_events); + } +} + + +function stripslashes_deep($value) +{ + $value = is_array($value) ? + array_map('stripslashes_deep', $value) : + stripslashes($value); + return $value; +} + +// Thanks Z +if (get_magic_quotes_gpc()) { + $_POST = array_map('stripslashes_deep', $_POST); + $_GET = array_map('stripslashes_deep', $_GET); + $_COOKIE = array_map('stripslashes_deep', $_COOKIE); +} +if (get_magic_quotes_runtime()) { + set_magic_quotes_runtime(0); +} + +?> \ No newline at end of file diff --git a/css/ba.gif b/css/ba.gif new file mode 100644 index 0000000..fa1d375 Binary files /dev/null and b/css/ba.gif differ diff --git a/css/burichan.css b/css/burichan.css new file mode 100644 index 0000000..3514be9 --- /dev/null +++ b/css/burichan.css @@ -0,0 +1,196 @@ +html, body { + font-size:12pt; + background:#EEF2FF; + color:#000000; +} +a { + background:inherit; + color:#34345C; + text-decoration:none; + font-family:sans-serif; +} +a:visited { + background:inherit; + color:#34345C; + text-decoration:none; + font-family:sans-serif; +} +a:hover { + color:#DD0000; + background:inherit; + font-family:sans-serif; +} +.filesize a { + text-decoration:underline; +} +.filesize a:visited { + text-decoration:underline; +} +.adminbar { + text-align:right; + background:inherit; + clear:both; + float:right; +} +.logo { + clear:both; + text-align:center; + background:inherit; + font-size:24pt; + color:#AF0A0F; + width:100%; +} +.replymode { + background:#0010E0; + color:#FFFFFF; + width:100%; +} +.catalogmode { + background:#0040E0; + color:#FFFFFF; + width:100%; +} +.postarea { + background:inherit; +} +.rules { + /*font-size:0.7em;*/ + width: 468px; + font-size: 10px; + font-family: sans-serif; +} +.rules li { + margin-left: 1em; + /*text-indent: 0em;*/ +} +.postblock { + background:#9988EE; + color:#000000; + font-weight:800; +} +.footer { + text-align:center; + font-size:10px; + font-family:sans-serif; +} +.passvalid { + background:#9988EE; + text-align:center; + width:100%; + color:#ffffff; +} +.dellist { + background:inherit; + text-align:center; +} +.delbuttons { + background:inherit; + text-align:center; + padding-bottom:4px; +} +.managehead { + background:#0F8FE1; + color:#000000; + font-family:sans-serif; + font-size:14px; + padding:0px; +} +.postlists { + background:#FFFFFF; + width:100%; + padding:0px; + color:#000000; +} +.row1 { + background:#9AD2F6; + font-family:sans-serif; + font-size:12px; + color:#000000; +} +.row2 { + background:#FFFFFF; + font-family:sans-serif; + font-size:12px; + color:#000000; +} +.unkfunc { + color:#789922; +} +.filesize { + font-size:12px; + font-family:sans-serif; + text-decoration:underline; + padding-left:3em; +} +.filetitle { + background:inherit; + font-size:18px; + font-family:serif; + color:#0F0C5D; + font-weight:800; +} +.postername { + background:inherit; + font-size:12px; + font-family:serif; + color:#117743; + font-weight:800; +} +.oldpost { + background:inherit; + font-size:18px; + font-family:serif; + color:#0F0C5D; + font-weight:800; +} +.omittedposts { + background:inherit; + font-size:18px; + font-family:serif; + color:#070707; + font-weight:800; +} +.reply { + background:#D6DAF0; + color:#000000; + font-family:serif; +} +.replyhl { + background: #D6BAD0; + color: #000000; +} +.doubledash { + vertical-align:top; + clear:both; + float:left; +} +.replytitle { + background:inherit; + font-size:18px; + font-family:serif; + color:#0F0C5D; + font-weight:800; +} +.commentpostername { + background:inherit; + font-size:12px; + font-family:serif; + color:#117743; + font-weight:800; +} +.thumbnailmsg { + background:inherit; + font-size:9px; + font-family:sans-serif; + color:#000000; +} + +.watchedthreads { + background-color: #D6DAF0 !important; + border: 1px dotted #D6DAF0 !important; + border-top: 0px none !important; +} + +.reflinkpreview { + background-color: #D6DAF0 !important; +} \ No newline at end of file diff --git a/css/extras/fuhrerchan.css b/css/extras/fuhrerchan.css new file mode 100644 index 0000000..4a4d207 --- /dev/null +++ b/css/extras/fuhrerchan.css @@ -0,0 +1,135 @@ +html, body { + font-size:10pt; + background:#FFFFFF; + color:#000000; +} +* { + font-family: "Trebuchet MS", Tahoma, Verdana, Arial, sans-serif; + font-size: 10pt; +} +input, textarea { + background-color: #DCDDDE; + border: 1px solid #919191; +} +a { + background:inherit; + color:#000000; +} +a:visited { + background:inherit; + color:#212121; +} +a:hover { + color:#212121; + background:inherit; +} +a.quotelink { + background:inherit; + color:#404040; +} +.logo { + clear:both; + text-align:center; + background:inherit; + font-size:24pt; + color:#000000; + width:100%; +} +.postarea { + background:inherit; +} +.postblock { + background: #919191; + border: 1px solid #000000; + color: black; + font-weight: bold; + padding: 2px 5px 2px 5px; +} +.footer { + text-align:center; + font-size:12px; +} +.unkfunc { + background:inherit; + color:#BFBFBF; +} +.filesize { + text-decoration:none; +} +.filetitle { + background:inherit; + color:#404040; + font-weight:800; +} +.postername { + background:inherit; + font-size:11pt; + color:#737373; + font-weight: bold; +} +.postertrip { + background:inherit; + color:#000000; +} +.oldpost { + background:inherit; + color:#404040; + font-weight:800; +} +.omittedposts { + background:inherit; + color:#070707; +} +.reply { + background:#DCDDDC; + color:#000000; + border:1px solid #919191; +} +.replyhl { + background:#BFBFBF; + color:#000000; +} +.doubledash { + vertical-align:top; + clear:both; + float:left; +} +.replytitle { + background:inherit; + font-size:18px; + color:#FFFFFF; + font-weight:800; +} +.commentpostername { + background:inherit; + font-size:11pt; + color:#737373; + font-weight: bold; +} +a.quotejs { + color:#000000; + text-decoration: none; +} +a.quotejs:hover { + font-weight:bold; +} + +.adminbar { + text-align: left; +} + +hr { + border-style: solid none none none; + border-width: 1px; + border-color: #000000; +} + +#watchedthreads { + background-color: #DCDDDC !important; + border: 1px solid #919191 !important; + border-top: 0px none !important; +} + +.reflinkpreview { + background-color: #DCDDDC !important; +} \ No newline at end of file diff --git a/css/extras/gurochan.css b/css/extras/gurochan.css new file mode 100644 index 0000000..1247b9f --- /dev/null +++ b/css/extras/gurochan.css @@ -0,0 +1,129 @@ +html, body { + font-size:10pt; + background:#EDDAD2; + color:#000000; +} +* { + font-family: "Trebuchet MS", Tahoma, Verdana, Arial, sans-serif; + font-size: 10pt; +} +input, textarea { + background-color: #E6CBC0; + border: 1px solid #CA927B; +} +a { + background:inherit; + color:#34345C; +} +a:visited { + background:inherit; + color:#34345C; +} +a:hover { + color:#DD0000; + background:inherit; +} +a.quotelink { + background:inherit; + color:#DD0000; +} +.logo { + clear:both; + text-align:center; + background:inherit; + font-size:24pt; + color:#AF0A0F; + width:100%; +} +.postarea { + background:inherit; +} +.postblock { + background: #D9AF9E; + border: 1px solid #CA927B; + color: black; + font-weight: bold; + padding: 2px 5px 2px 5px; +} +.footer { + text-align:center; + font-size:12px; +} +.unkfunc { + background:inherit; + color:#789922; +} +.filesize { + text-decoration:none; +} +.filetitle { + background:inherit; + color:#0F0C5D; + font-weight:800; +} +.postername { + background:inherit; + font-size:11pt; + color:#117743; + font-weight: bold; +} +.postertrip { + background:inherit; + color:#228854; +} +.oldpost { + background:inherit; + color:#0F0C5D; + font-weight:800; +} +.omittedposts { + background:inherit; + color:#070707; +} +.reply { + background:#D9AF9E; + color:#000000; + border:1px solid #CA927B; +} +.replyhl { + background: #D6BAD0; + color: #000000; +} +.doubledash { + vertical-align:top; + clear:both; + float:left; +} +.replytitle { + background:inherit; + font-size:18px; + color:#0F0C5D; + font-weight:800; +} +.commentpostername { + background:inherit; + font-size:11pt; + color:#117743; + font-weight: bold; +} +a.quotejs { + color:#000000; + text-decoration: none; +} +a.quotejs:hover { + font-weight:bold; +} + +.adminbar { + text-align: center; +} + +#watchedthreads { + background-color: #D9AF9E !important; + border: 1px solid #CA927B !important; + border-top: 0px none !important; +} + +.reflinkpreview { + background-color: #D9AF9E !important; +} \ No newline at end of file diff --git a/css/extras/harrischan.css b/css/extras/harrischan.css new file mode 100644 index 0000000..2059f85 --- /dev/null +++ b/css/extras/harrischan.css @@ -0,0 +1,188 @@ +/* +This css file was created by Harrison for 24chan.org. Use anywhere else without permission is prohibited. +Contact: HarrisonHopkins@Gmail.com +*/ + +html, body { + background:#000; + color:#FFF; +} +a { + color:#888; + text-decoration: none; +} +a:hover { + color:#888; +} +.reflink a:hover{ + font-weight: bold; +} +input, textarea { +background-color: #000; +color: #fff; +border: 1px solid #CCC; +} +input:focus, textarea:focus +{ +background-color: #444; +} +.adminbar { + text-align:right; + clear:both; + float:right; + font-size: 13px; +} +.navbar { + font-size: 13px; +} +.logo { + clear:both; + text-align:center; + font-size:2em; + color:#FFF; + width:100%; +} +.replymode { + background:#AAA; + text-align:center; + padding:2px; + color:#000; + width:100%; +} +.catalogmode { + background:#0040E0; + text-align:center; + padding:2px; + color:#FFFFFF; + width:100%; +} +.postarea { +} +.rules { + /*font-size:0.7em;*/ + width: 468px; + font-size: 10px; + font-family: sans-serif; +} +.rules li { + margin-left: 1em; + /*text-indent: 0em;*/ +} +.postblock { + background:#444; + color:#CCC; + font-weight:800; + text-align: left; + padding-left: 3px; + padding-right: 3px; + border: 1px solid #666; +} +.footer { + text-align:center; + font-size:12px; + font-family:serif; +} +.passvalid { + background:#444; + text-align:center; + width:100%; + color:#ffffff; +} +.dellist { + font-weight: bold; + text-align:center; +} +.delbuttons { + text-align:center; + padding-bottom:4px; + +} +.managehead { + background:#AAAA66; + color:#400000; + padding:0px; +} +.postlists { + background:#FFFFFF; + width:100%; + padding:0px; + color:#FFF; +} +.row1 { + background:#EEEECC; + color:#FFF; +} +.row2 { + background:#DDDDAA; + color:#FFF; +} +.unkfunc { + background:inherit; + color:#789922; +} +.filesize { + text-decoration:none; +} +.filetitle { + background:inherit; + font-size:1.2em; + color:#CC1105; + font-weight:800; +} +.postername { + color:#CCC; + font-weight:bold; +} +.postertrip { + color:#CCC; +} +.oldpost { + color:#CC1105; + font-weight:800; +} +.omittedposts { + color:#707070; +} +.reply { + background: #444; + color: #FFF; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + padding: 5px; +} +.replyhl { + background: #F0C0B0; + color: #FFF; +} +.doubledash { + vertical-align:top; + clear:both; + float:left; +} +.replytitle { + font-size: 1.2em; + color:#CC1105; + font-weight:800; +} +.commentpostername { + color:#117743; + font-weight:800; +} +.thumbnailmsg { + font-size: small; + color:#FFF; +} +.abbrev { + color:#707070; +} +.highlight { + background:#444; + color:#FFF; + border: 2px dashed #FFF; +} +#watchedthreads { + background-color: #444 !important; +} +.reflinkpreview { + background-color: #444 !important; +} \ No newline at end of file diff --git a/css/extras/kusaba.css b/css/extras/kusaba.css new file mode 100644 index 0000000..d23a9fa --- /dev/null +++ b/css/extras/kusaba.css @@ -0,0 +1,232 @@ +html, body { + font-size:12pt; + background:#EEFFEE; + color:#000000; +} +a { + background:inherit; + color:#345C34; + text-decoration:none; + font-family:sans-serif; +} +a:visited { + background:inherit; + color:#345C34; + text-decoration:none; + font-family:sans-serif; +} +a:hover { + color:#117743; + background:inherit; + text-decoration:underline; + font-family:sans-serif; +} +.adminbar { + text-align:right; + background:inherit; + clear:both; + float:right; +} +.logo { + clear:both; + text-align:center; + background:inherit; + font-size:24pt; + color:#117743; + width:100%; +} +.theader { + background:#00E010; + color:#FFFFFF; + width:100%; +} +.postarea { + background:inherit; +} +.rules { + font-size:10px; + font-family:sans-serif; +} +.postblock { + background:#88DD88; + color:#000000; + font-weight:800; +} +.footer { + text-align:center; + font-size:10px; + font-family:sans-serif; +} +.passvalid { + background:#99EE88; + text-align:center; + width:100%; + color:#ffffff; +} +.dellist { + background:inherit; + text-align:center; +} +.delbuttons { + background:inherit; + text-align:center; + padding-bottom:4px; + +} +.managehead { + background:#0FE18F; + color:#000000; + font-family:sans-serif; + font-size:14px; + padding:0px; +} +.postlists { + background:#FFFFFF; + width:100%; + padding:0px; + color:#000000; +} +.row1 { + background:#9AF6D2; + font-family:sans-serif; + font-size:12px; + color:#000000; +} +.row2 { + background:#FFFFFF; + font-family:sans-serif; + font-size:12px; + color:#000000; +} +.unkfunc { + color:#117743; +} +.filesize { + font-size:12px; + font-family:sans-serif; + text-decoration:underline; + padding-left:3em; +} +.filetitle { + background:inherit; + font-size:18px; + font-family:serif; + color:#0F5D0C; + font-weight:800; +} +.postername { + background:inherit; + font-family:serif; + color:#117743; + font-weight:bold; +} +.postername a { + font-family:inherit; +} +.oldpost { + background:inherit; + font-size:18px; + font-family:serif; + color:#0F5D0C; + font-weight:800; +} +.omittedposts { + background:inherit; + font-size:18px; + font-family:serif; + color:#070707; + font-weight:800; +} +.reply { + background:#DAF0D6; + color:#000000; + font-family:serif; +} +.doubledash { + vertical-align:top; + clear:both; + float:left; +} +.replytitle { + background:inherit; + font-size:18px; + font-family:serif; + color:#0F5D0C; + font-weight:800; +} +.commentpostername { + background:inherit; + font-size:12px; + font-family:serif; + color:#117743; + font-weight:800; +} +.thumbnailmsg { + background:inherit; + font-size:9px; + font-family:sans-serif; + color:#000000; +} + +.highlight { + background: #88DD88; + border: 2px dashed #117743; +} + +#watchedthreads { + background-color: #DAF0D6 !important; + border: 1px solid #88DD88 !important; +} + +.replymode { + background:#DAF0D6; + text-align:center; + padding:2px; + color:#000000; + width:100%; + font-weight: bold; +} +.catalogmode { + background:#88DD88; + text-align:center; + padding:2px; + color:#000000; + width:100%; + font-weight: bold; +} + +.hidethread { + background: transparent url('./icons/green/icons.gif') -32px -16px no-repeat; +} + +.unhidethread { + background: transparent url('./icons/green/icons.gif') -48px 0px no-repeat; +} + +.watchthread { + background: transparent url('./icons/green/icons.gif') -32px 0px no-repeat; +} + +.expandthread { + background: transparent url('./icons/green/icons.gif') 0px -16px no-repeat; +} + +.quickreply { + background: transparent url('./icons/green/icons.gif') 0px 0px no-repeat; +} + +.hidewatchedthreads { + background: transparent url('./icons/green/icons.gif') -48px -16px no-repeat; +} + +.refreshwatchedthreads { + background: transparent url('./icons/green/icons.gif') -16px -16px no-repeat; +} + +.restorewatchedthreads { + background: transparent url('./icons/green/icons.gif') -16px 0px no-repeat; +} + +.reflinkpreview { + background-color: #DAF0D6 !important; +} \ No newline at end of file diff --git a/css/extras/photon.css b/css/extras/photon.css new file mode 100644 index 0000000..9478317 --- /dev/null +++ b/css/extras/photon.css @@ -0,0 +1,171 @@ +html, body { + background-color: #EEEEEE; + color: #333333; + font-family: "Trebuchet MS",Trebuchet,serif; +} +a { + color: #FF6600; +} +a:hover { + color: #0066FF; +} +.adminbar { + clear:both; + float:right; + font-size: .8em; +} +.adminbar a { + font-weight: bold; +} +.logo { + clear:both; + text-align:left; + font-size:2em; + font-weight: bold; + color:#FF6600; +} +.theader, .passvalid, .replymode { + background:#DDDDDD; + text-align:center; + padding:2px; + color:#2266AA; + clear: both; + font-weight: bold; + margin-bottom: .5em; + border: solid 1px #CCCCCC; + -moz-border-radius: 5px; +} +.rules { + font-size:0.7em; +} +.postblock { + background:transparent; + color:#002244; + font-weight:bold; +} +.footer { + text-align:center; + font-size:12px; + font-family:serif; + margin: 2em 0 0 0; +} +.dellist { + font-weight: bold; + text-align:center; +} +.delbuttons { + text-align:center; + padding-bottom:4px; +} +.managehead { + background:#DDDDDD; + color:#002244; + padding:0px; +} +.postlists { + background:#FFFFFF; + width:100%; + padding:0px; + color:#800000; +} +.row1 { + background:#DDDDDD; + color:#002244; +} +.row2 { + background:#CCCCCC; + color:#002244; +} +.unkfunc { + background:inherit; + color:#789922; +} +.reflink { + font-size: .8em; + font-weight: bold; +} +.filesize { + text-decoration:none; + color: #666666; + font-size: .8em; +} +.filetitle { + background:inherit; + font-size:1.2em; + color:#002244; + font-weight:bold; +} +.postername { + color:#004A99; + font-weight:bold; +} +.postertrip { + color:#FF3300; +} +.oldpost { + color:#CC1105; + font-weight:bold; +} +.omittedposts { + color:#666666; +} +.reply { + background:#DDDDDD; + border: solid 1px #CCCCCC; + padding: 0; + margin: 0; + -moz-border-radius: 5px; +} +blockquote { + margin: .5em .5em .5em 1em; +} +blockquote p { + margin: 0; + padding: 0; +} +.reply blockquote { + margin: .5em; +} +.doubledash { + display: none; + vertical-align:top; + clear:both; + float:left; +} +.replytitle { + font-size: 1.2em; + color:#002244; + font-weight:bold; +} +.commentpostername { + color:#004A99; + font-weight:800; +} +.thumbnailmsg { + font-size: .8em; + color:#666666; +} +hr { + border-style: solid none none none; + border-width: 1px; + border-color: #BBBBBB; +} +table { + border-style: none; +} +table td { + border-style: none; +} +.nothumb { + background-color: #FFFFFF; + border-style: dotted; + margin: .3em .5em; +} +.abbrev { + color:#666666; +} +.highlight { + background:#EEDACB; + color:#333333; + border: 2px dashed #EE6600; +} \ No newline at end of file diff --git a/css/extras/site_harrischan.css b/css/extras/site_harrischan.css new file mode 100644 index 0000000..7f2cb4e --- /dev/null +++ b/css/extras/site_harrischan.css @@ -0,0 +1,142 @@ +/* +This css file was created by Harrison for 24chan.org. Use anywhere else without permission is prohibited. +Contact: HarrisonHopkins@Gmail.com +*/ +body { + font-family: sans-serif; + background: #000; + color: #FFF; + margin: 0; + font-size: 75%; + width: 90%; +} + +#topmenu li { + display: block; + float: left; + border: 1px solid #888; + padding-top: 3px; + padding-bottom: 2px; + padding-left: 10px; + padding-right: 10px; + border-left: none; + margin-top: -7px; + background-color: #666; +} + +#topmenu li.first { + border-left: 1px solid #888; +} + +#topmenu li.current { + margin-top: -8px; + padding-top: 5px; + border-bottom: none; + background-color: #444; + background-image: url('/css/images/grad-bg.png'); + background-repeat: repeat-x; +} +a { + color: #CCC; + text-decoration: none; +} + +h2 { + margin-top: 0px; + background: #444; + font-size: 100%; + padding: 1px 5px 1px 5px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + -moz-border-radius-topleft: 0px; +} + +h2 a { + text-decoration: none; + color: #CCC; +} + +h1, h3, .menu { + font-family: Verdana,Tahoma,sans-serif; +} + +h1 { + margin: 0; + color: #FFF; + text-align: center; + margin-top: 1em; +} + +h3 { + margin: 0; + color: #FFF; + text-align: center; + font-weight: normal; + font-size: medium; +} + +.menu { + margin-top: 1em; + text-align: center; +} + +.content { + margin-left: 3em; + text-align: justify; + padding-left: 4px; +} + +.newssub { + position: absolute; +} + +.permalink { + text-align: right; + display: block; +} + +.permalink a { + color: #CCC; + text-decoration: underline; +} + + +#boards .column { + float: left; + width: 33%; + height: 200px; + padding-bottom: 10px; + border-left: 1px solid #444; + border-right: 1px solid #444; + border-bottom: 1px solid #444; +} + +ul {list-style: none;} + +h4 { +text-align: center; +} + +#boards a:hover { + text-decoration: underline; +} + +#boardhead { + text-align: center; + background-color: #444; + height: 20px; +margin-top: 15px; + padding-top: 0px; + padding-bottom: 3px; + font-size: 150%; + background-image: url('/css/images/grad-bg.png'); + background-repeat: repeat-x; + -moz-border-radius-topleft: 2px; + -moz-border-radius-topright: 2px; +} + +h4 { + font-size: 100%; + font-weight: bold; + margin-top: 16px; +} \ No newline at end of file diff --git a/css/extras/site_kusaba.css b/css/extras/site_kusaba.css new file mode 100644 index 0000000..5141aec --- /dev/null +++ b/css/extras/site_kusaba.css @@ -0,0 +1,73 @@ +body { + font-family: sans-serif; + font-size: 75%; + background: #EEFFEE; + color: #000000; + margin: 0; + width: 90%; +} + +h2 { + margin: 0px; + background: #DAF0D6; + color: #117743; + font-size: 100%; +} + +h2 a { + text-decoration: none; + color:#345C34; +} + +h1, h3, .menu { + font-family: Verdana,Tahoma,sans-serif; +} + +h1 { + margin: 0; + /*color: #800;*/ + text-align: center; + margin-top: 1em; +} + +h3 { + margin: 0; + /*color: #800;*/ + text-align: center; + font-weight: normal; + font-size: medium; +} + +.menu { + margin-top: 1em; + text-align: center; +} + +.content { + margin-left: 3em; +} + +.newssub { + position: absolute; +} + +.permalink { + text-align: right; + display: block; +} + +.permalink a { + color: blue; + text-decoration: none; +} +/*h1 { font-size: 150% }*/ +/*h2 { font-size: 100%; margin-top: 1em } +.hl { + font-style: italic; +} +.plus { float: right; font-size: 8px; font-weight: normal; padding: 1px 4px 2px 4px; margin: 0px 0px; background: #eb9; color: #000; border: 1px solid #da8; cursor: hand; cursor: pointer } +.plus:hover { background: #da8; border: 1px solid #c97 } +ul { list-style: none; padding-left: 0px; margin: 0px } +li { margin: 0px } +li:hover { background: #fec; } +li a { display: block; width: 100%; }/* \ No newline at end of file diff --git a/css/extras/site_photon.css b/css/extras/site_photon.css new file mode 100644 index 0000000..75e7d87 --- /dev/null +++ b/css/extras/site_photon.css @@ -0,0 +1,83 @@ +body { + background-color: #EEEEEE; + color: #333333; + font-family: "Trebuchet MS",Trebuchet,serif; + margin: 0; + width: 90%; +} + +a { + color: #FF6600; +} + +a:hover { + color: #0066FF; +} + +.menu { + margin-top: 1em; + text-align: center; +} + +.content { + margin-left: 2.5em; + text-align: justify; + padding-left: 4px; + background-color: #DDDDDD; + border: 1px solid #888; +} + +.newssub { + position: absolute; +} + +.permalink { + text-align: right; + display: block; +} + +#topmenu li { + display: block; + float: left; + border: 1px solid #888; + padding-top: 3px; + padding-bottom: 2px; + padding-left: 10px; + padding-right: 10px; + border-left: none; + margin-top: -7px; + background-color: #CCCCCC; + -moz-border-radius-topright: 5px; + -moz-border-radius-topleft: 5px; +} + +#topmenu li.first { + border-left: 1px solid #888; + padding-bottom: 3px; +} + +#topmenu li.current { + margin-top: -8px; + padding-top: 5px; + border-bottom: none; + background-color: #DDDDDD; +} + +h2 { + background:#CDCDCD; + border: solid 1px #888; + -moz-border-radius: 5px; + margin-top: 1em; + padding-left: .5em; + margin-right: .3em; + cursor: pointer; + font-size: 1.1em; + margin-bottom: 0em; + padding-bottom: 0em; +} + +h3 { + font-size: 1.1em; + text-align: right; + font-style: Arial; +} \ No newline at end of file diff --git a/css/extras/sitemenu_harrischan.css b/css/extras/sitemenu_harrischan.css new file mode 100644 index 0000000..e1d0712 --- /dev/null +++ b/css/extras/sitemenu_harrischan.css @@ -0,0 +1,77 @@ +/* +This css file was created by Harrison for 24chan.org. Use anywhere else without permission is prohibited. +Contact: HarrisonHopkins@Gmail.com +*/ + +body { + font-size: 70%; + margin: 8px; + font-family: sans-serif; + width: 90% !important; +} + +a { + text-decoration: none; + color: #CCC; +} + +h1, h2 { + background: #444; + text-align: left; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + padding: 0px; + margin: 0; +} + +h1 { + margin-top: 0px; + font-size: 150%; + color: #FFF; + padding-left: 5px; +} + +h2 { + font-size: 100%; + margin-top: 1em; +} + +.plus { + float: right; + font-size: 8px; + font-weight: normal; + padding: 1px 4px 2px 4px; + margin: 0px 0px; + background: #444; + color: #FFF; + cursor: hand; + cursor: pointer; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; +} + +.plus:hover { + background: #444; +} + +ul { + list-style: none; + padding-left: 0px; + margin: 0px; +} + +li { + margin: 0px; + padding-left: 5px; +} + +li:hover { + background: #333; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; +} + +li a { + display: block; + width: 99%; +} \ No newline at end of file diff --git a/css/extras/sitemenu_kusaba.css b/css/extras/sitemenu_kusaba.css new file mode 100644 index 0000000..9696617 --- /dev/null +++ b/css/extras/sitemenu_kusaba.css @@ -0,0 +1,61 @@ +body { + margin: 8px; +} + +a { + text-decoration: none; + color: #550; +} + +h1, h2 { + background: #DAF0D6; + text-align: left; +} + +h1 { + margin-top: 0px; + font-size: 150%; + color: #000; +} + +h2 { + font-size: 100%; + margin-top: 1em; +} + +.plus { + float: right; + font-size: 8px; + font-weight: normal; + padding: 1px 4px 2px 4px; + margin: 0px 0px; + background: #88DD88; + color: #000; + border: 1px solid #117743; + cursor: hand; + cursor: pointer; +} + +.plus:hover { + background: #da8; + border: 1px solid #c97; +} + +ul { + list-style: none; + padding-left: 0px; + margin: 0px; +} + +li { + margin: 0px; +} + +li:hover { + background: #DAF0D6; +} + +li a { + display: block; + width: 100%; +} \ No newline at end of file diff --git a/css/extras/sitemenu_photon.css b/css/extras/sitemenu_photon.css new file mode 100644 index 0000000..c596ede --- /dev/null +++ b/css/extras/sitemenu_photon.css @@ -0,0 +1,46 @@ +body { + margin-top: 0; + margin-left: .1em; + margin-right: 1.em; +} + +a { + color: #FF6600; +} + +a:hover { + color: #0066FF; +} + +h1 { + margin-top: .1em; + margin-left: .5em; +} + +h2 { + background:#DDDDDD; + border: solid 1px #CCCCCC; + margin-top: 1em; + padding-left: .5em; + cursor: pointer; + font-size: 1.1em; + margin-bottom: 0em; + padding-bottom: 0em; + -moz-border-radius: 5px; +} + +li { + margin-left: .5em; + padding-left: .5em; + border-left: solid 1px #CCCCCC; + list-style: none; + margin-top: 0em; + padding-top: 0em; +} + +ol, ul { + list-style-position: inside; + padding-left: 0em; + margin-top: 0em; + padding-top: 0em; +} \ No newline at end of file diff --git a/css/extras/txt_harristxt.css b/css/extras/txt_harristxt.css new file mode 100644 index 0000000..d8c7372 --- /dev/null +++ b/css/extras/txt_harristxt.css @@ -0,0 +1,262 @@ +body +{ + background: #000; + font-family: sans-serif; + margin: 0; + color: #FFF; +} +a +{ + color: #888; + text-decoration: none; +} +a:hover +{ + text-decoration: underline; +} +h1 +{ + color: #000; + padding: .5em; +} +.head +{ + background: #444; +} +.threadldiv, body.board .thread, .midhead, .newthread, .head +{ + margin: 1em; + margin-left: 2.5%; + margin-right: 2.5%; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} +.threadldiv, .thread, .midhead, .newthread +{ + background: #444; + padding: 1px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + margin-top: 5px; + margin-bottom: 5px; +} +.midhead +{ + padding: .5em; +} +.threadlink, .boldthreadlink +{ + display: block; + text-align: center; +} +.boldthreadlink +{ + font-weight: bold; + } +.tolder +{ + display: none; +} +h2 +{ + margin: .1em; + padding-left: .3em; + padding-top: .1em; +} +h2 a +{ + background: #444; + text-decoration: underline; +} +.replies +{ + font-size: x-large; + font-weight: bolder; + padding-right: .5em; + font-family: serif; +} +.topbar a +{ + color: #888; + font-family: IPAMonaPGothic,Mona,'MS PGothic',YOzFontAA97; +} +.threadlistflat +{ + margin-bottom:0; +} +.postheader * +{ + clear: none; + margin: 0; + margin-bottom: .1em; +} +.post, form +{ + width: 90%; + margin-left: 9%; + margin-top: 1em; +} +.hidden +{ + margin-left: .5em; +} +form +{ + margin-left: 2.9em; +} +.post +{ + background: #000; + /*border: 1px solid #888;*/ + padding-bottom: .1em; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; +} +h3 +{ + font-weight: normal; + font-size: x-small; +/* color: grey;*/ + margin: 0; + margin-right: .1em; + text-align: right; + clear: none; + height: 0; +} +h3 a +{ +/* color: grey;*/ + font-weight: bold; +} +h3 .postnum a, form .postnum +{ + text-decoration: none; + font-size: xx-large; + color: black; + font-style: italic; + font-family: serif; + font-weight: bolder; + float: left; + clear: none; + width: 1.5em; + text-align: right; + vertical-align: middle; +} +.namelabel +{ + display: none; +} +form .postnum +{ + padding-right: .3em; +} +h3 .postnum a, blockquote +{ + position: relative; + left: -2em; +} +h3 .postnum a +{ + height: 0; +} +blockquote +{ + clear: left; +} +blockquote p +{ + margin: 0; +} +table .submit +{ + width: 100%; +} +td.label +{ + text-align: right; +} +table .mail +{ + width: auto; + float: right; +} +.legal +{ + text-align: center; + font-size: small; +} +.manage +{ + text-align: center; + font-size: x-small; +} +.stylelist +{ + display: inline-block; + float: right; +} +body.read h2 +{ + color: #888; + font-size: larger; +} +.read +{ + background: #444; +} +.pages +{ + font-size: smaller; +} +.bottomnav +{ + text-align: center; +} +.topbar +{ + margin-bottom: .5em; + width: 100%; + text-align: left; +} +.threads +{ + background: #000; +} +.threads th +{ + padding: 0px; + margin: 0px; +} +.threads thead +{ + background: #444; +} +.threads a +{ + /*display: block; +*/} +.threads a:hover +{ + text-decoration: none; +} +.threads tr:hover +{ +/* background: #dfe3f9;*/ +} +.threads th +{ + background: #444 !important; +} +.threads a +{ + display: block; +} +.quote:hover +{ + background: #444 !important; +} +.thread +{ +margin-left: 2px; +margin-right: 2px; +} \ No newline at end of file diff --git a/css/extras/txt_headline.css b/css/extras/txt_headline.css new file mode 100644 index 0000000..ab3baa2 --- /dev/null +++ b/css/extras/txt_headline.css @@ -0,0 +1,170 @@ +body { + padding: 0px 8px 8px 8px; + margin: 0px; + background: #FFFFFF; + color: #000000; +} + +a { + color: #DD6600; +} + +a:visited { + color: #DD6600; +} + +a:hover { + color:#FFAA44; +} + +form { + clear: both; + background: #EEEEEE; + color: #000000; + border-bottom: 2px solid #BBBBBB; + font-family: sans-serif; + margin: 3px; + padding: 3px; +} + +input, textarea { + border: 1px solid #000000; +} + +input[type="file"] > input[type="text"] { + border: 1px solid #000000; +} + +ol ul, ul ol, ul ul, ol ol { + margin-top: 0; + margin-bottom: 0; +} + +ol p:first-child, ul p:first-child { + margin-top: 0; +} + +ol p:last-child, ul p:last-child { + margin-bottom: 0; +} + +.topbar { + width: 100%; + text-align: right; +} + +.head { + background: #EEEEEE; + color: #000000; + font-family: sans-serif; + clear: both; + margin-bottom: 0.5em; + padding-bottom: 0; +} + +.hborder .head { + border-bottom: 2px solid #BBBBBB; +} + +h1 { + font-size: 2em; + font-weight: bold; + text-align: center; + border-bottom: 2px solid #FF7700; + padding: 4px 4px 0px 4px; +} + +h2 { + float: left; + background: #EEEEEE; + border-bottom: 2px solid #FF7700; + font-size: 1.2em; + font-family: sans-serif; + font-weight: bold; + margin: 0px 0px 0.7em 0px; + padding: 0px 0.2em 0px 0px; +} + +h2 a { + color: #000000; + text-decoration: none; +} + +h2 a:hover { + color:#FFAA44; +} + +h2 small { + font-size: 1em; + font-weight: normal; + margin-left: 0.5em; +} + +.midhead { + padding: 1em 0.5em 0.2em 0.5em; +} + +.navlinks { + font-size: 1.5em; +} + +.threadlinks { + font-weight: bold; +} + +.postnum { + width: 1.5em; + font-family: sans-serif; + text-align: right; + font-weight: bold; + margin-right: 0.5em; + float: left; +} + + +.postnum a { + color: #000000; + text-decoration: none; +} + +.postnum a:hover { + color:#FFAA44; +} + +.replies { + clear: both; + margin-bottom: 1.2em; + padding: 4px; + font-size: 1em; + font-weight: normal; +} + +h3 { + font-size: 1em; + font-family: sans-serif; + font-weight: normal; + margin: 0px 0px 0px 0px; + clear: both; +} + +h3 a { + color: #000000; +} + +h3 a:hover { + color:#FFAA44; +} + +.postername { + color: #000000; + font-weight: bold; +} + +.postertrip { + color: #000000; +} + +.legal { + text-align: center; + font-size: small; +} \ No newline at end of file diff --git a/css/extras/txt_pseud0ch.css b/css/extras/txt_pseud0ch.css new file mode 100644 index 0000000..cdfa2da --- /dev/null +++ b/css/extras/txt_pseud0ch.css @@ -0,0 +1,55 @@ +a:link, a:visited {color: blue} +a:hover, a:active {color: red} + +body.board, body.list {margin: 0} +body.board {background-image: url(ba.gif);} +body.read {background-color: #efefef;} +.head, body.board .thread { border: 1px inset gray; padding: 6px;} +table.postform td {text-align: left;} +table.postform td input {width: auto;} +table.newthreadform .submit {width: 100%;} +table.postform td textarea {width: auto;} +table.postform td.label {text-align: right;} +table.postform .mail {width: auto; float: right;} +.legal {text-align: center; font-size: small;} +.manage {text-align: center; font-size: x-small;} +.postnum {font-weight: bold; margin-right: .1em;} +.postername,.postertrip {color: green;} +.postername {font-weight: bold;} +blockquote {text-align: left; font-family: serif; margin-top: 0.5em;} +blockquote p {margin-top: 0;} +.border, .hborder {border: 1px outset gray; margin-left: 2.5%; margin-right: 2.5%; width: 95%; padding: 6px; margin-bottom: 1em; background-color: #efefef} +.hborder {background-color: #cfc} +h2 {margin-top: 0px; clear: both;} +/*.threadldiv {margin-right: 2.5%; margin-left: 2.5%; margin-bottom: 1em; background-color: #cfc; width: 95%;}*/ +.threads {font-size: small; text-align: left;} +table.threads th {text-align: center;} +.topbar {margin: -2px; margin-bottom: .5em; background: white; border: 1px inset black; width: 100%; text-align: right} +.styles {border: 2px outset black; margin: 2px; background: white; float: left; margin-top: 0; margin-left: 0} +.threads th a, .threads td a, .postfieldleft a, .postnum a {color: black;} +.postfieldleft a, .postnum a, h2 a {text-decoration: none} +.postfieldleft {vertical-align: top;} +.replies {font-size: 70%; font-weight: bolder;} +h2 a:link, h2 a:visited, h2 a:active, h2 a:hover {color: red;} +h2 a:hover, h2 a:active {text-decoration: underline} +h2, .navlinks {clear: none; margin-bottom: .1em;} +.pages {font-size: smaller} +.bottomnav {text-align: center;} +.newthread h2 {color: black;} +.postinfo {margin-left: .3em;} +.navlinks a {font-family: IPAMonaPGothic,Mona,'MS PGothic',YOzFontAA97} +h3 {font-weight: normal; font-size: 100%; margin-top: 0; margin-bottom: 0} +.tolder {font-size: smaller} + +body.read h2 {color: red; font-size: larger} + +.threadlistflat {display: inline; padding: 0; margin: 0} +.threadlink {display: inline; text-align: justify;} +.pages {text-align: center; font-size: small;} + +.navlinks {float: right;} +.navlinks a {text-decoration: none} +.threadlink {padding-right: .55em;} +.boldthreadlink {padding-right: .55em; font-weight: bold;} + +.stylelist {display: inline-block; float: right} \ No newline at end of file diff --git a/css/extras/txt_yotsuba.css b/css/extras/txt_yotsuba.css new file mode 100644 index 0000000..5929af3 --- /dev/null +++ b/css/extras/txt_yotsuba.css @@ -0,0 +1,121 @@ +body {background: #ffe; font-family: sans-serif; margin: 0} +a { color: #550 } + +h1 {color: #800; padding: .5em} +.head {background: #fca;} + +.threadldiv, body.board .thread, .midhead, .newthread, .head { +margin: 1em; +margin-left: 2.5%; +margin-right: 2.5%; +} + +.threadldiv, .thread, .midhead, .newthread { +background: #f9e9dd; padding: 1px; +} + +.midhead {padding: .5em} + +.threadlink, .boldthreadlink { +display: block; +text-align: center +} + +.boldthreadlink {font-weight: bold} + +.tolder {display: none} + +h2 {margin: .1em; padding-left: .3em; padding-top: .1em} +h2 a {color: #cc1105; text-decoration: none} + +.replies { +font-size: x-large; +font-weight: bolder; +padding-right: .5em; +font-family: serif +} + +.topbar a { +color: #cc1105; +font-family: IPAMonaPGothic,Mona,'MS PGothic',YOzFontAA97 +} + +.threadlistflat {margin-bottom:0} + +.postheader * {clear: none; margin: 0; margin-bottom: .1em;} + +.post, form { +width: 90%; +margin-left: 9%; +margin-top: 1em; +} + +.hidden {margin-left: .5em;} + +form {margin-left: 2.9em} + +.post { +background: #ffe; +/*border: 1px solid #fca;*/ +padding-bottom: .1em; +} + +h3 { +font-weight: normal; +font-size: x-small; +color: grey; +margin: 0; +margin-right: .1em; +text-align: right; +clear: none; +height: 0; +} + +h3 a {color: grey; font-weight: bold} + +h3 .postnum a, form .postnum { +text-decoration: none; +font-size: xx-large; +color: black; +font-style: italic; +font-family: serif; +font-weight: bolder; +float: left; +clear: none; +width: 1.5em; +text-align: right; +vertical-align: middle +} + +.namelabel {display: none} + +form .postnum {padding-right: .3em} + +h3 .postnum a, blockquote { +position: relative; +left: -2em; +} + +h3 .postnum a {height: 0} + +blockquote { +clear: left; +} + +blockquote p {margin: 0} + +table .submit {width: 100%;} +td.label {text-align: right;} +table .mail {width: auto; float: right;} + +.legal {text-align: center; font-size: small;} +.manage {text-align: center; font-size: x-small;} + +.stylelist {display: inline-block; float: right} + +body.read, body.read .thread {background: #f9e9dd} +body.read h2 {color: red; font-size: larger} +.pages {font-size: smaller} +.bottomnav {text-align: center;} + +.topbar {margin: -2px; margin-bottom: .5em; background: #f9e9dd; border: 1px inset #cc1105; width: 100%; text-align: right} \ No newline at end of file diff --git a/css/futaba.css b/css/futaba.css new file mode 100644 index 0000000..f19c97f --- /dev/null +++ b/css/futaba.css @@ -0,0 +1,165 @@ +html, body { + background:#FFFFEE; + color:#800000; +} +a { + color:#0000EE; +} +a:hover { + color:#DD0000; +} +.reflink a:hover{ + font-weight: bold; +} +.adminbar { + text-align:right; + clear:both; + float:right; +} +.logo { + clear:both; + text-align:center; + font-size:2em; + color:#800000; + width:100%; +} +.replymode { + background:#E04000; + text-align:center; + padding:2px; + color:#FFFFFF; + width:100%; +} +.catalogmode { + background:#0040E0; + text-align:center; + padding:2px; + color:#FFFFFF; + width:100%; +} +.postarea { +} +.rules { + /*font-size:0.7em;*/ + width: 468px; + font-size: 10px; + font-family: sans-serif; +} +.rules li { + margin-left: 1em; + /*text-indent: 0em;*/ +} +.postblock { + background:#EEAA88; + color:#800000; + font-weight:800; +} +.footer { + text-align:center; + font-size:12px; + font-family:serif; +} +.passvalid { + background:#EEAA88; + text-align:center; + width:100%; + color:#ffffff; +} +.dellist { + font-weight: bold; + text-align:center; +} +.delbuttons { + text-align:center; + padding-bottom:4px; + +} +.managehead { + background:#AAAA66; + color:#400000; + padding:0px; +} +.postlists { + background:#FFFFFF; + width:100%; + padding:0px; + color:#800000; +} +.row1 { + background:#EEEECC; + color:#800000; +} +.row2 { + background:#DDDDAA; + color:#800000; +} +.unkfunc { + background:inherit; + color:#789922; +} +.filesize { + text-decoration:none; +} +.filetitle { + background:inherit; + font-size:1.2em; + color:#CC1105; + font-weight:800; +} +.postername { + color:#117743; + font-weight:bold; +} +.postertrip { + color:#228854; +} +.oldpost { + color:#CC1105; + font-weight:800; +} +.omittedposts { + color:#707070; +} +.reply { + background: #F0E0D6; + color: #800000; +} +.replyhl { + background: #F0C0B0; + color: #800000; +} +.doubledash { + vertical-align:top; + clear:both; + float:left; +} +.replytitle { + font-size: 1.2em; + color:#CC1105; + font-weight:800; +} +.commentpostername { + color:#117743; + font-weight:800; +} +.thumbnailmsg { + font-size: small; + color:#800000; +} + +.abbrev { + color:#707070; +} +.highlight { + background:#F0E0D6; + color:#800000; + border: 2px dashed #EEAA88; +} + +#watchedthreads { + background-color: #F0E0D6 !important; +} + +.reflinkpreview { + background-color: #F0E0D6 !important; +} \ No newline at end of file diff --git a/css/icons/blank.gif b/css/icons/blank.gif new file mode 100644 index 0000000..ede75be Binary files /dev/null and b/css/icons/blank.gif differ diff --git a/css/icons/blue/icons.gif b/css/icons/blue/icons.gif new file mode 100644 index 0000000..cdb4210 Binary files /dev/null and b/css/icons/blue/icons.gif differ diff --git a/css/icons/brown/icons.gif b/css/icons/brown/icons.gif new file mode 100644 index 0000000..fc468df Binary files /dev/null and b/css/icons/brown/icons.gif differ diff --git a/css/icons/dark/icons.gif b/css/icons/dark/icons.gif new file mode 100644 index 0000000..85e9a0c Binary files /dev/null and b/css/icons/dark/icons.gif differ diff --git a/css/icons/gray/icons.gif b/css/icons/gray/icons.gif new file mode 100644 index 0000000..3467843 Binary files /dev/null and b/css/icons/gray/icons.gif differ diff --git a/css/icons/green/icons.gif b/css/icons/green/icons.gif new file mode 100644 index 0000000..45a8c67 Binary files /dev/null and b/css/icons/green/icons.gif differ diff --git a/css/icons/purple/icons.gif b/css/icons/purple/icons.gif new file mode 100644 index 0000000..3d4e3db Binary files /dev/null and b/css/icons/purple/icons.gif differ diff --git a/css/icons/red/icons.gif b/css/icons/red/icons.gif new file mode 100644 index 0000000..9d971a6 Binary files /dev/null and b/css/icons/red/icons.gif differ diff --git a/css/images/grad-bg.png b/css/images/grad-bg.png new file mode 100644 index 0000000..2ec172d Binary files /dev/null and b/css/images/grad-bg.png differ diff --git a/css/img_global.css b/css/img_global.css new file mode 100644 index 0000000..074c4b3 --- /dev/null +++ b/css/img_global.css @@ -0,0 +1,160 @@ +body { + margin: 0; + padding: 8px; + margin-bottom: auto; +} + +blockquote blockquote { + margin-left: 0em; +} + +form { + margin-bottom: 0px; +} + +form .trap { + display:none; +} + +.postarea { + text-align: center; +} + +.postarea table { + margin: 0px auto; + text-align: left; +} + +.thumb { + border: none; + float: left; + margin: 2px 20px; +} + +.nothumb { + float: left; + background: inherit; + border: 2px dashed #aaa; + text-align: center; + margin: 2px 20px; + padding: 1em 0.5em 1em 0.5em; + font-family: none; +} + +.reply blockquote, blockquote :last-child { + margin-bottom: 0em; +} + +.reflink a { + color: inherit; + text-decoration: none; +} + +.reflink a:hover{ + color: #800000; +} + +.reply .filesize { + margin-left: 20px; +} + +.userdelete { + float: right; + text-align: center; + white-space: nowrap; +} + +.replypage .replylink { + display: none; +} + +.pagelist { + max-width: 600px; +} + +.admin { + color: #800080; + font-weight: normal; +} + +.mod { + color: #FF0000; + font-weight: normal; +} + +.vip { + color: #336600; + font-weight: normal; +} + +#watchedthreads { + position: absolute; + background-color: #F0E0D6; + border: 1px dotted #EEAA88; + border-top: 0px none; +} + +#watchedthreadsdraghandle { + text-align: center; + font-family: Trebuchet MS; + cursor: move; +} + +#watchedthreadlist { + padding: 3px; + font-size: 0.8em; +} + +#watchedthreadsbuttons { + position: absolute; + bottom: 3px; + left: 3px; +} + +.spoiler { + color: black; + background-color: black; +} + +.extrabtns { + vertical-align: middle; +} + +.hidethread { + background: transparent url('./icons/blue/icons.gif') -32px -16px no-repeat; +} + +.unhidethread { + background: transparent url('./icons/blue/icons.gif') -48px 0px no-repeat; +} + +.watchthread { + background: transparent url('./icons/blue/icons.gif') -32px 0px no-repeat; +} + +.expandthread { + background: transparent url('./icons/blue/icons.gif') 0px -16px no-repeat; +} + +.quickreply { + background: transparent url('./icons/blue/icons.gif') 0px 0px no-repeat; +} + +.hidewatchedthreads { + background: transparent url('./icons/blue/icons.gif') -48px -16px no-repeat; +} + +.refreshwatchedthreads { + background: transparent url('./icons/blue/icons.gif') -16px -16px no-repeat; +} + +.restorewatchedthreads { + background: transparent url('./icons/blue/icons.gif') -16px 0px no-repeat; +} + +.reflinkpreview { + position: absolute; + padding: 5px; + background-color: #F0E0D6; + border: 1px dotted #000000; +} \ No newline at end of file diff --git a/css/kusabax.css b/css/kusabax.css new file mode 100644 index 0000000..733e0dd --- /dev/null +++ b/css/kusabax.css @@ -0,0 +1,206 @@ +html, body { + font-size:12pt; + background:#E6E6D1; + color:#000000; +} +input, textarea { + background-color: #AEB08D; + color: #000; + border: 1px solid #000; +} +a { + background:inherit; + color:#6E735E; + text-decoration:none; +} +a:visited { + background:inherit; + color:#6E735E; + text-decoration:none; +} +a:hover { + color:#000; + background:inherit; +} +.filesize a { + text-decoration:underline; +} +.filesize a:visited { + text-decoration:underline; +} +.adminbar { + text-align:right; + background:inherit; + clear:both; + float:right; +} +.logo { + clear:both; + text-align:center; + background:inherit; + font-size:24pt; + color:#AF0A0F; + width:100%; +} +.replymode { + background:#6E735E; + color:#FFFFFF; + width:100%; + text-align: center; + font-weight: 800; +} +.catalogmode { + background:#6E735E; + color:#FFFFFF; + width:100%; + text-align: center; + font-weight: 800; +} +.postarea { + background:inherit; +} +.rules { + /*font-size:0.7em;*/ + width: 468px; + font-size: 10px; + font-family: sans-serif; +} +.rules li { + margin-left: 1em; + /*text-indent: 0em;*/ +} +.postblock { + background:#6E735E; + font-family: sans-serif; + color:#000000; + font-weight:800; + font-size: 80%; + padding: 0px 5px; + border: 1px solid; +} +.footer { + text-align:center; + font-size:10px; + font-family:sans-serif; +} +.passvalid { + background:#9988EE; + text-align:center; + width:100%; + color:#ffffff; +} +.dellist { + background:inherit; + text-align:center; +} +.delbuttons { + background:inherit; + text-align:center; + padding-bottom:4px; +} +.managehead { + background:#0F8FE1; + color:#000000; + font-family:sans-serif; + font-size:14px; + padding:0px; +} +.postlists { + background:#FFFFFF; + width:100%; + padding:0px; + color:#000000; +} +.row1 { + background:#9AD2F6; + font-family:sans-serif; + font-size:12px; + color:#000000; +} +.row2 { + background:#FFFFFF; + font-family:sans-serif; + font-size:12px; + color:#000000; +} +.unkfunc { + color:#789922; +} +.filesize { + font-size:12px; + font-family:sans-serif; + text-decoration:underline; + padding-left:3em; +} +.filetitle { + background:inherit; + font-size:18px; + font-family:serif; + color:#0F0C5D; + font-weight:800; +} +.postername { + background:inherit; + font-size:12px; + font-family:serif; + color:#117743; + font-weight:800; +} +.oldpost { + background:inherit; + font-size:18px; + font-family:serif; + color:#0F0C5D; + font-weight:800; +} +.omittedposts { + background:inherit; + font-size:18px; + font-family:serif; + color:#070707; + font-weight:800; +} +.reply { + background:#AEB08D; + color:#000000; + font-family:serif; +} +.replyhl { + background: #AEB08D; + color: #000000; +} +.doubledash { + vertical-align:top; + clear:both; + float:left; +} +.replytitle { + background:inherit; + font-size:18px; + font-family:serif; + color:#0F0C5D; + font-weight:800; +} +.commentpostername { + background:inherit; + font-size:12px; + font-family:serif; + color:#117743; + font-weight:800; +} +.thumbnailmsg { + background:inherit; + font-size:9px; + font-family:sans-serif; + color:#000000; +} + +.watchedthreads { + background-color: #AEB08D!important; + border: 1px dotted!important; + border-top: 0px none !important; +} + +.reflinkpreview { + background-color: #AEB08D!important; +} \ No newline at end of file diff --git a/css/locked.gif b/css/locked.gif new file mode 100644 index 0000000..3934d9b Binary files /dev/null and b/css/locked.gif differ diff --git a/css/manage_basic.css b/css/manage_basic.css new file mode 100644 index 0000000..d22ecc4 --- /dev/null +++ b/css/manage_basic.css @@ -0,0 +1,157 @@ +html { min-width: 600px; } + +body, div, td, th, h2, h3, h4 { /* redundant rules for bad browsers */ + font-family: verdana,sans-serif; + font-size: x-small; + voice-family: "\"}\""; + voice-family: inherit; + font-size: small; + color: #333; +} +.clearhack { display: inline; } /*Clears Box Model Hack in IE5*/ + +body { + background: #EDEBE3; + color: #333; + padding: 1em 20px 3em 20px; + margin: 0; +} + +a { color: #06C; } +a:hover { color: #333; } +a:active { color: #000; } + +p { line-height: 140%; } + +h1,h2 { + font-family: trebuchet ms; + font-weight: bold; + color: #333; +} + +h1 { + font-size: 180%; + margin: 0; +} + +h1 a { text-decoration: none; color: #333; } +h1 a:hover { border-bottom: 1px dotted #666; color: #000; } + +h2 { + font-size: 140%; + padding-bottom: 2px; + border-bottom: 1px solid #CCC; + margin: 0; +} + +p.note { + background: #EEE; + padding: 4px; + font-family: tahoma; + font-size: 85%; + line-height: 130%; + margin-top: 0; +} + +br { + clear: left; +} + +label,input { + display: block; + width: auto; + float: left; + margin-bottom: 10px; +} + +label { + font-size: 12px; + text-align: right; + width: 175px; + padding-right: 20px; +} + +.desc { + text-indent: 5px; + font-size : 80%; + /*white-space: nowrap;*/ +} + +.footer { + text-align:center; + font-size:10px; + font-family:sans-serif; +} + +th,td { + font-size:10px; + font-family:verdana; +} + +.unkfunc { + color:#789922; +} +.filesize { + font-size:12px; + font-family:sans-serif; + text-decoration:underline; + padding-left:3em; +} +.filetitle { + background:inherit; + font-size:18px; + font-family:serif; + color:#0F0C5D; + font-weight:800; +} +.postername { + background:inherit; + font-size:12px; + font-family:serif; + color:#117743; + font-weight:800; +} +.oldpost { + background:inherit; + font-size:18px; + font-family:serif; + color:#0F0C5D; + font-weight:800; +} +.omittedposts { + background:inherit; + font-size:18px; + font-family:serif; + color:#070707; + font-weight:800; +} +.reply { + background:#D6DAF0; + color:#000000; + font-family:serif; +} +.doubledash { + vertical-align:top; + clear:both; + float:left; +} +.replytitle { + background:inherit; + font-size:18px; + font-family:serif; + color:#0F0C5D; + font-weight:800; +} +.commentpostername { + background:inherit; + font-size:12px; + font-family:serif; + color:#117743; + font-weight:800; +} +.thumbnailmsg { + background:inherit; + font-size:9px; + font-family:sans-serif; + color:#000000; +} \ No newline at end of file diff --git a/css/manage_tabs.css b/css/manage_tabs.css new file mode 100644 index 0000000..017d702 --- /dev/null +++ b/css/manage_tabs.css @@ -0,0 +1,108 @@ +#main { + border: 1px solid #666; + clear: both; + background: #FFF3B3; + padding-top: 2em; +} + +#contents { + padding: 1.5em; + background: #FFFDF3; + min-height: 300px; +} + +#header { + position: relative; + width: 100%; + height: 3em; + width: 45em; /* a width is required for Opera, older Mozilla browsers, and Konqueror browsers */ +} + +#header ul#primary { + margin: 0; + padding: 0; + position: absolute; + bottom: -1px; + width: 45em; /* a width is required for Opera, older Mozilla browsers, and Konqueror browsers */ +} + +#header ul#primary li { + display: inline; + list-style: none; +} + +#header ul#primary a,#header ul#primary span,#header ul#primary a.current { + width: 8em; + display: block; + float: left; + padding: 4px 0; + margin: 1px 2px 0 0; + text-align: center; + font-family: tahoma, verdana, sans-serif; + font-size: 85%; + text-decoration: none; + color: #333; +} + +#header ul#primary span,#header ul#primary a.current,#header ul#primary a.current:hover { + border: 1px solid #666; + border-bottom: none; + background: #FFF3B3; + padding-bottom: 6px; + margin-top: 0; +} + +#header ul#primary a { + background: #FFFAE1; + border: 1px solid #AAA; + border-bottom: none; +} + +#header ul#primary a:hover { + margin-top: 0; + border-color: #666; + background: #FFF7CD; + padding-bottom: 5px; +} + +#header ul#secondary { + position: absolute; + margin: 0; + padding: 0; + bottom: -1.4em; + left: 1px; + width: 50em; /* a width is required for Opera, older Mozilla browsers, and Konqueror browsers */ +} + +#header ul#secondary li a,#header ul#secondary li span { + width: auto; + display: block; + float: left; + padding: 0 10px; + margin: 0; + text-align: auto; + border: none; + border-right: 1px dotted #AAA; + background: none; + +} + +#header ul#secondary li a { + color: #06C; + text-decoration: underline; +} + +#header ul#secondary li a:hover { + color: #333; + background: transparent; + padding: 0 10px; + border: none; + border-right: 1px dotted #AAA; +} + +#header ul#secondary li a:active { + color: #000; + background: transparent; +} + +#header ul#secondary li:last-child a { border: none; } \ No newline at end of file diff --git a/css/menu_global.css b/css/menu_global.css new file mode 100644 index 0000000..e8bb3a1 --- /dev/null +++ b/css/menu_global.css @@ -0,0 +1,9 @@ +img { + border: none; +} +.pop { + font-weight: bold; +} +.trial { + font-style: italic; +} \ No newline at end of file diff --git a/css/site_burichan.css b/css/site_burichan.css new file mode 100644 index 0000000..4be4868 --- /dev/null +++ b/css/site_burichan.css @@ -0,0 +1,87 @@ +body { + font-family: sans-serif; + font-size: 75%; + background: #EEF2FF; + color: #000; + margin: 0; + width: 90%; +} +#topmenu li { + display: block; + float: left; + border: 1px solid #9295a4; + padding-top: 3px; + padding-bottom: 2px; + padding-left: 10px; + padding-right: 10px; + border-left: none; + margin-top: -7px; + background-color: #DFDFFE; +} + +#topmenu li.first { + border-left: 1px solid #9295a4; +} + +#topmenu li.current { + margin-top: -8px; + padding-top: 5px; + border-bottom: none; + background-color: #D6DAF0; +} + +h2 { + margin-top: 0px; + margin-left: 0px; + background: #D6DAF0; + font-size: 100%; +} + +h2 a { + text-decoration: none; + color: #550; +} + +h1, h3, .menu { + font-family: Verdana,Tahoma,sans-serif; +} + +h1 { + margin: 0px; + color: #800; + text-align: center; + margin-top: 1em; +} + +h3 { + margin: 0px; + color: #800; + text-align: center; + font-weight: normal; + font-size: medium; +} + +.menu { + margin-top: 1em; + text-align: center; +} + +.content { + margin-left: 3em; + text-align: justify; + padding-left: 4px; +} + +.newssub { + position: absolute; +} + +.permalink { + text-align: right; + display: block; +} + +.permalink a { + color: blue; + text-decoration: none; +} \ No newline at end of file diff --git a/css/site_futaba.css b/css/site_futaba.css new file mode 100644 index 0000000..9dbf773 --- /dev/null +++ b/css/site_futaba.css @@ -0,0 +1,88 @@ +body { + font-family: sans-serif; + font-size: 75%; + background: #ffe; + color: #000; + margin: 0; + width: 90%; +} + +#topmenu li { + display: block; + float: left; + border: 1px solid #888; + padding-top: 3px; + padding-bottom: 2px; + padding-left: 10px; + padding-right: 10px; + border-left: none; + margin-top: -7px; + background-color: #FDB; +} + +#topmenu li.first { + border-left: 1px solid #888; +} + +#topmenu li.current { + margin-top: -8px; + padding-top: 5px; + border-bottom: none; + background-color: #fca; +} + +h2 { + margin-top: 0px; + background: #fca; + font-size: 100%; + padding: 1px 5px 1px 5px; +} + +h2 a { + text-decoration: none; + color: #550; +} + +h1, h3, .menu { + font-family: Verdana,Tahoma,sans-serif; +} + +h1 { + margin: 0; + color: #800; + text-align: center; + margin-top: 1em; +} + +h3 { + margin: 0; + color: #800; + text-align: center; + font-weight: normal; + font-size: medium; +} + +.menu { + margin-top: 1em; + text-align: center; +} + +.content { + margin-left: 3em; + text-align: justify; + padding-left: 4px; +} + +.newssub { + position: absolute; +} + +.permalink { + text-align: right; + display: block; +} + +.permalink a { + color: blue; + text-decoration: none; +} \ No newline at end of file diff --git a/css/site_kusabax.css b/css/site_kusabax.css new file mode 100644 index 0000000..1690caf --- /dev/null +++ b/css/site_kusabax.css @@ -0,0 +1,91 @@ +body { + font-family: sans-serif; + font-size: 75%; + background: #E6E6D1; + color: #000; + margin: 0; + width: 90%; +} +#topmenu li { + display: block; + float: left; + border: 1px solid #9295a4; + padding-top: 3px; + padding-bottom: 2px; + padding-left: 10px; + padding-right: 10px; + border-left: none; + margin-top: -7px; + background-color: #CFCBA3; +} + +#topmenu li.first { + border-left: 1px solid #9295a4; +} + +#topmenu li.current { + margin-top: -8px; + padding-top: 5px; + border-bottom: none; + background-color: #AEB08D; +} + +h2 { + margin-top: 0px; + margin-left: 0px; + background: #AEB08D; + font-size: 100%; + padding: 1px 5px 1px 5px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + -moz-border-radius-topleft: 0px; +} + +h2 a { + text-decoration: none; + color: #6E735E; +} + +h1, h3, .menu { + font-family: Verdana,Tahoma,sans-serif; +} + +h1 { + margin: 0px; + color: #800; + text-align: center; + margin-top: 1em; +} + +h3 { + margin: 0px; + color: #800; + text-align: center; + font-weight: normal; + font-size: medium; +} + +.menu { + margin-top: 1em; + text-align: center; +} + +.content { + margin-left: 3em; + text-align: justify; + padding-left: 4px; +} + +.newssub { + position: absolute; +} + +.permalink { + text-align: right; + display: block; +} + +.permalink a { + color: #6E735E; + text-decoration: none; +} \ No newline at end of file diff --git a/css/sitemenu_burichan.css b/css/sitemenu_burichan.css new file mode 100644 index 0000000..1dff827 --- /dev/null +++ b/css/sitemenu_burichan.css @@ -0,0 +1,61 @@ +body { + margin: 8px; +} + +a { + text-decoration: none; + color: #34345C; +} + +h1, h2 { + background: #D6DAF0; + text-align: left; +} + +h1 { + margin-top: 0px; + font-size: 150%; + color: #000; +} + +h2 { + margin: 0; + font-size: 100%; + margin-top: 1em; +} + +.plus { + float: right; + font-size: 8px; + font-weight: normal; + padding: 1px 4px 2px 4px; + margin: 0px 0px; + background: #c5c9e0; + color: #000; + border: 1px solid #b4b8d0; + cursor: pointer; +} + +.plus:hover { + background: #c5c9e0; + border: 1px solid #c97; +} + +ul { + list-style: none; + padding-left: 0px; + margin: 0px; +} + +li { + margin: 0px; +} + +li:hover { + background: #C6DAF0; +} + +li a { + display: block; + width: 100%; +} \ No newline at end of file diff --git a/css/sitemenu_futaba.css b/css/sitemenu_futaba.css new file mode 100644 index 0000000..76c3130 --- /dev/null +++ b/css/sitemenu_futaba.css @@ -0,0 +1,61 @@ +body { + margin: 8px; +} + +a { + text-decoration: none; + color: #550; +} + +h1, h2 { + background: #fca; + text-align: left; +} + +h1 { + margin-top: 0px; + font-size: 150%; + color: #000; +} + +h2 { + margin: 0; + font-size: 100%; + margin-top: 1em; +} + +.plus { + float: right; + font-size: 8px; + font-weight: normal; + padding: 1px 4px 2px 4px; + margin: 0px 0px; + background: #eb9; + color: #000; + border: 1px solid #da8; + cursor: pointer; +} + +.plus:hover { + background: #da8; + border: 1px solid #c97; +} + +ul { + list-style: none; + padding-left: 0px; + margin: 0px; +} + +li { + margin: 0px; +} + +li:hover { + background: #fec; +} + +li a { + display: block; + width: 100%; +} \ No newline at end of file diff --git a/css/sitemenu_kusabax.css b/css/sitemenu_kusabax.css new file mode 100644 index 0000000..be0a18e --- /dev/null +++ b/css/sitemenu_kusabax.css @@ -0,0 +1,58 @@ +body { + font-size: 70%; + margin: 8px; + font-family: sans-serif; + width: 90%; +} +a { + text-decoration: none; + color: #6E735E; +} +h1, h2 { + background: #AEB08D; + text-align: left; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + padding: 0px; + margin: 0; +} +h1 { + margin-top: 0px; + font-size: 150%; + color: #000; + padding-left: 5px; +} +h2 { + font-size: 100%; + margin-top: 1em; +} +.plus { + float: right; + font-size: 8px; + font-weight: normal; + padding: 1px 4px 2px 4px; + margin: 0px 0px; + background: #AEB08D; + color: #000; + cursor: pointer; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; +} +ul { + list-style: none; + padding-left: 0px; + margin: 0px; +} +li { + margin: 0px; + padding-left: 5px; +} +li:hover { + background: #AEB08D; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; +} +li a { + display: block; + width: 100%; +} \ No newline at end of file diff --git a/css/sticky.gif b/css/sticky.gif new file mode 100644 index 0000000..da4ec3a Binary files /dev/null and b/css/sticky.gif differ diff --git a/css/txt_bluemoon.css b/css/txt_bluemoon.css new file mode 100644 index 0000000..4022986 --- /dev/null +++ b/css/txt_bluemoon.css @@ -0,0 +1,188 @@ +body, html { + margin: 0px; + padding: 0px 8px 8px 8px; + background: #6B7B8D; + color: #FFFFFF; +} + +a { + color: #AFB9C5; +} + +a:visited { + color: #9DA6B0; +} + +a:hover { + color:#EEEEEE; +} + +h1 { + color: #EEEEEE; + text-align: center; + font-size: 2em; + font-weight: bold; + padding: 0px; + margin: 0px; +} + +h2 { + float: left; + color: #eeeeee; + font-size: 1.2em; + font-weight: bold; + margin: 0px 0px 0px 1em; + padding: 0px; +} + +h2 a { + color: #eeeeee !important; + text-decoration: none; + margin-right: -0.25em; +} + +h2 a:hover { + text-decoration: underline; +} + +h3 { + font-size: 1em; + font-weight: normal; + margin: -3px; + padding: 0px; + padding-top: 3px; + background-color: #DDD; +} + +.replies { + clear: both; + margin: 3px; + padding: 3px; + font-weight: normal; +} + +form { + clear: both; + background: #99a9ba; + color: #49525d; + font-family: serif; + margin: 3px; + padding: 3px; + -moz-border-radius: 4px; +} + +label { + font-weight: bold !important; +} +input, textarea { + border: 1px solid #49525d; +} +input[type=submit], input[type=button] { + color: #400000; +} +textarea { + -moz-border-radius: 4px; +} + +.hborder { + background: #49525D; + color: #EEE; + padding: 4px; + clear: both; + -moz-border-radius: 4px; +} + +.topbar { + width: 100%; + text-align: right +} + +.fullhead { + background: #49525D; + -moz-border-radius: 6px; + padding: 0.25em; +} + +.head { + -moz-border-radius: 6px; +} + +.hborder .head { + -moz-border-radius: 6px; +} + +.midhead { + margin-left: 1em; +} + +.newthread { + margin-top: 2em; + margin-bottom: 2em; +} + +.newthread h2 { + color: #EEE; + font-weight: normal; +} + +.thread { + background-color: #49525D; + padding: 4px; + margin-bottom: 2em; + clear: both; + -moz-border-radius: 6px; +} + +.post { + background-color: #FFF; + color: #000080; + /*font-family: serif;*/ + font-size: .8em; + margin: 3px; + padding: 3px; + -moz-border-radius: 4px; + border: 6px solid #DDD; +} + +.postnum { + font-weight: bold; + margin-left: 0.3em; + margin-right: 0.3em; + color: #49525d; +} +.postnum a { + color: #49525d; + text-decoration: none; +} +.postnum a:hover { + color:#DD0000; +} + +.threadldiv { + background: #49525D; + /*margin-bottom: 1em;*/ + -moz-border-radius: 6px; +} + +.hidden { + clear: both; + background: #EEAA88; + margin: -0.3em 1em 0.5em 1em; + -moz-border-radius: 4px; +} + +.postername { + color: #2B3037; + font-weight: bold; + font-size: 1.2em; +} +.postertrip { + color: #49525D; + font-style: italic; + font-size: 1.2em; +} + +.legal { + text-align: center; + font-size: 0.8em; +} \ No newline at end of file diff --git a/css/txt_buritxt.css b/css/txt_buritxt.css new file mode 100644 index 0000000..0ebb7b2 --- /dev/null +++ b/css/txt_buritxt.css @@ -0,0 +1,220 @@ +/* Thanks meltingwax */ +body { + background: #eef2ff; + font-family: sans-serif; + margin: 0 +} +a { + color: #34345c; + text-decoration: none; +} +a:hover { + text-decoration: underline +} +h1 { + /*color: black;*/ + color: #800; /* i prefer black but 7chan has #800 headers */ + padding: .5em +} +.head { + background: #d6daf0; +} + +.threadldiv, body.board .thread, .midhead, .newthread, .head { + margin: 1em; + margin-left: 2.5%; + margin-right: 2.5%; +} + +.threadldiv, .thread, .midhead, .newthread { + background: #d6daf0; + padding: 1px; +} + +.midhead { + padding: .5em +} + +.threadlink, .boldthreadlink { + display: block; + text-align: center +} + +.boldthreadlink { font-weight: bold } + +.tolder { display: none } + +h2 { + margin: .1em; + padding-left: .3em; + padding-top: .1em +} +h2 a { + background: #d6daf0; + text-decoration: underline; +} + +.replies { + font-size: x-large; + font-weight: bolder; + padding-right: .5em; + font-family: serif +} + +.topbar a { + color: #cc1105; + font-family: IPAMonaPGothic,Mona,'MS PGothic',YOzFontAA97 +} + +.threadlistflat { + margin-bottom:0 +} + +.postheader * { + clear: none; + margin: 0; + margin-bottom: .1em; +} + +.post, form { + width: 90%; + margin-left: 9%; + margin-top: 1em; +} + +.hidden { + margin-left: .5em; +} + +form { + margin-left: 2.9em; +} + +.post { + background: #eef2ff; + /*border: 1px solid #34345c;*/ + padding-bottom: .1em; +} + +h3 { + font-weight: normal; + font-size: x-small; + color: grey; + margin: 0; + margin-right: .1em; + text-align: right; + clear: none; + height: 0; +} + +h3 a { + color: grey; + font-weight: bold +} + +h3 .postnum a, form .postnum { + text-decoration: none; + font-size: xx-large; + color: black; + font-style: italic; + font-family: serif; + font-weight: bolder; + float: left; + clear: none; + width: 1.5em; + text-align: right; + vertical-align: middle +} + +.namelabel { + display: none +} + +form .postnum { + padding-right: .3em +} + +h3 .postnum a, blockquote { + position: relative; + left: -2em; +} + +h3 .postnum a {height: 0} + +blockquote { + clear: left; +} + +blockquote p { + margin: 0 +} + +table .submit { + width: 100%; +} +td.label { + text-align: right; +} +table .mail {width: auto; float: right;} + +.legal { + text-align: center; + font-size: small; +} +.manage { + text-align: center; + font-size: x-small; +} + +.stylelist { + display: inline-block; + float: right +} +body.read h2 { + color: #34345c; + font-size: larger +} +.read { + background: #d6daf0; +} +.pages { + font-size: smaller +} +.bottomnav { + text-align: center; +} +.topbar { + margin: -2px; + margin-bottom: .5em; + width: 100%; + text-align: right +} +.threads { + background: #eef2ff; +} +.threads th { + padding: 0px; + margin: 0px; +} +.threads thead { + background: #d6daf0; +} + +.threads a { + /*display: block;*/ +} +.threads a:hover { + text-decoration: none; +} +.threads tr:hover { + background: #dfe3f9; +} +.threads th { + background: #d6daf0 !important +} +.threads a { + display: block; +} +.quote:hover { + background: #d6daf0; !important +} \ No newline at end of file diff --git a/css/txt_futatxt.css b/css/txt_futatxt.css new file mode 100644 index 0000000..4a03211 --- /dev/null +++ b/css/txt_futatxt.css @@ -0,0 +1,176 @@ +body { + margin: 0px; + padding: 0px 8px 8px 8px; + background: #FFFFEE; + color: #800000; +} + +a { + color: #0000EE; +} + +a:visited { + color: #0000DD; +} + +a:hover { + color:#DD0000; +} + +h1 { + background: #EEAA88; + font-size: 2em; + font-weight: normal; + text-align: center; + padding: 0px; + margin: 0px; +} + +h2 { + float: left; + color: #CC1105; + font-size: 1.2em; + font-weight: bold; + margin: 0px 0px 0px 1em; + padding: 0px; +} + +h2 a { + color: #CC1105 !important; + text-decoration: none; + margin-right: -0.25em; +} + +h2 a:hover { + text-decoration: underline; +} + +h3 { + font-size: 1em; + font-weight: normal; + margin: 0px; + padding: 0px; +} + +.replies { + clear: both; + margin: 3px; + padding: 3px; + font-weight: normal; +} + +form { + clear: both; + background: #F0E0D6; + color: #800000; + font-family: serif; + margin: 3px; + padding: 3px; + -moz-border-radius: 4px; +} + +label { + font-weight: bold !important; +} +input, textarea { + border: 1px solid #800000; +} +input[type=submit], input[type=button] { + color: #400000; +} +textarea { + -moz-border-radius: 4px; +} + +.hborder { + background: #EEAA88; + color: #800000; + padding: 4px; + clear: both; + -moz-border-radius: 4px; +} + +.topbar { + width: 100%; + text-align: right +} + +.fullhead { + background: #EEAA88; + -moz-border-radius: 6px; + padding: 0.25em; +} + +.head { + -moz-border-radius: 6px; +} + +.hborder .head { + -moz-border-radius: 6px; +} + +.midhead { + margin-left: 1em; +} + +.newthread { + margin-top: 2em; + margin-bottom: 2em; +} + +.newthread h2 { + color: #800000; + font-weight: normal; +} + +.thread { + background: #F0E0D6; + padding: 4px; + margin-bottom: 2em; + -moz-border-radius: 6px; + clear: both; +} + +.post { + clear: both; + margin: 0px 0px 0.5em 0px; +} + +.postnum { + font-weight: bold; + margin-left: 0.3em; + margin-right: 0.3em; +} +.postnum a { + color: #800000; + text-decoration: none; +} +.postnum a:hover { + color:#DD0000; +} + +.threadldiv { + background: #F0E0D6; + /*margin-bottom: 1em;*/ + -moz-border-radius: 6px; +} + +.hidden { + clear: both; + background: #EEAA88; + margin: -0.3em 1em 0.5em 1em; + -moz-border-radius: 4px; +} + +.postername { + color: #117743; + font-weight: bold; +} +.postertrip { + color: #228854; +} + +.legal { + text-align: center; + font-size: 0.8em; +} \ No newline at end of file diff --git a/css/txt_global.css b/css/txt_global.css new file mode 100644 index 0000000..de5ba9e --- /dev/null +++ b/css/txt_global.css @@ -0,0 +1,62 @@ +.quote { + border-left: solid 2px #666; + padding: 0px 0px 0px 10px; + margin: 3px 0px; + display: block; +} + +.quote .quote { + border-left: solid 2px #888; +} + +.quote .quote .quote { + border-left: solid 2px #aaa; +} + +.quote:hover { + background: #f0f0e0; +} + +.spoiler { + color: black; + background-color: black; +} + +.aa { + text-align: left; + font: 100% Mona, IPAMonaPGothic, 'MS PGothic' !important; +} + +.o { + text-decoration: overline; +} + +tt { + font-size: smaller; +} + +.navlinks { + float: right; +} + +.navlinks a { + text-decoration: none; +} + +.threadlinks { + text-align: right; +} + +.threadlinks a { + font-weight: bold; +} + +.userdelete { + float: right; + text-align: center; + white-space: nowrap; +} + +.abbrev { + color: #707070; +} \ No newline at end of file diff --git a/dwoo/templates/banned.tpl b/dwoo/templates/banned.tpl new file mode 100644 index 0000000..1820509 --- /dev/null +++ b/dwoo/templates/banned.tpl @@ -0,0 +1,71 @@ + + + +{t}YOU ARE BANNED{/t}! + + + + +

{%KU_NAME}

+

{%KU_SLOGAN}

+
+

 {t}YOU ARE BANNED{/t}! :\

+ :'( + {foreach name=bans item=ban from=$bans} + {if not $.foreach.bans.first} + {t}Additionally{/t}, + {/if} + {if $ban.expired eq 1} + {t}You were banned from posting on{/t} + {else} + {t}You have been banned from posting on{/t} + {/if} + {if $ban.globalban eq 1}{t}All boards{/t}{else}/{implode('/, /', explode('|', $ban.boards))}/{/if} {t}for the following reason{/t}:

+ {$ban.reason}

+ {t}Your ban was placed on{/t} {$ban.at|date_format:"%B %e, %Y, %I:%M %P %Z"}, {t}and{/t} + {if $ban.expired eq 1} + {t}expired on{/t} {$ban.until|date_format:"%B %e, %Y, %I:%M %P"}
+ {t}This ban has already expired, this message is for your information only and will not be displayed again{/t} + {else} + {if $ban.until > 0}{t}will expire on{/t} {$ban.until|date_format:"%B %e, %Y, %I:%M %P"}{else}{t}will not expire{/t}{/if} + {/if} +

+ {if %KU_APPEAL neq '' && $ban.expired eq 0} + {if $ban.appealat eq 0} + {t}You may not appeal this ban.{/t} + {elseif $ban.appealat eq -1} + {t}Your appeal is currently pending review.{/t} + {t}For reference, your appeal message is{/t}:
+ {$ban.appeal} + {elseif $ban.appealat eq -2} + {t}Your appeal was reviewed and denied. You may not appeal this ban again.{/t} + {t}For reference, your appeal message was{/t}:
+ {$ban.appeal} + {else} + {if $ban.appealat < $.now} + {t}You may now appeal this ban.{/t} +

+
+ + +
+ +
+
+ {else} + {t}You may appeal this ban in{/t} {$ban.appealin}. + {/if} + {/if} +
+ {/if} + {if $.foreach.bans.last} +
{t}Your IP address is{/t} {$.server.REMOTE_ADDR}.

+ {/if} + {if count($bans) > 1 && not $.foreach.bans.last} +
+ {/if} + + {/foreach} +
+ + diff --git a/dwoo/templates/error.tpl b/dwoo/templates/error.tpl new file mode 100644 index 0000000..7fcdd89 --- /dev/null +++ b/dwoo/templates/error.tpl @@ -0,0 +1,33 @@ + + + +{%KU_NAME} + + +{loop $styles} + + +{/loop} + + + + +

{t}Error{/t}

+
+

+{$errormsg} +

+{$errormsgext} +
+
+ + + \ No newline at end of file diff --git a/dwoo/templates/front_bans.tpl b/dwoo/templates/front_bans.tpl new file mode 100644 index 0000000..70944c2 --- /dev/null +++ b/dwoo/templates/front_bans.tpl @@ -0,0 +1,26 @@ +{include(file='front_header.tpl')} + + + + + + + + + + + + {foreach $bans ban} + + + + + + + + + {/foreach} + +
IPMotivoBoardsBanido emExpira emModerador
{md5_decrypt($ban.ip, $seed)}{$ban.reason}{if $ban.boards eq ''}Todas{else}{replace $ban.boards "|" " / "}{/if}{date_format $ban.at "%d/%m @ %H:%M"}{if $ban.until eq 0}Nunca{else}{date_format $ban.until "%d/%m @ %H:%M"}{/if}{$ban.by}
+ +{include(file='front_footer.tpl')} \ No newline at end of file diff --git a/dwoo/templates/front_faq.tpl b/dwoo/templates/front_faq.tpl new file mode 100644 index 0000000..5163f6b --- /dev/null +++ b/dwoo/templates/front_faq.tpl @@ -0,0 +1,12 @@ +{include(file='front_header.tpl')} + +{foreach $faq faq} +
+
{$faq.subject}
+
+

{$faq.message}

+
+
+{/foreach} + +{include(file='front_footer.tpl')} \ No newline at end of file diff --git a/dwoo/templates/front_footer.tpl b/dwoo/templates/front_footer.tpl new file mode 100644 index 0000000..332fc4a --- /dev/null +++ b/dwoo/templates/front_footer.tpl @@ -0,0 +1,11 @@ +
+ + + + + + \ No newline at end of file diff --git a/dwoo/templates/front_header.tpl b/dwoo/templates/front_header.tpl new file mode 100644 index 0000000..2de7af3 --- /dev/null +++ b/dwoo/templates/front_header.tpl @@ -0,0 +1,22 @@ + + + + + + + + {$title} + + + + + + \ No newline at end of file diff --git a/dwoo/templates/front_index.tpl b/dwoo/templates/front_index.tpl new file mode 100644 index 0000000..5e28a4b --- /dev/null +++ b/dwoo/templates/front_index.tpl @@ -0,0 +1,85 @@ +{include(file='front_header.tpl')} + +
+
Boards
+
+ {foreach $sections section} + + {/foreach} +
+
+
+ +
+
{$last_new.0.subject} - {date_format $last_new.0.timestamp "%d/%m/%Y @ %H:%M:%S"} - by {$last_new.0.poster}
+
+

{$last_new.0.message}

+
+
+ +
+
Ultimas Imagens
+
+
    + {foreach $last_images last_image} +
  • + + + +
  • + {/foreach} +
+
+
+ +
+
Ultimos Posts
+
+
    + {foreach $last_posts last_post} +
  • + {date_format $last_post.timestamp "%d/%m @ %H:%M"} - + /{$last_post.board}/ - + #{$last_post.id} - + {truncate strip_tags($last_post.message) 40} +
  • + {/foreach} +
+
+
+ + + + + +{include(file='front_footer.tpl')} diff --git a/dwoo/templates/front_news.tpl b/dwoo/templates/front_news.tpl new file mode 100644 index 0000000..1a6d97b --- /dev/null +++ b/dwoo/templates/front_news.tpl @@ -0,0 +1,12 @@ +{include(file='front_header.tpl')} + +{foreach $news new} +
+
{$new.subject} - {date_format $new.timestamp "%d/%m/%Y @ %H:%M:%S"} - by {$new.poster}
+
+

{$new.message}

+
+
+{/foreach} + +{include(file='front_footer.tpl')} \ No newline at end of file diff --git a/dwoo/templates/front_rules.tpl b/dwoo/templates/front_rules.tpl new file mode 100644 index 0000000..4f650e2 --- /dev/null +++ b/dwoo/templates/front_rules.tpl @@ -0,0 +1,14 @@ +{include(file='front_header.tpl')} + +
+
Regras
+
+
    + {foreach $rules rule} +
  • {$rule.message}
  • + {/foreach} +
+
+
+ +{include(file='front_footer.tpl')} \ No newline at end of file diff --git a/dwoo/templates/global_board_footer.tpl b/dwoo/templates/global_board_footer.tpl new file mode 100644 index 0000000..c3b11cf --- /dev/null +++ b/dwoo/templates/global_board_footer.tpl @@ -0,0 +1,3 @@ + + + diff --git a/dwoo/templates/global_board_header.tpl b/dwoo/templates/global_board_header.tpl new file mode 100644 index 0000000..71e6e53 --- /dev/null +++ b/dwoo/templates/global_board_header.tpl @@ -0,0 +1,16 @@ + + + +{$title} + +{if $locale != 'en'} + +{/if} + + + + + + + + \ No newline at end of file diff --git a/dwoo/templates/img_board_page.tpl b/dwoo/templates/img_board_page.tpl new file mode 100644 index 0000000..9a6770b --- /dev/null +++ b/dwoo/templates/img_board_page.tpl @@ -0,0 +1,428 @@ +
+ +{foreach name=thread item=postsa from=$posts} + {foreach key=postkey item=post from=$postsa} + {if $post.parentid eq 0} + +
+ + + + {if ($post.file neq '' || $post.file_type neq '' ) && (($post.videobox eq '' && $post.file neq '') && $post.file neq 'removed')} + + {if $post.file_type eq 'mp3'} + {t}Audio{/t} + {else} + {t}File{/t} + {/if} + {if $post.file_type neq 'jpg' && $post.file_type neq 'gif' && $post.file_type neq 'png' && $post.videobox eq ''} + + {else} + + {/if} + {if isset($post.id3.comments_html)} + {if $post.id3.comments_html.artist.0 neq ''} + {$post.id3.comments_html.artist.0} + {if $post.id3.comments_html.title.0 neq ''} + - + {/if} + {/if} + {if $post.id3.comments_html.title.0 neq ''} + {$post.id3.comments_html.title.0} + {/if} + + {else} + {$post.file}.{$post.file_type} + {/if} + - ({$post.file_size_formatted} + {if $post.id3.comments_html.bitrate neq 0 || $post.id3.audio.sample_rate neq 0} + {if $post.id3.audio.bitrate neq 0} + - {round($post.id3.audio.bitrate / 1000)} kbps + {if $post.id3.audio.sample_rate neq 0} + - + {/if} + {/if} + {if $post.id3.audio.sample_rate neq 0} + {$post.id3.audio.sample_rate / 1000} kHz + {/if} + {/if} + {if $post.image_w > 0 && $post.image_h > 0} + , {$post.image_w}x{$post.image_h} + {/if} + {if $post.file_original neq '' && $post.file_original neq $post.file} + , {$post.file_original}.{$post.file_type} + {/if} + ) + {if $post.id3.playtime_string neq ''} + {t}Length{/t}: {$post.id3.playtime_string} + {/if} + + {if %KU_THUMBMSG} + + {if $post.file_type neq 'jpg' && $post.file_type neq 'gif' && $post.file_type neq 'png' && $post.videobox eq ''} + {t}Extension icon displayed, click image to open file.{/t} + {else} + {t}Thumbnail displayed, click image for full size.{/t} + {/if} + + {/if} +
+ {/if} + {if $post.videobox eq '' && $post.file neq '' && ( $post.file_type eq 'jpg' || $post.file_type eq 'gif' || $post.file_type eq 'png')} + {if $post.file eq 'removed'} +
+ {t}File
Removed{/t} +
+ {else} + + {$post.id} + + {/if} + {elseif $post.nonstandard_file neq ''} + {if $post.file eq 'removed'} +
+ {t}File
Removed{/t} +
+ {else} + + {$post.id} + + {/if} + {/if} + + + + {$post.reflink} + + {if $board.showid} + ID: {$post.ipmd5|substr:0:6} + {/if} + + {if $post.locked eq 1} + {t}Locked{/t} + {/if} + {if $post.stickied eq 1} + {t}Stickied{/t} + {/if} + hide + {if %KU_WATCHTHREADS} + watch + {/if} + {if %KU_EXPAND && $post.replies && ($post.replies + %KU_REPLIES) < 300} + expand + {/if} + {if %KU_QUICKREPLY} + quickreply + {/if} + + + [{t}Reply{/t}] + {if %KU_FIRSTLAST && (($post.stickied eq 1 && $post.replies + %KU_REPLIESSTICKY > 50) || ($post.stickied eq 0 && $post.replies + %KU_REPLIES > 50))} + {if (($post.stickied eq 1 && $post.replies + %KU_REPLIESSTICKY > 100) || ($post.stickied eq 0 && $post.replies + %KU_REPLIES > 100))} + [{t}First 100 posts{/t}] + {/if} + [{t}Last 50 posts{/t}] + {/if} +
+ {else} + + + + + + + +
+ >> + + + + + + {$post.reflink} + + {if $board.showid} + ID: {$post.ipmd5|substr:0:6} + {/if} + + {if $post.locked eq 1} + {t}Locked{/t} + {/if} + {if $post.stickied eq 1} + {t}Stickied{/t} + {/if} + + + {if ($post.file neq '' || $post.file_type neq '' ) && (( $post.videobox eq '' && $post.file neq '') && $post.file neq 'removed')} +
+ {if $post.file_type eq 'mp3'} + {t}Audio{/t} + {else} + {t}File{/t} + {/if} + {if $post.file_type neq 'jpg' && $post.file_type neq 'gif' && $post.file_type neq 'png' && $post.videobox eq ''} + + {else} + + {/if} + {if isset($post.id3.comments_html)} + {if $post.id3.comments_html.artist.0 neq ''} + {$post.id3.comments_html.artist.0} + {if $post.id3.comments_html.title.0 neq ''} + - + {/if} + {/if} + {if $post.id3.comments_html.title.0 neq ''} + {$post.id3.comments_html.title.0} + {/if} + + {else} + {$post.file}.{$post.file_type} + {/if} + - ({$post.file_size_formatted} + {if $post.id3.comments_html.bitrate neq 0 || $post.id3.audio.sample_rate neq 0} + {if $post.id3.audio.bitrate neq 0} + - {round($post.id3.audio.bitrate / 1000)} kbps + {if $post.id3.audio.sample_rate neq 0} + - + {/if} + {/if} + {if $post.id3.audio.sample_rate neq 0} + {$post.id3.audio.sample_rate / 1000} kHz + {/if} + {/if} + {if $post.image_w > 0 && $post.image_h > 0} + , {$post.image_w}x{$post.image_h} + {/if} + {if $post.file_original neq '' && $post.file_original neq $post.file} + , {$post.file_original}.{$post.file_type} + {/if} + ) + {if $post.id3.playtime_string neq ''} + {t}Length{/t}: {$post.id3.playtime_string} + {/if} + + {if %KU_THUMBMSG} + + {if $post.file_type neq 'jpg' && $post.file_type neq 'gif' && $post.file_type neq 'png' && $post.videobox eq ''} + {t}Extension icon displayed, click image to open file.{/t} + {else} + {t}Thumbnail displayed, click image for full size.{/t} + {/if} + + {/if} + + {/if} + {if $post.videobox eq '' && $post.file neq '' && ( $post.file_type eq 'jpg' || $post.file_type eq 'gif' || $post.file_type eq 'png')} +
+ {if $post.file eq 'removed'} +
+ {t}File
Removed{/t} +
+ {else} + + {$post.id} + + {/if} + {elseif $post.nonstandard_file neq ''} +
+ {if $post.file eq 'removed'} +
+ {t}File
Removed{/t} +
+ {else} + + {$post.id} + + {/if} + {/if} + + {/if} + {if $post.file_type eq 'mp3'} + + + + + + + + {/if} +
+ {if $post.videobox} + {$post.videobox} + {/if} + {$post.message} +
+ {if not $post.stickied && $post.parentid eq 0 && (($board.maxage > 0 && ($post.timestamp + ($board.maxage * 3600)) < (time() + 7200 ) ) || ($post.deleted_timestamp > 0 && $post.deleted_timestamp <= (time() + 7200)))} + + {t}Marked for deletion (old){/t} + +
+ {/if} + {if $post.parentid eq 0} +
+ {if $post.replies} + + {if $post.stickied eq 0} + {$post.replies} + {if $post.replies eq 1} + {t lower="yes"}Post{/t} + {else} + {t lower="yes"}Posts{/t} + {/if} + {else} + {$post.replies} + {if $post.replies eq 1} + {t lower="yes"}Post{/t} + {else} + {t lower="yes"}Posts{/t} + {/if} + {/if} + {if $post.images > 0} + {t}and{/t} {$post.images} + {if $post.images eq 1} + {t lower="yes"}Image{/t} + {else} + {t lower="yes"}Images{/t} + {/if} + {/if} + {t}omitted{/t}. {t}Click Reply to view.{/t} + + {/if} + {else} +
+ + {/if} + {/foreach} +
+
+
+
+{/foreach} diff --git a/dwoo/templates/img_footer.tpl b/dwoo/templates/img_footer.tpl new file mode 100644 index 0000000..ffed8b3 --- /dev/null +++ b/dwoo/templates/img_footer.tpl @@ -0,0 +1,101 @@ +{if not $isread} + + + + + + + + + +
+ {t}Delete post{/t} + []
{t}Password{/t} +   + + {if $board.enablereporting eq 1} +
+ {t}Report post{t}
+ {t}Reason{/t} +   + {/if} + +
+ + + +{/if} +{if $replythread eq 0} + + + + + + + + +
+ {if $thispage eq 0} + {t}Previous{/t} + {else} +
+
+ {/if} +
+ [{if $thispage neq 0}{/if}0{if $thispage neq 0}{/if}] + {section name=pages loop=$numpages} + {strip} + [ + {if $.section.pages.iteration neq $thispage} + {/if} + + {$.section.pages.iteration} + + {if $.section.pages.iteration neq $thispage} + + {/if} + ] + {/strip} + {/section} + + {if $thispage eq $numpages} + {t}Next{/t} + {else} +
+ {/if} + +
+{/if} +
+{if $boardlist} + +{/if} +
+ \ No newline at end of file diff --git a/dwoo/templates/img_header.tpl b/dwoo/templates/img_header.tpl new file mode 100644 index 0000000..6d9bf67 --- /dev/null +++ b/dwoo/templates/img_header.tpl @@ -0,0 +1,103 @@ + + +{loop $ku_styles} + +{/loop} +{if $locale eq 'ja'} + {literal} + + {/literal} +{/if} +{if %KU_RSS neq ''} + +{/if} + + + +{if $board.enablecaptcha eq 1} + {literal} + + {/literal} +{/if} + + +
+{if %KU_STYLESWITCHER} + {if %KU_DROPSWITCHER} + + {else} + {loop $ku_styles} + [{$|capitalize}]  + {/loop} + {/if} + {if count($ku_styles) > 0} + -  + {/if} +{/if} +{if %KU_WATCHTHREADS} + [WT]  +{/if} +[{t}Home{/t}] [{t}Manage{/t}] +
+ +{if %KU_WATCHTHREADS && not $isoekaki && not $hidewatchedthreads} + +{/if} + + +{$board.includeheader} +
\ No newline at end of file diff --git a/dwoo/templates/img_post_box.tpl b/dwoo/templates/img_post_box.tpl new file mode 100644 index 0000000..3f45cd8 --- /dev/null +++ b/dwoo/templates/img_post_box.tpl @@ -0,0 +1,215 @@ +
+ +
+ + + +{if $board.maximagesize > 0} + +{/if} + + + + {if $board.forcedanon neq 1} + + + + + {/if} + + + + + + + + + + + + + + + + + {if $board.enablecaptcha eq 1} + + + + + {/if} + {if $board.uploadtype eq 0 || $board.uploadtype eq 1} + + + + + {/if} + {if ($board.uploadtype eq 1 || $board.uploadtype eq 2) && $board.embeds_allowed neq ''} + + + + + {/if} + + + + + + + + + + +
+ {t}Name{/t} + +
+ {t}Email{/t} + +
+ {t}Subject{/t} + + {strip}  ({t}new thread{/t}) + {elseif %KU_QUICKREPLY && $replythread neq 0} + {t}Reply{/t}" accesskey="z" /> ({t}reply to{/t} ) + {else} + {t}Submit{/t}" accesskey="z" /> + {/if}{/strip} +
+ 颜文字 + +
+ {t}Message{/t} + + +
{t}Captcha{/t}{$recaptcha}
+ {t}File{/t} + + + {if $replythread eq 0 && $board.enablenofile eq 1 } + [] + {/if} +
+ {t}Embed{/t} + +   + Help +
+ {t}Password{/t} + +  {t}(for post and file deletion){/t} +
+
+ + + + + + +
+
+
    +
  • {t}Supported file types are{/t}: + {if $board.filetypes_allowed neq ''} + {foreach name=files item=filetype from=$board.filetypes_allowed} + {$filetype.0|upper}{if $.foreach.files.last}{else}, {/if} + {/foreach} + {else} + {t}None{/t} + {/if} +
  • +
  • {t}Maximum file size allowed is{/t} {math "round(x/1024)" x=$board.maximagesize} KB.
  • +
  • {t 1=%KU_THUMBWIDTH 2=%KU_THUMBHEIGHT}Images greater than %1x%2 pixels will be thumbnailed.{/t}
  • +
  • {t 1=$board.uniqueposts}Currently %1 unique user posts.{/t} + {if $board.enablecatalog eq 1} + {t}View catalog{/t} + {/if} +
  • +
+ {if %KU_BLOTTER && $blotter} +
+ + + {/if} +
+
+
+{if $topads neq ''} +
+
+ {$topads} +
+
+
+{/if} +
+ \ No newline at end of file diff --git a/dwoo/templates/img_reply_header.tpl b/dwoo/templates/img_reply_header.tpl new file mode 100644 index 0000000..bf4a3ce --- /dev/null +++ b/dwoo/templates/img_reply_header.tpl @@ -0,0 +1,19 @@ +[{t}Return{/t}] +{if %KU_FIRSTLAST && ( count($posts) > 50 || $replycount > 50)} + [{t}Entire Thread{/t}] + [{t}Last 50 posts{/t}] + {if ( count($posts) > 100 || $replycount > 100) } + [{t}First 100 posts{/t}] + {/if} +{/if} +{if not $isread} +
{t}Posting mode: Reply{/t} + {if $modifier eq 'first100'} + [{t}First 100 posts{/t}] + {elseif $modifier eq 'last50'} + [{t}Last 50 posts{/t}] + {/if} +{else} + [{t}Entire Thread{/t}] +{/if} +
\ No newline at end of file diff --git a/dwoo/templates/img_thread.tpl b/dwoo/templates/img_thread.tpl new file mode 100644 index 0000000..929be4a --- /dev/null +++ b/dwoo/templates/img_thread.tpl @@ -0,0 +1,420 @@ +{if not $isexpand and not $isread} +
+ +{/if} + {foreach key=postkey item=post from=$posts name=postsloop} + + {if $post.parentid eq 0} +
+ + + {if ($post.file neq '' || $post.file_type neq '' ) && (( $post.videobox eq '' && $post.file neq '') && $post.file neq 'removed')} + + {if $post.file_type eq 'mp3'} + {t}Audio{/t} + {else} + {t}File{/t} + {/if} + {if $post.file_type neq 'jpg' && $post.file_type neq 'gif' && $post.file_type neq 'png' && $post.videobox eq ''} + + {else} + + {/if} + {if isset($post.id3.comments_html)} + {if $post.id3.comments_html.artist.0 neq ''} + {$post.id3.comments_html.artist.0} + {if $post.id3.comments_html.title.0 neq ''} + - + {/if} + {/if} + {if $post.id3.comments_html.title.0 neq ''} + {$post.id3.comments_html.title.0} + {/if} + + {else} + {$post.file}.{$post.file_type} + {/if} + - ({$post.file_size_formatted} + {if $post.id3.comments_html.bitrate neq 0 || $post.id3.audio.sample_rate neq 0} + {if $post.id3.audio.bitrate neq 0} + - {round($post.id3.audio.bitrate / 1000)} kbps + {if $post.id3.audio.sample_rate neq 0} + - + {/if} + {/if} + {if $post.id3.audio.sample_rate neq 0} + {$post.id3.audio.sample_rate / 1000} kHz + {/if} + {/if} + {if $post.image_w > 0 && $post.image_h > 0} + , {$post.image_w}x{$post.image_h} + {/if} + {if $post.file_original neq '' && $post.file_original neq $post.file} + , {$post.file_original}.{$post.file_type} + {/if} + ) + {if $post.id3.playtime_string neq ''} + {t}Length{/t}: {$post.id3.playtime_string} + {/if} + + {if %KU_THUMBMSG} + + {if $post.file_type neq 'jpg' && $post.file_type neq 'gif' && $post.file_type neq 'png' && $post.videobox eq ''} + {t}Extension icon displayed, click image to open file.{/t} + {else} + {t}Thumbnail displayed, click image for full size.{/t} + {/if} + + {/if} +
+ {/if} + {if $post.videobox eq '' && $post.file neq '' && ( $post.file_type eq 'jpg' || $post.file_type eq 'gif' || $post.file_type eq 'png')} + {if $post.file eq 'removed'} +
+ {t}File
Removed{/t} +
+ {else} + + {$post.id} + + {/if} + {elseif $post.nonstandard_file neq ''} + {if $post.file eq 'removed'} +
+ {t}File
Removed{/t} +
+ {else} + + {$post.id} + + {/if} + {/if} + + + + {$post.reflink} + + {if $board.showid} + ID: {$post.ipmd5|substr:0:6} + {/if} + +
+ {else} + {if $numimages > 0 && $isexpand && $.foreach.postsloop.first} + {t}Expand all images{/t} + {/if} + + + + + + + + +
+ >> + + + + + + {$post.reflink} + + {if $board.showid} + ID: {$post.ipmd5|substr:0:6} + {/if} + + {if $post.locked eq 1} + {t}Locked{/t} + {/if} + {if $post.stickied eq 1} + {t}Stickied{/t} + {/if} + + + {if ($post.file neq '' || $post.file_type neq '' ) && (( $post.videobox eq '' && $post.file neq '') && $post.file neq 'removed')} +
+ {if $post.file_type eq 'mp3'} + {t}Audio{/t} + {else} + {t}File{/t} + {/if} + {if $post.file_type neq 'jpg' && $post.file_type neq 'gif' && $post.file_type neq 'png' && $post.videobox eq ''} + + {else} + + {/if} + {if isset($post.id3.comments_html)} + {if $post.id3.comments_html.artist.0 neq ''} + {$post.id3.comments_html.artist.0} + {if $post.id3.comments_html.title.0 neq ''} + - + {/if} + {/if} + {if $post.id3.comments_html.title.0 neq ''} + {$post.id3.comments_html.title.0} + {/if} + + {else} + {$post.file}.{$post.file_type} + {/if} + - ({$post.file_size_formatted} + {if $post.id3.comments_html.bitrate neq 0 || $post.id3.audio.sample_rate neq 0} + {if $post.id3.audio.bitrate neq 0} + - {round($post.id3.audio.bitrate / 1000)} kbps + {if $post.id3.audio.sample_rate neq 0} + - + {/if} + {/if} + {if $post.id3.audio.sample_rate neq 0} + {$post.id3.audio.sample_rate / 1000} kHz + {/if} + {/if} + {if $post.image_w > 0 && $post.image_h > 0} + , {$post.image_w}x{$post.image_h} + {/if} + {if $post.file_original neq '' && $post.file_original neq $post.file} + , {$post.file_original}.{$post.file_type} + {/if} + ) + {if $post.id3.playtime_string neq ''} + {t}Length{/t}: {$post.id3.playtime_string} + {/if} + + {if %KU_THUMBMSG} + + {if $post.file_type neq 'jpg' && $post.file_type neq 'gif' && $post.file_type neq 'png' && $post.videobox eq ''} + {t}Extension icon displayed, click image to open file.{/t} + {else} + {t}Thumbnail displayed, click image for full size.{/t} + {/if} + + {/if} + + {/if} + {if $post.videobox eq '' && $post.file neq '' && ( $post.file_type eq 'jpg' || $post.file_type eq 'gif' || $post.file_type eq 'png')} +
+ {if $post.file eq 'removed'} +
+ {t}File
Removed{/t} +
+ {else} + + {$post.id} + + {/if} + {elseif $post.nonstandard_file neq ''} +
+ {if $post.file eq 'removed'} +
+ {t}File
Removed{/t} +
+ {else} + + {$post.id} + + {/if} + {/if} + + {/if} + {if $post.file_type eq 'mp3'} + + + + + + + + {/if} +
+ {if $post.videobox} + {$post.videobox} + {/if} + {$post.message} +
+ {if not $post.stickied && $post.parentid eq 0 && (($board.maxage > 0 && ($post.timestamp + ($board.maxage * 3600)) < (time() + 7200 ) ) || ($post.deleted_timestamp > 0 && $post.deleted_timestamp <= (time() + 7200)))} + + {t}Marked for deletion (old){/t} + +
+ {/if} + {if $post.parentid eq 0} + {if $modifier eq 'last50'} + + {$replycount-50} + {if $replycount-50 eq 1} + {t lower="yes"}Post{/t} + {else} + {t lower="yes"}Posts{/t} + {/if} + {t}omitted{/t}. {t}Last 50 shown{/t}. + + {/if} + {if $numimages > 0} + {t}Expand all images{/t} + {/if} + {else} +
+ {/if} + {/foreach} + {if $modifier eq 'first100'} + + {$replycount-100} + {if $replycount-100 eq 1} + {t lower="yes"}Post{/t} + {else} + {t lower="yes"}Posts{/t} + {/if} + {t}omitted{/t}. {t}First 100 shown{/t}. + + {/if} + {if not $isread} + {if $replycount > 2} + + [{t}Return{/t}] + {if %KU_FIRSTLAST && ( count($posts) > 50 || $replycount > 50)} + [{t}Entire Thread{/t}] + [{t}Last 50 posts{/t}] + {if ( count($posts) > 100 || $replycount > 100) } + [{t}First 100 posts{/t}] + {/if} + {/if} + + {/if} +
+ {if not $isexpand} +
+
+ {/if} +{/if} diff --git a/dwoo/templates/manage.tpl b/dwoo/templates/manage.tpl new file mode 100644 index 0000000..bb25b41 --- /dev/null +++ b/dwoo/templates/manage.tpl @@ -0,0 +1,69 @@ + + + +{t}Manage Boards{/t} + +{loop $styles} + +{/loop} +{literal}{/literal} + + + +{$includeheader} +
+
+ {$page} +
+
+{$footer} + + \ No newline at end of file diff --git a/dwoo/templates/manage_menu.tpl b/dwoo/templates/manage_menu.tpl new file mode 100644 index 0000000..5cbe358 --- /dev/null +++ b/dwoo/templates/manage_menu.tpl @@ -0,0 +1,33 @@ + + + + +{t}Manage Boards{/t} +{loop $styles} + + +{/loop} + +{literal} + +{/literal} + + + +

{t}Manage Boards{/t}

+
    + {$links} +
+ + \ No newline at end of file diff --git a/dwoo/templates/menu.tpl b/dwoo/templates/menu.tpl new file mode 100644 index 0000000..70e5118 --- /dev/null +++ b/dwoo/templates/menu.tpl @@ -0,0 +1,160 @@ + + + + +{%KU_NAME} Navigation +{if %KU_MENUTYPE eq 'normal'} + + {loop $styles} + + + {/loop} +{else} + {literal}{/literal} +{/if} + + + + + + + + + + +

{%KU_NAME}

+ +{if empty($boards)} +
    +
  • {t}No visible boards{/t}
  • +
+{else} + + {foreach name=sections item=sect from=$boards} + + {if %KU_MENUTYPE eq 'normal'} +

+ {else} +


+ {/if} + {if %KU_MENUTYPE eq 'normal'} + {if $sect.hidden eq 1}+{else}−{/if}  + {/if} + {$sect.name}

+ {if %KU_MENUTYPE eq 'normal'} + + {/if} + {/foreach} +{/if} +{if %KU_IRC} + {if %KU_MENUTYPE eq 'normal'} +

+ {else} +


+ {/if} +  IRC

+
    +
  • {%KU_IRC}
  • +
+{/if} + + + + diff --git a/dwoo/templates/news.tpl b/dwoo/templates/news.tpl new file mode 100644 index 0000000..7ab8faf --- /dev/null +++ b/dwoo/templates/news.tpl @@ -0,0 +1,38 @@ + + + + {$dwoo.const.KU_NAME} + + + {for style $styles} + + {/for} + + + + + +

{$dwoo.const.KU_NAME}

+ {if $dwoo.const.KU_SLOGAN neq ''}

{$dwoo.const.KU_SLOGAN}

{/if} + + +{foreach item=entry from=$entries} +
+

{$entry.subject|stripslashes}{if $dwoo.get.p eq ''} by {if $entry.email neq ''}{/if}{$entry.poster|stripslashes}{if $entry.email neq ''}{/if} - {$entry.timestamp|date_format:"%D @ %I:%M %p %Z"}{/if} + #

+ {$entry.message|stripslashes} +

+{/foreach} + {$botads} + + \ No newline at end of file diff --git a/dwoo/templates/oek_board_page.tpl b/dwoo/templates/oek_board_page.tpl new file mode 100644 index 0000000..c36a714 --- /dev/null +++ b/dwoo/templates/oek_board_page.tpl @@ -0,0 +1,428 @@ + + +{foreach name=thread item=postsa from=$posts} + {foreach key=postkey item=post from=$postsa} + {if $post.parentid eq 0} + +
+ + + + {if ($post.file neq '' || $post.file_type neq '' ) && (($post.videobox eq '' && $post.file neq '') && $post.file neq 'removed')} + + {if $post.file_type eq 'mp3'} + {t}Audio{/t} + {else} + {t}File{/t} + {/if} + {if $post.file_type neq 'jpg' && $post.file_type neq 'gif' && $post.file_type neq 'png' && $post.videobox eq ''} + + {else} + + {/if} + {if isset($post.id3.comments_html)} + {if $post.id3.comments_html.artist.0 neq ''} + {$post.id3.comments_html.artist.0} + {if $post.id3.comments_html.title.0 neq ''} + - + {/if} + {/if} + {if $post.id3.comments_html.title.0 neq ''} + {$post.id3.comments_html.title.0} + {/if} + + {else} + {$post.file}.{$post.file_type} + {/if} + - ({$post.file_size_formatted} + {if $post.id3.comments_html.bitrate neq 0 || $post.id3.audio.sample_rate neq 0} + {if $post.id3.audio.bitrate neq 0} + - {round($post.id3.audio.bitrate / 1000)} kbps + {if $post.id3.audio.sample_rate neq 0} + - + {/if} + {/if} + {if $post.id3.audio.sample_rate neq 0} + {$post.id3.audio.sample_rate / 1000} kHz + {/if} + {/if} + {if $post.image_w > 0 && $post.image_h > 0} + , {$post.image_w}x{$post.image_h} + {/if} + {if $post.file_original neq '' && $post.file_original neq $post.file} + , {$post.file_original}.{$post.file_type} + {/if} + ) + {if $post.id3.playtime_string neq ''} + {t}Length{/t}: {$post.id3.playtime_string} + {/if} + + {if %KU_THUMBMSG} + + {if $post.file_type neq 'jpg' && $post.file_type neq 'gif' && $post.file_type neq 'png' && $post.videobox eq ''} + {t}Extension icon displayed, click image to open file.{/t} + {else} + {t}Thumbnail displayed, click image for full size.{/t} + {/if} + + {/if} +
+ {/if} + {if $post.videobox eq '' && $post.file neq '' && ( $post.file_type eq 'jpg' || $post.file_type eq 'gif' || $post.file_type eq 'png')} + {if $post.file eq 'removed'} +
+ {t}File
Removed{/t} +
+ {else} + + {$post.id} + + {/if} + {elseif $post.nonstandard_file neq ''} + {if $post.file eq 'removed'} +
+ {t}File
Removed{/t} +
+ {else} + + {$post.id} + + {/if} + {/if} + + + + {$post.reflink} + + {if $board.showid} + ID: {$post.ipmd5|substr:0:6} + {/if} + + {if $post.locked eq 1} + {t}Locked{/t} + {/if} + {if $post.stickied eq 1} + {t}Stickied{/t} + {/if} + hide + {if %KU_WATCHTHREADS} + watch + {/if} + {if %KU_EXPAND && $post.replies && ($post.replies + %KU_REPLIES) < 300} + expand + {/if} + {if %KU_QUICKREPLY} + quickreply + {/if} + + + [{t}Reply{/t}] + {if %KU_FIRSTLAST && (($post.stickied eq 1 && $post.replies + %KU_REPLIESSTICKY > 50) || ($post.stickied eq 0 && $post.replies + %KU_REPLIES > 50))} + {if (($post.stickied eq 1 && $post.replies + %KU_REPLIESSTICKY > 100) || ($post.stickied eq 0 && $post.replies + %KU_REPLIES > 100))} + [{t}First 100 posts{/t}] + {/if} + [{t}Last 50 posts{/t}] + {/if} +
+ {else} + + + + + + + +
+ >> + + + + + + {$post.reflink} + + {if $board.showid} + ID: {$post.ipmd5|substr:0:6} + {/if} + + {if $post.locked eq 1} + {t}Locked{/t} + {/if} + {if $post.stickied eq 1} + {t}Stickied{/t} + {/if} + + + {if ($post.file neq '' || $post.file_type neq '' ) && (( $post.videobox eq '' && $post.file neq '') && $post.file neq 'removed')} +
+ {if $post.file_type eq 'mp3'} + {t}Audio{/t} + {else} + {t}File{/t} + {/if} + {if $post.file_type neq 'jpg' && $post.file_type neq 'gif' && $post.file_type neq 'png' && $post.videobox eq ''} + + {else} + + {/if} + {if isset($post.id3.comments_html)} + {if $post.id3.comments_html.artist.0 neq ''} + {$post.id3.comments_html.artist.0} + {if $post.id3.comments_html.title.0 neq ''} + - + {/if} + {/if} + {if $post.id3.comments_html.title.0 neq ''} + {$post.id3.comments_html.title.0} + {/if} + + {else} + {$post.file}.{$post.file_type} + {/if} + - ({$post.file_size_formatted} + {if $post.id3.comments_html.bitrate neq 0 || $post.id3.audio.sample_rate neq 0} + {if $post.id3.audio.bitrate neq 0} + - {round($post.id3.audio.bitrate / 1000)} kbps + {if $post.id3.audio.sample_rate neq 0} + - + {/if} + {/if} + {if $post.id3.audio.sample_rate neq 0} + {$post.id3.audio.sample_rate / 1000} kHz + {/if} + {/if} + {if $post.image_w > 0 && $post.image_h > 0} + , {$post.image_w}x{$post.image_h} + {/if} + {if $post.file_original neq '' && $post.file_original neq $post.file} + , {$post.file_original}.{$post.file_type} + {/if} + ) + {if $post.id3.playtime_string neq ''} + {t}Length{/t}: {$post.id3.playtime_string} + {/if} + + {if %KU_THUMBMSG} + + {if $post.file_type neq 'jpg' && $post.file_type neq 'gif' && $post.file_type neq 'png' && $post.videobox eq ''} + {t}Extension icon displayed, click image to open file.{/t} + {else} + {t}Thumbnail displayed, click image for full size.{/t} + {/if} + + {/if} + + {/if} + {if $post.videobox eq '' && $post.file neq '' && ( $post.file_type eq 'jpg' || $post.file_type eq 'gif' || $post.file_type eq 'png')} +
+ {if $post.file eq 'removed'} +
+ {t}File
Removed{/t} +
+ {else} + + {$post.id} + + {/if} + {elseif $post.nonstandard_file neq ''} +
+ {if $post.file eq 'removed'} +
+ {t}File
Removed{/t} +
+ {else} + + {$post.id} + + {/if} + {/if} + + {/if} + {if $post.file_type eq 'mp3'} + + + + + + + + {/if} +
+ {if $post.videobox} + {$post.videobox} + {/if} + {$post.message} +
+ {if not $post.stickied && $post.parentid eq 0 && (($board.maxage > 0 && ($post.timestamp + ($board.maxage * 3600)) < (time() + 7200 ) ) || ($post.deleted_timestamp > 0 && $post.deleted_timestamp <= (time() + 7200)))} + + {t}Marked for deletion (old){/t} + +
+ {/if} + {if $post.parentid eq 0} +
+ {if $post.replies} + + {if $post.stickied eq 0} + {$post.replies} + {if $post.replies eq 1} + {t lower="yes"}Post{/t} + {else} + {t lower="yes"}Posts{/t} + {/if} + {else} + {$post.replies} + {if $post.replies eq 1} + {t lower="yes"}Post{/t} + {else} + {t lower="yes"}Posts{/t} + {/if} + {/if} + {if $post.images > 0} + {t}and{/t} {$post.images} + {if $post.images eq 1} + {t lower="yes"}Image{/t} + {else} + {t lower="yes"}Images{/t} + {/if} + {/if} + {t}omitted{/t}. {t}Click Reply to view.{/t} + + {/if} + {else} +
+ + {/if} + {/foreach} +
+ +
+
+{/foreach} diff --git a/dwoo/templates/oek_footer.tpl b/dwoo/templates/oek_footer.tpl new file mode 100644 index 0000000..ffed8b3 --- /dev/null +++ b/dwoo/templates/oek_footer.tpl @@ -0,0 +1,101 @@ +{if not $isread} + + + + + + + + + +
+ {t}Delete post{/t} + []
{t}Password{/t} +   + + {if $board.enablereporting eq 1} +
+ {t}Report post{t}
+ {t}Reason{/t} +   + {/if} + +
+
+ + +{/if} +{if $replythread eq 0} + + + + + + + + +
+ {if $thispage eq 0} + {t}Previous{/t} + {else} +
+
+ {/if} +
+ [{if $thispage neq 0}{/if}0{if $thispage neq 0}{/if}] + {section name=pages loop=$numpages} + {strip} + [ + {if $.section.pages.iteration neq $thispage} + {/if} + + {$.section.pages.iteration} + + {if $.section.pages.iteration neq $thispage} + + {/if} + ] + {/strip} + {/section} + + {if $thispage eq $numpages} + {t}Next{/t} + {else} +
+ {/if} + +
+{/if} +
+{if $boardlist} + +{/if} +
+ \ No newline at end of file diff --git a/dwoo/templates/oek_header.tpl b/dwoo/templates/oek_header.tpl new file mode 100644 index 0000000..f5f4e06 --- /dev/null +++ b/dwoo/templates/oek_header.tpl @@ -0,0 +1,103 @@ + + +{loop $ku_styles} + +{/loop} +{if $locale eq 'ja'} + {literal} + + {/literal} +{/if} +{if %KU_RSS neq ''} + +{/if} + + + +{if $board.enablecaptcha eq 1} + {literal} + + {/literal} +{/if} + + +
+{if %KU_STYLESWITCHER} + {if %KU_DROPSWITCHER} + + {else} + {loop $ku_styles} + [{$|capitalize}]  + {/loop} + {/if} + {if count($ku_styles) > 0} + -  + {/if} +{/if} +{if %KU_WATCHTHREADS} + [WT]  +{/if} +[{t}Home{/t}] [{t}Manage{/t}] +
+ +{if %KU_WATCHTHREADS && not $isoekaki && not $hidewatchedthreads} + +{/if} + + +{$board.includeheader} +
\ No newline at end of file diff --git a/dwoo/templates/oek_post_box.tpl b/dwoo/templates/oek_post_box.tpl new file mode 100644 index 0000000..c919d1a --- /dev/null +++ b/dwoo/templates/oek_post_box.tpl @@ -0,0 +1,173 @@ +
+ +{if $.get.postoek eq ''} +
+ + + +   +   +   +   + {if $replythread neq 0} +   + {/if} +
+
+{/if} +{if $replythread neq 0 || $.get.postoek neq ''} + +
+ + + {if $board.maximagesize > 0} + + {/if} + + + + {if $board.forcedanon neq 1} + + + + + {/if} + + + + + + + + + + + + + {if $board.enablecaptcha eq 1} + + + + + {/if} + {if $board.uploadtype eq 0 || $board.uploadtype eq 1} + + + + + {/if} + + + + + + + + + +
+ {t}Name{/t} + +
+ {t}Email{/t} + +
+ {t}Subject{/t} + {strip}  ({t}new thread{/t}) + {elseif %KU_QUICKREPLY && $replythread neq 0} + {t}Reply{/t}" accesskey="z" /> ({t}reply to{/t} {$replythread}) + {else} + {t}Submit{/t}" accesskey="z" /> + {/if}{/strip} +
+ {t}Message{/t} + + +
{t}Captcha{/t}{$recaptcha}
+ {t}File{/t} + + {if $.get.postoek eq ''} + + {else} + {t}Shown Below{/t} + {/if} +
+ {t}Password{/t} + +  {t}(for post and file deletion){/t} +
+
    +
  • {t}Supported file types are{/t}: + {if $board.filetypes_allowed neq ''} + {foreach name=files item=filetype from=$board.filetypes_allowed} + {$filetype.0|upper}{if $.foreach.files.last}{else}, {/if} + {/foreach} + {else} + {t}None{/t} + {/if} +
  • +
  • {t}Maximum file size allowed is{/t} {math "round(x/1024)" x=$board.maximagesize} KB.
  • +
  • {t 1=%KU_THUMBWIDTH 2=%KU_THUMBHEIGHT}Images greater than %1x%2 pixels will be thumbnailed.{/t}
  • +
  • {t 1=$board.uniqueposts}Currently %1 unique user posts.{/t} + {if $board.enablecatalog eq 1} + {t}View catalog{/t} + {/if} +
  • +
+ {if %KU_BLOTTER && $blotter} +
+ + + {/if} +
+
+
+{/if} +{if $topads neq ''} +
+
+ {$topads} +
+
+
+{/if} +
+ +{if $.get.postoek} +
+ {t}Your image{/t}:
+ +
+{/if} diff --git a/dwoo/templates/oek_reply_header.tpl b/dwoo/templates/oek_reply_header.tpl new file mode 100644 index 0000000..bf4a3ce --- /dev/null +++ b/dwoo/templates/oek_reply_header.tpl @@ -0,0 +1,19 @@ +[{t}Return{/t}] +{if %KU_FIRSTLAST && ( count($posts) > 50 || $replycount > 50)} + [{t}Entire Thread{/t}] + [{t}Last 50 posts{/t}] + {if ( count($posts) > 100 || $replycount > 100) } + [{t}First 100 posts{/t}] + {/if} +{/if} +{if not $isread} +
{t}Posting mode: Reply{/t} + {if $modifier eq 'first100'} + [{t}First 100 posts{/t}] + {elseif $modifier eq 'last50'} + [{t}Last 50 posts{/t}] + {/if} +{else} + [{t}Entire Thread{/t}] +{/if} +
\ No newline at end of file diff --git a/dwoo/templates/oek_thread.tpl b/dwoo/templates/oek_thread.tpl new file mode 100644 index 0000000..7e85081 --- /dev/null +++ b/dwoo/templates/oek_thread.tpl @@ -0,0 +1,420 @@ +{if not $isexpand and not $isread} +
+ +{/if} + {foreach key=postkey item=post from=$posts name=postsloop} + + {if $post.parentid eq 0} +
+ + + {if ($post.file neq '' || $post.file_type neq '' ) && (( $post.videobox eq '' && $post.file neq '') && $post.file neq 'removed')} + + {if $post.file_type eq 'mp3'} + {t}Audio{/t} + {else} + {t}File{/t} + {/if} + {if $post.file_type neq 'jpg' && $post.file_type neq 'gif' && $post.file_type neq 'png' && $post.videobox eq ''} + + {else} + + {/if} + {if isset($post.id3.comments_html)} + {if $post.id3.comments_html.artist.0 neq ''} + {$post.id3.comments_html.artist.0} + {if $post.id3.comments_html.title.0 neq ''} + - + {/if} + {/if} + {if $post.id3.comments_html.title.0 neq ''} + {$post.id3.comments_html.title.0} + {/if} + + {else} + {$post.file}.{$post.file_type} + {/if} + - ({$post.file_size_formatted} + {if $post.id3.comments_html.bitrate neq 0 || $post.id3.audio.sample_rate neq 0} + {if $post.id3.audio.bitrate neq 0} + - {round($post.id3.audio.bitrate / 1000)} kbps + {if $post.id3.audio.sample_rate neq 0} + - + {/if} + {/if} + {if $post.id3.audio.sample_rate neq 0} + {$post.id3.audio.sample_rate / 1000} kHz + {/if} + {/if} + {if $post.image_w > 0 && $post.image_h > 0} + , {$post.image_w}x{$post.image_h} + {/if} + {if $post.file_original neq '' && $post.file_original neq $post.file} + , {$post.file_original}.{$post.file_type} + {/if} + ) + {if $post.id3.playtime_string neq ''} + {t}Length{/t}: {$post.id3.playtime_string} + {/if} + + {if %KU_THUMBMSG} + + {if $post.file_type neq 'jpg' && $post.file_type neq 'gif' && $post.file_type neq 'png' && $post.videobox eq ''} + {t}Extension icon displayed, click image to open file.{/t} + {else} + {t}Thumbnail displayed, click image for full size.{/t} + {/if} + + {/if} +
+ {/if} + {if $post.videobox eq '' && $post.file neq '' && ( $post.file_type eq 'jpg' || $post.file_type eq 'gif' || $post.file_type eq 'png')} + {if $post.file eq 'removed'} +
+ {t}File
Removed{/t} +
+ {else} + + {$post.id} + + {/if} + {elseif $post.nonstandard_file neq ''} + {if $post.file eq 'removed'} +
+ {t}File
Removed{/t} +
+ {else} + + {$post.id} + + {/if} + {/if} + + + + {$post.reflink} + + {if $board.showid} + ID: {$post.ipmd5|substr:0:6} + {/if} + +
+ {else} + {if $numimages > 0 && $isexpand && $.foreach.postsloop.first} + {t}Expand all images{/t} + {/if} + + + + + + + + +
+ >> + + + + + + {$post.reflink} + + {if $board.showid} + ID: {$post.ipmd5|substr:0:6} + {/if} + + {if $post.locked eq 1} + {t}Locked{/t} + {/if} + {if $post.stickied eq 1} + {t}Stickied{/t} + {/if} + + + {if ($post.file neq '' || $post.file_type neq '' ) && (( $post.videobox eq '' && $post.file neq '') && $post.file neq 'removed')} +
+ {if $post.file_type eq 'mp3'} + {t}Audio{/t} + {else} + {t}File{/t} + {/if} + {if $post.file_type neq 'jpg' && $post.file_type neq 'gif' && $post.file_type neq 'png' && $post.videobox eq ''} + + {else} + + {/if} + {if isset($post.id3.comments_html)} + {if $post.id3.comments_html.artist.0 neq ''} + {$post.id3.comments_html.artist.0} + {if $post.id3.comments_html.title.0 neq ''} + - + {/if} + {/if} + {if $post.id3.comments_html.title.0 neq ''} + {$post.id3.comments_html.title.0} + {/if} + + {else} + {$post.file}.{$post.file_type} + {/if} + - ({$post.file_size_formatted} + {if $post.id3.comments_html.bitrate neq 0 || $post.id3.audio.sample_rate neq 0} + {if $post.id3.audio.bitrate neq 0} + - {round($post.id3.audio.bitrate / 1000)} kbps + {if $post.id3.audio.sample_rate neq 0} + - + {/if} + {/if} + {if $post.id3.audio.sample_rate neq 0} + {$post.id3.audio.sample_rate / 1000} kHz + {/if} + {/if} + {if $post.image_w > 0 && $post.image_h > 0} + , {$post.image_w}x{$post.image_h} + {/if} + {if $post.file_original neq '' && $post.file_original neq $post.file} + , {$post.file_original}.{$post.file_type} + {/if} + ) + {if $post.id3.playtime_string neq ''} + {t}Length{/t}: {$post.id3.playtime_string} + {/if} + + {if %KU_THUMBMSG} + + {if $post.file_type neq 'jpg' && $post.file_type neq 'gif' && $post.file_type neq 'png' && $post.videobox eq ''} + {t}Extension icon displayed, click image to open file.{/t} + {else} + {t}Thumbnail displayed, click image for full size.{/t} + {/if} + + {/if} + + {/if} + {if $post.videobox eq '' && $post.file neq '' && ( $post.file_type eq 'jpg' || $post.file_type eq 'gif' || $post.file_type eq 'png')} +
+ {if $post.file eq 'removed'} +
+ {t}File
Removed{/t} +
+ {else} + + {$post.id} + + {/if} + {elseif $post.nonstandard_file neq ''} +
+ {if $post.file eq 'removed'} +
+ {t}File
Removed{/t} +
+ {else} + + {$post.id} + + {/if} + {/if} + + {/if} + {if $post.file_type eq 'mp3'} + + + + + + + + {/if} +
+ {if $post.videobox} + {$post.videobox} + {/if} + {$post.message} +
+ {if not $post.stickied && $post.parentid eq 0 && (($board.maxage > 0 && ($post.timestamp + ($board.maxage * 3600)) < (time() + 7200 ) ) || ($post.deleted_timestamp > 0 && $post.deleted_timestamp <= (time() + 7200)))} + + {t}Marked for deletion (old){/t} + +
+ {/if} + {if $post.parentid eq 0} + {if $modifier eq 'last50'} + + {$replycount-50} + {if $replycount-50 eq 1} + {t lower="yes"}Post{/t} + {else} + {t lower="yes"}Posts{/t} + {/if} + {t}omitted{/t}. {t}Last 50 shown{/t}. + + {/if} + {if $numimages > 0} + {t}Expand all images{/t} + {/if} + {else} +
+ {/if} + {/foreach} + {if $modifier eq 'first100'} + + {$replycount-100} + {if $replycount-100 eq 1} + {t lower="yes"}Post{/t} + {else} + {t lower="yes"}Posts{/t} + {/if} + {t}omitted{/t}. {t}First 100 shown{/t}. + + {/if} + {if not $isread} + {if $replycount > 2} + + [{t}Return{/t}] + {if %KU_FIRSTLAST && ( count($posts) > 50 || $replycount > 50)} + [{t}Entire Thread{/t}] + [{t}Last 50 posts{/t}] + {if ( count($posts) > 100 || $replycount > 100) } + [{t}First 100 posts{/t}] + {/if} + {/if} + + {/if} +
+ {if not $isexpand} +
+
+ {/if} +{/if} diff --git a/dwoo/templates/rss_board.tpl b/dwoo/templates/rss_board.tpl new file mode 100644 index 0000000..03f7d6d --- /dev/null +++ b/dwoo/templates/rss_board.tpl @@ -0,0 +1,32 @@ + + + +{%KU_NAME} - {$boardname} +{%KU_BOARDSPATH}/{$boardname} +Live RSS feed for {%KU_BOARDSPATH}/{$boardname} +{%KU_LOCALE}'; +{foreach name=rss from=$posts item=item} + + {$item.id} + + {if $item.parentid neq 0} + {%KU_BOARDSPATH}/{$boardname}/res/{$item.parentid}.html#{$item.id} + {else} + {%KU_BOARDSPATH}/{$boardname}/res/{$item.id}.html + {/if} +

+ {else} + [{%KU_BOARDSPATH}/{$boardname}/src/{$item.file}.{$item.file_type}]

+ {/if} + {/if} + {if trim($item.message) neq ''} + {$item.message|stripslashes}
+ {/if} + ]]>
+
+{/foreach} +
+
diff --git a/dwoo/templates/rss_mod.tpl b/dwoo/templates/rss_mod.tpl new file mode 100644 index 0000000..bb55e52 --- /dev/null +++ b/dwoo/templates/rss_mod.tpl @@ -0,0 +1,15 @@ + + + +{%KU_NAME} - Modlog +{%KU_WEBPATH} +Live view of all moderative actions on {%KU_WEBPATH} +{%KU_LOCALE} +{foreach from=$entries item=item} + + {$item.timestamp|date_format:"%a %m/%d %H:%M"} + + +{/foreach} + + diff --git a/dwoo/templates/txt_board_page.tpl b/dwoo/templates/txt_board_page.tpl new file mode 100644 index 0000000..98f29c9 --- /dev/null +++ b/dwoo/templates/txt_board_page.tpl @@ -0,0 +1,164 @@ +{foreach name=thread item=postsa from=$posts} + {foreach name=pst key=postkey item=post from=$postsa} + {if $post.parentid eq 0} +
+
+ + {/if} + {if $post.parentid eq 0} + {if $.foreach.thread.last} + +   +   + + + {else} + +   +   + + + {/if} + {/if} + + {if $post.parentid eq 0} +

+ {$post.subject} + ({$postsa.0.replies})

+ {/if} + + {if $.foreach.thread.iteration % 2 eq 0} +
+ {else} +
+ {/if} +

+ + + {if $post.parentid eq 0} + 1 + . + {else} + {math "replies-postcount+iteration+x" replies=$postsa.0.replies postcount=$postsa|count iteration=$.foreach.pst.iteration x=1} + . + {/if} + + +

+
+ {$post.message} +
+
+ {if $.foreach.pst.last} + + + + + + + {if $board.forcedanon neq 1} + + + {/if} + + + {if $board.forcedanon neq 1} + + + + {/if} + + {if $board.enablecaptcha eq 1} + + + {/if} + {if ($board.forcedanon eq 1 && $board.enablecaptcha neq 1) || $board.forcedanon neq 1} + + + {/if} + {if $board.forcedanon eq 1} + + {if $board.enablecaptcha eq 1} + + + + + {/if} + {/if} + + + + + + +
+ + + + + + + + + + {t}More{/t}... +
+ + Captcha image +   + + + + + + + + {t}More{/t}... +
+ + + +
+ + {$postsa.0.replies+2} + + + +
+
+ + +
+ {/if} + {/foreach} + +{/foreach} + diff --git a/dwoo/templates/txt_footer.tpl b/dwoo/templates/txt_footer.tpl new file mode 100644 index 0000000..d38c007 --- /dev/null +++ b/dwoo/templates/txt_footer.tpl @@ -0,0 +1,8 @@ +
+ \ No newline at end of file diff --git a/dwoo/templates/txt_header.tpl b/dwoo/templates/txt_header.tpl new file mode 100644 index 0000000..6d52877 --- /dev/null +++ b/dwoo/templates/txt_header.tpl @@ -0,0 +1,103 @@ + + +{loop $ku_styles} + +{/loop} +{if $locale eq 'ja'} + {literal} + + {/literal} +{/if} +{if %KU_RSS neq ''} + +{/if} + + + +{if $board.enablecaptcha eq 1} + {literal} + + {/literal} +{/if} + +{if $replythread eq 0} + +{else} + +{/if} +
+{if %KU_GENERATEBOARDLIST} + {foreach name=sections item=sect from=$boardlist} + [ + {foreach name=brds item=brd from=$sect} + {$brd.name}{if $.foreach.brds.last}{else} / {/if} + {/foreach} + ] + {/foreach} +{else} + {if is_file($boardlist)} + {include $boardlist} + {/if} +{/if} +
+{if not $isthread} +
+
+
+ + {if $isindex eq 1} +   + {/if} +

{$board.desc}

+ {$board.includeheader} +
+
+ {if %KU_TXTSTYLESWITCHER && $isindex} + + {/if} + {if $isindex eq 0} + {t}Pages{/t}: {t}Front{/t} + {section name=pages loop=$numpages} +   + {if $.section.pages.iteration neq $thispage} + + {/if} + {$.section.pages.iteration} + {if $.section.pages.iteration neq $thispage} + + {/if} + {/section} +
+ {/if} +{/if} diff --git a/dwoo/templates/txt_post_box.tpl b/dwoo/templates/txt_post_box.tpl new file mode 100644 index 0000000..75feca2 --- /dev/null +++ b/dwoo/templates/txt_post_box.tpl @@ -0,0 +1,93 @@ +
+

{t}New Thread{/t}

+ +
+ + + {if $board.maximagesize > 0} + + {/if} + + + + + + + + + {if $board.forcedanon neq 1} + + + {/if} + + + {if $board.forcedanon neq 1} + + + + {/if} + + {if $board.enablecaptcha eq 1} + + + + + {/if} + {if ($board.forcedanon eq 1 && $board.enablecaptcha neq 1) || $board.forcedanon neq 1} + + + {/if} + {if $board.forcedanon eq 1} + + {if $board.enablecaptcha eq 1} + + + + + {/if} + {/if} + + + + + + +
+ + + +
+ + + + + + + + + + {t}More{/t}... +
{t}Captcha{/t}{$recaptcha}
+ + + + + + {t}More{/t}... +
+ + + +
+ + 1 + + + +
+
+
+
+ \ No newline at end of file diff --git a/dwoo/templates/txt_reply_header.tpl b/dwoo/templates/txt_reply_header.tpl new file mode 100644 index 0000000..ba2cf58 --- /dev/null +++ b/dwoo/templates/txt_reply_header.tpl @@ -0,0 +1,12 @@ +{t}Return{/t} +{if $replythread} + {t}Entire Thread{/t} +{/if} +{if %KU_FIRSTLAST && ( count($posts) > 50 || $replycount > 50)} + {t}Last 50 posts{/t} + {if ( count($posts) > 100 || $replycount > 100) } + {t}First 100 posts{/t} + {/if} +{/if} +
+
\ No newline at end of file diff --git a/dwoo/templates/txt_thread.tpl b/dwoo/templates/txt_thread.tpl new file mode 100644 index 0000000..1044870 --- /dev/null +++ b/dwoo/templates/txt_thread.tpl @@ -0,0 +1,189 @@ +{foreach name=pst key=postkey item=post from=$posts} + + + {if $post.parentid eq 0 || isread} +
+ + + {if $post.parentid eq 0 } +

+ {$post.subject} + ({$posts|count - 1})

+ {/if} + {/if} + +
+

+ + {if $post.parentid eq 0} + 1 + . + {else} + {if not $postnum}{$.foreach.pst.iteration}{else}{$postnum}{/if} + . + {/if} + + +

+
+ {$post.message} +
+
+ {if not $post.stickied && $post.parentid eq 0 && (($board.maxage > 0 && ($post + ($board.maxage * 3600)) < (time() + 7200 ) ) || ($post.deleted_timestamp > 0 && $post.deleted_timestamp <= (time() + 7200)))} + + {t}Marked for deletion (old){/t} + +
+ {/if} + {if $post.parentid eq 0} +
+ {if $modifier} + + {if $modifier eq 'last50'} + {$replycount-50} + {if $replycount-50 eq 1} + {t lower="yes"}Post{/t} + {else} + {t lower="yes"}Posts{/t} + {/if} + {t}omitted{/t}. {t}Last 50 posts shown{/t}. + {elseif $modifier eq 'first100'} + {$replycount-100} + {if $replycount-100 eq 1} + {t lower="yes"}Post{/t} + {else} + {t lower="yes"}Posts{/t} + {/if} + {t}omitted{/t}. {t}First 100 posts shown{/t}. + {/if} + + {/if} + {/if} + {if $.foreach.pst.last && not $isread} + + + + + + +
+ {t}Delete Post{/t}:   +
+ + + + {if !$posts.0.locked} +
+ + + + + + {if $board.forcedanon neq 1} + + + {/if} + + + {if $board.forcedanon neq 1} + + + + {/if} + + {if $board.enablecaptcha eq 1} + + + {/if} + {if ($board.forcedanon eq 1 && $board.enablecaptcha neq 1) || $board.forcedanon neq 1} + + + {/if} + {if $board.forcedanon eq 1} + + {if $board.enablecaptcha eq 1} + + + + + {/if} + {/if} + + + + + + +
+ + + + + + + + + + {t}More{/t}... +
+ + Captcha image +   + + + + + + + + {t}More{/t}... +
+ + + +
+ + {$posts|count+1} + + + +
+
+
+ + {elseif $isread} + + {/if} + {/if} + {/foreach} diff --git a/dwoo/templates/txt_threadlist.tpl b/dwoo/templates/txt_threadlist.tpl new file mode 100644 index 0000000..7b6fa64 --- /dev/null +++ b/dwoo/templates/txt_threadlist.tpl @@ -0,0 +1,54 @@ +
+
+ + {if not $board.compactlist || not $isindex} + + + + + + + + + + + {/if} + {if count($threads) > 0} + {foreach key=threadkey name=list item=thread from=$threads} + + {if $board.compactlist && $isindex} + {$.foreach.list.iteration}: {else}res/{$thread.id}.html">{$.foreach.list.iteration}: {/if}{$thread.subject} ({$thread.replies + 1}){if $.foreach.thread.last}{else}  {/if} + + {else} + + {/if} + {/foreach} + {else} + {if $board.compactlist && $isindex} + {t}There are currently no threads to display.{/t} + {else} + + {/if} + {/if} + {if $isindex} + {if $board.compactlist} +
+ {/if} + {/if} + {if not $board.compactlist || not $isindex} + +
#{t}Subject{/t}{t}Posts{/t}{t}Last Post{/t}
{$.foreach.list.iteration}{$thread.subject}{$thread.replies + 1}{$thread.bumped|date_format:"%e %B %Y %H:%M"}
N/A{t}There are currently no threads to display.{/t}N/AN/A
+ {/if} + +
+
+
+
diff --git a/dwoo/templates/upl_board_page.tpl b/dwoo/templates/upl_board_page.tpl new file mode 100644 index 0000000..d1cb517 --- /dev/null +++ b/dwoo/templates/upl_board_page.tpl @@ -0,0 +1,97 @@ +{if count($posts) > 0} +
+ + + + + + + + + + + + + {foreach key=postkey item=post from=$posts} + + + + + + + + + + + + {/foreach} +
+ No. + + {t}Name{/t} + + {t}File{/t} + + {t}Tag{/t} + + {t}Subject{/t} + + {t}Size{/t} + + {t}Date{/t} + + Rep. + +   +
+ {$post.id} + + + {if $post.email neq '' && $board.anonymous neq ''} + + {/if} + {if $post.name eq '' && $post.tripcode eq ''} + {$board.anonymous} + {elseif $post.name eq '' && $post.tripcode neq ''} + {else} + {$post.name} + {/if} + {if $post.email neq '' && $board.anonymous neq ''} + + {/if} + + + + {if $post.tripcode neq ''} + !{$post.tripcode} + {/if} + {if $post.posterauthority eq 1} + + ## {t}Admin{/t} ## + + {elseif $post.posterauthority eq 4} + + ## {t}Super Mod{/t} ## + + {elseif $post.posterauthority eq 2} + + ## {t}Mod{/t} ## + + {/if} + + + [{$post.file}.{$post.file_type}] + + [{$post.tag}] + + {$post.subject} + + {$post.file_size_formatted} + + {$post.timestamp|date_format:"%y/%m/%d(%a)%H:%M"} + + {$post.replies} + + [Reply] +


+{/if} \ No newline at end of file diff --git a/dwoo/templates/upl_footer.tpl b/dwoo/templates/upl_footer.tpl new file mode 100644 index 0000000..be86591 --- /dev/null +++ b/dwoo/templates/upl_footer.tpl @@ -0,0 +1,100 @@ +{if $replythread > 0 && not $isread} + + + + + + + + + +
+ {t}Delete post{/t} + []
{t}Password{/t} +   + + {if $board.enablereporting eq 1} +
+ {t}Report post{t}
+ {t}Reason{/t} +   + {/if} + +
+ +{/if} + +{if $replythread eq 0} + + + + + + + + +
+ {if $thispage eq 0} + {t}Previous{/t} + {else} +
+
+ {/if} +
+ [{if $thispage neq 0}{/if}0{if $thispage neq 0}{/if}] + {section name=pages loop=$numpages} + {strip} + [ + {if $.section.pages.iteration neq $thispage} + {/if} + + {$.section.pages.iteration} + + {if $.section.pages.iteration neq $thispage} + + {/if} + ] + {/strip} + {/section} + + {if $thispage eq $numpages} + {t}Next{/t} + {else} +
+ {/if} + +
+{/if} +
+{if $boardlist} + +{/if} +
+ \ No newline at end of file diff --git a/dwoo/templates/upl_header.tpl b/dwoo/templates/upl_header.tpl new file mode 100644 index 0000000..f5f4e06 --- /dev/null +++ b/dwoo/templates/upl_header.tpl @@ -0,0 +1,103 @@ + + +{loop $ku_styles} + +{/loop} +{if $locale eq 'ja'} + {literal} + + {/literal} +{/if} +{if %KU_RSS neq ''} + +{/if} + + + +{if $board.enablecaptcha eq 1} + {literal} + + {/literal} +{/if} + + +
+{if %KU_STYLESWITCHER} + {if %KU_DROPSWITCHER} + + {else} + {loop $ku_styles} + [{$|capitalize}]  + {/loop} + {/if} + {if count($ku_styles) > 0} + -  + {/if} +{/if} +{if %KU_WATCHTHREADS} + [WT]  +{/if} +[{t}Home{/t}] [{t}Manage{/t}] +
+ +{if %KU_WATCHTHREADS && not $isoekaki && not $hidewatchedthreads} + +{/if} + + +{$board.includeheader} +
\ No newline at end of file diff --git a/dwoo/templates/upl_post_box.tpl b/dwoo/templates/upl_post_box.tpl new file mode 100644 index 0000000..7fd8103 --- /dev/null +++ b/dwoo/templates/upl_post_box.tpl @@ -0,0 +1,156 @@ +
+ +
+ + +{if $board.maximagesize > 0} + +{/if} + + + + {if $board.forcedanon neq 1} + + + + + {/if} + + + + + + + + + + + + + {if $board.enablecaptcha eq 1} + + + + + {/if} + {if $board.uploadtype eq 0 || $board.uploadtype eq 1} + + + + + {/if} + {if $replythread eq 0 && %KU_TAGS neq ''} + + + + + {/if} + + + + + + + + + +
+ {t}Name{/t} + +
+ {t}Email{/t} + +
+ {t}Subject{/t} + {strip}  ({t}new thread{/t}) + {elseif %KU_QUICKREPLY && $replythread neq 0} + {t}Reply{/t}" accesskey="z" /> ({t}reply to{/t} ) + {else} + {t}Submit{/t}" accesskey="z" /> + {/if}{/strip} +
+ {t}Message{/t} + + +
{t}Captcha{/t}{$recaptcha}
+ {t}File{/t} + + + {if $replythread eq 0 && $board.enablenofile eq 1 } + [] + {/if} +
+ {t}Tag{/t} + + +
+ {t}Password{/t} + +  {t}(for post and file deletion){/t} +
+
    +
  • {t}Supported file types are{/t}: + {if $board.filetypes_allowed neq ''} + {foreach name=files item=filetype from=$board.filetypes_allowed} + {$filetype.0|upper}{if $.foreach.files.last}{else}, {/if} + {/foreach} + {else} + {t}None{/t} + {/if} +
  • +
  • {t}Maximum file size allowed is{/t} {math "round(x/1024)" x=$board.maximagesize} KB.
  • +
  • {t 1=%KU_THUMBWIDTH 2=%KU_THUMBHEIGHT}Images greater than %1x%2 pixels will be thumbnailed.{/t}
  • +
  • {t 1=$board.uniqueposts}Currently %1 unique user posts.{/t}
  • +
+ {if %KU_BLOTTER && $blotter} +
+ + + {/if} +
+
+
+{if $topads neq ''} +
+
+ {$topads} +
+
+
+{/if} +
+ diff --git a/dwoo/templates/upl_reply_header.tpl b/dwoo/templates/upl_reply_header.tpl new file mode 100644 index 0000000..2dd4cf0 --- /dev/null +++ b/dwoo/templates/upl_reply_header.tpl @@ -0,0 +1,20 @@ +[{t}Return{/t}] +{if %KU_FIRSTLAST && ( count($posts) > 50 || $replycount > 50)} + [{t}Entire Thread{/t}] + [{t}Last 50 posts{/t}] + {if ( count($posts) > 100 || $replycount > 100) } + [{t}First 100 posts{/t}] + {/if} +{/if} + +{if not $isread} +
{t}Posting mode: Reply{/t} + {if $modifier eq 'first100'} + [{t}First 100 posts{/t}] + {elseif $modifier eq 'last50'} + [{t}Last 50 posts{/t}] + {/if} +{else} + [{t}Entire Thread{/t}] +{/if} +
\ No newline at end of file diff --git a/dwoo/templates/upl_thread.tpl b/dwoo/templates/upl_thread.tpl new file mode 100644 index 0000000..7e85081 --- /dev/null +++ b/dwoo/templates/upl_thread.tpl @@ -0,0 +1,420 @@ +{if not $isexpand and not $isread} +
+ +{/if} + {foreach key=postkey item=post from=$posts name=postsloop} + + {if $post.parentid eq 0} +
+ + + {if ($post.file neq '' || $post.file_type neq '' ) && (( $post.videobox eq '' && $post.file neq '') && $post.file neq 'removed')} + + {if $post.file_type eq 'mp3'} + {t}Audio{/t} + {else} + {t}File{/t} + {/if} + {if $post.file_type neq 'jpg' && $post.file_type neq 'gif' && $post.file_type neq 'png' && $post.videobox eq ''} + + {else} + + {/if} + {if isset($post.id3.comments_html)} + {if $post.id3.comments_html.artist.0 neq ''} + {$post.id3.comments_html.artist.0} + {if $post.id3.comments_html.title.0 neq ''} + - + {/if} + {/if} + {if $post.id3.comments_html.title.0 neq ''} + {$post.id3.comments_html.title.0} + {/if} + + {else} + {$post.file}.{$post.file_type} + {/if} + - ({$post.file_size_formatted} + {if $post.id3.comments_html.bitrate neq 0 || $post.id3.audio.sample_rate neq 0} + {if $post.id3.audio.bitrate neq 0} + - {round($post.id3.audio.bitrate / 1000)} kbps + {if $post.id3.audio.sample_rate neq 0} + - + {/if} + {/if} + {if $post.id3.audio.sample_rate neq 0} + {$post.id3.audio.sample_rate / 1000} kHz + {/if} + {/if} + {if $post.image_w > 0 && $post.image_h > 0} + , {$post.image_w}x{$post.image_h} + {/if} + {if $post.file_original neq '' && $post.file_original neq $post.file} + , {$post.file_original}.{$post.file_type} + {/if} + ) + {if $post.id3.playtime_string neq ''} + {t}Length{/t}: {$post.id3.playtime_string} + {/if} + + {if %KU_THUMBMSG} + + {if $post.file_type neq 'jpg' && $post.file_type neq 'gif' && $post.file_type neq 'png' && $post.videobox eq ''} + {t}Extension icon displayed, click image to open file.{/t} + {else} + {t}Thumbnail displayed, click image for full size.{/t} + {/if} + + {/if} +
+ {/if} + {if $post.videobox eq '' && $post.file neq '' && ( $post.file_type eq 'jpg' || $post.file_type eq 'gif' || $post.file_type eq 'png')} + {if $post.file eq 'removed'} +
+ {t}File
Removed{/t} +
+ {else} + + {$post.id} + + {/if} + {elseif $post.nonstandard_file neq ''} + {if $post.file eq 'removed'} +
+ {t}File
Removed{/t} +
+ {else} + + {$post.id} + + {/if} + {/if} + + + + {$post.reflink} + + {if $board.showid} + ID: {$post.ipmd5|substr:0:6} + {/if} + +
+ {else} + {if $numimages > 0 && $isexpand && $.foreach.postsloop.first} + {t}Expand all images{/t} + {/if} + + + + + + + + +
+ >> + + + + + + {$post.reflink} + + {if $board.showid} + ID: {$post.ipmd5|substr:0:6} + {/if} + + {if $post.locked eq 1} + {t}Locked{/t} + {/if} + {if $post.stickied eq 1} + {t}Stickied{/t} + {/if} + + + {if ($post.file neq '' || $post.file_type neq '' ) && (( $post.videobox eq '' && $post.file neq '') && $post.file neq 'removed')} +
+ {if $post.file_type eq 'mp3'} + {t}Audio{/t} + {else} + {t}File{/t} + {/if} + {if $post.file_type neq 'jpg' && $post.file_type neq 'gif' && $post.file_type neq 'png' && $post.videobox eq ''} + + {else} + + {/if} + {if isset($post.id3.comments_html)} + {if $post.id3.comments_html.artist.0 neq ''} + {$post.id3.comments_html.artist.0} + {if $post.id3.comments_html.title.0 neq ''} + - + {/if} + {/if} + {if $post.id3.comments_html.title.0 neq ''} + {$post.id3.comments_html.title.0} + {/if} + + {else} + {$post.file}.{$post.file_type} + {/if} + - ({$post.file_size_formatted} + {if $post.id3.comments_html.bitrate neq 0 || $post.id3.audio.sample_rate neq 0} + {if $post.id3.audio.bitrate neq 0} + - {round($post.id3.audio.bitrate / 1000)} kbps + {if $post.id3.audio.sample_rate neq 0} + - + {/if} + {/if} + {if $post.id3.audio.sample_rate neq 0} + {$post.id3.audio.sample_rate / 1000} kHz + {/if} + {/if} + {if $post.image_w > 0 && $post.image_h > 0} + , {$post.image_w}x{$post.image_h} + {/if} + {if $post.file_original neq '' && $post.file_original neq $post.file} + , {$post.file_original}.{$post.file_type} + {/if} + ) + {if $post.id3.playtime_string neq ''} + {t}Length{/t}: {$post.id3.playtime_string} + {/if} + + {if %KU_THUMBMSG} + + {if $post.file_type neq 'jpg' && $post.file_type neq 'gif' && $post.file_type neq 'png' && $post.videobox eq ''} + {t}Extension icon displayed, click image to open file.{/t} + {else} + {t}Thumbnail displayed, click image for full size.{/t} + {/if} + + {/if} + + {/if} + {if $post.videobox eq '' && $post.file neq '' && ( $post.file_type eq 'jpg' || $post.file_type eq 'gif' || $post.file_type eq 'png')} +
+ {if $post.file eq 'removed'} +
+ {t}File
Removed{/t} +
+ {else} + + {$post.id} + + {/if} + {elseif $post.nonstandard_file neq ''} +
+ {if $post.file eq 'removed'} +
+ {t}File
Removed{/t} +
+ {else} + + {$post.id} + + {/if} + {/if} + + {/if} + {if $post.file_type eq 'mp3'} + + + + + + + + {/if} +
+ {if $post.videobox} + {$post.videobox} + {/if} + {$post.message} +
+ {if not $post.stickied && $post.parentid eq 0 && (($board.maxage > 0 && ($post.timestamp + ($board.maxage * 3600)) < (time() + 7200 ) ) || ($post.deleted_timestamp > 0 && $post.deleted_timestamp <= (time() + 7200)))} + + {t}Marked for deletion (old){/t} + +
+ {/if} + {if $post.parentid eq 0} + {if $modifier eq 'last50'} + + {$replycount-50} + {if $replycount-50 eq 1} + {t lower="yes"}Post{/t} + {else} + {t lower="yes"}Posts{/t} + {/if} + {t}omitted{/t}. {t}Last 50 shown{/t}. + + {/if} + {if $numimages > 0} + {t}Expand all images{/t} + {/if} + {else} +
+ {/if} + {/foreach} + {if $modifier eq 'first100'} + + {$replycount-100} + {if $replycount-100 eq 1} + {t lower="yes"}Post{/t} + {else} + {t lower="yes"}Posts{/t} + {/if} + {t}omitted{/t}. {t}First 100 shown{/t}. + + {/if} + {if not $isread} + {if $replycount > 2} + + [{t}Return{/t}] + {if %KU_FIRSTLAST && ( count($posts) > 50 || $replycount > 50)} + [{t}Entire Thread{/t}] + [{t}Last 50 posts{/t}] + {if ( count($posts) > 100 || $replycount > 100) } + [{t}First 100 posts{/t}] + {/if} + {/if} + + {/if} +
+ {if not $isexpand} +
+
+ {/if} +{/if} diff --git a/embedhelp.php b/embedhelp.php new file mode 100644 index 0000000..1d631dd --- /dev/null +++ b/embedhelp.php @@ -0,0 +1,38 @@ +GetAll("SELECT * FROM `" . KU_DBPREFIX . "embeds`"); +foreach ($embeds as $embed) { + if(file_exists(KU_ROOTDIR."inc/embedhelp/" . strtolower($embed['name']) .".jpg")){ + $options .= '\n'; + } +} +echo' + + + +How To Embed + + +'; +if ($options != '') { + +echo '
+
+ + + + + +
+'; +} +else { + echo 'No embed help images found!'; +} +echo' + +'; +?> \ No newline at end of file diff --git a/expand.php b/expand.php new file mode 100644 index 0000000..764a139 --- /dev/null +++ b/expand.php @@ -0,0 +1,103 @@ +GetOne("SELECT `name` FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($_GET['board']) . ""); +if ($board_name != '') { + $board_class = new Board($board_name); + if ($board_class->board['locale'] != '') { + changeLocale($board_class->board['locale']); + } +} else { + die('Invalid board.'); +} +$board_class->InitializeDwoo(); +$board_class->dwoo_data->assign('isexpand', true); +$board_class->dwoo_data->assign('board', $board_class->board); +$board_class->dwoo_data->assign('file_path', getCLBoardPath($board_class->board['name'], $board_class->board['loadbalanceurl_formatted'], '')); +if (isset($_GET['preview'])) { + require KU_ROOTDIR . 'inc/classes/parse.class.php'; + $parse_class = new Parse(); + + if (isset($_GET['board']) && isset($_GET['parentid']) && isset($_GET['message'])) { + die('' . _gettext('Post preview') . ':
' . $parse_class->ParsePost($_GET['message'], $board_class->board['name'], $board_class->board['type'], $_GET['parentid'], $board_class->board['id']) . '
'); + } + + die('Error'); +} + +$posts = $tc_db->GetAll('SELECT * FROM `'.KU_DBPREFIX.'posts` WHERE `boardid` = ' . $board_class->board['id'] . ' AND `IS_DELETED` = 0 AND `parentid` = '.$tc_db->qstr($_GET['threadid']).' ORDER BY `id` ASC'); + +global $expandjavascript; +$output = ''; +$expandjavascript = ''; +$numimages = 0; +if ($board_class->board['type'] != 1) { + $embeds = $tc_db->GetAll("SELECT filetype FROM `" . KU_DBPREFIX . "embeds`"); + foreach ($embeds as $embed) { + $board_class->board['filetypes'][] .= $embed['filetype']; + } + $board_class->dwoo_data->assign('filetypes', $board_class->board['filetypes']); +} +foreach ($posts as $key=>$post) { + if ($post['file_type'] == 'jpg' || $post['file_type'] == 'gif' || $post['file_type'] == 'png') { + $numimages++; + } + + $posts[$key] = $board_class->BuildPost($post, false); + + $newlastid = $post['id']; +} +$board_class->dwoo_data->assign('numimages', $numimages); +$board_class->dwoo_data->assign('posts', $posts); +switch ($board_class->board['type']) { + case 0: + $output = $board_class->dwoo->get(KU_TEMPLATEDIR . '/img_thread.tpl', $board_class->dwoo_data); + break; + case 1: + $output = $board_class->dwoo->get(KU_TEMPLATEDIR . '/txt_thread.tpl', $board_class->dwoo_data); + break; + case 2: + $output = $board_class->dwoo->get(KU_TEMPLATEDIR . '/oek_thread.tpl', $board_class->dwoo_data); + break; + case 3: + $output = $board_class->dwoo->get(KU_TEMPLATEDIR . '/upl_thread.tpl', $board_class->dwoo_data); + break; + default: + die('Invalid board.'); + break; +} +if ($expandjavascript != '') { + $output = '' . _gettext('Expand all images') . '' . $output; +} + +echo $output; + +?> \ No newline at end of file diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..332aebd Binary files /dev/null and b/favicon.ico differ diff --git a/inc/classes/bans.class.php b/inc/classes/bans.class.php new file mode 100644 index 0000000..3405855 --- /dev/null +++ b/inc/classes/bans.class.php @@ -0,0 +1,142 @@ +GetAll("SELECT * FROM `".KU_DBPREFIX."banlist` WHERE ((`type` = '0' AND ( `ipmd5` = '" . md5($ip) . "' OR `ipmd5` = '". md5($_COOKIE['tc_previousip']) . "' )) OR `type` = '1') AND (`expired` = 0)" ); + if (count($results)>0) { + foreach($results AS $line) { + if(($line['type'] == 1 && strpos($ip, md5_decrypt($line['ip'], KU_RANDOMSEED)) === 0) || $line['type'] == 0) { + if ($line['until'] != 0 && $line['until'] < time()){ + $tc_db->Execute("UPDATE `".KU_DBPREFIX."banlist` SET `expired` = 1 WHERE `id` = ".$line['id']); + $line['expired'] = 1; + $this->UpdateHtaccess(); + } + if ($line['globalban']!=1) { + if ((in_array($board, explode('|', $line['boards'])) || $board == '')) { + $line['appealin'] = substr(timeDiff($line['appealat'], true, 2), 0, -1); + $bans[] = $line; + } + } else { + $line['appealin'] = substr(timeDiff($line['appealat'], true, 2), 0, -1); + $bans[] = $line; + } + } + } + } + if(count($bans) > 0){ + $tc_db->Execute("END TRANSACTION"); + echo $this->DisplayBannedMessage($bans); + die(); + } + + if ($force_display) { + /* Instructed to display a page whether banned or not, so we will inform them today is their rucky day */ + echo ''._gettext('YOU ARE NOT BANNED!').'


'._gettext('Unable to find record of your IP being banned.').'
'; + } else { + return true; + } + } + + /* Add a ip/ip range ban */ + function BanUser($ip, $modname, $globalban, $duration, $boards, $reason, $staffnote, $appealat=0, $type=0, $allowread=1, $proxyban=false) { + global $tc_db; + + if ($proxyban) { + $check = $tc_db->GetOne("SELECT COUNT(*) FROM `".KU_DBPREFIX."banlist` WHERE `type` = '".$type."' AND `ipmd5` = '".md5($ip)."'"); + if ($check[0] > 0) { + return false; + } + } + + if ($duration>0) { + $ban_globalban = '0'; + } else { + $ban_globalban = '1'; + } + if ($duration>0) { + $ban_until = time()+$duration; + } else { + $ban_until = '0'; + } + + $tc_db->Execute("INSERT INTO `".KU_DBPREFIX."banlist` ( `ip` , `ipmd5` , `type` , `allowread` , `globalban` , `boards` , `by` , `at` , `until` , `reason`, `staffnote`, `appealat` ) VALUES ( ".$tc_db->qstr(md5_encrypt($ip, KU_RANDOMSEED))." , ".$tc_db->qstr(md5($ip))." , ".intval($type)." , ".intval($allowread)." , ".intval($globalban)." , ".$tc_db->qstr($boards)." , ".$tc_db->qstr($modname)." , ".time()." , ".intval($ban_until)." , ".$tc_db->qstr($reason)." , ".$tc_db->qstr($staffnote).", ".intval($appealat)." ) "); + + if (!$proxyban && $type == 1) { + $this->UpdateHtaccess(); + } + return true; + } + + /* Return the page which will inform the user a quite unfortunate message */ + function DisplayBannedMessage($bans, $board='') { + /* Set a cookie with the users current IP address in case they use a proxy to attempt to make another post */ + setcookie('tc_previousip', $_SERVER['REMOTE_ADDR'], (time() + 604800), KU_BOARDSFOLDER); + + require_once KU_ROOTDIR . 'lib/dwoo.php'; + + $dwoo_data->assign('bans', $bans); + + return $dwoo->get(KU_TEMPLATEDIR .'/banned.tpl', $dwoo_data); + } + + function UpdateHtaccess() { + global $tc_db; + + $htaccess_contents = file_get_contents(KU_BOARDSDIR.'.htaccess'); + $htaccess_contents_preserve = substr($htaccess_contents, 0, strpos($htaccess_contents, '## !KU_BANS:')+12)."\n"; + + $htaccess_contents_bans_iplist = ''; + $results = $tc_db->GetAll("SELECT `ip` FROM `".KU_DBPREFIX."banlist` WHERE `allowread` = 0 AND `type` = 0 AND (`expired` = 1) ORDER BY `ip` ASC"); + if (count($results) > 0) { + $htaccess_contents_bans_iplist .= 'RewriteCond %{REMOTE_ADDR} ('; + foreach($results AS $line) { + $htaccess_contents_bans_iplist .= str_replace('.', '\\.', md5_decrypt($line['ip'], KU_RANDOMSEED)) . '|'; + } + $htaccess_contents_bans_iplist = substr($htaccess_contents_bans_iplist, 0, -1); + $htaccess_contents_bans_iplist .= ')$' . "\n"; + } + if ($htaccess_contents_bans_iplist!='') { + $htaccess_contents_bans_start = "\nRewriteEngine On\n"; + $htaccess_contents_bans_end = "RewriteRule !^(banned.php|youarebanned.jpg|favicon.ico|css/site_futaba.css)$ " . KU_BOARDSFOLDER . "banned.php [L]\n"; + } else { + $htaccess_contents_bans_start = ''; + $htaccess_contents_bans_end = ''; + } + $htaccess_contents_new = $htaccess_contents_preserve.$htaccess_contents_bans_start.$htaccess_contents_bans_iplist.$htaccess_contents_bans_end; + file_put_contents(KU_BOARDSDIR.'.htaccess', $htaccess_contents_new); + } +} + +?> diff --git a/inc/classes/board-post.class.php b/inc/classes/board-post.class.php new file mode 100644 index 0000000..eef42f4 --- /dev/null +++ b/inc/classes/board-post.class.php @@ -0,0 +1,958 @@ +qstr($board)." LIMIT 1"; + $results = $tc_db->GetAll($query); + foreach ($results[0] as $key=>$line) { + if (!is_numeric($key)) { + $this->board[$key] = $line; + } + } + // Type + $types = array('img', 'txt', 'oek', 'upl'); + $this->board['text_readable'] = $types[$this->board['type']]; + if ($extra) { + // Boardlist + $this->board['boardlist'] = $this->DisplayBoardList(); + + // Get the unique posts for this board + $this->board['uniqueposts'] = $tc_db->GetOne("SELECT COUNT(DISTINCT `ipmd5`) FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $this->board['id']. " AND `IS_DELETED` = 0"); + + if($this->board['type'] != 1) { + $this->board['filetypes_allowed'] = $tc_db->GetAll("SELECT ".KU_DBPREFIX."filetypes.filetype FROM ".KU_DBPREFIX."boards, ".KU_DBPREFIX."filetypes, ".KU_DBPREFIX."board_filetypes WHERE ".KU_DBPREFIX."boards.id = " . $this->board['id'] . " AND ".KU_DBPREFIX."board_filetypes.boardid = " . $this->board['id'] . " AND ".KU_DBPREFIX."board_filetypes.typeid = ".KU_DBPREFIX."filetypes.id ORDER BY ".KU_DBPREFIX."filetypes.filetype ASC;"); + } + + if ($this->board['locale'] && $this->board['locale'] != KU_LOCALE) { + changeLocale($this->board['locale']); + } + } + $this->board['loadbalanceurl_formatted'] = ($this->board['loadbalanceurl'] != '') ? substr($this->board['loadbalanceurl'], 0, strrpos($this->board['loadbalanceurl'], '/')) : ''; + + if ($this->board['loadbalanceurl'] != '' && $this->board['loadbalancepassword'] != '') { + require_once KU_ROOTDIR . 'inc/classes/loadbalancer.class.php'; + $this->loadbalancer = new Load_Balancer; + + $this->loadbalancer->url = $this->board['loadbalanceurl']; + $this->loadbalancer->password = $this->board['loadbalancepassword']; + } + } + } + + function __destruct() { + changeLocale(KU_LOCALE); + } + + /** + * Regenerate all board and thread pages + */ + function RegenerateAll() { + $this->RegeneratePages(); + $this->RegenerateThreads(); + } + + /** + * Regenerate all pages + */ + function RegeneratePages() { + global $tc_db, $CURRENTLOCALE; + + $this->InitializeDwoo(); + $results = $tc_db->GetAll("SELECT `filetype` FROM `" . KU_DBPREFIX . "embeds`"); + foreach ($results as $line) { + $this->board['filetypes'][] .= $line[0]; + } + $this->dwoo_data->assign('filetypes', $this->board['filetypes']); + $maxpages = $this->board['maxpages']; + $numposts = $tc_db->GetAll("SELECT COUNT(*) FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $this->board['id'] . " AND `parentid` = 0 AND `IS_DELETED` = 0"); + + if ($this->board['type'] == 1) { + $postsperpage = KU_THREADSTXT; + } elseif ($this->board['type'] == 3) { + $postsperpage = 30; + } else { + $postsperpage = KU_THREADS; + } + $i = 0; + $liststooutput = 0; + $totalpages = calculatenumpages($this->board['type'], ($numposts[0][0]-1)); + if ($totalpages == '-1') { + $totalpages = 0; + } + $this->dwoo_data->assign('numpages', $totalpages); + while ($i <= $totalpages) { + $newposts = Array(); + $this->dwoo_data->assign('thispage', $i); + $threads = $tc_db->GetAll("SELECT * FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $this->board['id'] . " AND `parentid` = 0 AND `IS_DELETED` = 0 ORDER BY `stickied` DESC, `bumped` DESC LIMIT ". ($postsperpage)." OFFSET ". $postsperpage * $i); + + $executiontime_start_page = microtime_float(); + foreach ($threads as $k=>$thread) { + // If the thread is on the page set to mark, && hasn't been marked yet, mark it + if ($thread['deleted_timestamp'] == 0 && $this->board['markpage'] > 0 && $i >= $this->board['markpage']) { + $tc_db->Execute("UPDATE `".KU_DBPREFIX."posts` SET `deleted_timestamp` = '" . (time() + 7200) . "' WHERE `boardid` = " . $tc_db->qstr($this->board['id'])." AND `id` = '" . $thread['id'] . "'"); + clearPostCache($thread['id'], $this->board['name']); + $this->RegenerateThreads($thread['id']); + $this->dwoo_data->assign('replythread', 0); + } + $thread = $this->BuildPost($thread, true); + + if ($this->board['type'] != 3) { + $omitids = ''; + $posts = $tc_db->GetAll("SELECT * FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $this->board['id']." AND `parentid` = ".$thread['id']." " . (($this->board['type'] != 1) ? ("AND `IS_DELETED` = 0") : ("")) . " ORDER BY `id` DESC LIMIT ".(($thread['stickied'] == 1) ? (KU_REPLIESSTICKY) : (KU_REPLIES))); + foreach ($posts as $key=>$post) { + $omitids .= $post['id'].","; + $posts[$key] = $this->BuildPost($post, true); + } + + $posts = array_reverse($posts); + $omitids = substr($omitids, 0, -1); + array_unshift($posts, $thread); + $newposts[] = $posts; + } else { + if (!$thread['tag']) $thread['tag'] = '*'; + $newposts[] = $thread; + } + $replycount = Array(); + if ($this->board['type'] == 1 || $this->board['type'] == 3 ) { + $replycount = $tc_db->GetAll("SELECT COUNT(`id`) FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $tc_db->qstr($this->board['id'])." AND `parentid` = " . $thread['id']); + } else { + $replycount = $tc_db->GetAll("SELECT COUNT(`id`) AS replies, SUM(CASE WHEN `file_md5` = '' THEN 0 ELSE 1 END) AS files FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $this->board['id']." AND `parentid` = ".$thread['id']." AND `is_deleted` = 0 AND `id` NOT IN (" . $omitids . ")"); + } + // Workaround for upload boards + if ($this->board['type'] == 3) { + $newposts[$k]['replies'] = $replycount[0][0]; + } else { + $newposts[$k][0]['replies'] = $replycount[0][0]; + $newposts[$k][0]['images'] = (isset($replycount[0][1]) ? $replycount[0][1] : ''); + } + } + if ($this->board['type'] == 0 && !isset($embeds)) { + $embeds = $tc_db->GetAll("SELECT * FROM `" . KU_DBPREFIX . "embeds`"); + $this->dwoo_data->assign('embeds', $embeds); + } + if (!isset($header)){ + $header = $this->PageHeader(); + $header = str_replace("", 0, $header); + } + if (!isset($postbox)) { + $postbox = $this->Postbox(); + $postbox = str_replace("", 0, $postbox); + } + $this->dwoo_data->assign('posts', $newposts); + $this->dwoo_data->assign('file_path', getCLBoardPath($this->board['name'], $this->board['loadbalanceurl_formatted'], '')); + + $content = $this->dwoo->get(KU_TEMPLATEDIR . '/' . $this->board['text_readable'] . '_board_page.tpl', $this->dwoo_data); + $footer = $this->Footer(false, (microtime_float() - $executiontime_start_page), (($this->board['type'] == 1) ? (true) : (false))); + $content = $header.$postbox.$content.$footer; + + $content = str_replace("\t", '',$content); + $content = str_replace(" \r\n", ' ',$content); + + if ($i == 0) { + $page = KU_BOARDSDIR.$this->board['name'].'/'.KU_FIRSTPAGE; + $this->PrintPage($page, $content, $this->board['name']); + } else { + $page = KU_BOARDSDIR.$this->board['name'].'/'.$i.'.html'; + $this->PrintPage($page, $content, $this->board['name']); + } + $i++; + } + // If text board, rebuild thread list html files + if ($this->board['type'] == 1) { + $numpostsleft = $tc_db->GetOne("SELECT COUNT(*) FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $this->board['id'] . " AND `IS_DELETED` = 0 AND `parentid` = 0"); + $liststooutput = floor(($numpostsleft-1) / 40); + $this->dwoo_data->assign('numpages', $liststooutput+1); + $listpage = 0; + $currentpostwave = 0; + while ($numpostsleft>0) { + $this->dwoo_data->assign('thispage', $listpage+1); + $executiontime_start_list = microtime_float(); + $page = $this->PageHeader(0, $currentpostwave, $liststooutput); + $this->Footer(false, (microtime_float()-$executiontime_start_list), true); + if ($listpage==0) { + $this->PrintPage(KU_BOARDSDIR.$this->board['name'].'/list.html', $page, $this->board['name']); + } else { + $this->PrintPage(KU_BOARDSDIR.$this->board['name'].'/list'.($listpage+1).'.html', $page, $this->board['name']); + } + $currentpostwave += 40; + $numpostsleft -= 40; + $listpage++; + } + } + // If the board has catalog mode enabled, build it + if ($this->board['enablecatalog'] == 1 && ($this->board['type'] == 0 || $this->board['type'] == 2)) { + $executiontime_start_catalog = microtime_float(); + $catalog_head = $this->PageHeader(). + '['._gettext('Return').']
'._gettext('Catalog Mode').'
' . "\n" . + '' . "\n" . '' . "\n"; + $catalog_page = ''; + $results = $tc_db->GetAll("SELECT `id` , `subject` , `file` , `file_type` FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $this->board['id'] . " AND `IS_DELETED` = 0 AND `parentid` = 0 ORDER BY `stickied` DESC, `bumped` DESC"); + $numresults = count($results); + if ($numresults > 0) { + $celnum = 0; + $trbreak = 0; + $row = 1; + // Calculate the number of rows we will actually output + $maxrows = max(1, (($numresults - ($numresults % 12)) / 12)); + foreach ($results as $line) { + $celnum++; + $trbreak++; + if ($trbreak == 13 && $celnum != $numresults) { + $catalog_page .= '' . "\n" . '' . "\n"; + $row++; + $trbreak = 1; + } + if ($row <= $maxrows) { + $replies = $tc_db->GetOne("SELECT COUNT(*) FROM `".KU_DBPREFIX."posts` WHERE `boardid` = " . $this->board['id'] . " AND `IS_DELETED` = 0 AND `parentid` = " . $line['id']); + $catalog_page .= '' . "\n"; + } + } + } else { + $catalog_page .= '' . "\n"; + } + + $catalog_page .= '' . "\n" . '
' . "\n" . + 'board['name'], $this->board['loadbalanceurl_formatted'], $this->archive_dir); + $catalog_page .= '' . $line['id'] . ''; + } else { + $catalog_page .= _gettext('File'); + } + } elseif ($line['file'] == 'removed') { + $catalog_page .= 'Rem.'; + } else { + $catalog_page .= _gettext('None'); + } + $catalog_page .= '
' . "\n" . '' . $replies . '' . "\n" . '
' . "\n" . + _gettext('No threads.') . "\n" . + '


' . + $this->Footer(false, (microtime_float()-$executiontime_start_catalog)); + + $this->PrintPage(KU_BOARDSDIR . $this->board['name'] . '/catalog.html', $catalog_head.$catalog_page, $this->board['name']); + } + // Delete old pages + $dir = KU_BOARDSDIR.$this->board['name']; + $files = glob ("$dir/*.html"); + if (is_array($files)) { + foreach ($files as $htmlfile) { + if (preg_match("/[0-9+].html/", $htmlfile)) { + if (substr(basename($htmlfile), 0, strpos(basename($htmlfile), '.html'))>$totalpages) { + unlink($htmlfile); + } + } + if (preg_match("/list[0-9+].html/", $htmlfile)) { + if (substr(basename($htmlfile), 4, strpos(basename($htmlfile), '.html'))>($liststooutput+1)) { + unlink($htmlfile); + } + } + if (preg_match("/catalog.html/", $htmlfile)) { + if (!($this->board['enablecatalog'] == 1 && ($this->board['type'] == 0 || $this->board['type'] == 2))) { + unlink($htmlfile); + } + } + } + } + } + + /** + * Regenerate each thread's corresponding html file, starting with the most recently bumped + */ + function RegenerateThreads($id = 0) { + global $tc_db, $CURRENTLOCALE; + require_once(KU_ROOTDIR."lib/dwoo.php"); + if (!isset($this->dwoo)) { $this->dwoo = New Dwoo; $this->dwoo_data = new Dwoo_Data(); $this->InitializeDwoo(); } + $embeds = Array(); + $numimages = 0; + if ($this->board['type'] != 1 && !$embeds) { + $embeds = $tc_db->GetAll("SELECT * FROM `" . KU_DBPREFIX . "embeds`"); + $this->dwoo_data->assign('embeds', $embeds); + foreach ($embeds as $embed) { + $this->board['filetypes'][] .= $embed['filetype']; + } + $this->dwoo_data->assign('filetypes', $this->board['filetypes']); + } + if ($id == 0) { + // Build every thread + $header = $this->PageHeader(1); + if ($this->board['type'] != 2){ + $postbox = $this->Postbox(1); + } + $threads = $tc_db->GetAll("SELECT * FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $this->board['id'] . " AND `parentid` = 0 AND `IS_DELETED` = 0 ORDER BY `id` DESC"); + + if (count($threads) > 0) { + foreach($threads as $thread) { + $numimages = 0; + $executiontime_start_thread = microtime_float(); + $posts = $tc_db->GetAll("SELECT * FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $this->board['id'] . " AND (`id` = " . $thread['id'] . " OR `parentid` = " . $thread['id'] . ") " . (($this->board['type'] != 1) ? ("AND `IS_DELETED` = 0") : ("")) . " ORDER BY `id` ASC"); + if ($this->board['type'] != 1 || ((isset($posts[0]['IS_DELETED']) && $posts[0]['IS_DELETED'] == 0) || (isset($posts[0]['is_deleted']) && $posts[0]['is_deleted'] == 0))) { + // There might be a chance that the post was deleted during another RegenerateThreads() session, if there are no posts, move on to the next thread. + if(count($posts) > 0){ + foreach ($posts as $key=>$post) { + if (($post['file_type'] == 'jpg' || $post['file_type'] == 'gif' || $post['file_type'] == 'png') && $post['parentid'] != 0) { + $numimages++; + } + $posts[$key] = $this->BuildPost($post, false); + } + + $header_replaced = str_replace("", $thread['id'], $header); + $this->dwoo_data->assign('numimages', $numimages); + $this->dwoo_data->assign('replythread', $thread['id']); + $this->dwoo_data->assign('posts', $posts); + $this->dwoo_data->assign('file_path', getCLBoardPath($this->board['name'], $this->board['loadbalanceurl_formatted'], '')); + if ($this->board['type'] != 2){ + $postbox_replaced = str_replace("", $thread['id'], $postbox); + } + else { + $postbox_replaced = $this->Postbox($thread['id']); + } + $reply = $this->dwoo->get(KU_TEMPLATEDIR . '/' . $this->board['text_readable'] . '_reply_header.tpl', $this->dwoo_data); + $content = $this->dwoo->get(KU_TEMPLATEDIR . '/' . $this->board['text_readable'] . '_thread.tpl', $this->dwoo_data); + if (!isset($footer)) $footer = $this->Footer(false, (microtime_float() - $executiontime_start_thread), (($this->board['type'] == 1) ? (true) : (false))); + $content = $header_replaced.$reply.$postbox_replaced.$content.$footer; + + $content = str_replace("\t", '',$content); + $content = str_replace(" \r\n", ' ',$content); + + $this->PrintPage(KU_BOARDSDIR . $this->board['name'] . $this->archive_dir . '/res/' . $thread['id'] . '.html', $content, $this->board['name']); + if (KU_FIRSTLAST) { + + $replycount = (count($posts)-1); + if ($replycount > 50) { + $this->dwoo_data->assign('replycount', $replycount); + $this->dwoo_data->assign('modifier', "last50"); + + // Grab the last 50 replies + $posts50 = array_slice($posts, -50, 50); + + // Add on the OP + array_unshift($posts50, $posts[0]); + + $this->dwoo_data->assign('posts', $posts50); + + $content = $this->dwoo->get(KU_TEMPLATEDIR . '/img_thread.tpl', $this->dwoo_data); + $content = $header_replaced.$reply.$postbox_replaced.$content.$footer; + $content = str_replace("\t", '',$content); + $content = str_replace(" \r\n", ' ',$content); + + unset($posts50); + + $this->PrintPage(KU_BOARDSDIR . $this->board['name'] . $this->archive_dir . '/res/' . $thread['id'] . '+50.html', $content, $this->board['name']); + if ($replycount > 100) { + $this->dwoo_data->assign('modifier', "first100"); + + // Grab the first 100 posts + $posts100 = array_slice($posts, 0, 100); + + $this->dwoo_data->assign('posts', $posts100); + + $content = $this->dwoo->get(KU_TEMPLATEDIR . '/img_thread.tpl', $this->dwoo_data); + $content = $header_replaced.$reply.$postbox_replaced.$content.$footer; + $content = str_replace("\t", '',$content); + $content = str_replace(" \r\n", ' ',$content); + + unset($posts100); + + $this->PrintPage(KU_BOARDSDIR . $this->board['name'] . $this->archive_dir . '/res/' . $thread['id'] . '-100.html', $content, $this->board['name']); + } + $this->dwoo_data->assign('modifier', ""); + } + } + } + } + } + } + } else { + $executiontime_start_thread = microtime_float(); + // Build only that thread + $thread = $tc_db->GetAll("SELECT * FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $this->board['id'] . " AND (`id` = " . $id . " OR `parentid` = " . $id . ") " . (($this->board['type'] != 1) ? ("AND `IS_DELETED` = 0") : ("")) . " ORDER BY `id` ASC"); + if ($this->board['type'] != 1 || ((isset($thread[0]['IS_DELETED']) && $thread[0]['IS_DELETED'] == 0) || (isset($thread[0]['is_deleted']) && $thread[0]['is_deleted'] == 0))) { + foreach ($thread as $key=>$post) { + if (($post['file_type'] == 'jpg' || $post['file_type'] == 'gif' || $post['file_type'] == 'png') && $post['parentid'] != 0) { + $numimages++; + } + $thread[$key] = $this->BuildPost($post, false); + } + $header = $this->PageHeader($id); + $postbox = $this->Postbox($id); + $this->dwoo_data->assign('numimages', $numimages); + $header = str_replace("", $id, $header); + + $this->dwoo_data->assign('replythread', $id); + if ($this->board['type'] != 2){ + $postbox = str_replace("", $id, $postbox); + } + + $this->dwoo_data->assign('threadid', $thread[0]['id']); + $this->dwoo_data->assign('posts', $thread); + $this->dwoo_data->assign('file_path', getCLBoardPath($this->board['name'], $this->board['loadbalanceurl_formatted'], '')); + + $postbox = $this->dwoo->get(KU_TEMPLATEDIR . '/' . $this->board['text_readable'] . '_reply_header.tpl', $this->dwoo_data).$postbox; + $content = $this->dwoo->get(KU_TEMPLATEDIR . '/' . $this->board['text_readable'] . '_thread.tpl', $this->dwoo_data); + + if (!isset($footer)) $footer = $this->Footer(false, (microtime_float() - $executiontime_start_thread), (($this->board['type'] == 1) ? (true) : (false))); + $content = $header.$postbox.$content.$footer; + + $content = str_replace("\t", '',$content); + $content = str_replace(" \r\n", ' ',$content); + + $this->PrintPage(KU_BOARDSDIR . $this->board['name'] . $this->archive_dir . '/res/' . $id . '.html', $content, $this->board['name']); + if (KU_FIRSTLAST) { + $replycount = $tc_db->GetOne("SELECT COUNT(`id`) FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $this->board['id'] . " AND `parentid` = " . $id . " AND `IS_DELETED` = 0"); + if ($replycount > 50) { + $this->dwoo_data->assign('replycount', $replycount); + $this->dwoo_data->assign('modifier', "last50"); + + // Grab the last 50 replies + $posts50 = array_slice($thread, -50, 50); + + // Add the thread to the top of this, since it wont be included in the result + array_unshift($posts50, $thread[0]); + + $this->dwoo_data->assign('posts', $posts50); + + $content = $this->dwoo->get(KU_TEMPLATEDIR . '/img_thread.tpl', $this->dwoo_data); + $content = $header.$reply.$postbox.$content.$footer; + $content = str_replace("\t", '',$content); + $content = str_replace(" \r\n", ' ',$content); + + unset($posts50); + + $this->PrintPage(KU_BOARDSDIR . $this->board['name'] . $this->archive_dir . '/res/' . $id . '+50.html', $content, $this->board['name']); + if ($replycount > 100) { + $this->dwoo_data->assign('modifier', "first100"); + + // Grab the first 100 posts + $posts100 = array_slice($thread, 0, 100); + + $this->dwoo_data->assign('posts', $posts100); + + $this->dwoo_data->assign('posts', $posts); + $content = $this->dwoo->get(KU_TEMPLATEDIR . '/img_thread.tpl', $this->dwoo_data); + $content = $header.$reply.$postbox.$content.$footer; + $content = str_replace("\t", '',$content); + $content = str_replace(" \r\n", ' ',$content); + + unset($posts100); + + $this->PrintPage(KU_BOARDSDIR . $this->board['name'] . $this->archive_dir . '/res/' . $id . '-100.html', $content, $this->board['name']); + } + $this->dwoo_data->assign('modifier', ""); + } + } + } + } + } + + function BuildPost($post, $page) { + global $CURRENTLOCALE; + if ($this->board['type'] == 1 && ((isset($post['IS_DELETED']) && $post['IS_DELETED'] == 1) || (isset($post['is_deleted']) && $post['is_deleted'] == 1))) { + $post['name'] = ''; + $post['email'] = ''; + $post['tripcode'] = _gettext('Deleted'); + $post['message'] = ''._gettext('This post has been deleted.').''; + } + $dateEmail = (empty($this->board['anonymous'])) ? $post['email'] : 0; + $post['message'] = stripslashes(formatLongMessage($post['message'], $this->board['name'], (($post['parentid'] == 0) ? ($post['id']) : ($post['parentid'])), $page)); + $post['timestamp_formatted'] = formatDate($post['timestamp'], 'post', $CURRENTLOCALE, $dateEmail); + $post['reflink'] = formatReflink($this->board['name'], (($post['parentid'] == 0) ? ($post['id']) : ($post['parentid'])), $post['id'], $CURRENTLOCALE); + if (isset($this->board['filetypes']) && in_array($post['file_type'], $this->board['filetypes'])) { + $post['videobox'] = embeddedVideoBox($post); + } + if ($post['file_type'] == 'mp3' && $this->board['loadbalanceurl'] == '') { + //Grab the ID3 info. TODO: Make this work for load-balanced boards. + // include getID3() library + + require_once(KU_ROOTDIR . 'lib/getid3/getid3.php'); + + // Initialize getID3 engine + $getID3 = new getID3; + + $post['id3'] = $getID3->analyze(KU_BOARDSDIR.$this->board['name'].'/src/'.$post['file'].'.mp3'); + getid3_lib::CopyTagsToComments($post['id3']); + } + if ($post['file_type']!='jpg'&&$post['file_type']!='gif'&&$post['file_type']!='png'&&$post['file_type']!=''&&!in_array($post['file_type'], $this->board['filetypes'])) { + if(!isset($filetype_info[$post['file_type']])) $filetype_info[$post['file_type']] = getfiletypeinfo($post['file_type']); + $post['nonstandard_file'] = KU_WEBPATH . '/inc/filetypes/' . $filetype_info[$post['file_type']][0]; + if($post['thumb_w']!=0&&$post['thumb_h']!=0) { + if(file_exists(KU_BOARDSDIR.$this->board['name'].'/thumb/'.$post['file'].'s.jpg')) + $post['nonstandard_file'] = KU_WEBPATH . '/' .$this->board['name'].'/thumb/'.$post['file'].'s.jpg'; + elseif(file_exists(KU_BOARDSDIR.$this->board['name'].'/thumb/'.$post['file'].'s.png')) + $post['nonstandard_file'] = KU_WEBPATH . '/' .$this->board['name'].'/thumb/'.$post['file'].'s.png'; + elseif(file_exists(KU_BOARDSDIR.$this->board['name'].'/thumb/'.$post['file'].'s.gif')) + $post['nonstandard_file'] = KU_WEBPATH . '/' .$this->board['name'].'/thumb/'.$post['file'].'s.gif'; + else { + $post['thumb_w'] = $filetype_info[$post['file_type']][1]; + $post['thumb_h'] = $filetype_info[$post['file_type']][2]; + } + } + else { + $post['thumb_w'] = $filetype_info[$post['file_type']][1]; + $post['thumb_h'] = $filetype_info[$post['file_type']][2]; + } + } + + return $post; + } + + /** + * Build the page header + * + * @param integer $replythread The ID of the thread the header is being build for. 0 if it is for a board page + * @param integer $liststart The number which the thread list starts on (text boards only) + * @param integer $liststooutput The number of list pages which will be generated (text boards only) + * @return string The built header + */ + function PageHeader($replythread = '0', $liststart = '0', $liststooutput = '-1') { + global $tc_db, $CURRENTLOCALE; + + $tpl = Array(); + + $tpl['htmloptions'] = ((KU_LOCALE == 'he' && empty($this->board['locale'])) || $this->board['locale'] == 'he') ? ' dir="rtl"' : '' ; + + $tpl['title'] = ''; + + if (KU_DIRTITLE) { + $tpl['title'] .= '/' . $this->board['name'] . '/ - '; + } + $tpl['title'] .= $this->board['desc']; + + $ad_top = 185; + $ad_right = 25; + if ($this->board['type']==1) { + $ad_top -= 50; + } else { + if ($replythread!=0) { + $ad_top += 50; + } + } + if ($this->board['type']==2) { + $ad_top += 40; + } + $this->dwoo_data->assign('title', $tpl['title']); + $this->dwoo_data->assign('htmloptions', $tpl['htmloptions']); + $this->dwoo_data->assign('locale', $CURRENTLOCALE); + $this->dwoo_data->assign('ad_top', $ad_top); + $this->dwoo_data->assign('ad_right', $ad_right); + $this->dwoo_data->assign('board', $this->board); + $this->dwoo_data->assign('replythread', $replythread); + if ($this->board['type'] != 1) { + $topads = $tc_db->GetOne("SELECT code FROM `" . KU_DBPREFIX . "ads` WHERE `position` = 'top' AND `disp` = '1'"); + $this->dwoo_data->assign('topads', $topads); + $this->dwoo_data->assign('ku_styles', explode(':', KU_STYLES)); + $this->dwoo_data->assign('ku_defaultstyle', (!empty($this->board['defaultstyle']) ? ($this->board['defaultstyle']) : (KU_DEFAULTSTYLE))); + } else { + $this->dwoo_data->assign('ku_styles', explode(':', KU_TXTSTYLES)); + $this->dwoo_data->assign('ku_defaultstyle', (!empty($this->board['defaultstyle']) ? ($this->board['defaultstyle']) : (KU_DEFAULTTXTSTYLE))); + } + $this->dwoo_data->assign('boardlist', $this->board['boardlist']); + + $global_header = $this->dwoo->get(KU_TEMPLATEDIR . '/global_board_header.tpl', $this->dwoo_data); + + if ($this->board['type'] != 1) { + $header = $this->dwoo->get(KU_TEMPLATEDIR . '/' . $this->board['text_readable'] . '_header.tpl', $this->dwoo_data); + } else { + if ($liststooutput == -1) { + $this->dwoo_data->assign('isindex', true); + } else { + $this->dwoo_data->assign('isindex', false); + } + if ($replythread != 0) $this->dwoo_data->assign('isthread', true); + $header = $this->dwoo->get(KU_TEMPLATEDIR . '/txt_header.tpl', $this->dwoo_data); + + if ($replythread == 0) { + $startrecord = ($liststooutput >= 0 || $this->board['compactlist']) ? 40 : KU_THREADSTXT ; + $threads = $tc_db->GetAll("SELECT * FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $tc_db->qstr($this->board['id']) . " AND `parentid` = 0 AND `IS_DELETED` = 0 ORDER BY `stickied` DESC, `bumped` DESC LIMIT " . $startrecord . " OFFSET " . $liststart); + foreach($threads AS $key=>$thread) { + $replycount = $tc_db->GetOne("SELECT COUNT(`id`) FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $tc_db->qstr($this->board['id']) . " AND `parentid` = " . $thread['id']); + $threads[$key]['replies'] = $replycount; + } + $this->dwoo_data->assign('threads', $threads); + $header .= $this->dwoo->get(KU_TEMPLATEDIR . '/txt_threadlist.tpl', $this->dwoo_data); + } + } + + return $global_header.$header; + } + + /** + * Build the page header for an oekaki posting + * + * @param integer $replyto The ID of the thread being replied to. 0 for a new thread + */ + function OekakiHeader($replyto, $postoek) { + $executiontime_start = microtime_float(); + $this->InitializeDwoo(); + + $page = $this->PageHeader(); + $this->dwoo_data->assign('replythread', $replyto); + $page .= $this->Postbox(); + + $executiontime_stop = microtime_float(); + + $page .= $this->Footer(false, ($executiontime_stop - $executiontime_start)); + + $this->PrintPage('', $page, true); + } + + /** + * Generate the postbox area + * + * @param integer $replythread The ID of the thread being replied to. 0 if not replying + * @param string $postboxnotice The postbox notice + * @return string The generated postbox + */ + function Postbox($replythread = 0) { + global $tc_db; + if (KU_BLOTTER && $this->board['type'] != 1) { + $this->dwoo_data->assign('blotter', getBlotter()); + $this->dwoo_data->assign('blotter_updated', getBlotterLastUpdated()); + } + $postbox = ''; + + if ($this->board['type'] == 2 && $replythread > 0) { + $oekposts = $tc_db->GetAll("SELECT `id` FROM `" . KU_DBPREFIX."posts` WHERE `boardid` = " . $this->board['id']." AND (`id` = ".$replythread." OR `parentid` = ".$replythread.") AND `file` != '' AND `file` != 'removed' AND `file_type` IN ('jpg', 'gif', 'png') AND `IS_DELETED` = 0 ORDER BY `parentid` ASC, `timestamp` ASC"); + $this->dwoo_data->assign('oekposts', $oekposts); + } + if ($this->board['enablecaptcha'] == 1) { + require_once(KU_ROOTDIR.'recaptchalib.php'); + $publickey = "6LdVg8YSAAAAAOhqx0eFT1Pi49fOavnYgy7e-lTO"; + $this->dwoo_data->assign('recaptcha', recaptcha_get_html($publickey)); + } + if(($this->board['type'] == 1 && $replythread == 0) || $this->board['type'] != 1) { + $postbox .= $this->dwoo->get(KU_TEMPLATEDIR . '/' . $this->board['text_readable'] . '_post_box.tpl', $this->dwoo_data); + } + return $postbox; + } + + /** + * Display the user-defined list of boards found in boards.html + * + * @param boolean $is_textboard If the board this is being displayed for is a text board + * @return string The board list + */ + function DisplayBoardList($is_textboard = false) { + if (KU_GENERATEBOARDLIST) { + global $tc_db; + + $output = ''; + $results = $tc_db->GetAll("SELECT `id` FROM `" . KU_DBPREFIX . "sections` ORDER BY `order` ASC"); + $boards = array(); + foreach($results AS $line) { + $results2 = $tc_db->GetAll("SELECT * FROM `" . KU_DBPREFIX . "boards` WHERE `section` = '" . $line['id'] . "' ORDER BY `order` ASC, `name` ASC"); + foreach($results2 AS $line2) { + $boards[$line['id']][$line2['id']]['name'] = htmlspecialchars($line2['name']); + $boards[$line['id']][$line2['id']]['desc'] = htmlspecialchars($line2['desc']); + } + } + } else { + $boards = KU_ROOTDIR . 'boards.html'; + } + + return $boards; + } + + + /** + * Display the page footer + * + * @param boolean $noboardlist Force the board list to not be displayed + * @param string $executiontime The time it took the page to be created + * @param boolean $hide_extra Hide extra footer information, and display the manage link + * @return string The generated footer + */ + function Footer($noboardlist = false, $executiontime = '', $hide_extra = false) { + global $tc_db, $dwoo, $dwoo_data; + + $footer = ''; + + if ($hide_extra || $noboardlist) $this->dwoo_data->assign('boardlist', ''); + + if ($executiontime != '') $this->dwoo_data->assign('executiontime', round($executiontime, 2)); + + $botads = $tc_db->GetOne("SELECT code FROM `" . KU_DBPREFIX . "ads` WHERE `position` = 'bot' AND `disp` = '1'"); + $this->dwoo_data->assign('botads', $botads); + $footer = $this->dwoo->get(KU_TEMPLATEDIR . '/' . $this->board['text_readable'] . '_footer.tpl', $this->dwoo_data); + + $footer .= $this->dwoo->get(KU_TEMPLATEDIR . '/global_board_footer.tpl', $this->dwoo_data); + + return $footer; + } + + /** + * Finalize the page and print it to the specified filename + * + * @param string $filename File to print the page to + * @param string $contents Page contents + * @param string $board Board which the file is being generated for + * @return string The page contents, if requested + */ + function PrintPage($filename, $contents, $board) { + + if ($board !== true) { + print_page($filename, $contents, $board); + } else { + echo $contents; + } + } + + /** + * Initialize the instance of smary which will be used for generating pages + */ + function InitializeDwoo() { + + require_once KU_ROOTDIR . 'lib/dwoo.php'; + $this->dwoo = new Dwoo(); + $this->dwoo_data = new Dwoo_Data(); + + $this->dwoo_data->assign('cwebpath', getCWebpath()); + $this->dwoo_data->assign('boardpath', getCLBoardPath()); + } + + /** + * Enable/disable archive mode + * + * @param boolean $mode True/false for enabling/disabling archive mode + */ + function ArchiveMode($mode) { + $this->archive_dir = ($mode && $this->board['enablearchiving'] == 1) ? '/arch' : ''; + } +} + +/** + * Post class + * + * Used for post insertion, deletion, and reporting. + * + * @package kusaba + */ +class Post extends Board { + // Declare the public variables + var $post = Array(); + + function Post($postid, $board, $boardid, $is_inserting = false) { + global $tc_db; + + $results = $tc_db->GetAll("SELECT * FROM `".KU_DBPREFIX."posts` WHERE `boardid` = '" . $boardid . "' AND `id` = ".$tc_db->qstr($postid)." LIMIT 1"); + if (count($results)==0&&!$is_inserting) { + exitWithErrorPage('Invalid post ID.'); + } elseif ($is_inserting) { + $this->Board($board, false); + } else { + foreach ($results[0] as $key=>$line) { + if (!is_numeric($key)) $this->post[$key] = $line; + } + $results = $tc_db->GetAll("SELECT `cleared` FROM `".KU_DBPREFIX."reports` WHERE `postid` = ".$tc_db->qstr($this->post['id'])." LIMIT 1"); + if (count($results)>0) { + foreach($results AS $line) { + $this->post['isreported'] = ($line['cleared'] == 0) ? true : 'cleared'; + } + } else { + $this->post['isreported'] = false; + } + $this->post['isthread'] = ($this->post['parentid'] == 0) ? true : false; + if (empty($this->board) || $this->board['name'] != $board) { + $this->Board($board, false); + } + } + } + + function Delete($allow_archive = false) { + global $tc_db; + + $i = 0; + if ($this->post['isthread'] == true) { + if ($allow_archive && $this->board['enablearchiving'] == 1 && $this->board['loadbalanceurl'] == '') { + $this->ArchiveMode(true); + $this->RegenerateThreads($this->post['id']); + @copy(KU_BOARDSDIR . $this->board['name'] . '/src/' . $this->post['file'] . '.' . $this->post['filetype'], KU_BOARDSDIR . $this->board['name'] . $this->archive_dir . '/src/' . $this->post['file'] . '.' . $this->post['filetype']); + @copy(KU_BOARDSDIR . $this->board['name'] . '/thumb/' . $this->post['file'] . 's.' . $this->post['filetype'], KU_BOARDSDIR . $this->board['name'] . $this->archive_dir . '/thumb/' . $this->post['file'] . 's.' . $this->post['filetype']); + } + $results = $tc_db->GetAll("SELECT `id`, `file`, `file_type` FROM `".KU_DBPREFIX."posts` WHERE `boardid` = '" . $this->board['id'] . "' AND `IS_DELETED` = 0 AND `parentid` = ".$tc_db->qstr($this->post['id'])); + foreach($results AS $line) { + $i++; + if ($allow_archive && $this->board['enablearchiving'] == 1) { + @copy(KU_BOARDSDIR . $this->board['name'] . '/src/' . $line['file'] . '.' . $line['file_type'], KU_BOARDSDIR . $this->board['name'] . $this->archive_dir . '/src/' . $line['file'] . '.' . $line['file_type']); + @copy(KU_BOARDSDIR . $this->board['name'] . '/thumb/' . $line['file'] . 's.' . $line['file_type'], KU_BOARDSDIR . $this->board['name'] . $this->archive_dir . '/thumb/' . $line['file'] . 's.' . $line['file_type']); + } + } + if ($allow_archive && $this->board['enablearchiving'] == 1) { + $this->ArchiveMode(false); + } + @unlink(KU_BOARDSDIR.$this->board['name'].'/res/'.$this->post['id'].'.html'); + @unlink(KU_BOARDSDIR.$this->board['name'].'/res/'.$this->post['id'].'-100.html'); + @unlink(KU_BOARDSDIR.$this->board['name'].'/res/'.$this->post['id'].'+50.html'); + $this->DeleteFile(false, true); + foreach($results AS $line) { + $tc_db->Execute("UPDATE `".KU_DBPREFIX."posts` SET `IS_DELETED` = 1 , `deleted_timestamp` = '" . time() . "' WHERE `boardid` = '" . $this->board['id'] . "' AND `id` = '".$line['id']."' AND `parentid` = ".$tc_db->qstr($this->post['id'])); + clearPostCache($line['id'], $this->board['name']); + } + $tc_db->Execute("DELETE FROM `".KU_DBPREFIX."watchedthreads` WHERE `threadid` = ".$tc_db->qstr($this->post['id'])." AND `board` = '".$this->board['name']."'"); + $tc_db->Execute("UPDATE `".KU_DBPREFIX."posts` SET `IS_DELETED` = 1 , `deleted_timestamp` = '" . time() . "' WHERE `boardid` = '" . $this->board['id'] . "' AND `id` = ".$tc_db->qstr($this->post['id'])); + clearPostCache($this->post['id'], $this->board['name']); + + return $i.' '; + } else { + $this->DeleteFile(false); + $tc_db->Execute("UPDATE `".KU_DBPREFIX."posts` SET `IS_DELETED` = 1 , `deleted_timestamp` = '" . time() . "' WHERE `boardid` = '" . $this->board['id'] . "' AND `id` = ".$tc_db->qstr($this->post['id'])); + clearPostCache($this->post['id'], $this->board['name']); + + return true; + } + } + + function DeleteFile($update_to_removed = true, $whole_thread = false) { + global $tc_db; + if ($whole_thread && $this->post['isthread']) { + $results = $tc_db->GetAll("SELECT `id`, `file`, `file_type` FROM `".KU_DBPREFIX."posts` WHERE `boardid` = " . $this->board['id'] . " AND `IS_DELETED` = 0 AND `parentid` = ".$tc_db->qstr($this->post['id'])); + if (count($results)>0) { + foreach($results AS $line) { + if ($line['file'] != '' && $line['file'] != 'removed') { + if ($this->board['loadbalanceurl'] != '') { + $this->loadbalancer->Delete($line['file'], $line['file_type']); + } else { + @unlink(KU_BOARDSDIR.$this->board['name'].'/src/'.$line['file'].'.'.$line['file_type']); + @unlink(KU_BOARDSDIR.$this->board['name'].'/src/'.$line['file'].'.pch'); + @unlink(KU_BOARDSDIR.$this->board['name'].'/thumb/'.$line['file'].'s.'.$line['file_type']); + @unlink(KU_BOARDSDIR.$this->board['name'].'/thumb/'.$line['file'].'c.'.$line['file_type']); + if ($line['file_type'] == 'mp3') { + @unlink(KU_BOARDSDIR.$this->board['name'].'/thumb/'.$line['file'].'s.jpg'); + @unlink(KU_BOARDSDIR.$this->board['name'].'/thumb/'.$line['file'].'s.png'); + @unlink(KU_BOARDSDIR.$this->board['name'].'/thumb/'.$line['file'].'s.gif'); + } + } + if ($update_to_removed) { + $tc_db->Execute("UPDATE `".KU_DBPREFIX."posts` SET `file` = 'removed', `file_md5` = '' WHERE `boardid` = '" . $this->board['id'] . "' AND `id` = ".$line['id']); + clearPostCache($line['id'], $this->board['name']); + } + } + } + } + $this->DeleteFile($update_to_removed); + } else { + if ($this->post['file']!=''&&$this->post['file']!='removed') { + if ($this->board['loadbalanceurl'] != '') { + $this->loadbalancer->Delete($this->post['file'], $this->post['filetype']); + } else { + @unlink(KU_BOARDSDIR.$this->board['name'].'/src/'.$this->post['file'].'.'.$this->post['file_type']); + @unlink(KU_BOARDSDIR.$this->board['name'].'/src/'.$this->post['file'].'.pch'); + @unlink(KU_BOARDSDIR.$this->board['name'].'/thumb/'.$this->post['file'].'s.'.$this->post['file_type']); + @unlink(KU_BOARDSDIR.$this->board['name'].'/thumb/'.$this->post['file'].'c.'.$this->post['file_type']); + if ($this->post['file_type'] == 'mp3') { + @unlink(KU_BOARDSDIR.$this->board['name'].'/thumb/'.$this->post['file'].'s.jpg'); + @unlink(KU_BOARDSDIR.$this->board['name'].'/thumb/'.$this->post['file'].'s.png'); + @unlink(KU_BOARDSDIR.$this->board['name'].'/thumb/'.$this->post['file'].'s.gif'); + } + } + if ($update_to_removed) { + $tc_db->Execute("UPDATE `".KU_DBPREFIX."posts` SET `file` = 'removed', `file_md5` = '' WHERE `boardid` = '" . $this->board['id'] . "' AND `id` = ".$tc_db->qstr($this->post['id'])); + clearPostCache($this->post['id'], $this->board['name']); + } + } + } + } + + function Insert($parentid, $name, $tripcode, $email, $subject, $message, $filename, $file_original, $filetype, $file_md5, $image_w, $image_h, $filesize, $thumb_w, $thumb_h, $password, $timestamp, $bumped, $ip, $posterauthority, $tag, $stickied, $locked, $boardid) { + global $tc_db; + + $query = "INSERT INTO `".KU_DBPREFIX."posts` ( `parentid` , `boardid`, `name` , `tripcode` , `email` , `subject` , `message` , `file` , `file_original`, `file_type` , `file_md5` , `image_w` , `image_h` , `file_size` , `file_size_formatted` , `thumb_w` , `thumb_h` , `password` , `timestamp` , `bumped` , `ip` , `ipmd5` , `posterauthority` , `tag` , `stickied` , `locked` ) VALUES ( ".$tc_db->qstr($parentid).", ".$tc_db->qstr($boardid).", ".$tc_db->qstr($name).", ".$tc_db->qstr($tripcode).", ".$tc_db->qstr($email).", ".$tc_db->qstr($subject).", ".$tc_db->qstr($message).", ".$tc_db->qstr($filename).", ".$tc_db->qstr($file_original).", ".$tc_db->qstr($filetype).", ".$tc_db->qstr($file_md5).", ".$tc_db->qstr(intval($image_w)).", ".$tc_db->qstr(intval($image_h)).", ".$tc_db->qstr($filesize).", ".$tc_db->qstr(ConvertBytes($filesize)).", ".$tc_db->qstr($thumb_w).", ".$tc_db->qstr($thumb_h).", ".$tc_db->qstr($password).", ".$tc_db->qstr($timestamp).", ".$tc_db->qstr($bumped).", ".$tc_db->qstr(md5_encrypt($ip, KU_RANDOMSEED)).", '".md5($ip)."', ".$tc_db->qstr($posterauthority).", ".$tc_db->qstr($tag).", ".$tc_db->qstr($stickied).", ".$tc_db->qstr($locked)." )"; + $tc_db->Execute($query); + $id = $tc_db->Insert_Id(); + if(!$id || KU_DBTYPE == 'sqlite') { + // Non-mysql installs don't return the insert ID after insertion, we need to manually get it. + $id = $tc_db->GetOne("SELECT `id` FROM `".KU_DBPREFIX."posts` WHERE `boardid` = ".$tc_db->qstr($boardid)." AND timestamp = ".$tc_db->qstr($timestamp)." AND `ipmd5` = '".md5($ip)."' LIMIT 1"); + } + + if ($id == 1 && $this->board['start'] > 1) { + $tc_db->Execute("UPDATE `".KU_DBPREFIX."posts` SET `id` = '".$this->board['start']."' WHERE `boardid` = ".$boardid); + return $this->board['start']; + } + return $id; + } + + function Report() { + global $tc_db; + + return $tc_db->Execute("INSERT INTO `".KU_DBPREFIX."reports` ( `board` , `postid` , `when` , `ip`, `reason` ) VALUES ( " . $tc_db->qstr($this->board['name']) . " , " . $tc_db->qstr($this->post['id']) . " , ".time()." , '" . md5_encrypt($_SERVER['REMOTE_ADDR'], KU_RANDOMSEED) . "', " . $tc_db->qstr($_POST['reportreason']) . " )"); + } +} + +?> \ No newline at end of file diff --git a/inc/classes/loadbalancer.class.php b/inc/classes/loadbalancer.class.php new file mode 100644 index 0000000..fe22dbb --- /dev/null +++ b/inc/classes/loadbalancer.class.php @@ -0,0 +1,83 @@ +url); + + $post = array('password' => $this->password, + 'type' => $type, + 'isreply' => $isreply_formatted, + 'file' => $file, + 'targetname' => $targetname, + 'targetthumb' => $targetthumb, + 'targetthumb_c' => $targetthumb_c, + 'checkmime' => $checkmime); + + curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:')); + + curl_setopt($ch, CURLOPT_POSTFIELDS, $post); + + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_HEADER, 0); + + $return = curl_exec($ch); + + curl_close($ch); + + if ($handle_errors) { + if ($return == 'bad password') die(_gettext('The passwords of the load balancer password in the board configuration and the load receiver script differ.')); + if ($return == 'unable to thumbnail') die(_gettext('The load balancer script was unable to create the thumbnail for that image.')); + if ($return == 'file already exists') die(_gettext('That file already exists on the server.')); + if ($return == 'unable to copy') die(_gettext('The load balancer script was unable to copy the file you uploaded.')); + if ($return == 'bad mime type') die(_gettext('That file does not match up with the required mime type for that format.')); + if ($return == '' || $return == 'failure') die(_gettext('The load balancer script stopped unexpectedly.')); + } + + return $return; + } + + function Delete($filename, $filetype) { + $ch = curl_init($this->url); + + $post = array('password' => $this->password, + 'type' => 'delete', + 'filename' => $filename, + 'filetype' => $filetype); + + curl_setopt($ch, CURLOPT_POSTFIELDS, $post); + + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_HEADER, 0); + + $return = curl_exec($ch); + + curl_close($ch); + + return $return; + } +} + +?> \ No newline at end of file diff --git a/inc/classes/manage.class.php b/inc/classes/manage.class.php new file mode 100644 index 0000000..ca6830d --- /dev/null +++ b/inc/classes/manage.class.php @@ -0,0 +1,4095 @@ +assign('includeheader', $tpl_includeheader); + } + + /* Show the footer of the manage page */ + function Footer() { + global $dwoo_data, $dwoo, $tpl_page; + + $dwoo_data->assign('page', $tpl_page); + + $board_class = new Board(''); + + $dwoo->output(KU_TEMPLATEDIR . '/manage.tpl', $dwoo_data); + } + + // Creates a salt to be used for passwords + function CreateSalt() { + $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + $salt = ''; + + for ($i = 0; $i < 3; ++$i) { + $salt .= $chars[mt_rand(0, strlen($chars) - 1)]; + } + return $salt; + } + + /* Validate the current session */ + function ValidateSession($is_menu = false) { + global $tc_db, $tpl_page; + + if (isset($_SESSION['manageusername']) && isset($_SESSION['managepassword'])) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `username` FROM `" . KU_DBPREFIX . "staff` WHERE `username` = " . $tc_db->qstr($_SESSION['manageusername']) . " AND `password` = " . $tc_db->qstr($_SESSION['managepassword']) . " LIMIT 1"); + if (count($results) == 0) { + session_destroy(); + exitWithErrorPage(_gettext('Invalid session.'), ''. _gettext('Log in again.') . ''); + } + + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "staff` SET `lastactive` = " . time() . " WHERE `username` = " . $tc_db->qstr($_SESSION['manageusername'])); + + return true; + } else { + if (!$is_menu) { + $this->LoginForm(); + die($tpl_page); + } else { + return false; + } + } + } + + /* Show the login form and halt execution */ + function LoginForm() { + global $tc_db, $tpl_page; + + if (file_exists(KU_ROOTDIR . 'inc/pages/manage_login.html')) { + $tpl_page .= file_get_contents(KU_ROOTDIR . 'inc/pages/manage_login.html'); + } + } + + /* Check login names and create session if user/pass is correct */ + function CheckLogin() { + global $tc_db, $action; + + $tc_db->Execute("DELETE FROM `" . KU_DBPREFIX . "loginattempts` WHERE `timestamp` < '" . (time() - 1200) . "'"); + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `ip` FROM `" . KU_DBPREFIX . "loginattempts` WHERE `ip` = '" . $_SERVER['REMOTE_ADDR'] . "' LIMIT 6"); + if (count($results) > 5) { + exitWithErrorPage(_gettext('System lockout'), _gettext('Sorry, because of your numerous failed logins, you have been locked out from logging in for 20 minutes. Please wait and then try again.')); + } else { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `username`, `password`, `salt` FROM `" . KU_DBPREFIX . "staff` WHERE `username` = " . $tc_db->qstr($_POST['username']) . " AND `type` != 3 LIMIT 1"); + if (count($results) > 0) { + if (empty($results[0]['salt'])) { + if (md5($_POST['password']) == $results[0]['password']) { + $salt = $this->CreateSalt(); + $tc_db->Execute("UPDATE `" .KU_DBPREFIX. "staff` SET salt = '" .$salt. "' WHERE username = " .$tc_db->qstr($_POST['username'])); + $newpass = md5($_POST['password'] . $salt); + $tc_db->Execute("UPDATE `" .KU_DBPREFIX. "staff` SET password = '" .$newpass. "' WHERE username = " .$tc_db->qstr($_POST['username'])); + $_SESSION['manageusername'] = $_POST['username']; + $_SESSION['managepassword'] = $newpass; + $_SESSION['token'] = md5($_SESSION['manageusername'] . $_SESSION['managepassword'] . rand(0,100)); + $this->SetModerationCookies(); + $tc_db->Execute("DELETE FROM `" . KU_DBPREFIX . "loginattempts` WHERE `ip` < '" . $_SERVER['REMOTE_ADDR'] . "'"); + $action = 'posting_rates'; + management_addlogentry(_gettext('Logged in'), 1); + die(''); + } else { + $tc_db->Execute("INSERT HIGH_PRIORITY INTO `" . KU_DBPREFIX . "loginattempts` ( `username` , `ip` , `timestamp` ) VALUES ( " . $tc_db->qstr($_POST['username']) . " , '" . $_SERVER['REMOTE_ADDR'] . "' , '" . time() . "' )"); + exitWithErrorPage(_gettext('Incorrect username/password.')); + } + } else { + if (md5($_POST['password'] . $results[0]['salt']) == $results[0]['password']) { + $_SESSION['manageusername'] = $_POST['username']; + $_SESSION['managepassword'] = md5($_POST['password'] . $results[0]['salt']); + $_SESSION['token'] = md5($_SESSION['manageusername'] . $_SESSION['managepassword'] . rand(0,100)); + $this->SetModerationCookies(); + $action = 'posting_rates'; + management_addlogentry(_gettext('Logged in'), 1); + die(''); + } else { + $tc_db->Execute("INSERT HIGH_PRIORITY INTO `" . KU_DBPREFIX . "loginattempts` ( `username` , `ip` , `timestamp` ) VALUES ( " . $tc_db->qstr($_POST['username']) . " , '" . $_SERVER['REMOTE_ADDR'] . "' , '" . time() . "' )"); + exitWithErrorPage(_gettext('Incorrect username/password.')); + } + } + } else { + $tc_db->Execute("INSERT HIGH_PRIORITY INTO `" . KU_DBPREFIX . "loginattempts` ( `username` , `ip` , `timestamp` ) VALUES ( " . $tc_db->qstr($_POST['username']) . " , '" . $_SERVER['REMOTE_ADDR'] . "' , '" . time() . "' )"); + exitWithErrorPage(_gettext('Incorrect username/password.')); + } + } + } + + /* Set mod cookies for boards */ + function SetModerationCookies() { + global $tc_db, $tpl_page; + + if (isset($_SESSION['manageusername'])) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `boards` FROM `" . KU_DBPREFIX . "staff` WHERE `username` = " . $tc_db->qstr($_SESSION['manageusername']) . " LIMIT 1"); + if ($this->CurrentUserIsAdministrator() || $results[0][0] == 'allboards') { + setcookie("kumod", "allboards", time() + 3600, KU_BOARDSFOLDER, KU_DOMAIN); + } else { + if ($results[0][0] != '') { + setcookie("kumod", $results[0][0], time() + 3600, KU_BOARDSFOLDER, KU_DOMAIN); + } + } + } + } + + function CheckToken($posttoken) { + if ($posttoken != $_SESSION['token']) { + // Something is strange + session_destroy(); + exitWithErrorPage(_gettext('Invalid Token')); + } + } + + /* Log current user out */ + function Logout() { + global $tc_db, $tpl_page; + + setcookie('kumod', '', time() - 3600, KU_BOARDSFOLDER, KU_DOMAIN); + + session_destroy(); + unset($_SESSION['manageusername']); + unset($_SESSION['managepassword']); + unset($_SESSION['token']); + die(''); + } + + /* If the user logged in isn't an admin, kill the script */ + function AdministratorsOnly() { + global $tc_db, $tpl_page; + + if (!$this->CurrentUserIsAdministrator()) { + exitWithErrorPage('That page is for admins only.'); + } + } + + /* If the user logged in isn't an moderator or higher, kill the script */ + function ModeratorsOnly() { + global $tc_db, $tpl_page; + + if ($this->CurrentUserIsAdministrator()) { + return true; + } else { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `type` FROM `" . KU_DBPREFIX . "staff` WHERE `username` = '" . $_SESSION['manageusername'] . "' AND `password` = '" . $_SESSION['managepassword'] . "' LIMIT 1"); + foreach ($results as $line) { + if ($line['type'] != 2) { + exitWithErrorPage(_gettext('That page is for moderators and administrators only.')); + } + } + } + } + + /* See if the user logged in is an admin */ + function CurrentUserIsAdministrator() { + global $tc_db, $tpl_page; + + if ($_SESSION['manageusername'] == '' || $_SESSION['managepassword'] == '' || $_SESSION['token'] == '') { + $_SESSION['manageusername'] = ''; + $_SESSION['managepassword'] = ''; + $_SESSION['token'] = ''; + return false; + } + + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `type` FROM `" . KU_DBPREFIX . "staff` WHERE `username` = '" . $_SESSION['manageusername'] . "' AND `password` = '" . $_SESSION['managepassword'] . "' LIMIT 1"); + foreach ($results as $line) { + if ($line['type'] == 1) { + return true; + } else { + return false; + } + } + + /* If the function reaches this point, something is fishy. Kill their session */ + session_destroy(); + exitWithErrorPage(_gettext('Invalid session, please log in again.')); + } + + /* See if the user logged in is a moderator */ + function CurrentUserIsModerator() { + global $tc_db, $tpl_page; + + if ($_SESSION['manageusername'] == '' || $_SESSION['managepassword'] == '' || $_SESSION['token'] == '') { + $_SESSION['manageusername'] = ''; + $_SESSION['managepassword'] = ''; + $_SESSION['token'] = ''; + return false; + } + + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `type` FROM `" . KU_DBPREFIX . "staff` WHERE `username` = '" . $_SESSION['manageusername'] . "' AND `password` = '" . $_SESSION['managepassword'] . "' LIMIT 1"); + foreach ($results as $line) { + if ($line['type'] == 2) { + return true; + } else { + return false; + } + } + + /* If the function reaches this point, something is fishy. Kill their session */ + session_destroy(); + exitWithErrorPage(_gettext('Invalid session, please log in again.')); + } + + /* See if the user logged in is a moderator of a specified board */ + function CurrentUserIsModeratorOfBoard($board, $username) { + global $tc_db, $tpl_page; + + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `type`, `boards` FROM `" . KU_DBPREFIX . "staff` WHERE `username` = '" . $username . "' LIMIT 1"); + if (count($results) > 0) { + foreach ($results as $line) { + if ($line['boards'] == 'allboards') { + return true; + } else { + if ($line['type'] == '1') { + return true; + } else { + $array_boards = explode('|', $line['boards']); + if (in_array($board, $array_boards)) { + return true; + } else { + return false; + } + } + } + } + } else { + return false; + } + } + + /* + * +------------------------------------------------------------------------------+ + * Manage pages + * +------------------------------------------------------------------------------+ + */ + + + /* + * +------------------------------------------------------------------------------+ + * Home Pages + * +------------------------------------------------------------------------------+ + */ + + /* View Announcements */ + function announcements() { + global $tc_db, $tpl_page; + $this->ModeratorsOnly(); + + $tpl_page .= '

'. _gettext('Announcements') .'

'. "\n"; + + $entries = 0; + /* Get all of the announcements, ordered with the newest one placed on top */ + $results = $tc_db->GetAll("SELECT * FROM `".KU_DBPREFIX."announcements` ORDER BY `postedat` DESC"); + foreach($results AS $line) { + $entries++; + $tpl_page .= '

'.stripslashes($line['subject']).' '. _gettext('by') .' '; + $tpl_page .= stripslashes($line['postedby']); + $tpl_page .= ' - '.date("n/j/y @ g:iA T", $line['postedat']); + $tpl_page .= '

' . + '

'. stripslashes($line['message']) . '

'; + } + } + + function posting_rates() { + global $tc_db, $tpl_page; + + $tpl_page .= '

'. _gettext('Posting rates (past hour)') . '


'; + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "boards` ORDER BY `name` ASC"); + if (count($results) > 0) { + $tpl_page .= ''; + foreach ($results as $line) { + $rows_threads = $tc_db->GetOne("SELECT HIGH_PRIORITY count(id) FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $line['id'] . " AND `parentid` = 0 AND `timestamp` >= " . (time() - 3600)); + $rows_replies = $tc_db->GetOne("SELECT HIGH_PRIORITY count(id) FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $line['id'] . " AND `parentid` != 0 AND `timestamp` >= " . (time() - 3600)); + $rows_posts = $rows_threads + $rows_replies; + $threads_perminute = $rows_threads; + $replies_perminute = $rows_replies; + $posts_perminute = $rows_posts; + $tpl_page .= ''; + } + $tpl_page .= '
'. _gettext('Board') . ''. _gettext('Threads') . ''. _gettext('Replies') . ''. _gettext('Posts') . '
'. $line['name'] . ''. $threads_perminute . ''. $replies_perminute . ''. $posts_perminute . '
'; + } else { + $tpl_page .= _gettext('No boards'); + } + } + + function statistics() { + global $tc_db, $tpl_page; + + $tpl_page .= '

'. _gettext('Statistics') .'


'; + $tpl_page .= ' + + + + '; + } + + function changepwd() { + global $tc_db, $tpl_page; + + $tpl_page .= '

'. _gettext('Change account password') . '


'; + if (isset($_POST['oldpwd']) && isset($_POST['newpwd']) && isset($_POST['newpwd2'])) { + $this->CheckToken($_POST['token']); + if ($_POST['oldpwd'] != '' && $_POST['newpwd'] != '' && $_POST['newpwd2'] != '') { + if ($_POST['newpwd'] == $_POST['newpwd2']) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "staff` WHERE `username` = " . $tc_db->qstr($_SESSION['manageusername']) . ""); + foreach ($results as $line) { + $staff_passwordenc = $line['password']; + $staff_salt = $line['salt']; + } + if (md5($_POST['oldpwd'].$staff_salt) == $staff_passwordenc) { + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "staff` SET `password` = '" . md5($_POST['newpwd'].$staff_salt) . "' WHERE `username` = " . $tc_db->qstr($_SESSION['manageusername']) . ""); + $_SESSION['managepassword'] = md5($_POST['newpwd'].$staff_salt); + $tpl_page .= _gettext('Password successfully changed.'); + } else { + $tpl_page .= _gettext('The old password you provided did not match the current one.'); + } + } else { + $tpl_page .= _gettext('The second password did not match the first.'); + } + } else { + $tpl_page .= _gettext('Please fill in all required fields.'); + } + $tpl_page .= '
'; + } + $tpl_page .= '
+ + +
+ + +
+ + +
+ + + +
'; + } + + /* + * +------------------------------------------------------------------------------+ + * Site Administration Pages + * +------------------------------------------------------------------------------+ + */ + + function addannouncement() { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + $disptable = true; $formval = 'add'; $title = _gettext('Announcement Management'); + if(isset($_GET['act'])) { + if ($_GET['act'] == 'edit') { + if (isset($_POST['announcement'])) { + $this->CheckToken($_POST['token']); + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "announcements` SET `subject` = " . $tc_db->qstr($_POST['subject']) . ", `message` = " . $tc_db->qstr($_POST['announcement']) . " WHERE `id` = " . $tc_db->qstr($_GET['id'])); + $tpl_page .= '

'. _gettext('Announcement edited') .'


'; + management_addlogentry(_gettext('Edited an announcement')); + } + $formval = 'edit&id='. $_GET['id']; $title .= ' - Edit'; + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "announcements` WHERE `id` = " . $tc_db->qstr($_GET['id']) . ""); + $values = $results[0]; $disptable = false; + } elseif ($_GET['act'] == 'del') { + $tc_db->Execute("DELETE FROM `" . KU_DBPREFIX . "announcements` WHERE `id` = " . $tc_db->qstr($_GET['id']) . ""); + $tpl_page .= '

'. _gettext('Announcement successfully deleted') .'


'; + management_addlogentry(_gettext('Deleted an announcement'), 9); + } elseif ($_GET['act'] == 'add' && isset($_POST['announcement']) && isset($_POST['subject'])) { + if (!empty($_POST['announcement']) && !empty($_POST['subject'])) { + $tpl_page .= '
'; + $tc_db->Execute("INSERT HIGH_PRIORITY INTO `" . KU_DBPREFIX . "announcements` ( `subject` , `message` , `postedat` , `postedby` ) VALUES ( " . $tc_db->qstr($_POST['subject']) . " , " . $tc_db->qstr($_POST['announcement']) . " , '" . time() . "' , " . $tc_db->qstr($_SESSION['manageusername']) . " )"); + $tpl_page .= '

'. _gettext('Announcement successfully added.') . '

'; + management_addlogentry(_gettext('Added an announcement'), 9); + $tpl_page .= '
'; + } else { + $tpl_page .= '
'. _gettext('You must enter a subject as well as a post.') .'
'; + } + } + } + $tpl_page .= '

'. $title . '


+
+ + + +
'. _gettext('Can not be left blank') . '

+ +
+ +
'; + if ($disptable) { + $tpl_page .= '

'. _gettext('Edit/Delete announcement') .'

'; + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "announcements` ORDER BY `id` DESC"); + if (count($results) > 0) { + $tpl_page .= ''; + foreach ($results as $line) { + $tpl_page .= ''; + } + $tpl_page .= '
'. _gettext('Date Added') .''. _gettext('Subject') .''. _gettext('Message') .''. _gettext('Edit/Delete') .'
'. date('F j, Y, g:i a', $line['postedat']) . ''. $line['subject'] . ''. $line['message'] . '['. _gettext('Edit') .'] ['. _gettext('Delete') .']
'; + } else { + $tpl_page .= _gettext('No announcements yet.'); + } + } + } + + /* Edit Dwoo templates */ + function templates() { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + + $files = array(); + + $tpl_page .= '

'. _gettext('Template editor') .'


'; + if ($dh = opendir(KU_TEMPLATEDIR)) { + while (($file = readdir($dh)) !== false) { + if($file != '.' && $file != '..') + $files[] = $file; + } + closedir($dh); + } + sort($files); + + if(isset($_POST['templatedata']) && isset($_POST['template'])) { + $this->CheckToken($_POST['token']); + $file = basename($_POST['template']); + if (in_array($file, $files)) { + if(file_exists(KU_TEMPLATEDIR . '/'. $file)) { + file_put_contents(KU_TEMPLATEDIR . '/'. $file, $_POST['templatedata']); + $tpl_page .= '

'. _gettext('Template edited') .'


'; + if (isset($_POST['rebuild'])) { + $this->rebuildall(); + } + unset($_POST['template']); + unset($_POST['templatedata']); + } + } + } + + if(!isset($_POST['templatedata']) && !isset($_POST['template'])) { + $tpl_page .= '
+ + '; + + } + + if(!isset($_POST['templatedata']) && isset($_POST['template'])) { + $file = basename($_POST['template']); + if (in_array($file, $files)) { + if(file_exists(KU_TEMPLATEDIR . '/'. $file)) { + $tpl_page .= ' + + + + +

+
'. _gettext('Visit http://wiki.dwoo.org/ for syntax information.') . '
+
'. sprintf(_gettext('To access Kusaba variables, use {%%KU_VARNAME}, for example {%%KU_BOARDSPATH} would be replaced with %s'), KU_BOARDSPATH) . '
+
'. _gettext('Enclose text in {t}{/t} blocks to allow them to be translated for different languages.') . '


'; + } + } + } + + $tpl_page .= '
'; + } + + /* Add, edit, delete, and view news entries */ + function news() { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + $disptable = true; $formval = 'add'; $title = _gettext('News Management'); + if(isset($_GET['act'])) { + if ($_GET['act'] == 'edit') { + if (isset($_POST['news'])) { + $this->CheckToken($_POST['token']); + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "front` SET `subject` = " . $tc_db->qstr($_POST['subject']) . ", `message` = " . $tc_db->qstr($_POST['news']) . ", `email` = " . $tc_db->qstr($_POST['email']) . " WHERE `id` = " . $tc_db->qstr($_GET['id']) . " AND `page` = 0"); + $tpl_page .= '

'. _gettext('News post edited') .'


'; + management_addlogentry(_gettext('Edited a news entry'), 9); + } + $formval = 'edit&id='. $_GET['id']; $title .= ' - Edit'; + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "front` WHERE `id` = " . $tc_db->qstr($_GET['id']) . ""); + $values = $results[0]; + $disptable = false; + } elseif ($_GET['act'] == 'del') { + $results = $tc_db->Execute("DELETE FROM `" . KU_DBPREFIX . "front` WHERE `id` = " . $tc_db->qstr($_GET['id']) . ""); + $tpl_page .= '

'. _gettext('News post deleted') .'


'; + management_addlogentry(_gettext('Deleted a news entry'), 9); + } elseif ($_GET['act'] == 'add') { + if (isset($_POST['news']) && isset($_POST['subject']) && isset($_POST['email'])) { + if (!empty($_POST['news']) || !empty($_POST['subject'])) { + $this->CheckToken($_POST['token']); + $tpl_page .= '
'; + $tc_db->Execute("INSERT HIGH_PRIORITY INTO `" . KU_DBPREFIX . "front` ( `page`, `subject` , `message` , `timestamp` , `poster` , `email` ) VALUES ( '0', " . $tc_db->qstr($_POST['subject']) . " , " . $tc_db->qstr($_POST['news']) . " , '" . time() . "' , " . $tc_db->qstr($_SESSION['manageusername']) . " , " . $tc_db->qstr($_POST['email']) . " )"); + $tpl_page .= '

'. _gettext('News entry successfully added.') . '

'; + management_addlogentry(_gettext('Added a news entry'), 9); + $tpl_page .= '
'; + } else { + $tpl_page .= '
'. _gettext('You must enter a subject as well as a post.') .'
'; + } + } + } + } + $tpl_page .= '

'. $title . '


+
+ + + +
'. _gettext('Can not be left blank.') . '

+ +

+ + +
'. _gettext('Can be left blank.') . '

+ +
'; + if ($disptable) { + $tpl_page .= '

'. _gettext('Edit/Delete News') .'

'; + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "front` WHERE `page` = 0 ORDER BY `timestamp` DESC"); + if (count($results) > 0) { + $tpl_page .= ''; + foreach ($results as $line) { + $tpl_page .= ''; + } + $tpl_page .= '
'. _gettext('Date Added') .''. _gettext('Subject') .''. _gettext('Message') .''. _gettext('Edit/Delete') .'
'. date('F j, Y, g:i a', $line['timestamp']) . ''. $line['subject'] . ''. $line['message'] . '['. _gettext('Edit') .'] ['. _gettext('Delete') .']
'; + } else { + $tpl_page .= _gettext('No news posts yet.'); + } + } + } + + /* Add, edit, or delete FAQ entries */ + function faq() { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + $disptable = true; $formval = 'add'; $title = _gettext('FAQ Management'); + if(isset($_GET['act'])) { + if ($_GET['act'] == 'edit') { + if (isset($_POST['faq'])) { + $this->CheckToken($_POST['token']); + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "front` SET `subject` = " . $tc_db->qstr($_POST['heading']) . ", `message` = " . $tc_db->qstr($_POST['faq']) . ", `order` = " . intval($_POST['order']) . " WHERE `id` = " . $tc_db->qstr($_GET['id']) . ""); + $tpl_page .= '

'. _gettext('FAQ entry edited') .'


'; + management_addlogentry(_gettext('Edited a FAQ entry'), 9); + } + $formval = 'edit&id='. $_GET['id']; $title .= ' - Edit'; + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "front` WHERE `id` = " . $tc_db->qstr($_GET['id'])); + $values = $results[0]; + $disptable = false; + } elseif ($_GET['act'] == 'del') { + $results = $tc_db->Execute("DELETE FROM `" . KU_DBPREFIX . "front` WHERE `id` = " . $tc_db->qstr($_GET['id'])); + $tpl_page .= '

'. _gettext('FAQ entry deleted') .'


'; + management_addlogentry(_gettext('Deleted a FAQ entry'), 9); + } elseif ($_GET['act'] == 'add') { + if (isset($_POST['faq']) && isset($_POST['heading']) && isset($_POST['order'])) { + if (!empty($_POST['faq']) || !empty($_POST['heading'])) { + $this->CheckToken($_POST['token']); + $tpl_page .= '
'; + $tc_db->Execute("INSERT HIGH_PRIORITY INTO `" . KU_DBPREFIX . "front` ( `page`, `subject` , `message` , `order` ) VALUES ( '1', " . $tc_db->qstr($_POST['heading']) . " , " . intval($_POST['faq']) . " , " . intval($_POST['order']) . " )"); + $tpl_page .= '

'. _gettext('FAQ entry successfully added.') . '

'; + management_addlogentry(_gettext('Added a FAQ entry'), 9); + $tpl_page .= '
'; + } else { + $tpl_page .= '
'. _gettext('You must enter a heading as well as a post.') .'
'; + } + } + } + } + $tpl_page .= '

'. $title . '


+
+ + + +
'. _gettext('Can not be left blank.') . '

+ +

+ + +
'. _gettext('This can be left blank, however it will appear at the very top of the list') . '

+ +
'; + if ($disptable) { + $tpl_page .= '

'. _gettext('Edit/Delete FAQ Entries') .'

'; + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "front` WHERE `page` = 1 ORDER BY `order` ASC"); + if (count($results) > 0) { + $tpl_page .= ''; + foreach ($results as $line) { + $tpl_page .= ''; + } + $tpl_page .= '
'. _gettext('Order') .''. _gettext('Heading') .''. _gettext('Message') .''. _gettext('Edit/Delete') .'
'. $line['order'] . ''. $line['subject'] . ''. $line['message'] . '['. _gettext('Edit') .'] ['. _gettext('Delete') .']
'; + } else { + $tpl_page .= _gettext('No FAQ entries yet.'); + } + } + } + + /* Add, edit, or delete Rules Entries */ + function rules() { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + $disptable = true; $formval = 'add'; $title = _gettext('Rules Management'); + if(isset($_GET['act'])) { + if ($_GET['act'] == 'edit') { + if (isset($_POST['rules'])) { + $this->CheckToken($_POST['token']); + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "front` SET `subject` = " . $tc_db->qstr($_POST['heading']) . ", `message` = " . $tc_db->qstr($_POST['rules']) . ", `order` = " . intval($_POST['order']) . " WHERE `id` = " . $tc_db->qstr($_GET['id']) . ""); + $tpl_page .= '

'. _gettext('Rules entry edited') .'


'; + management_addlogentry(_gettext('Edited a Rule entry'), 9); + } + $formval = 'edit&id='. $_GET['id']; $title .= ' - Edit'; + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "front` WHERE `id` = " . $tc_db->qstr($_GET['id']) . ""); + $values = $results[0]; + $disptable = false; + } elseif ($_GET['act'] == 'del') { + $results = $tc_db->Execute("DELETE FROM `" . KU_DBPREFIX . "front` WHERE `id` = " . $tc_db->qstr($_GET['id']) . ""); + $tpl_page .= '

'. _gettext('Rule entry deleted') .'


'; + management_addlogentry(_gettext('Deleted a Rules entry'), 9); + } elseif ($_GET['act'] == 'add') { + if (isset($_POST['rules']) && isset($_POST['heading']) && isset($_POST['order'])) { + if (!empty($_POST['rules']) || !empty($_POST['heading'])) { + $this->CheckToken($_POST['token']); + $tpl_page .= '
'; + $tc_db->Execute("INSERT HIGH_PRIORITY INTO `" . KU_DBPREFIX . "front` ( `page`, `subject` , `message` , `order` ) VALUES ( '2', " . $tc_db->qstr($_POST['heading']) . " , " . $tc_db->qstr($_POST['rules']) . " , " . intval($_POST['order']) . " )"); + $tpl_page .= '

'. _gettext('Rules entry successfully added.') . '

'; + management_addlogentry(_gettext('Added a Rule entry'), 9); + $tpl_page .= '
'; + } else { + $tpl_page .= '
'. _gettext('You must enter a heading as well as a post.') .'
'; + } + } + } + } + $tpl_page .= '

'. $title . '


+
+ + + +
'. _gettext('Can not be left blank.') . '

+ +

+ + +
'. _gettext('This can be left blank, however it will appear at the very top of the list') . '

+ +
'; + if ($disptable) { + $tpl_page .= '

'. _gettext('Edit/Delete Rule Entries') .'

'; + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "front` WHERE `page` = 2 ORDER BY `order` ASC"); + if (count($results) > 0) { + $tpl_page .= ''; + foreach ($results as $line) { + $tpl_page .= ''; + } + $tpl_page .= '
'. _gettext('Order') .''. _gettext('Heading') .''. _gettext('Message') .''. _gettext('Edit/Delete') .'
'. $line['order'] . ''. $line['subject'] . ''. $line['message'] . '['. _gettext('Edit') .'] ['. _gettext('Delete') .']
'; + } else { + $tpl_page .= _gettext('No Rule entries yet.'); + } + } + } + + function blotter() { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + if (!KU_BLOTTER) exitWithErrorPage(_gettext('Blotter is disabled')); + $tpl_page .= '

' ._gettext('Blotter'). '


'; + $act = 'add'; $values = array(); + if (isset($_GET['act'])) { + switch($_GET['act']) { + case 'add': + if (isset($_POST['message'])) { + $this->CheckToken($_POST['token']); + $important = (isset($_POST['important'])) ? 1 : 0; + $tc_db->Execute("INSERT INTO `" . KU_DBPREFIX . "blotter` (`at`, `message`, `important`) VALUES ('" . time() . "', " . $tc_db->qstr($_POST['message']) . ", '" . $important . "')"); + $tpl_page .= '

'. _gettext('Blotter entry added.') . '

'; + clearBlotterCache(); + } + break; + case 'del': + if (is_numeric($_GET['id'])) { + $tc_db->Execute("DELETE FROM `" . KU_DBPREFIX . "blotter` WHERE `id` = " . $tc_db->qstr($_GET['id']) . ""); + $tpl_page .= '

'. _gettext('Blotter entry deleted.') . '


'; + clearBlotterCache(); + } else { + exitWithErrorPage(_gettext('Invalid ID')); + } + break; + case 'edit': + if (is_numeric($_GET['id'])) { + $act = 'edit&id=' .$_GET['id']; + if (isset($_POST['message'])) { + $this->CheckToken($_POST['token']); + $important = (isset($_POST['important'])) ? 1 : 0; + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "blotter` SET `message` = " . $tc_db->qstr($_POST['message']) . ", `important` = '" . $important . "' WHERE `id` = " . $tc_db->qstr($_GET['id']) . ""); + $tpl_page .= '

'. _gettext('Blotter entry updated.') . '

'; + clearBlotterCache(); + } + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "blotter` WHERE `id` = " . $tc_db->qstr($_GET['id']) . " LIMIT 1"); + $values = $results[0]; + } else { + exitWithErrorPage(_gettext('Invalid ID')); + } + break; + default: + exitWithErrorPage(_gettext('Invalid value for \'act\'')); + break; + } + } + + $tpl_page .= '
+ + +
+ +
+


'; + + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "blotter` ORDER BY `id` DESC"); + if (count($results) > 0) { + $tpl_page .= ''; + foreach ($results as $line) { + $tpl_page .= ''; + } + $tpl_page .= '
'. _gettext('At') . ''. _gettext('Message') . ''. _gettext('Important') . ' 
'. date('m/d/y', $line['at']) . ''. $line['message'] . ''; + $tpl_page .= ($line['important'] == 1) ? _gettext('Yes') : _gettext('No'); + $tpl_page .= '['. _gettext('Edit') .'] ['. _gettext('Delete') .']
'; + } else { + $tpl_page .= _gettext('No blotter entries'); + } + } + + /* Display disk space used per board, and finally total in a large table */ + function spaceused() { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + + $tpl_page .= '

'. _gettext('Disk space used') . '


'; + $spaceused_res = 0; + $spaceused_src = 0; + $spaceused_thumb = 0; + $spaceused_total = 0; + $files_res = 0; + $files_src = 0; + $files_thumb = 0; + $files_total = 0; + $tpl_page .= ''; + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `name` FROM `" . KU_DBPREFIX . "boards` ORDER BY `name` ASC"); + foreach ($results as $line) { + list($spaceused_board_res, $files_board_res) = recursive_directory_size(KU_BOARDSDIR . $line['name'] . '/res'); + list($spaceused_board_src, $files_board_src) = recursive_directory_size(KU_BOARDSDIR . $line['name'] . '/src'); + list($spaceused_board_thumb, $files_board_thumb) = recursive_directory_size(KU_BOARDSDIR . $line['name'] . '/thumb'); + + $spaceused_board_total = $spaceused_board_res + $spaceused_board_src + $spaceused_board_thumb; + $files_board_total = $files_board_res + $files_board_src + $files_board_thumb; + + $spaceused_res += $spaceused_board_res; + $files_res += $files_board_res; + + $spaceused_src += $spaceused_board_src; + $files_src += $files_board_src; + + $spaceused_thumb += $spaceused_board_thumb; + $files_thumb += $files_board_thumb; + + $spaceused_total += $spaceused_board_total; + $files_total += $files_board_total; + + $tpl_page .= ''; + $tpl_page .= ''; + $tpl_page .= ''; + $tpl_page .= ''; + } + $tpl_page .= ''; + $tpl_page .= ''; + $tpl_page .= ''; + $tpl_page .= ''; + $tpl_page .= '
'. _gettext('Board') .''. _gettext('Area') .''. _gettext('Files') .''. _gettext('Space Used') .'
/'.$line['name'].'/res/'. number_format($files_board_res) . ''. ConvertBytes($spaceused_board_res) . '
src/'. number_format($files_board_src) . ''. ConvertBytes($spaceused_board_src) . '
thumb/'. number_format($files_board_thumb) . ''. ConvertBytes($spaceused_board_thumb) . '
'. _gettext('Total') .''. number_format($files_board_total) . ''. ConvertBytes($spaceused_board_total) . '
'. _gettext('All boards') .'res/'. number_format($files_res) . ''. ConvertBytes($spaceused_res) . '
src/'. number_format($files_src) . ''. ConvertBytes($spaceused_src) . '
thumb/'. number_format($files_thumb) . ''. ConvertBytes($spaceused_thumb) . '
'. _gettext('Total') .''. number_format($files_total) . ''. ConvertBytes($spaceused_total) . '
'; + management_addlogentry(_gettext('Viewed disk space used'), 0); + } + + function staff() { //183 lines + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + + $tpl_page .= '

' ._gettext('Staff'). '


'; + if (isset($_GET['add']) && !empty($_POST['username']) && !empty($_POST['password'])) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" .KU_DBPREFIX. "staff` WHERE `username` = " .$tc_db->qstr($_POST['username'])); + if (count($results) == 0) { + if ($_POST['type'] < 3 && $_POST['type'] >= 0) { + $this->CheckToken($_POST['token']); + $salt = $this->CreateSalt(); + $tc_db->Execute("INSERT HIGH_PRIORITY INTO `" .KU_DBPREFIX. "staff` ( `username` , `password` , `salt` , `type` , `addedon` ) VALUES (" .$tc_db->qstr($_POST['username']). " , '" .md5($_POST['password'] . $salt). "' , '" .$salt. "' , '" .$_POST['type']. "' , '" .time(). "' )"); + $log = _gettext('Added'). ' '; + switch ($_POST['type']) { + case 0: + $log .= _gettext('Janitor'); + break; + case 1: + $log .= _gettext('Administrator'); + break; + case 2: + $log .= _gettext('Moderator'); + break; + } + $log .= ' '. $_POST['username']; + management_addlogentry($log, 6); + $tpl_page .= _gettext('Staff member successfully added.'); + } else { + exitWithErrorPage('Invalid type'); + } + } else { + $tpl_page .= _gettext('A staff member with that ID already exists.'); + } + } elseif (isset($_GET['del']) && $_GET['del'] > 0) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "staff` WHERE `id` = " . $tc_db->qstr($_GET['del']) . ""); + if (count($results) > 0) { + $username = $results[0]['username']; + $tc_db->Execute("DELETE FROM `" . KU_DBPREFIX . "staff` WHERE `id` = " . $tc_db->qstr($_GET['del']) . ""); + $tpl_page .= _gettext('Staff successfully deleted') . '
'; + management_addlogentry(_gettext('Deleted staff member') . ': '. $username, 6); + } else { + $tpl_page .= _gettext('Invalid staff ID.'); + } + } elseif (isset($_GET['edit']) && $_GET['edit'] > 0) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "staff` WHERE `id` = " . $tc_db->qstr($_GET['edit']) . ""); + if (count($results) > 0) { + if (isset($_POST['submitting'])) { + $this->CheckToken($_POST['token']); + $username = $results[0]['username']; + $type = $results[0]['type']; + $boards = array(); + if (isset($_POST['modsallboards'])) { + $newboards = array('allboards'); + } else { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY name FROM `" . KU_DBPREFIX . "boards`"); + foreach ($results as $line) { + $boards = array_merge($boards, array($line['name'])); + } + $changed_boards = array(); + $newboards = array(); + while (list($postkey, $postvalue) = each($_POST)) { + if (substr($postkey, 0, 8) == "moderate") { + $changed_boards = array_merge($changed_boards, array(substr($postkey, 8))); + } + } + while (list(, $thisboard_name) = each($boards)) { + if (in_array($thisboard_name, $changed_boards)) { + $newboards = array_merge($newboards, array($thisboard_name)); + } + } + } + $logentry = _gettext('Updated staff member') . ' - '; + if ($_POST['type'] == '1') { + $logentry .= _gettext('Administrator'); + } elseif ($_POST['type'] == '2') { + $logentry .= _gettext('Moderator'); + } elseif ($_POST['type'] == '0') { + $logentry .= _gettext('Janitor'); + } else { + exitWithErrorPage('Something went wrong.'); + } + $logentry .= ': '. $username; + if ($_POST['type'] != '1') { + $logentry .= ' - '. _gettext('Moderates') . ': '; + if (isset($_POST['modsallboards'])) { + $logentry .= strtolower(_gettext('All boards')); + } else { + $logentry .= '/'. implode('/, /', $newboards) . '/'; + } + } + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "staff` SET `boards` = " . $tc_db->qstr(implode('|', $newboards)) . " , `type` = " .$tc_db->qstr($_POST['type']). " WHERE `id` = " . $tc_db->qstr($_GET['edit']) . ""); + management_addlogentry($logentry, 6); + $tpl_page .= _gettext('Staff successfully updated') . '
'; + } + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "staff` WHERE `id` = '" . $_GET['edit'] . "'"); + $username = $results[0]['username']; + $type = $results[0]['type']; + $boards = explode('|', $results[0]['boards']); + + $tpl_page .= '
+ + +
+ +

'; + + $tpl_page .= _gettext('Moderates') . '
+ '. "\n"; + $tpl_page .= ($boards==array('allboards')) ? '' : ''; + $tpl_page .= '
' ._gettext('or'). '
'; + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "boards`"); + foreach ($results as $line) { + $tpl_page .= ' +

'; + } + } + + $tpl_page .= '
+ + +
+ +
+ +
+ + +
+

'; + + $tpl_page .= ''. "\n"; + $i = 1; + while($i <= 3) { + if ($i == 1) { + $stafftype = 'Administrator'; + $numtype = 1; + } elseif ($i == 2) { + $stafftype = 'Moderator'; + $numtype = 2; + } elseif ($i == 3) { + $stafftype = 'Janitor'; + $numtype = 0; + } + $tpl_page .= ''. "\n"; + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "staff` WHERE `type` = '" .$numtype. "' ORDER BY `username` ASC"); + if (count($results) > 0) { + foreach ($results as $line) { + $tpl_page .= ''. "\n"; + } + } else { + $tpl_page .= ''. "\n"; + } + $i++; + } + $tpl_page .= '
'. _gettext('Username') . ''. _gettext('Added on') . ''. _gettext('Last active') . ''. _gettext('Moderating boards') . ' 
'. _gettext($stafftype) . '
' .$line['username']. '' .date("y/m/d(D)H:i", $line['addedon']). ''; + if ($line['lastactive'] == 0) { + $tpl_page .= _gettext('Never'); + } elseif ((time() - $line['lastactive']) > 300) { + $tpl_page .= timeDiff($line['lastactive'], false); + } else { + $tpl_page .= _gettext('Online now'); + } + $tpl_page .= ''; + if ($line['boards'] != '' || $line['type'] == 1) { + if ($line['boards'] == 'allboards' || $line['type'] == 1) { + $tpl_page .= _gettext('All boards') ; + } else { + $tpl_page .= '/'. implode('/, /', explode('|', $line['boards'])) . '/'; + } + } else { + $tpl_page .= _gettext('No boards'); + } + $tpl_page .= '['. _gettext('Edit') . '] ['. _gettext('Delete') .']
'. _gettext('None') . '
'; + } + + /* Display moderators and administrators actions which were logged */ + function modlog() { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + + $tc_db->Execute("DELETE FROM `" . KU_DBPREFIX . "modlog` WHERE `timestamp` < '" . (time() - KU_MODLOGDAYS * 86400) . "'"); + + $tpl_page .= '

'. ('ModLog') . '


+ '; + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "modlog` ORDER BY `timestamp` DESC"); + foreach ($results as $line) { + $tpl_page .= ""; + } + $tpl_page .= '
'. _gettext('Time') .''. _gettext('User') .''. _gettext('Action') .'
" . date("y/m/d(D)H:i", $line['timestamp']) . "" . $line['user'] . "" . $line['entry'] . "
'; + } + + function proxyban() { + global $tpl_page; + $this->AdministratorsOnly(); + + $tpl_page .= '

'. _gettext('Ban proxy list') . '


'; + if (isset($_FILES['imagefile'])) { + $bans_class = new Bans; + $ips = 0; + $successful = 0; + $proxies = file($_FILES['imagefile']['tmp_name']); + foreach($proxies as $proxy) { + if (preg_match('/.[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+.*/', $proxy)) { + $proxy = trim($proxy); + $ips++; + if ($bans_class->BanUser(preg_replace('/:.*/', '', $proxy), 'SERVER', 1, 0, '', 'IP from proxylist automatically banned', '', 0, 0, 1, true)) { + $successful++; + } + } + } + management_addlogentry(sprintf(_gettext('Banned %d IP addresses using an IP address list.'), $successful), 8); + $tpl_page .= $successful . ' of '. $ips . ' IP addresses banned.'; + } else { + $tpl_page .= '
'. _gettext('Proxy list') .'
+ +
'. _gettext('The proxy list is assumed to be in plaintext *.*.*.*:port or *.*.*.* format, one IP per line.') .'


'; + } + } + + function sql() { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + + $tpl_page .= '

'. _gettext('SQL query') . '


'; + if (isset($_POST['query'])) { + $this->CheckToken($_POST['token']); + $tpl_page .= '
'; + $result = $tc_db->Execute($_POST['query']); + if ($result) { + $tpl_page .= _gettext('Query executed successfully'); + } else { + $tpl_page .= 'Error: '. $tc_db->ErrorMsg(); + } + $tpl_page .= '
'; + management_addlogentry(_gettext('Inserted SQL'), 0); + } + $tpl_page .= ' + + +

+ + +
'; + } + + function cleanup() { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + $tpl_page .= '

'. _gettext('Cleanup') . '


'; + + if (isset($_POST['run'])) { + $tpl_page .= '
'. _gettext('Deleting non-deleted replies which belong to deleted threads.') .'
'; + $this->delorphanreplies(true); + $tpl_page .= '
'. _gettext('Deleting unused images.') .'
'; + $this->delunusedimages(true); + $tpl_page .= '
'. _gettext('Removing posts deleted more than one week ago from the database.') .'
'; + $results = $tc_db->GetAll("SELECT `name`, `type`, `id` FROM `" . KU_DBPREFIX . "boards`"); + foreach ($results AS $line) { + if ($line['type'] != 1) { + $tc_db->Execute("DELETE FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $line['id'] . " AND `IS_DELETED` = 1 AND `deleted_timestamp` < " . (time() - 604800) . ""); + } + } + $tpl_page .= _gettext('Optimizing all tables in database.') .'
'; + if (KU_DBTYPE == 'mysql' || KU_DBTYPE == 'mysqli') { + $results = $tc_db->GetAll("SHOW TABLES"); + foreach ($results AS $line) { + $tc_db->Execute("OPTIMIZE TABLE `" . $line[0] . "`"); + } + } + if (KU_DBTYPE == 'postgres7' || KU_DBTYPE == 'postgres8' || KU_DBTYPE == 'postgres') { + $results = $tc_db->GetAll("SELECT table_name FROM information_schema.tables WHERE table_schema='public' AND table_type='BASE TABLE'"); + foreach ($results AS $line) { + $tc_db->Execute("VACUUM ANALYZE `" . $line[0] . "`"); + } + } + $tpl_page .= _gettext('Cleanup finished.'); + management_addlogentry(_gettext('Ran cleanup'), 2); + } else { + $tpl_page .= '
'. "\n" . + ' '. "\n" . + '
'; + } + } + + /* + * +------------------------------------------------------------------------------+ + * Boards Administration Pages + * +------------------------------------------------------------------------------+ + */ + + function adddelboard() { + global $tc_db, $tpl_page, $board_class; + $this->AdministratorsOnly(); + + if (isset($_POST['directory'])) { + $this->CheckToken($_POST['token']); + if (isset($_POST['add'])) { + $tpl_page .= $this->addBoard($_POST['directory'], $_POST['desc']); + } elseif (isset($_POST['del'])) { + if (isset($_POST['confirmation'])) { + $tpl_page .= $this->delBoard($_POST['directory'], $_POST['confirmation']); + } else { + $tpl_page .= $this->delBoard($_POST['directory']); + } + } + } + $tpl_page .= '

'. _gettext('Add board') . '


+
+ + + + +
'. _gettext('The directory of the board.') . ' '. _gettext('Only put in the letter(s) of the board directory, no slashes!') . '

+ + + +
'. _gettext('The name of the board.') . '

+ + + +
'. _gettext('The first post of this board will recieve this ID.') . '

+ + + +


+ +

'. _gettext('Delete board') .'


+ +
+ + + ' . + $this->MakeBoardListDropdown('directory', $this->BoardList($_SESSION['manageusername'])) . + '
+ + + +
'; + } + + function addBoard($dir, $desc) { + global $tc_db; + $this->AdministratorsOnly(); + + $output = ''; + $output .= '

'. _gettext('Add Results') .'


'; + $dir = cleanBoardName($dir); + if ($dir != '' && $desc != '') { + if (strtolower($dir) != 'allboards') { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($dir) . ""); + if (count($results) == 0) { + if (mkdir(KU_BOARDSDIR . $dir, 0777) && mkdir(KU_BOARDSDIR . $dir . '/res', 0777) && mkdir(KU_BOARDSDIR . $dir . '/src', 0777) && mkdir(KU_BOARDSDIR . $dir . '/thumb', 0777)) { + file_put_contents(KU_BOARDSDIR . $dir . '/.htaccess', 'DirectoryIndex '. KU_FIRSTPAGE . ''); + file_put_contents(KU_BOARDSDIR . $dir . '/src/.htaccess', 'AddType text/plain .ASM .C .CPP .CSS .JAVA .JS .LSP .PHP .PL .PY .RAR .SCM .TXT'. "\n" . 'SetHandler default-handler'); + if ($_POST['firstpostid'] < 1) { + $_POST['firstpostid'] = 1; + } + $tc_db->Execute("INSERT INTO `" . KU_DBPREFIX . "boards` ( `name` , `desc` , `createdon`, `start`, `image`, `includeheader` ) VALUES ( " . $tc_db->qstr($dir) . " , " . $tc_db->qstr($desc) . " , '" . time() . "', " . $_POST['firstpostid'] . ", '', '' )"); + $boardid = $tc_db->Insert_Id(); + $filetypes = $tc_db->GetAll("SELECT " . KU_DBPREFIX . "filetypes.id FROM " . KU_DBPREFIX . "filetypes WHERE " . KU_DBPREFIX . "filetypes.filetype = 'JPG' OR " . KU_DBPREFIX . "filetypes.filetype = 'GIF' OR " . KU_DBPREFIX . "filetypes.filetype = 'PNG';"); + foreach ($filetypes AS $filetype) { + $tc_db->Execute("INSERT INTO `" . KU_DBPREFIX . "board_filetypes` ( `boardid` , `typeid` ) VALUES ( " . $boardid . " , " . $filetype['id'] . " );"); + } + $board_class = new Board($dir); + $board_class->RegenerateAll(); + unset($board_class); + $output .= _gettext('Board successfully added.') . '

/'. $dir . '/!
'; + $output .= '


'; + management_addlogentry(_gettext('Added board') . ': /'. $dir . '/', 3); + } else { + $output .= '
'. _gettext('Unable to create directories.'); + } + } else { + $output .= _gettext('A board with that name already exists.'); + } + } else { + $output .= _gettext('That name is for internal use. Please pick another.'); + } + } else { + $output .= _gettext('Please fill in all required fields.'); + } + return $output; + } + + function delboard($dir, $confirm = '') { + global $tc_db; + $this->AdministratorsOnly(); + + $output = ''; + $output .= '

'. _gettext('Delete Results') .'


'; + if (!empty($dir)) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($dir) . ""); + foreach ($results as $line) { + $board_id = $line['id']; + $board_dir = $line['name']; + } + if (count($results) > 0) { + if (!empty($confirm)) { + if (removeBoard($board_dir)) { + $tc_db->Execute("DELETE FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = '" . $board_id . "'"); + $tc_db->Execute("DELETE FROM `" . KU_DBPREFIX . "boards` WHERE `id` = '" . $board_id . "'"); + $tc_db->Execute("DELETE FROM `" . KU_DBPREFIX . "board_filetypes` WHERE `boardid` = '" . $board_id . "'"); + require_once KU_ROOTDIR . 'inc/classes/menu.class.php'; + $menu_class = new Menu(); + $menu_class->Generate(); + $output .= _gettext('Board successfully deleted.'); + management_addlogentry(_gettext('Deleted board') .': /'. $dir . '/', 3); + } else { + // Error + $output .= _gettext('Unable to delete board.'); + } + } else { + $output .= sprintf(_gettext('Are you absolutely sure you want to delete %s?'),'/'. $board_dir . '/') . + '
+
+ + + + + + + +

'; + } + } else { + $output .= _gettext('A board with that name does not exist.'); + } + } + $output .= '
'; + + return $output; + } + + /* Replace words in posts with something else */ + function wordfilter() { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + + $tpl_page .= '

'. _gettext('Wordfilter') . '


'; + if (isset($_POST['word'])) { + $this->CheckToken($_POST['token']); + if ($_POST['word'] != '' && $_POST['replacedby'] != '') { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "wordfilter` WHERE `word` = " . $tc_db->qstr($_POST['word']) . ""); + if (count($results) == 0) { + $wordfilter_boards = array(); + + foreach ($results as $line) { + $wordfilter_word = $line['word']; + } + $wordfilter_boards = array(); + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "boards`"); + foreach ($_POST['wordfilter'] as $board) { + $check = $tc_db->GetOne("SELECT `id` FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($board)); + if (!empty($check)) { + $wordfilter_boards[] = $board; + } + } + + $is_regex = (isset($_POST['regex'])) ? '1' : '0'; + + $tc_db->Execute("INSERT HIGH_PRIORITY INTO `" . KU_DBPREFIX . "wordfilter` ( `word` , `replacedby` , `boards` , `time` , `regex` ) VALUES ( " . $tc_db->qstr($_POST['word']) . " , " . $tc_db->qstr($_POST['replacedby']) . " , " . $tc_db->qstr(implode('|', $wordfilter_boards)) . " , '" . time() . "' , '" . $is_regex . "' )"); + + $tpl_page .= _gettext('Word successfully added.'); + management_addlogentry(sprintf(_gettext("Added word to wordfilter: %s - Changes to: %s - Boards: /%s/"),$_POST['word'], $_POST['replacedby'], implode('/, /', $wordfilter_boards)), 11); + } else { + $tpl_page .= _gettext('That word already exists.'); + } + } else { + $tpl_page .= _gettext('Please fill in all required fields.'); + } + $tpl_page .= '
'; + } elseif (isset($_GET['delword'])) { + if ($_GET['delword'] > 0) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "wordfilter` WHERE `id` = " . $tc_db->qstr($_GET['delword']) . ""); + if (count($results) > 0) { + foreach ($results as $line) { + $del_word = $line['word']; + } + $tc_db->Execute("DELETE FROM `" . KU_DBPREFIX . "wordfilter` WHERE `id` = " . $tc_db->qstr($_GET['delword']) . ""); + $tpl_page .= _gettext('Word successfully removed.'); + management_addlogentry(_gettext('Removed word from wordfilter') . ': '. $del_word, 11); + } else { + $tpl_page .= _gettext('That ID does not exist.'); + } + $tpl_page .= '
'; + } + } elseif (isset($_GET['editword'])) { + if ($_GET['editword'] > 0) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "wordfilter` WHERE `id` = " . $tc_db->qstr($_GET['editword']) . ""); + if (count($results) > 0) { + if (!isset($_POST['replacedby'])) { + foreach ($results as $line) { + $tpl_page .= '
+ + +
+ + +
+ + +
'; + + $array_boards = array(); + $resultsboard = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "boards`"); + foreach ($resultsboard as $lineboard) { + $array_boards = array_merge($array_boards, array($lineboard['name'])); + } + foreach ($array_boards as $this_board_name) { + $tpl_page .= ' + +
'; + } + } else { + $this->CheckToken($_POST['token']); + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "wordfilter` WHERE `id` = " . $tc_db->qstr($_GET['editword']) . ""); + if (count($results) > 0) { + foreach ($results as $line) { + $wordfilter_word = $line['word']; + } + $wordfilter_boards = array(); + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "boards`"); + + if (isset($_POST['wordfilter'])){ + foreach ($_POST['wordfilter'] as $board) { + $check = $tc_db->GetOne("SELECT `id` FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($board)); + if (!empty($check)) { + $wordfilter_boards[] = $board; + } + } + } + + $is_regex = (isset($_POST['regex'])) ? '1' : '0'; + + $tc_db->Execute("UPDATE `". KU_DBPREFIX ."wordfilter` SET `replacedby` = " . $tc_db->qstr($_POST['replacedby']) . " , `boards` = " . $tc_db->qstr(implode('|', $wordfilter_boards)) . " , `regex` = '" . $is_regex . "' WHERE `id` = " . $tc_db->qstr($_GET['editword']) . ""); + + $tpl_page .= _gettext('Word successfully updated.'); + management_addlogentry(_gettext('Updated word on wordfilter') . ': '. $wordfilter_word, 11); + } else { + $tpl_page .= _gettext('Unable to locate that word.'); + } + } + } else { + $tpl_page .= _gettext('That ID does not exist.'); + } + $tpl_page .= '
'; + } + } else { + $tpl_page .= '
+ + +
+ + +
+ + +
+ +
'; + + $array_boards = array(); + $resultsboard = $tc_db->GetAll("SELECT HIGH_PRIORITY name FROM `" . KU_DBPREFIX . "boards`"); + $array_boards = array_merge($array_boards, $resultsboard); + $tpl_page .= $this->MakeBoardListCheckboxes('wordfilter', $array_boards) . + + '
+ + + +
+
'; + } + $tpl_page .= '
'; + + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "wordfilter`"); + if ($results > 0) { + $tpl_page .= ''. "\n"; + foreach ($results as $line) { + $tpl_page .= ''. "\n"; + } + $tpl_page .= '
'. _gettext('Word') . ''. _gettext('Replacement') . ''. _gettext('Boards') . ' 
'. $line['word'] . ''. $line['replacedby'] . ''; + if (explode('|', $line['boards']) != '') { + $tpl_page .= '/'. implode('/, /', explode('|', $line['boards'])) . '/ '; + } else { + $tpl_page .= _gettext('No boards'); + } + $tpl_page .= '['. _gettext('Edit') . '] ['. _gettext('Delete') .']
'; + } + } + + /* Ad Management */ + function ads() { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + + $tpl_page .= '

'. _gettext('Ad Management') .'

'. _gettext('Anything can go here, such as banners, links, etc. It doesn\'t have to be just ads.') .''. "\n"; + + if (isset($_GET['edit']) && ($_GET['edit'] == 1 || $_GET['edit'] == 2)) { + if (isset($_POST['code']) and !empty($_POST['code'])) { + $this->CheckToken($_POST['token']); + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "ads` SET `disp` = " . $tc_db->qstr($_POST['disp']) . ", `code` = " . $tc_db->qstr($_POST['code']) . " WHERE `id` = " . $tc_db->qstr($_GET['edit']) . ""); + $tpl_page .= '

'. _gettext('Ad Edited.') .'

'.sprintf(_gettext('Click %shere%s to return to Ad Management.'),'','') .'


'. "\n"; + management_addlogentry(_gettext('Edited an ad')); + } + $results = $tc_db->GetAll("SELECT * FROM `" . KU_DBPREFIX . "ads` WHERE `id` = '" . $_GET['edit'] . "'"); + foreach ($results as $ad) { + $tpl_page .= '
'. "\n" . + '' . "\n" . + ''. "\n" . + '
'. "\n" . + ''. "\n" . + '' . "\n" . + ''. "\n" . + '
'. _gettext('Put 0 for no display, 1 to display.') .'

'. "\n" . + '
'. "\n"; + } + } else { + $results = $tc_db->GetAll("SELECT * FROM `" . KU_DBPREFIX . "ads`"); + if (count($results) > 0) { + $tpl_page .= ''. "\n"; + $tpl_page .= ''. "\n"; + foreach ($results as $line) { + $find = array('<', '>'); + $replace = array ('<', '>'); + if ($line['disp'] == 0) { + $disp = 'Not Displayed'; + } elseif ($line['disp'] == 1) { + $disp = _gettext('Displayed'); + } + $tpl_page .= ''. "\n"; + } + $tpl_page .= '
'. _gettext('Position') .''. _gettext('Display') .''. _gettext('Code') .' 
'. $line['position'] . ''. $disp . ''. str_replace($find, $replace, $line['code']) . ''. _gettext('Edit') .'
'. "\n"; + } else { + $tpl_page .= _gettext('There was an error during install, and the ads table didn\'t get populated.'); + } + } + } + + /* Add or delete Embed Entries */ + function embeds() { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + $disptable = true; $formval = 'add'; $title = _gettext('Embed Management'); + if(isset($_GET['act'])) { + if ($_GET['act'] == 'edit') { + if (isset($_POST['embeds'])) { + $this->CheckToken($_POST['token']); + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "embeds` SET `filetype` = " . $tc_db->qstr(trim($_POST['filetype'])) . ", `videourl` = " . $tc_db->qstr(trim($_POST['videourl'])) . ", `name` = " . $tc_db->qstr(trim($_POST['name'])) . ", `width` = " . $tc_db->qstr(trim($_POST['width'])) . ", `height` = " . $tc_db->qstr(trim($_POST['height'])) . ", `code` = " . $tc_db->qstr(trim($_POST['embeds'])) . " WHERE `id` = " . $tc_db->qstr($_GET['id']) . ""); + $tpl_page .= '

'. _gettext('Embed Edited') .'


'; + management_addlogentry(_gettext('Edited an embed'), 9); + } + $formval = 'edit&id='. $_GET['id']; $title .= ' - Edit'; + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "embeds` WHERE `id` = " . $tc_db->qstr($_GET['id']) . ""); + $values = $results[0]; + $disptable = false; + } elseif ($_GET['act'] == 'del') { + $results = $tc_db->Execute("DELETE FROM `" . KU_DBPREFIX . "embeds` WHERE `id` = " . $tc_db->qstr($_GET['id']) . ""); + $tpl_page .= '

'. _gettext('Embed deleted') .'


'; + management_addlogentry(_gettext('Deleted an Embed'), 9); + } elseif ($_GET['act'] == 'add') { + if (isset($_POST['embeds']) && isset($_POST['name']) && isset($_POST['filetype']) && isset($_POST['videourl'])) { + if ($_POST['embeds'] != '') { + $this->CheckToken($_POST['token']); + $width = ($_POST['width'] != '') ? $_POST['width'] : KU_YOUTUBEWIDTH; + $height = ($_POST['height'] != '') ? $_POST['height'] : KU_YOUTUBEHEIGHT; + + $tpl_page .= '
'; + if ($_POST['embeds'] != '') { + $tc_db->Execute("INSERT HIGH_PRIORITY INTO `" . KU_DBPREFIX . "embeds` ( `name` , `filetype` , `videourl` , `width` , `height` , `code` ) VALUES ( " . $tc_db->qstr(trim($_POST['name'])) . " , " . $tc_db->qstr(trim($_POST['filetype'])) . " , " . $tc_db->qstr(trim($_POST['videourl'])) . " , " . $tc_db->qstr(trim($width)) . " , " . $tc_db->qstr(trim($height)) . " , " . $tc_db->qstr(trim($_POST['embeds'])) . " )"); + $tpl_page .= '

'. _gettext('Embed successfully added.') . '

'; + management_addlogentry(_gettext('Added an Embed'), 9); + } else { + $tpl_page .= _gettext('You must enter code.'); + } + $tpl_page .= '
'; + } + } + } + } + $tpl_page .= '

'. $title . '


+ + + + +
'. _gettext('Can not be left blank.') . '

+ + + +
'. _gettext('Can not be left blank, or longer than 3 characters') . '

+ + + +
'. _gettext('Can not be left blank. This is what comes before the embed ID. Example: \'http://www.youtube.com/watch?v=\'') . '

+ + +
+ + + +
'. _gettext('This can be left blank. It will be reset with the default width set in config.php') . '

+ + + +
'. _gettext('This can be left blank. It will be reset with the default height set in config.php') . '

+ +
'. _gettext('When adding an embed, please check http://www.kusabax.org/wiki/embedding and check if there is a tutorial image for the site you are adding. Put this image in the /inc/embedhelp/ folder, or create your own in this folder if one does not exist. The image must be the same as the site name in all lowercase.') . '

+ +
'; + if ($disptable) { + $tpl_page .= '

'. _gettext('Edit/Delete Embeds') .'

'; + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "embeds` ORDER BY `id` ASC"); + if (count($results) > 0) { + $find = array('<', '>'); + $replace = array ('<', '>'); + $tpl_page .= ''; + foreach ($results as $line) { + $tpl_page .= ''; + } + $tpl_page .= '
'. _gettext('Site Name') .''. _gettext('Filetype') .''. _gettext('Video URL Start') .''. _gettext('Width') .''. _gettext('Height') .''. _gettext('Code') .'
'. $line['name'] . ''. $line['filetype'] . ''. $line['videourl'] . ''. $line['width'] . ''. $line['height'] . ''. str_replace($find, $replace, $line['code']) . '['. _gettext('Edit') .'] ['. _gettext('Delete') .']
'; + } else { + $tpl_page .= _gettext('No Embeds yet.'); + } + } + } + + + function movethread() { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + + $tpl_page .= '

'. _gettext('Move thread') . '


'; + + if (isset($_POST['id']) && isset($_POST['board_from']) && isset($_POST['board_to'])) { + $this->CheckToken($_POST['token']); + // Get the IDs for the from and to boards + $board_from_id = $tc_db->GetOne("SELECT HIGH_PRIORITY `id` FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($_POST['board_from']) . ""); + $board_to_id = $tc_db->GetOne("SELECT HIGH_PRIORITY `id` FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($_POST['board_to']) . ""); + $board_from = $_POST['board_from']; + $board_to = $_POST['board_to']; + $id = $tc_db->qstr($_POST['id']); + + if (isset($_POST['mf'])) { + $image = $tc_db->GetOne("SELECT `file` FROM " .KU_DBPREFIX. "posts WHERE `boardid` = " .$board_from_id. " AND `id` = " .$id); + $filetype = $tc_db->GetOne("SELECT `file_type` FROM " .KU_DBPREFIX. "posts WHERE `boardid` = " .$board_from_id. " AND `id` = " .$id); + $from_pic = KU_BOARDSDIR . $board_from . '/src/'. $image . '.'. $filetype; + $from_thumb = KU_BOARDSDIR . $board_from . '/thumb/'. $image . 's'. '.'. $filetype; + $from_cat = KU_BOARDSDIR . $board_from . '/thumb/'. $image . 'c'. '.'. $filetype; + $to_pic = KU_BOARDSDIR . $board_to . '/src/'. $image . '.'. $filetype; + $to_thumb = KU_BOARDSDIR . $board_to . '/thumb/'. $image . 's'. '.'. $filetype; + $to_cat = KU_BOARDSDIR . $board_to . '/thumb/'. $image . 'c'. '.'. $filetype; + @rename($from_pic, $to_pic); + @rename($from_thumb, $to_thumb); + @rename($from_cat, $to_cat); + @unlink($from_pic); + @unlink($from_thumb); + @unlink($from_cat); + } + + $from_html = KU_BOARDSDIR . $board_from . '/res/'. $_POST['id'] . '.html'; + $from_html_50 = KU_BOARDSDIR . $board_from . '/res/'. $_POST['id'] . '+50.html'; + $from_html_100 = KU_BOARDSDIR . $board_from . '/res/'. $_POST['id'] . '-100.html'; + @unlink($from_html); + @unlink($from_html_50); + @unlink($from_html_100); + + $tc_db->Execute("START TRANSACTION"); + $new_id = $tc_db->GetOne("SELECT COALESCE(MAX(id),0) + 1 FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $board_to_id); + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "posts` SET `id` = " . $new_id . ", `boardid` = " .$board_to_id. " WHERE `boardid` = " .$board_from_id. " AND `id` = " . $id); + processPost($new_id, $new_id, $id, $board_from, $board_to, $board_to_id); + + $results = $tc_db->GetAll("SELECT `id` FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " .$board_from_id. " AND `parentid` = " . $id . " ORDER BY `id` ASC"); + foreach ($results as $line) { + if (isset($_POST['mf'])) { + $image = $tc_db->GetOne("SELECT `file` FROM `" .KU_DBPREFIX. "posts` WHERE `boardid` = " .$board_from_id. " AND `id` = " .$line['id']); + $filetype = $tc_db->GetOne("SELECT `file_type` FROM `" .KU_DBPREFIX. "posts` WHERE `boardid` = " .$board_from_id. " AND `id` = " .$line['id']); + $from_pic = KU_BOARDSDIR . $board_from . '/src/'. $image . '.'. $filetype; + $from_thumb = KU_BOARDSDIR . $board_from . '/thumb/'. $image . 's'. '.'. $filetype; + $from_cat = KU_BOARDSDIR . $board_from . '/thumb/'. $image . 'c'. '.'. $filetype; + $to_pic = KU_BOARDSDIR . $board_to . '/src/'. $image . '.'. $filetype; + $to_thumb = KU_BOARDSDIR . $board_to . '/thumb/'. $image . 's'. '.'. $filetype; + $to_cat = KU_BOARDSDIR . $board_to . '/thumb/'. $image . 'c'. '.'. $filetype; + @rename($from_pic, $to_pic); + @rename($from_thumb, $to_thumb); + @rename($from_cat, $to_cat); + @unlink($from_pic); + @unlink($from_thumb); + @unlink($from_cat); + } + $insert_id = $tc_db->GetOne("SELECT COALESCE(MAX(id),0) + 1 FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $board_to_id); + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "posts` SET `id` = " . $insert_id . ", `boardid` = " .$board_to_id. " WHERE `boardid` = " .$board_from_id. " AND `id` = " . $line['id']); + processPost($insert_id, $new_id, $id, $board_from, $board_to, $board_to_id); + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "posts` SET `parentid` = " . $new_id . " WHERE `boardid` = " . $board_to_id . " AND `id` = " . $insert_id); + } + + $tc_db->Execute("COMMIT"); + + $board_class = new Board($board_from); + $board_class->RegenerateThreads(); + $board_class->RegeneratePages(); + unset($board_class); + + $board_class = new Board($board_to); + $board_class->RegenerateThreads(); + $board_class->RegeneratePages(); + unset($board_class); + + $tpl_page .= _gettext('Move complete.') . '

'; + } + + $tpl_page .= '
+ + + + +
+ + ' . + $this->MakeBoardListDropdown('board_from', $this->BoardList($_SESSION['manageusername'])) . + '
+ + ' . + $this->MakeBoardListDropdown('board_to', $this->BoardList($_SESSION['manageusername'])) . + '
+ +
+ '; + } + + /* Search for posts by IP */ + function ipsearch() { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + + $tpl_page .= '

'. _gettext('IP Address Search') .'


'. "\n"; + + if (isset($_GET['ip']) && !empty($_GET['board'])) { + if ($_GET['board'] == 'all') { + $queryextra = ""; + } else { + $queryextra = "`boardid` IN (" . $tc_db->GetOne("SELECT HIGH_PRIORITY `id` FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($_GET['board']) . "") . ") AND"; + } + + $results = $tc_db->GetAll("SELECT `" . KU_DBPREFIX . "posts`.`id` AS id, `" . KU_DBPREFIX . "posts`.`parentid` AS parentid, `" . KU_DBPREFIX . "posts`.`ip` AS ip, `" . KU_DBPREFIX . "posts`.`message` AS message, `" . KU_DBPREFIX . "posts`.`file` AS file, `" . KU_DBPREFIX . "posts`.`file_type` AS file_type, `" . KU_DBPREFIX . "boards`.`name` AS boardname FROM `" . KU_DBPREFIX . "posts`, `" . KU_DBPREFIX . "boards` WHERE ".$queryextra." `ipmd5` = '" . md5($_GET['ip']) . "' AND `IS_DELETED` = 0 AND `" . KU_DBPREFIX . "boards`.`id` = `" . KU_DBPREFIX . "posts`.`boardid` ORDER BY `boardid`"); + if (count($results) > 0) { + foreach ($results as $line) { + $tpl_page .= ''. "\n" . + ''. "\n"; + + $real_parentid = ($line['parentid'] == 0) ? $line['id'] : $line['parentid']; + + $tpl_page .= ''; + } + $tpl_page .= '
'. _gettext('Post Number') .''. _gettext('File') .''. _gettext('Message') .''. _gettext('IP Address') .'
/'. $line['boardname'] . '/'. $line['id'] . ''. (($line['file_type'] == 'jpg' || $line['file_type'] == 'gif' || $line['file_type'] == 'png') ? ('') : ('')) . ''. $line['message'] . ''. md5_decrypt($line['ip'], KU_RANDOMSEED) . '
'. "\n"; + } else { + $tpl_page .= _gettext('No results found for') .' '. $_GET['ip'] . '
'. "\n"; + } + } else { + $tpl_page .= ''. "\n" . + ''. "\n" . + ''. "\n" . + $this->MakeBoardListDropdown('board', $this->BoardList($_SESSION['manageusername']), true) . '
'. "\n" . + ''. "\n" . + '
'. "\n" . + ''. "\n"; + } + } + + /* Search for text in posts */ + function search() { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + + if (isset($_GET['query'])) { + $search_query = $_GET['query']; + if (isset($_GET['s'])) { + $s = $_GET['s']; + } else { + $s = 0; + } + $search_query_array = explode('KUSABA_AND', $search_query); + $trimmed = trim($search_query); + $limit = 10; + if ($trimmed == '') { + $tpl_page .= _gettext('Please enter a search query.'); + exit; + } + $boardlist = $this->BoardList($_SESSION['manageusername']); + $likequery = ''; + foreach ($search_query_array as $search_split) { + $likequery .= "`message` LIKE " . $tc_db->qstr(str_replace('_', '\_', $search_split)) . " AND "; + } + $likequery = substr($likequery, 0, -4); + $query = ''; + $query .= "SELECT `" . KU_DBPREFIX . "posts`.`id` AS id, `" . KU_DBPREFIX . "posts`.`parentid` AS parentid, `" . KU_DBPREFIX . "posts`.`message` AS message, `" . KU_DBPREFIX . "boards`.`name` AS boardname FROM `" . KU_DBPREFIX . "posts`, `" . KU_DBPREFIX . "boards` WHERE `IS_DELETED` = 0 AND " . $likequery . " AND `" . KU_DBPREFIX . "boards`.`id` = `" . KU_DBPREFIX . "posts`.`boardid` ORDER BY `timestamp` DESC"; + + $numresults = $tc_db->GetAll($query); + $numrows = count($numresults); + if ($numrows == 0) { + $tpl_page .= '

'. _gettext('Results') . '

'; + $tpl_page .= '

'. _gettext('Sorry, your search returned zero results.') . '

'; + } else { + $query .= " LIMIT $limit OFFSET $s"; + $results = $tc_db->GetAll($query); + $tpl_page .= '

'. _gettext('Results for') .': '. $search_query . '

'; + $count = 1 + $s; + foreach ($results as $line) { + $tpl_page .= ''. $count . '. '. _gettext('Board') .': /'. $line['boardname'] . '/, '; + } else { + $tpl_page .= $line['parentid'] . '.html#'. $line['id'] . '">'; + } + + if ($line['parentid'] == 0) { + $tpl_page .= _gettext('Thread') .' #'. $line['id']; + } else { + $tpl_page .= _gettext('Thread') .' #'. $line['parentid'] . ', Post #'. $line['id']; + } + $tpl_page .= ''; + + $regexp = '/('; + foreach ($search_query_array as $search_word) { + $regexp .= preg_quote($search_word) . '|'; + } + $regexp = substr($regexp, 0, -1) . ')/'; + //$line['message'] = preg_replace_callback($regexp, array(&$this, 'search_callback'), stripslashes($line['message'])); + $line['message'] = stripslashes($line['message']); + $tpl_page .= '
'. $line['message'] . '

'; + $count++; + } + $currPage = (($s / $limit) + 1); + $tpl_page .= '
'; + if ($s >= 1) { + $prevs = ($s - $limit); + $tpl_page .= " << "._gettext('Prev')." 10  "; + } + $pages = intval($numrows / $limit); + if ($numrows % $limit) { + $pages++; + } + if (!((($s + $limit) / $limit) == $pages) && $pages != 1) { + $news = $s + $limit; + $tpl_page .= " "._gettext('Next')." 10 >>"; + } + + $a = $s + ($limit); + if ($a > $numrows) { + $a = $numrows; + } + $b = $s + 1; + + $tpl_page .= $this->search_results_display($a, $b, $numrows); + } + } + + $tpl_page .= ' + + + + '. _gettext('Query') .':


+ +

'. _gettext('Search Help') .'

+ + '. _gettext('Separate search terms with the word KUSABA_AND') .'

+ + '. _gettext('To find a single phrase anywhere in a post\'s message, use:') .'
+ %'. _gettext('some phrase here') .'%

+ + '. _gettext('To find a phrase at the beginning of a post\'s message:') .'
+ '. _gettext('some phrase here') .'%

+ + '. _gettext('To find a phrase at the end of a post\'s message:') .'
+ %'. _gettext('some phrase here') .'

+ + '. _gettext('To find two phrases anywhere in a post\'s message, use:') .'
+ %'. _gettext('first phrase here') .'%KUSABA_AND%'. _gettext('second phrase here') .'%

+ +
'; + } + function search_callback($matches) { + print_r($matches); + return ''. $matches[0] . ''; + } + + function search_results_display($a, $b, $numrows) { + return '

'. _gettext('Results') . ' '. $b . ' to '. $a . ' of '. $numrows . '

'. "\n" . + '
'; + } + // Credits to Eman for this code + function viewthread() { + global $tc_db, $tpl_page; + $tpl_page .= '

'. _gettext('View Threads (including deleted)') .'

'; + $board = isset($_GET['board']) ? $_GET['board'] : ''; + $thread = isset($_GET['thread']) ? $_GET['thread'] : ''; + if (!$thread ) { + $thread = "0"; + } + if (!$board) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `name`, `id` FROM `". KU_DBPREFIX . "boards` ORDER BY `name` ASC"); + $tpl_page .= " + "; + $tpl_page .= '
'. _gettext('Select Board') .':  '; + } else { + $board_id = $tc_db->GetOne("SELECT HIGH_PRIORITY `id` FROM `". KU_DBPREFIX . "boards` WHERE `name` = ".$tc_db->qstr($board)); + $tpl_page .= " + + + + "; + if ($thread == "0" ) { + $tpl_page .= "

". sprintf(_gettext('All threads on /%s/'), $board) ."

"; + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = $board_id AND (`id` = ".$tc_db->qstr($thread)." OR `parentid` = ".$tc_db->qstr($thread).") ORDER BY `id` DESC LIMIT 500"); + } else { + $tpl_page .= "

". sprintf(_gettext('Thread %s on /%s/'), $thread, $board) ."

"; + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = $board_id AND (`id` = ".$tc_db->qstr($thread)." OR `parentid` = ".$tc_db->qstr($thread).") ORDER BY `id` ASC"); + } + $time = round(microtime(), 5); + $first = "1"; + foreach ($results as $line) { + $bans = ""; + $id = $line['id']; + $ip = md5_decrypt($line['ip'], KU_RANDOMSEED); + $filename = $line['file']; + $file_original = $line['file_original']; + $filetype = $line['file_type']; + $filesize_formatted = $line['file_size_formatted']; + $image_w = $line['image_w']; + $image_h = $line['image_h']; + $message = $line['message']; + $name = $line['name']; + $tripcode = $line['tripcode']; + $timestamp = date(r, $line['timestamp']); + $subject = $line['subject']; + $posterauthority = $line['posterauthority']; + $deleted = isset($line['IS_DELETED']) ? $line['IS_DELETED'] : $line['is_deleted'] ; + if ($thread == "0") { + $view = "[". _gettext('View') ."]"; + } else { + $view = ""; + } + if ($name == "") { + $name = _gettext('Anonymous'); + } else { + $name = "$name"; + } + if ($tripcode != "") { + $tripcode = "!$tripcode"; + } + if ($subject != "") { + $subject = "$subject - "; + } + if ($posterauthority == "1") { + $posterauthority = "##Admin##"; + } elseif ($posterauthority == "2") { + $posterauthority = "##Mod##"; + } else { + $posterauthority = ""; + } + if ($deleted == "1") { + $deleted = "". _gettext('DELETED') ." - "; + } else { + $deleted = ""; + if ($first == "1") { + $bans = "[D & B]"; + } else { + $bans = "[D & B]"; + } + } + + + if ($bans == "") { + $bans = " "; + } + $tpl_page .= " + + + + + + "; + if ($filename != "") { + $tpl_page .= " + + + + "; + } + $tpl_page .= " +
$deleted$subject$name$tripcode $posterauthority $timestamp ". _gettext('No.') ." $id ". _gettext('IP') .": $ip $view $bans +
". _gettext('File') .": $filename.$filetype -( $filesize_formatted, {$image_w}x{$image_h}, $file_original.$filetype )
+ + + "; + + + if ($filename != "") { + $tpl_page .= " + + "; + } + if ($message == "") { + $message = " "; + } + $tpl_page .= "
$message

"; + $first = "0"; + } + $time2 = round(microtime(), 5); + $generation = $time2 - $time; + $generation = abs($generation); + $tpl_page .= ' + '. _gettext('Render Time') .':'. $generation .' '._gettext('Seconds').' + +
'; + } + } + + /* View a thread marked as deleted */ + function viewdeletedthread() { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + + $tpl_page .= '

'. _gettext('View deleted thread') . '


'. "\n"; + + if (isset($_GET['board']) && isset($_GET['threadid']) && $_GET['threadid'] > 0) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($_GET['board']) . ""); + foreach ($results as $line) { + $board_id = $line['id']; + $board_dir = $line['name']; + } + if (count($results) > 0) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "posts_" . $board_dir . "` WHERE `id` = " . $tc_db->qstr($_GET['threadid']) . ""); + foreach ($results as $line) { + $thread_isdeleted = $line['IS_DELETED']; + $thread_parentid = $line['parentid']; + } + if ($thread_isdeleted == 1 && $thread_parentid == 0) { + foreach ($results as $line) { + if ($line['name'] != '') { + $name = $line['name']; + } else { + $name = _gettext('Anonymous') .' '; + } + $tpl_page .= '
'. "\n"; + $tpl_page .= $name . $line['tripcode'] . formatDate($line['postedat']) . ' | '. _gettext('No.') .' '. $line['id'] . ' | '. _gettext('IP') .': '. md5_decrypt($line['ip'], KU_RANDOMSEED) . '
'. "\n"; + if (isset($line['filename'])) { + $tpl_page .= ''. $line['filename'] . '.'. $line['filetype'] . '
'. "\n" . + ''. $line['filename'] . '.'. $line['filetype'] . ''. "\n"; + } + $tpl_page .= $line['message']; + $tpl_page .= '

'; + } + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "posts_" . $board_dir . "` WHERE `parentid` = " . $tc_db->qstr($_GET['threadid']) . ""); + foreach ($results as $line) { + if ($line['name'] != '') { + $name = $line['name'] . ' '; + } else { + $name = _gettext('Anonymous') .' '; + } + $tpl_page .= '
'. "\n"; + $tpl_page .= $name . $line['tripcode'] . formatDate($line['postedat']) . ' | No. '. $line['id'] . ' | IP: '. md5_decrypt($line['ip'], KU_RANDOMSEED) . '
'. "\n"; + if ($line['filename'] != '') { + $tpl_page .= ''. $line['filename'] . '.'. $line['filetype'] . '
'. "\n" . + ''. $line['filename'] . '.'. $line['filetype'] . ''. "\n"; + } + $tpl_page .= $line['message']; + $tpl_page .= '

'; + } + } else { + $tpl_page .= _gettext('That\'s either not a thread, or it\'s not deleted.') ; + } + } + } else { + + $tpl_page .= '
'. "\n" . + ''. "\n" . + ''. "\n" . + $this->MakeBoardListDropdown('board', $this->BoardList($_SESSION['manageusername'])) . "\n" . + '
'. "\n" . + ''. "\n" . + '
'. "\n" . + ''. "\n" . + '
'; + } + } + + /* Add, view, and delete filetypes */ + function editfiletypes() { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + + $tpl_page .= '

'. _gettext('Edit filetypes') . '


'; + if (isset($_GET['do'])) { + if ($_GET['do'] == 'addfiletype') { + if (isset($_POST['filetype']) || isset($_POST['image'])) { + $this->CheckToken($_POST['token']); + if ($_POST['filetype'] != '' && $_POST['image'] != '') { + $tc_db->Execute("INSERT HIGH_PRIORITY INTO `" . KU_DBPREFIX . "filetypes` ( `filetype` , `mime` , `image` , `image_w` , `image_h` ) VALUES ( " . $tc_db->qstr($_POST['filetype']) . " , " . $tc_db->qstr($_POST['mime']) . " , " . $tc_db->qstr($_POST['image']) . " , " . $tc_db->qstr($_POST['image_w']) . " , " . $tc_db->qstr($_POST['image_h']) . " )"); + $tpl_page .= _gettext('Filetype added.'); + } + } else { + $tpl_page .= '
+ + + +
'. _gettext('The extension this will be applied to. Must be lowercase') .'

+ + + +
'. _gettext('The MIME type which must be present with an image uploaded in this type. Leave blank to disable.') .'

+ + + +
'. _gettext('The image which will be used, found in inc/filetypes.') .'

+ + + +
'. _gettext('The width of the image. Needs to be set to prevent the page from jumping around while images load.') .'

+ + + +
'. _gettext('The height of the image. Needs to be set to prevent the page from jumping around while images load.') .'.

+ + + +
'; + } + $tpl_page .= '

'; + } + if ($_GET['do'] == 'editfiletype' && $_GET['filetypeid'] > 0) { + if (isset($_POST['filetype'])) { + if ($_POST['filetype'] != '' && $_POST['image'] != '') { + $this->CheckToken($_POST['token']); + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "filetypes` SET `filetype` = " . $tc_db->qstr($_POST['filetype']) . " , `mime` = " . $tc_db->qstr($_POST['mime']) . " , `image` = " . $tc_db->qstr($_POST['image']) . " , `image_w` = " . $tc_db->qstr($_POST['image_w']) . " , `image_h` = " . $tc_db->qstr($_POST['image_h']) . " WHERE `id` = " . $tc_db->qstr($_GET['filetypeid']) . ""); + if (KU_APC) { + apc_delete('filetype|'. $_POST['filetype']); + } + $tpl_page .= _gettext('Filetype updated.'); + } + } else { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "filetypes` WHERE `id` = " . $tc_db->qstr($_GET['filetypeid']) . ""); + if (count($results) > 0) { + foreach ($results as $line) { + $tpl_page .= '
+ + + +
'. _gettext('The extension this will be applied to. Must be lowercase') .'

+ + + +
'. _gettext('The MIME type which must be present with an image uploaded in this type. Leave blank to disable.') .'

+ + + +
'. _gettext('The image which will be used, found in inc/filetypes.') .'

+ + + +
'. _gettext('The width of the image. Needs to be set to prevent the page from jumping around while images load.') .'

+ + + +
'. _gettext('The height of the image. Needs to be set to prevent the page from jumping around while images load.') .'.

+ + + +
'; + } + } else { + $tpl_page .= _gettext('Unable to locate a filetype with that ID.'); + } + } + $tpl_page .= '

'; + } + if ($_GET['do'] == 'deletefiletype' && $_GET['filetypeid'] > 0) { + $tc_db->Execute("DELETE FROM `" . KU_DBPREFIX . "filetypes` WHERE `id` = " . $tc_db->qstr($_GET['filetypeid']) . ""); + $tpl_page .= _gettext('Filetype deleted.'); + $tpl_page .= '

'; + } + } + $tpl_page .= ''. _gettext('Add filetype') .'

'; + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "filetypes` ORDER BY `filetype` ASC"); + if (count($results) > 0) { + $tpl_page .= ''; + foreach ($results as $line) { + $tpl_page .= ''; + } + $tpl_page .= '
'. _gettext('ID') .''. _gettext('Filetype') .''. _gettext('Image') .''. _gettext('Edit/Delete') .'
'. $line['id'] . ''. $line['filetype'] . ''. $line['image'] . '['. _gettext('Edit') .'] ['. _gettext('Delete') .']
'; + } else { + $tpl_page .= _gettext('There are currently no filetypes.'); + } + } + + /* Add, view, and delete sections */ + function editsections() { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + + $tpl_page .= '

'. _gettext('Edit sections') . '


'; + if (isset($_GET['do'])) { + if ($_GET['do'] == 'addsection') { + if (isset($_POST['name'])) { + if ($_POST['name'] != '' && $_POST['abbreviation'] != '') { + $this->CheckToken($_POST['token']); + $tc_db->Execute("INSERT HIGH_PRIORITY INTO `" . KU_DBPREFIX . "sections` ( `name` , `abbreviation` , `order` , `hidden` ) VALUES ( " . $tc_db->qstr($_POST['name']) . " , " . $tc_db->qstr($_POST['abbreviation']) . " , " . $tc_db->qstr($_POST['order']) . " , '" . (isset($_POST['hidden']) ? '1' : '0') . "' )"); + require_once KU_ROOTDIR . 'inc/classes/menu.class.php'; + $menu_class = new Menu(); + $menu_class->Generate(); + $tpl_page .= _gettext('Section added.'); + } + } else { + $tpl_page .= '
+ +
'. _gettext('The name of the section') .'

+
'. _gettext('Abbreviation (less then 10 characters)') .'

+
'. _gettext('Order to show this section with others, in ascending order') .'

+
'. _gettext('If checked, this section will be collapsed by default when a user visits the site.') .'

+ +
'; + } + $tpl_page .= '

'; + } + if ($_GET['do'] == 'editsection' && $_GET['sectionid'] > 0) { + if (isset($_POST['name'])) { + if ($_POST['name'] != '' && $_POST['abbreviation'] != '') { + $this->CheckToken($_POST['token']); + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "sections` SET `name` = " . $tc_db->qstr($_POST['name']) . " , `abbreviation` = " . $tc_db->qstr($_POST['abbreviation']) . " , `order` = " . $tc_db->qstr($_POST['order']) . " , `hidden` = '" . (isset($_POST['hidden']) ? '1' : '0') . "' WHERE `id` = '" . $_GET['sectionid'] . "'"); + require_once KU_ROOTDIR . 'inc/classes/menu.class.php'; + $menu_class = new Menu(); + $menu_class->Generate(); + $tpl_page .= _gettext('Section updated.'); + } + } else { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "sections` WHERE `id` = " . $tc_db->qstr($_GET['sectionid']) . ""); + if (count($results) > 0) { + foreach ($results as $line) { + $tpl_page .= '
+ + + + + +
'. _gettext('The name of the section') .'

+ + + +
'. _gettext('Abbreviation (less then 10 characters)') .'

+ + + +
'. _gettext('Order to show this section with others, in ascending order') .'

+ + + +
'. _gettext('If checked, this section will be collapsed by default when a user visits the site.') .'

+ + + +
'; + } + } else { + $tpl_page .= _gettext('Unable to locate a section with that ID.'); + } + } + $tpl_page .= '

'; + } + if ($_GET['do'] == 'deletesection' && isset($_GET['sectionid'])) { + if ($_GET['sectionid'] > 0) { + $tc_db->Execute("DELETE FROM `" . KU_DBPREFIX . "sections` WHERE `id` = " . $tc_db->qstr($_GET['sectionid']) . ""); + require_once KU_ROOTDIR . 'inc/classes/menu.class.php'; + $menu_class = new Menu(); + $menu_class->Generate(); + $tpl_page .= _gettext('Section deleted.') . '

'; + } + } + } + $tpl_page .= ''. _gettext('Add section') .'

'; + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "sections` ORDER BY `order` ASC"); + if (count($results) > 0) { + $tpl_page .= ''; + foreach ($results as $line) { + $tpl_page .= ''; + } + $tpl_page .= '
'.('ID') .''.('Order') .''. _gettext('Abbreviation') .''. _gettext('Name') .''. _gettext('Edit/Delete') .'
'. $line['id'] . ''. $line['order'] . ''. $line['abbreviation'] . ''. $line['name'] . '['. _gettext('Edit') .'] ['. _gettext('Delete') .']
'; + } else { + $tpl_page .= _gettext('There are currently no sections.'); + } + } + + /* Rebuild all boards */ + function rebuildall() { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + + $tpl_page .= '

'. _gettext('Rebuild all HTML files') . '


'; + $time_start = time(); + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `id`, `name` FROM `" . KU_DBPREFIX . "boards`"); + foreach ($results as $line) { + $board_class = new Board($line['name']); + $board_class->RegenerateAll(); + $tpl_page .= sprintf(_gettext('Regenerated %s'), '/'. $line['name'] . '/') . '
'; + unset($board_class); + flush(); + } + require_once KU_ROOTDIR . 'inc/classes/menu.class.php'; + $menu_class = new Menu(); + $menu_class->Generate(); + $tpl_page .= _gettext('Regenerated menu pages') .'
'; + $tpl_page .= sprintf(_gettext('Rebuild complete. Took %d seconds.'), time() - $time_start); + management_addlogentry(_gettext('Rebuilt all boards and threads'), 2); + unset($board_class); + } + + /* + * +------------------------------------------------------------------------------+ + * Boards Pages + * +------------------------------------------------------------------------------+ + */ + + function boardopts() { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + + $tpl_page .= '

'. _gettext('Board options') . '


'; + if (isset($_GET['updateboard']) && isset($_POST['order']) && isset($_POST['maxpages']) && isset($_POST['maxage']) && isset($_POST['messagelength'])) { + $this->CheckToken($_POST['token']); + if (!$this->CurrentUserIsModeratorOfBoard($_GET['updateboard'], $_SESSION['manageusername'])) { + exitWithErrorPage(_gettext('You are not a moderator of this board.')); + } + $boardid = $tc_db->GetOne("SELECT HIGH_PRIORITY `id` FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($_GET['updateboard']) . " LIMIT 1"); + if ($boardid != '') { + if ($_POST['order'] >= 0 && $_POST['maxpages'] >= 0 && $_POST['markpage'] >= 0 && $_POST['maxage'] >= 0 && $_POST['messagelength'] >= 0 && ($_POST['defaultstyle'] == '' || in_array($_POST['defaultstyle'], explode(':', KU_STYLES)) || in_array($_POST['defaultstyle'], explode(':', KU_TXTSTYLES)))) { + $filetypes = array(); + while (list($postkey, $postvalue) = each($_POST)) { + if (substr($postkey, 0, 9) == 'filetype_') { + $filetypes[] = substr($postkey, 9); + } + } + $updateboard_enablecatalog = isset($_POST['enablecatalog']) ? '1' : '0'; + $updateboard_enablenofile = isset($_POST['enablenofile']) ? '1' : '0'; + $updateboard_redirecttothread = isset($_POST['redirecttothread']) ? '1' : '0'; + $updateboard_enablereporting = isset($_POST['enablereporting']) ? '1' : '0'; + $updateboard_enablecaptcha = isset($_POST['enablecaptcha']) ? '1' : '0'; + $updateboard_forcedanon = isset($_POST['forcedanon']) ? '1' : '0'; + $updateboard_trial = isset($_POST['trial']) ? '1' : '0'; + $updateboard_popular = isset($_POST['popular']) ? '1' : '0'; + $updateboard_enablearchiving = isset($_POST['enablearchiving']) ? '1' : '0'; + $updateboard_showid = isset($_POST['showid']) ? '1' : '0'; + $updateboard_compactlist = isset($_POST['compactlist']) ? '1' : '0'; + $updateboard_locked = isset($_POST['locked']) ? '1' : '0'; + + if (($_POST['type'] == '0' || $_POST['type'] == '1' || $_POST['type'] == '2' || $_POST['type'] == '3') && ($_POST['uploadtype'] == '0' || $_POST['uploadtype'] == '1' || $_POST['uploadtype'] == '2')) { + if (!($_POST['uploadtype'] != '0' && $_POST['type'] == '3')) { + if(count($_POST['allowedembeds']) > 0) { + $updateboard_allowedembeds = ''; + + $results = $tc_db->GetAll("SELECT `filetype` FROM `" . KU_DBPREFIX . "embeds`"); + foreach ($results as $line) { + if(in_array($line['filetype'], $_POST['allowedembeds'])) { + $updateboard_allowedembeds .= $line['filetype'].','; + } + } + if ($updateboard_allowedembeds != '') { + $updateboard_allowedembeds = substr($updateboard_allowedembeds, 0, -1); + } + } + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "boards` SET `type` = " . $tc_db->qstr($_POST['type']) . " , `uploadtype` = " . $tc_db->qstr($_POST['uploadtype']) . " , `order` = " . $tc_db->qstr(intval($_POST['order'])) . " , `section` = " . $tc_db->qstr(intval($_POST['section'])) . " , `desc` = " . $tc_db->qstr($_POST['desc']) . " , `locale` = " . $tc_db->qstr($_POST['locale']) . " , `showid` = '" . $updateboard_showid . "' , `compactlist` = '" . $updateboard_compactlist . "' , `locked` = '" . $updateboard_locked . "' , `maximagesize` = " . $tc_db->qstr($_POST['maximagesize']) . " , `messagelength` = " . $tc_db->qstr($_POST['messagelength']) . " , `maxpages` = " . $tc_db->qstr($_POST['maxpages']) . " , `maxage` = " . $tc_db->qstr($_POST['maxage']) . " , `markpage` = " . $tc_db->qstr($_POST['markpage']) . " , `maxreplies` = " . $tc_db->qstr($_POST['maxreplies']) . " , `image` = " . $tc_db->qstr($_POST['image']) . " , `includeheader` = " . $tc_db->qstr($_POST['includeheader']) . " , `redirecttothread` = '" . $updateboard_redirecttothread . "' , `anonymous` = " . $tc_db->qstr($_POST['anonymous']) . " , `forcedanon` = '" . $updateboard_forcedanon . "' , `embeds_allowed` = " . $tc_db->qstr($updateboard_allowedembeds) . " , `trial` = '" . $updateboard_trial . "' , `popular` = '" . $updateboard_popular . "' , `defaultstyle` = " . $tc_db->qstr($_POST['defaultstyle']) . " , `enablereporting` = '" . $updateboard_enablereporting . "', `enablecaptcha` = '" . $updateboard_enablecaptcha . "' , `enablenofile` = '" . $updateboard_enablenofile . "' , `enablearchiving` = '" . $updateboard_enablearchiving . "', `enablecatalog` = '" . $updateboard_enablecatalog . "' , `loadbalanceurl` = " . $tc_db->qstr($_POST['loadbalanceurl']) . " , `loadbalancepassword` = " . $tc_db->qstr($_POST['loadbalancepassword']) . " WHERE `name` = " . $tc_db->qstr($_GET['updateboard']) . ""); + $tc_db->Execute("DELETE FROM `" . KU_DBPREFIX . "board_filetypes` WHERE `boardid` = '" . $boardid . "'"); + foreach ($filetypes as $filetype) { + $tc_db->Execute("INSERT INTO `" . KU_DBPREFIX . "board_filetypes` ( `boardid`, `typeid` ) VALUES ( '" . $boardid . "', " . $tc_db->qstr($filetype) . " )"); + } + require_once KU_ROOTDIR . 'inc/classes/menu.class.php'; + $menu_class = new Menu(); + $menu_class->Generate(); + if (isset($_POST['submit_regenerate'])) { + $board_class = new Board($_GET['updateboard']); + $board_class->RegenerateAll(); + } + $tpl_page .= _gettext('Update successful.'); + management_addlogentry(_gettext('Updated board configuration') . " - /" . $_GET['updateboard'] . "/", 4); + } else { + $tpl_page .= _gettext('Sorry, embed may only be enabled on normal imageboards.'); + } + } else { + $tpl_page .= _gettext('Sorry, a generic error has occurred.'); + } + } else { + $tpl_page .= _gettext('Integer values must be entered correctly.'); + } + } else { + $tpl_page .= _gettext('Unable to locate a board named') . ' '. $_GET['updateboard'] . '.'; + } + } elseif (isset($_POST['board'])) { + if (!$this->CurrentUserIsModeratorOfBoard($_POST['board'], $_SESSION['manageusername'])) { + exitWithErrorPage(_gettext('You are not a moderator of this board.')); + } + $resultsboard = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($_POST['board']) . ""); + if (count($resultsboard) > 0) { + foreach ($resultsboard as $lineboard) { + $tpl_page .= '
+
+ '; + /* Directory */ + $tpl_page .= ' + +
'. _gettext('The directory of the board.') .'

'; + + /* Description */ + $tpl_page .= ' + +
'. _gettext('The name of the board.') .'

'; + + /* Locale */ + $tpl_page .= ' + +
'. _gettext('Locale to use on this board. Leave blank to use the locale defined in config.php') .'

'; + + /* Board type */ + $tpl_page .= ' + +
'. _gettext('The type of posts which will be accepted on this board. A normal imageboard will feature image and extended format posts, a text board will have no images, an Oekaki board will allow users to draw images and use them in their posts, and an Upload imageboard will be styled more towards file uploads.') .' '. _gettext('Default') .': Normal Imageboard

'; + + /* Upload type */ + $tpl_page .= ' + +
'. _gettext('Whether or not to allow embedding of videos.') .' '. _gettext('Default') .'.: '. _gettext('No Embedding') .'

'; + + /* Order */ + $tpl_page .= ' + +
'. _gettext('Order to show board in menu list, in ascending order.') .' '. _gettext('Default') .': 0

'; + + /* Section */ + $tpl_page .= '' . + $this->MakeSectionListDropdown('section', $lineboard['section']) . + '
'. _gettext('The section the board is in. This is used for displaying the list of boards on the top and bottom of pages.') .'
'. _gettext('If this is set to Select a Board, it will not be shown in the menu.') .'

'; + + /* Load balancer URL */ + $tpl_page .= ' + +
'. _gettext('The full http:// URL to the load balance script for this board. The script will handle file uploads, and creation of thumbnails. Only one script per board can be used, and there must be a src and thumb dir in the same folder as the script. Set to nothing to disable.') .'

'; + + /* Load balancer password */ + $tpl_page .= ' + +
'. _gettext('The password which will be passed to the script above. The script must have this same password entered at the top, in the configuration area.') .'

'; + + /* Allowed filetypes */ + $tpl_page .= ' +
'. _gettext('What filetypes users are allowed to upload.') .'

'; + $filetypes = $tc_db->GetAll("SELECT HIGH_PRIORITY `id`, `filetype` FROM `" . KU_DBPREFIX . "filetypes` ORDER BY `filetype` ASC"); + foreach ($filetypes as $filetype) { + $tpl_page .= 'GetOne("SELECT HIGH_PRIORITY COUNT(*) FROM `" . KU_DBPREFIX . "board_filetypes` WHERE `boardid` = '" . $lineboard['id'] . "' AND `typeid` = '" . $filetype['id'] . "' LIMIT 1"); + if ($filetype_isenabled == 1) { + $tpl_page .= ' checked'; + } + $tpl_page .= ' />
'; + } + + /* Allowed embeds */ + $tpl_page .= ' +
'. _gettext('What embed sites are allowed on this board. Only useful on board with embedding enabled.') .'

'; + $embeds = $tc_db->GetAll("SELECT HIGH_PRIORITY `id`, `filetype`, `name` FROM `" . KU_DBPREFIX . "embeds` ORDER BY `filetype` ASC"); + foreach ($embeds as $embed) { + $tpl_page .= ' + +
'. _gettext('Maxmimum size of uploaded images, in bytes.') . ' '. _gettext('Default') .': 1024000

'; + + /* Maximum message length */ + $tpl_page .= ' + +
'. _gettext('Default') .': 8192

'; + + /* Maximum board pages */ + $tpl_page .= ' + +
'. _gettext('Default') .': 11

'; + + /* Maximum thread age */ + $tpl_page .= ' + +
'. _gettext('Default') .': 0

'; + + /* Mark page */ + $tpl_page .= ' + +
'. _gettext('Threads which reach this page or further will be marked to be deleted in two hours.') .' '. _gettext('Default') .': 9

'; + + /* Maximum thread replies */ + $tpl_page .= ' + +
'. _gettext('The number of replies a thread can have before autosaging to the back of the board.') . ' '. _gettext('Default') .': 200

'; + + /* Header image */ + $tpl_page .= ' + +
'. _gettext('Overrides the header set in the config file. Leave blank to use configured global header image. Needs to be a full url including http://. Set to none to show no header image.') .'

'; + + /* Include header */ + $tpl_page .= ' + +
'. _gettext('Raw HTML which will be inserted at the top of each page of the board.') .'

'; + + /* Anonymous */ + $tpl_page .= ' + +
'. _gettext('Name to display when a name is not attached to a post.') . ' '. _gettext('Default') .': '. _gettext('Anonymous') .'

'; + + /* Locked */ + $tpl_page .= ' +
'; + + /* Show ID */ + $tpl_page .= ' +
'; + + /* Show ID */ + $tpl_page .= ' +
'; + + /* Enable reporting */ + $tpl_page .= ' + '. _gettext('Reporting allows users to report posts, adding the post to the report list.') .' '. _gettext('Default') .': '. _gettext('Yes') .'

'; + + /* Enable captcha */ + $tpl_page .= ' + '. _gettext('No') .'

'; + + /* Enable archiving */ + $tpl_page .= ' + '. _gettext('No') .'
'; + + /* Enable catalog */ + $tpl_page .= ' + '. _gettext('Yes') .'
'; + + /* Enable "no file" posting */ + $tpl_page .= ' + '. _gettext('No') .'
'; + + /* Redirect to thread */ + $tpl_page .= ' + '.('No') .'
'; + + /* Forced anonymous */ + $tpl_page .= ' + '. _gettext('No') .'
'; + + /* Trial */ + $tpl_page .= ' + '. _gettext('No') .'
'; + + /* Popular */ + $tpl_page .= ' + '. _gettext('No') .'
'; + + /* Default style */ + $tpl_page .= ' + +
'. _gettext('The style which will be set when the user first visits the board.') .' '. _gettext('Default') .': '. _gettext('Use Default') .'

'; + + /* Submit form */ + $tpl_page .= '
+ + +
'; + } + } else { + $tpl_page .= _gettext('Unable to locate a board named') . ' '. $_POST['board'] . '.'; + } + } else { + $tpl_page .= '
+ ' . + $this->MakeBoardListDropdown('board', $this->BoardList($_SESSION['manageusername'])) . + ' +
'; + } + } + + function unstickypost() { + global $tc_db, $tpl_page, $board_class; + $this->ModeratorsOnly(); + + $tpl_page .= '

'. _gettext('Manage stickies') . '


'; + if (isset($_GET['postid']) && isset($_GET['board'])) { + if ($_GET['postid'] > 0 && $_GET['board'] != '') { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `id`, `name` FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($_GET['board']) . ""); + if (count($results) > 0) { + if (!$this->CurrentUserIsModeratorOfBoard($_GET['board'], $_SESSION['manageusername'])) { + exitWithErrorPage(_gettext('You are not a moderator of this board.')); + } + foreach ($results as $line) { + $sticky_board_name = $line['name']; + $sticky_board_id = $line['id']; + } + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $sticky_board_id ." AND `IS_DELETED` = '0' AND `parentid` = '0' AND `id` = " . $tc_db->qstr($_GET['postid']) . ""); + if (count($results) > 0) { + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "posts` SET `stickied` = '0' WHERE `boardid` = " . $sticky_board_id ." AND `parentid` = '0' AND `id` = " . $tc_db->qstr($_GET['postid']) . ""); + $board_class = new Board($sticky_board_name); + $board_class->RegenerateAll(); + unset($board_class); + $tpl_page .= _gettext('Thread successfully un-stickied'); + management_addlogentry(_gettext('Unstickied thread') . ' #' . intval($_GET['postid']) . ' - /' . $sticky_board_name . '/', 5); + } else { + $tpl_page .= _gettext('Invalid thread ID. This may have been caused by the thread recently being deleted.'); + } + } else { + $tpl_page .= _gettext('Invalid board directory.'); + } + $tpl_page .= '
'; + } + } + $tpl_page .= $this->stickyforms(); + } + + function stickypost() { + global $tc_db, $tpl_page, $board_class; + $this->ModeratorsOnly(); + + $tpl_page .= '

'. _gettext('Manage stickies') . '


'; + if (isset($_GET['postid']) && isset($_GET['board'])) { + if ($_GET['postid'] > 0 && $_GET['board'] != '') { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `id`, `name` FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($_GET['board']) . ""); + if (count($results) > 0) { + if (!$this->CurrentUserIsModeratorOfBoard($_GET['board'], $_SESSION['manageusername'])) { + exitWithErrorPage(_gettext('You are not a moderator of this board.')); + } + foreach ($results as $line) { + $sticky_board_name = $line['name']; + $sticky_board_id = $line['id']; + } + $result = $tc_db->GetOne("SELECT HIGH_PRIORITY COUNT(*) FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $sticky_board_id . " AND `IS_DELETED` = '0' AND `parentid` = '0' AND `id` = " . $tc_db->qstr($_GET['postid']) . ""); + if ($result > 0) { + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "posts` SET `stickied` = '1' WHERE `boardid` = " . $sticky_board_id . " AND `parentid` = '0' AND `id` = " . $tc_db->qstr($_GET['postid']) . ""); + $board_class = new Board($sticky_board_name); + $board_class->RegenerateAll(); + unset($board_class); + $tpl_page .= _gettext('Thread successfully stickied.'); + management_addlogentry(_gettext('Stickied thread') . ' #' . intval($_GET['postid']) . ' - /' . $sticky_board_name . '/', 5); + } else { + $tpl_page .= _gettext('Invalid thread ID. This may have been caused by the thread recently being deleted.'); + } + } else { + $tpl_page .= _gettext('Invalid board directory.'); + } + $tpl_page .= '
'; + } + } + $tpl_page .= $this->stickyforms(); + } + + /* Create forms for stickying a post */ + function stickyforms() { + global $tc_db; + + $output = ' + +

'. _gettext('Sticky') . '

'. _gettext('Unsticky') . '


+ +
+ ' . + $this->MakeBoardListDropdown('board', $this->BoardList($_SESSION['manageusername'])) . + '
+ + +
+ + + +
+
'; + $results_boards = $tc_db->GetAll("SELECT HIGH_PRIORITY `name`, `id` FROM `" . KU_DBPREFIX . "boards` ORDER BY `name` ASC"); + foreach ($results_boards as $line_board) { + $output .= '

/'. $line_board['name'] . '/

'; + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `id` FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $line_board['id'] . " AND `IS_DELETED` = '0' AND `parentid` = '0' AND `stickied` = '1'"); + if (count($results) > 0) { + foreach ($results as $line) { + $output .= '#'. $line['id'] . '
'; + } + } else { + $output .= 'No stickied threads.
'; + } + } + $output .= '
'; + + return $output; + } + + function lockpost() { + global $tc_db, $tpl_page, $board_class; + $this->ModeratorsOnly(); + + $tpl_page .= '

'. _gettext('Manage locked threads') . '


'; + if (isset($_GET['postid']) && isset($_GET['board'])) { + if ($_GET['postid'] > 0 && $_GET['board'] != '') { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `id`, `name` FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($_GET['board']) . ""); + if (count($results) > 0) { + if (!$this->CurrentUserIsModeratorOfBoard($_GET['board'], $_SESSION['manageusername'])) { + exitWithErrorPage(_gettext('You are not a moderator of this board.')); + } + foreach ($results as $line) { + $lock_board_name = $line['name']; + $lock_board_id = $line['id']; + } + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $lock_board_id . " AND `IS_DELETED` = '0' AND `parentid` = '0' AND `id` = " . $tc_db->qstr($_GET['postid']) . ""); + if (count($results) > 0) { + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "posts` SET `locked` = '1' WHERE `boardid` = " . $lock_board_id . " AND `parentid` = '0' AND `id` = " . $tc_db->qstr($_GET['postid']) . ""); + $board_class = new Board($lock_board_name); + $board_class->RegenerateAll(); + unset($board_class); + $tpl_page .= _gettext('Thread successfully locked.'); + management_addlogentry(_gettext('Locked thread') . ' #'. intval($_GET['postid']) . ' - /'. intval($_GET['board']) . '/', 5); + } else { + $tpl_page .= _gettext('Invalid thread ID. This may have been caused by the thread recently being deleted.'); + } + } else { + $tpl_page .= _gettext('Invalid board directory.'); + } + $tpl_page .= '
'; + } + } + $tpl_page .= $this->lockforms(); + } + + function unlockpost() { + global $tc_db, $tpl_page, $board_class; + + $tpl_page .= '

'. _gettext('Manage locked threads') . '


'; + if ($_GET['postid'] > 0 && $_GET['board'] != '') { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `id`, `name` FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($_GET['board']) . ""); + if (count($results) > 0) { + if (!$this->CurrentUserIsModeratorOfBoard($_GET['board'], $_SESSION['manageusername'])) { + exitWithErrorPage(_gettext('You are not a moderator of this board.')); + } + foreach ($results as $line) { + $lock_board_name = $line['name']; + $lock_board_id = $line['id']; + } + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $lock_board_id . " AND `IS_DELETED` = '0' AND `parentid` = '0' AND `id` = " . $tc_db->qstr($_GET['postid']) . ""); + if (count($results) > 0) { + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "posts` SET `locked` = '0' WHERE `boardid` = " . $lock_board_id . " AND `parentid` = '0' AND `id` = " . $tc_db->qstr($_GET['postid']) . ""); + $board_class = new Board($lock_board_name); + $board_class->RegenerateAll(); + unset($board_class); + $tpl_page .= _gettext('Thread successfully unlocked.'); + management_addlogentry(_gettext('Unlocked thread') . ' #'. intval($_GET['postid']) . ' - /'. intval($_GET['board']) . '/', 5); + } else { + $tpl_page .= _gettext('Invalid thread ID. This may have been caused by the thread recently being deleted.'); + } + } else { + $tpl_page .= _gettext('Invalid board directory.'); + } + $tpl_page .= '
'; + } + $tpl_page .= $this->lockforms(); + } + + function lockforms() { + global $tc_db; + + $output = ' + +

'. _gettext('Lock') . '

'. _gettext('Unlock') . '


+ +
+ ' . + $this->MakeBoardListDropdown('board', $this->BoardList($_SESSION['manageusername'])) . + '
+ + +
+ + + +
+
'; + $results_boards = $tc_db->GetAll("SELECT HIGH_PRIORITY `id`, `name` FROM `" . KU_DBPREFIX . "boards` ORDER BY `name` ASC"); + foreach ($results_boards as $line_board) { + $output .= '

/'. $line_board['name'] . '/

'; + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `id` FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $line_board['id'] . " AND `IS_DELETED` = '0' AND `parentid` = '0' AND `locked` = '1'"); + if (count($results) > 0) { + foreach ($results as $line) { + $output .= '#'. $line['id'] . '
'; + } + } else { + $output .= 'No locked threads.
'; + } + } + $output .= '
'; + + return $output; + } + + /* Delete a post, or multiple posts */ + function delposts($multidel=false) { + global $tc_db, $tpl_page, $board_class; + + $isquickdel = false; + if (isset($_POST['boarddir']) || isset($_GET['boarddir'])) { + if (!isset($_GET['boarddir']) && isset($_POST['boarddir'])) { + $this->CheckToken($_POST['token']); + } + if (isset($_GET['boarddir'])) { + $isquickdel = true; + $_POST['boarddir'] = $_GET['boarddir']; + if (isset($_GET['delthreadid'])) { + $_POST['delthreadid'] = $_GET['delthreadid']; + } + if (isset($_GET['delpostid'])) { + $_POST['delpostid'] = $_GET['delpostid']; + } + } + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($_POST['boarddir']) . ""); + if (count($results) > 0) { + if (!$this->CurrentUserIsModeratorOfBoard($_POST['boarddir'], $_SESSION['manageusername'])) { + exitWithErrorPage(_gettext('You are not a moderator of this board.')); + } + foreach ($results as $line) { + $board_id = $line['id']; + $board_dir = $line['name']; + } + if (isset($_GET['cp'])) { + $cp = '&cp=y&instant=y'; + } + if (isset($_POST['delthreadid'])) { + if ($_POST['delthreadid'] > 0) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $board_id . " AND `IS_DELETED` = '0' AND `id` = " . $tc_db->qstr($_POST['delthreadid']) . " AND `parentid` = '0'"); + if (count($results) > 0) { + if (isset($_POST['fileonly'])) { + foreach ($results as $line) { + if (!empty($line['file'])) { + $del = unlink(KU_ROOTDIR . $_POST['boarddir'] . '/src/'. $line['file'] . '.'. $line['file_type']); + if ($del) { + @unlink(KU_ROOTDIR . $_POST['boarddir'] . '/thumb/'. $line['file'] . 's.'. $line['file_type']); + @unlink(KU_ROOTDIR . $_POST['boarddir'] . '/thumb/'. $line['file'] . 'c.'. $line['file_type']); + $tc_db->Execute("UPDATE `".KU_DBPREFIX."posts` SET `file` = 'removed', `file_md5` = '' WHERE `boardid` = " . $board_id . " AND `id` = ".$_POST['delthreadid']." LIMIT 1"); + $tpl_page .= '
File successfully deleted
'; + } else { + $tpl_page .= '
That file has already been deleted.
'; + } + } else { + $tpl_page .= '
Error: That thread doesn\'t have a file associated with it.
'; + } + } + } else { + foreach ($results as $line) { + $delthread_id = $line['id']; + } + $post_class = new Post($delthread_id, $board_dir, $board_id); + if (isset($_POST['archive'])) { + $numposts_deleted = $post_class->Delete(true); + } else { + $numposts_deleted = $post_class->Delete(); + } + $board_class = new Board($board_dir); + $board_class->RegenerateAll(); + unset($board_class); + unset($post_class); + $tpl_page .= _gettext('Thread '.$delthread_id.' successfully deleted.'); + management_addlogentry(_gettext('Deleted thread') . ' #'. $delthread_id . ' ('. $numposts_deleted . ' replies) - /'. $board_dir . '/', 7); + if (!empty($_GET['postid'])) { + $tpl_page .= '

'. _gettext('Redirecting') . ' to ban page...'; + } elseif ($isquickdel) { + $tpl_page .= '

'. _gettext('Redirecting') . ' back to board...'; + } + } + } else { + $tpl_page .= _gettext('Invalid thread ID '.$delpost_id.'. This may have been caused by the thread recently being deleted.'); + } + } + } elseif (isset($_POST['delpostid'])) { + if ($_POST['delpostid'] > 0) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $board_id . " AND `IS_DELETED` = '0' AND `id` = " . $tc_db->qstr($_POST['delpostid']) . ""); + if (count($results) > 0) { + if (isset($_POST['fileonly'])) { + foreach ($results as $line) { + if (!empty($line['file'])) { + $del = @unlink(KU_ROOTDIR . $_POST['boarddir'] . '/src/'. $line['file'] . '.'. $line['file_type']); + if ($del) { + @unlink(KU_ROOTDIR . $_POST['boarddir'] . '/thumb/'. $line['file'] . 's.'. $line['file_type']); + @unlink(KU_ROOTDIR . $_POST['boarddir'] . '/thumb/'. $line['file'] . 'c.'. $line['file_type']); + $tc_db->Execute("UPDATE `".KU_DBPREFIX."posts` SET `file` = 'removed', `file_md5` = '' WHERE `boardid` = " . $board_id . " AND `id` = ".$_POST['delpostid']." LIMIT 1"); + $tpl_page .= '
File successfully deleted
'; + } else { + $tpl_page .= '
That file has already been deleted.
'; + } + } else { + $tpl_page .= '
Error: That thread doesn\'t have a file associated with it.
'; + } + } + } else { + foreach ($results as $line) { + $delpost_id = $line['id']; + $delpost_parentid = $line['parentid']; + } + $post_class = new Post($delpost_id, $board_dir, $board_id); + $post_class->Delete(); + $board_class = new Board($board_dir); + $board_class->RegenerateThreads($delpost_parentid); + $board_class->RegeneratePages(); + unset($board_class); + unset($post_class); + $tpl_page .= _gettext('Post '.$delpost_id.' successfully deleted.'); + management_addlogentry(_gettext('Deleted post') . ' #'. $delpost_id . ' - /'. $board_dir . '/', 7); + if ($_GET['postid'] != '') { + $tpl_page .= '

'. _gettext('Redirecting') . ' to ban page...'; + } elseif ($isquickdel) { + $tpl_page .= '

'. _gettext('Redirecting') . ' back to thread...'; + } + } + } else { + $tpl_page .= _gettext('Invalid thread ID '.$delpost_id.'. This may have been caused by the thread recently being deleted.'); + } + } + } + } else { + $tpl_page .= _gettext('Invalid board directory.'); + } + } + $tpl_page .= '

'. _gettext('Delete thread/post') . '


'; + if (!$multidel) { + $tpl_page .= '
+ + ' . + $this->MakeBoardListDropdown('boarddir', $this->BoardList($_SESSION['manageusername'])) . + '
+ + +
+ + +
+ + + +
+

+ +
+ + ' . + $this->MakeBoardListDropdown('boarddir', $this->BoardList($_SESSION['manageusername'])) . + '
+ + +
+ + +
+ + +
+ + + +
'; + } + } + + /* + * +------------------------------------------------------------------------------+ + * Moderation Pages + * +------------------------------------------------------------------------------+ + */ + + /* View and delete reports */ + function reports() { + global $tc_db, $tpl_page; + $this->ModeratorsOnly(); + + $tpl_page .= '

'. _gettext('Reports') . '


'; + if (isset($_GET['clear'])) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `id` FROM `" . KU_DBPREFIX . "reports` WHERE `id` = " . $tc_db->qstr($_GET['clear']) . " LIMIT 1"); + if (count($results) > 0) { + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "reports` SET `cleared` = '1' WHERE `id` = " . $tc_db->qstr($_GET['clear'])); + $tpl_page .= 'Report successfully cleared.
'; + } + } + $query = "SELECT * FROM `" . KU_DBPREFIX . "reports` WHERE `cleared` = 0"; + if (!$this->CurrentUserIsAdministrator()) { + $boardlist = $this->BoardList($_SESSION['manageusername']); + if (!empty($boardlist)) { + $query .= ' AND ('; + foreach ($boardlist as $board) { + $query .= ' `board` = \''. $board['name'] .'\' OR'; + } + $query = substr($query, 0, -3) . ')'; + } else { + $tpl_page .= _gettext('You do not moderate any boards.'); + } + } + $resultsreport = $tc_db->GetAll($query); + if (count($resultsreport) > 0) { + $tpl_page .= ''; + foreach ($resultsreport as $linereport) { + $reportboardid = $tc_db->GetOne("SELECT HIGH_PRIORITY `id` FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($linereport['board']) . ""); + $results = $tc_db->GetAll("SELECT * FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $reportboardid . " AND `id` = " . $tc_db->qstr($linereport['postid']) . ""); + foreach ($results as $line) { + if ($line['IS_DELETED'] == 0) { + $tpl_page .= ''; + } else { + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "reports` SET `cleared` = 1 WHERE id = " . $linereport['id'] . ""); + } + } + } + $tpl_page .= '
BoardPostFileMessageReasonReporter IPAction
/'. $linereport['board'] . '/'. $line['id'] . ''; + if ($line['file'] == 'removed') { + $tpl_page .= 'removed'; + } elseif ($line['file'] == '') { + $tpl_page .= 'none'; + } elseif ($line['file_type'] == 'jpg' || $line['file_type'] == 'gif' || $line['file_type'] == 'png') { + $tpl_page .= ''; + } else { + $tpl_page .= 'File'; + } + $tpl_page .= ''; + if ($line['message'] != '') { + $tpl_page .= stripslashes($line['message']); + } else { + $tpl_page .= ' '; + } + $tpl_page .= ''; + if ($linereport['reason'] != '') { + $tpl_page .= htmlspecialchars(stripslashes($linereport['reason'])); + } else { + $tpl_page .= ' '; + } + $tpl_page .= ''. md5_decrypt($linereport['ip'], KU_RANDOMSEED) . 'Clear [D & B]
'; + } else { + $tpl_page .= 'No reports to show.'; + } + } + + /* Addition, modification, deletion, and viewing of bans */ + function bans() { + global $tc_db, $tpl_page, $bans_class; + + $this->ModeratorsOnly(); + $reason = KU_BANREASON; + $ban_ip = ''; $ban_hash = ''; $ban_parentid = 0; $multiban = Array(); + if (isset($_POST['modban']) && is_array($_POST['post']) && $_POST['board']) { + $ban_board_id = $tc_db->GetOne("SELECT HIGH_PRIORITY `id` FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($_POST['board']) . ""); + if (!empty($ban_board_id)) { + foreach ( $_POST['post'] as $post ) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = '" . $ban_board_id . "' AND `id` = " . intval($post) . ""); + if (count($results) > 0) { + $multiban[] = md5_decrypt($results[0]['ip'], KU_RANDOMSEED); + $multiban_hash[] = $results[0]['file_md5']; + $multiban_parentid[] = $results[0]['parentid']; + } + } + } + } + if (isset($_GET['banboard']) && isset($_GET['banpost'])) { + $ban_board_id = $tc_db->GetOne("SELECT HIGH_PRIORITY `id` FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($_GET['banboard']) . ""); + $ban_board = $_GET['banboard']; + $ban_post_id = $_GET['banpost']; + if (!empty($ban_board_id)) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = '" . $ban_board_id . "' AND `id` = " . $tc_db->qstr($_GET['banpost']) . ""); + if (count($results) > 0) { + $ban_ip = md5_decrypt($results[0]['ip'], KU_RANDOMSEED); + $ban_hash = $results[0]['file_md5']; + $ban_parentid = $results[0]['parentid']; + } else { + $tpl_page.= _gettext('A post with that ID does not exist.') . '
'; + } + } + } + $instantban = false; + if ((isset($_GET['instant']) || isset($_GET['cp'])) && $ban_ip) { + if (isset($_GET['cp'])) { + $ban_reason = "You have been banned for posting Child Pornography. Your IP has been logged, and the proper authorities will be notified."; + } else { + if($_GET['reason']) { + $ban_reason = urldecode($_GET['reason']); + } else { + $ban_Reason = KU_BANREASON; + } + } + $instantban = true; + } + $tpl_page .= '

'. _gettext('Bans') . '


'; + if (((isset($_POST['ip']) || isset($_POST['multiban'])) && isset($_POST['seconds']) && (!empty($_POST['ip']) || (empty($_POST['ip']) && !empty($_POST['multiban'])))) || $instantban) { + if ($_POST['seconds'] >= 0 || $instantban) { + $banning_boards = array(); + $ban_boards = ''; + if (isset($_POST['banfromall']) || $instantban) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `name` FROM `" . KU_DBPREFIX . "boards`"); + foreach ($results as $line) { + if (!$this->CurrentUserIsModeratorOfBoard($line['name'], $_SESSION['manageusername'])) { + exitWithErrorPage('/'. $line['name'] . '/: '. _gettext('You can only make bans applying to boards you moderate.')); + } + } + } else { + if (empty($_POST['bannedfrom'])) { + exitWithErrorPage(_gettext('Please select a board.')); + } + if(isset($_POST['deleteposts'])) { + $_POST['deletefrom'] = $_POST['bannedfrom']; + } + foreach($_POST['bannedfrom'] as $board) { + if (!$this->CurrentUserIsModeratorOfBoard($board, $_SESSION['manageusername'])) { + exitWithErrorPage('/'. $board . '/: '. _gettext('You can only make bans applying to boards you moderate.')); + } + } + $ban_boards = implode('|', $_POST['bannedfrom']); + } + $ban_globalban = (isset($_POST['banfromall']) || $instantban) ? 1 : 0; + $ban_allowread = ($_POST['allowread'] == 0 || $instantban) ? 0 : 1; + if (isset($_POST['quickbanboardid'])) { + $ban_board_id = $_POST['quickbanboardid']; + } + if(isset($_POST['quickbanboard'])) { + $ban_board = $_POST['quickbanboard']; + } + if(isset($_POST['quickbanpostid'])) { + $ban_post_id = $_POST['quickbanpostid']; + } + $ban_ip = ($instantban) ? $ban_ip : $_POST['ip']; + $ban_duration = ($_POST['seconds'] == 0 || $instantban) ? 0 : $_POST['seconds']; + $ban_type = ($_POST['type'] <= 2 && $_POST['type'] >= 0) ? $_POST['type'] : 0; + $ban_reason = ($instantban) ? $ban_reason : $_POST['reason']; + $ban_note = ($instantban) ? '' : $_POST['staffnote']; + $ban_appealat = 0; + if (KU_APPEAL != '' && !$instantban) { + $ban_appealat = intval($_POST['appealdays'] * 86400); + if ($ban_appealat > 0) $ban_appealat += time(); + } + if (isset($_POST['multiban'])) + $ban_ips = unserialize($_POST['multiban']); + else + $ban_ips = Array($ban_ip); + $i = 0; + foreach ($ban_ips as $ban_ip) { + $ban_msg = ''; + $whitelist = $tc_db->GetAll("SELECT `ipmd5` FROM `" . KU_DBPREFIX . "banlist` WHERE `type` = 2"); + if (in_array(md5($ban_ip), $whitelist)) { + exitWithErrorPage(_gettext('That IP is on the whitelist')); + } + if ($bans_class->BanUser($ban_ip, $_SESSION['manageusername'], $ban_globalban, $ban_duration, $ban_boards, $ban_reason, $ban_note, $ban_appealat, $ban_type, $ban_allowread)) { + $regenerated = array(); + if (((KU_BANMSG != '' || $_POST['banmsg'] != '') && isset($_POST['addbanmsg']) && (isset($_POST['quickbanpostid']) || isset($_POST['quickmultibanpostid']))) || $instantban ) { + $ban_msg = ((KU_BANMSG == $_POST['banmsg']) || empty($_POST['banmsg'])) ? KU_BANMSG : $_POST['banmsg']; + if (isset($ban_post_id)) + $postids = Array($ban_post_id); + else + $postids = unserialize($_POST['quickmultibanpostid']); + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `parentid`, `message` FROM `".KU_DBPREFIX."posts` WHERE `boardid` = " . $tc_db->qstr($ban_board_id) . " AND `id` = ".$tc_db->qstr($postids[$i])." LIMIT 1"); + + foreach($results AS $line) { + $tc_db->Execute("UPDATE `".KU_DBPREFIX."posts` SET `message` = ".$tc_db->qstr($line['message'] . $ban_msg)." WHERE `boardid` = " . $tc_db->qstr($ban_board_id) . " AND `id` = ".$tc_db->qstr($postids[$i])); + clearPostCache($postids[$i], $ban_board_id); + if ($line['parentid']==0) { + if (!in_array($postids, $regenerated)) { + $regenerated[] = $postids[$i]; + } + } else { + if (!in_array($line['parentid'], $regenerated)) { + $regenerated[] = $line['parentid']; + } + } + } + } + $tpl_page .= _gettext('Ban successfully placed.')."
"; + } else { + exitWithErrorPage(_gettext('Sorry, a generic error has occurred.')); + } + + $logentry = _gettext('Banned') . ' '. $ban_ip; + $logentry .= ($ban_duration == 0) ? ' '. _gettext('without expiration') : ' '. _gettext('until') . ' '. date('F j, Y, g:i a', time() + $ban_duration); + $logentry .= ' - '. _gettext('Reason') . ': '. $ban_reason . (($ban_note) ? (" (".$ban_note.")") : ("")). ' - '. _gettext('Banned from') . ': '; + $logentry .= ($ban_globalban == 1) ? _gettext('All boards') . ' ' : '/'. implode('/, /', explode('|', $ban_boards)) . '/ '; + management_addlogentry($logentry, 8); + $ban_ip = ''; + $i++; + } + if (count($regenerated) > 0) { + $board_class = new Board($ban_board); + foreach($regenerated as $thread) { + $board_class->RegenerateThreads($thread); + } + $board_class->RegeneratePages(); + unset($board_class); + } + + if(isset($_POST['deleteposts'])) { + $tpl_page .= '
'; + $this->deletepostsbyip(true); + } + + if ((isset($_GET['instant']) && !isset($_GET['cp']))) { + die("success"); + } + + if (isset($_POST['banhashtime']) && $_POST['banhashtime'] !== '' && ($_POST['hash'] !== '' || isset($_POST['multibanhashes'])) && $_POST['banhashtime'] >= 0) { + if (isset($_POST['multibanhashes'])) + $banhashes = unserialize($_POST['multibanhashes']); + else + $banhashes = Array($_POST['hash']); + foreach ($banhashes as $banhash){ + $results = $tc_db->GetOne("SELECT HIGH_PRIORITY COUNT(*) FROM `".KU_DBPREFIX."bannedhashes` WHERE `md5` = ".$tc_db->qstr($banhash)." LIMIT 1"); + if ($results == 0) { + $tc_db->Execute("INSERT INTO `".KU_DBPREFIX."bannedhashes` ( `md5` , `bantime` , `description` ) VALUES ( ".$tc_db->qstr($banhash)." , ".$tc_db->qstr($_POST['banhashtime'])." , ".$tc_db->qstr($_POST['banhashdesc'])." )"); + management_addlogentry('Banned md5 hash '. $banhash . ' with a description of '. $_POST['banhashdesc'], 8); + } + } + } + if (!empty($_POST['quickbanboard']) && !empty($_POST['quickbanthreadid'])) { + $tpl_page .= '

'. _gettext('Redirecting') . '...'; + } + } else { + $tpl_page .= _gettext('Please enter a positive amount of seconds, or zero for a permanent ban.'); + } + $tpl_page .= '
'; + } elseif (isset($_GET['delban']) && $_GET['delban'] > 0) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "banlist` WHERE `id` = " . $tc_db->qstr($_GET['delban']) . ""); + if (count($results) > 0) { + $unban_ip = md5_decrypt($results[0]['ip'], KU_RANDOMSEED); + $tc_db->Execute("DELETE FROM `" . KU_DBPREFIX . "banlist` WHERE `id` = " . $tc_db->qstr($_GET['delban']) . ""); + $bans_class->UpdateHtaccess(); + $tpl_page .= _gettext('Ban successfully removed.'); + management_addlogentry(_gettext('Unbanned') . ' '. $unban_ip, 8); + } else { + $tpl_page .= _gettext('Invalid ban ID'); + } + $tpl_page .= '

'; + } elseif (isset($_GET['delhashid'])) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "bannedhashes` WHERE `id` = " . $tc_db->qstr($_GET['delhashid']) . ""); + if (count($results) > 0) { + $tc_db->Execute("DELETE FROM `" . KU_DBPREFIX . "bannedhashes` WHERE `id` = " . $tc_db->qstr($_GET['delhashid']) . ""); + $tpl_page .= _gettext('Hash removed from ban list.') . '

'; + } + } + + flush(); + + $isquickban = false; + + $tpl_page .= '
'; + + if ((!empty($ban_ip) && isset($_GET['banboard']) && isset($_GET['banpost'])) || (!empty($multiban) && isset($_POST['board']) && isset($_POST['post']))) { + $isquickban = true; + $tpl_page .= ''; + if(!empty($multiban)) { + $tpl_page .= ''; + } else { + $tpl_page .= ''; + } + } elseif (isset($_GET['ip'])) { + $ban_ip = $_GET['ip']; + } + + $tpl_page .= '
+ '. _gettext('IP address and ban type') . ' + '; + if (!$multiban) { + $tpl_page .= ' +
+ '; + } + else { + $tpl_page .= ' + Multiple IPs +
+ '; + } + + $tpl_page .= '
+ + +
'. _gettext('Whether or not the user(s) affected by this ban will be allowed to read the boards.') . '
'. _gettext('Warning') . ': '. _gettext('Selecting "No" will prevent any reading of any page on the level of the boards on the server. It will also act as a global ban.') . '

+ + + +
'. _gettext('The type of ban. A single IP can be banned by providing the full address. A whitelist ban prevents that IP from being banned. An IP range can be banned by providing the IP range you would like to ban, in this format: 123.123.12') . '

'; + + if ($isquickban && KU_BANMSG != '') { + $tpl_page .= ' + +
'. _gettext('If checked, the configured ban message will be added to the end of the post.') . '

+ + '; + } + + $tpl_page .='
+
+ '. _gettext('Ban from') . ' + +


' . + $this->MakeBoardListCheckboxes('bannedfrom', $this->BoardList($_SESSION['manageusername'])) . + '
'; + + if (isset($ban_hash)) { + $tpl_page .= '
+ '. _gettext('Ban file') . ' + + + + +
'. _gettext('The amount of time to ban the hash of the image which was posted under this ID. Leave blank to not ban the image, 0 for an infinite global ban, or any number of seconds for that duration of a global ban.') . '

+ + + +
'. _gettext('The description of the image being banned. Not applicable if the above box is blank.') . '
+
'; + } + + $tpl_page .= '
+ '. _gettext('Ban duration, reason, and appeal information') . ' + + +
'. _gettext('Presets') . ': 1hr 1d 3d 1w 2w 30d 1yr '. _gettext('never') .'

+ + + +
'. _gettext('Presets') .': CP '. _gettext('Proxy') .'

+ + + +
'. _gettext('Presets') . ': CP || '. _gettext('This message will be shown only on this page and only to staff, not to the user.') .'

'; + + if (KU_APPEAL != '') { + $tpl_page .= ' + +
'; + } + + $tpl_page .= '
+ + +
+

'; + + for ($i = 2; $i >= 0; $i--) { + switch ($i) { + case 2: + $tpl_page .= ''. _gettext('Whitelisted IPs') . ':
'; + break; + case 1: + $tpl_page .= '
'. _gettext('IP Range Bans') . ':
'; + break; + case 0: + if (!empty($ban_ip)) + $tpl_page .= '
'. _gettext('Previous bans on this IP') . ':
'; + else + $tpl_page .= '
'. _gettext('Single IP Bans') . ':
'; + break; + } + if (isset($_GET['allbans'])) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "banlist` WHERE `type` = '" . $i . "' AND `by` != 'SERVER' ORDER BY `id` DESC"); + $hiddenbans = 0; + } elseif (isset($_GET['limit'])) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "banlist` WHERE `type` = '" . $i . "' ORDER BY `id` DESC LIMIT ".intval($_GET['limit'])); + $hiddenbans = 0; + } else { + if (!empty($ban_ip) && $i == 0) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "banlist` WHERE `ipmd5` = '" . md5($ban_ip) . "' AND `type` = '" . $i . "' AND `by` != 'SERVER' ORDER BY `id` DESC"); + } else { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "banlist` WHERE `type` = '" . $i . "' AND `by` != 'SERVER' ORDER BY `id` DESC LIMIT 15"); + // Get the number of bans in the database of this type + $hiddenbans = $tc_db->GetAll("SELECT HIGH_PRIORITY COUNT(*) FROM `" . KU_DBPREFIX . "banlist` WHERE `type` = '" . $i . "'"); + // Subtract 15 from the count, since we only want the number not shown + $hiddenbans = $hiddenbans[0][0] - 15; + } + } + if (count($results) > 0) { + $tpl_page .= ''; + foreach ($results as $line) { + $tpl_page .= ''; + } + $tpl_page .= '
'; + $tpl_page .= ($i == 1) ? _gettext('IP Range') : _gettext('IP Address'); + $tpl_page .= ''. _gettext('Boards') . ''. _gettext('Reason') . ''. _gettext('Staff Note') . ''. _gettext('Date added') . ''. _gettext('Expires/Expired') . ''. _gettext('Added By') . ' 
'. md5_decrypt($line['ip'], KU_RANDOMSEED) . ''; + if ($line['globalban'] == 1) { + $tpl_page .= ''. _gettext('All boards') . ''; + } elseif (!empty($line['boards'])) { + $tpl_page .= '/'. implode('/, /', explode('|', $line['boards'])) . '/ '; + } + $tpl_page .= ''; + $tpl_page .= (!empty($line['reason'])) ? htmlentities(stripslashes($line['reason'])) : ' '; + $tpl_page .= ''; + $tpl_page .= (!empty($line['staffnote'])) ? htmlentities(stripslashes($line['staffnote'])) : ' '; + $tpl_page .= ''. date("F j, Y, g:i a", $line['at']) . ''; + $tpl_page .= ($line['until'] == 0) ? ''. _gettext('Does not expire') . '' : date("F j, Y, g:i a", $line['until']); + $tpl_page .= ''. $line['by'] . '['. _gettext('Delete') .']
'; + if ($hiddenbans > 0) { + $tpl_page .= sprintf(_gettext('%s bans not shown.'), $hiddenbans) . + ' '. _gettext('View all bans') . ''.' View last 100 bans'; + } + } else { + $tpl_page .= _gettext('There are currently no bans'); + } + } + $tpl_page .= '

'. _gettext('File hash bans') . ':
'; + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `".KU_DBPREFIX."bannedhashes` ". ((!isset($_GET['allbans'])) ? ("LIMIT 5") : (""))); + if (count($results) == 0) { + $tpl_page .= ''; + } else { + foreach ($results as $line) { + $tpl_page .= ''; + } + } + $tpl_page .= '
'. _gettext('Hash') . ''. _gettext('Description') . ''. _gettext('Ban time') . ' 
'. _gettext('None') . '
'. $line['md5'] . ''. $line['description'] . ''; + $tpl_page .= ($line['bantime'] == 0) ? ''. _gettext('Does not expire') . '' : $line['bantime'] . ' seconds'; + $tpl_page .= '[x]
'; + } + + function appeals() { + global $tc_db, $tpl_page, $bans_class; + $this->ModeratorsOnly(); + $tpl_page .= '

'. _gettext('Appeals') . '


'; + $ban_ip = ''; + if (isset($_GET['accept'])) { + if ($_GET['accept'] > 0) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "banlist` WHERE `id` = " . $tc_db->qstr($_GET['accept']) . ""); + if (count($results) > 0) { + foreach ($results as $line) { + $unban_ip = md5_decrypt($line['ip'], KU_RANDOMSEED); + } + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "banlist` SET `expired` = 1, `appealat` = -4 WHERE `id` = " . $tc_db->qstr($_GET['accept']) . ""); + $bans_class->UpdateHtaccess(); + $tpl_page .= _gettext('Ban successfully removed.'); + management_addlogentry('Accepted appeal #'.$_GET['accept'].' from: '. $unban_ip, 8); + } else { + $tpl_page .= _gettext('Invalid ID'); + } + $tpl_page .= '
'; + } + } elseif (isset($_GET['deny'])) { + if ($_GET['deny'] > 0) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "banlist` WHERE `id` = " . $tc_db->qstr($_GET['deny']) . ""); + if (count($results) > 0) { + foreach ($results as $line) { + $unban_ip = md5_decrypt($line['ip'], KU_RANDOMSEED); + } + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "banlist` SET `appealat` = -2 WHERE `id` = " . $tc_db->qstr($_GET['deny']) . ""); + $bans_class->UpdateHtaccess(); + $tpl_page .= _gettext('Appeal successfully denied.'); + management_addlogentry(_gettext('Denied the ban appeal for') . ' '. $unban_ip, 8); + } else { + $tpl_page .= _gettext('Invalid ID'); + } + $tpl_page .= '
'; + } + } + flush(); + + for ($i = 1; $i >= 0; $i--) { + if ($i == 1) { + $tpl_page .= ''. _gettext('IP Range bans') . ':
'; + } else { + $tpl_page .= '
'. _gettext('Single IP Bans') . ':
'; + } + + if ($ban_ip != '') { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "banlist` WHERE `ipmd5` = '" . md5($ban_ip) . "' AND `type` = '" . $i . "' AND `expired` = 0 ORDER BY `id` DESC"); + } else { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "banlist` WHERE `type` = '" . $i . "' AND `appealat` = -1 AND `expired` = 0 ORDER BY `id` DESC"); + } + if (count($results) > 0) { + $tpl_page .= ''; + foreach ($results as $line) { + $tpl_page .= ''; + $tpl_page .= ' + + + '; + $tpl_page .= ''; + } + $tpl_page .= '
'; + if ($i == 1) { + $tpl_page .= 'IP Range'; + } else { + $tpl_page .= 'IP Address'; + } + $tpl_page .= 'BoardsReasonStaff NoteDate AddedExpiresAdded ByAppeal MessageDenyAccept
'. md5_decrypt($line['ip'], KU_RANDOMSEED) . ''; + if ($line['globalban'] == '1') { + $tpl_page .= ''. _gettext('All boards') . ''; + } else { + if ($line['boards'] != '') { + $tpl_page .= '/'. implode('/, /', explode('|', $line['boards'])) . '/ '; + } + } + $tpl_page .= ''; + if ($line['reason'] != '') { + $tpl_page .= htmlentities(stripslashes($line['reason'])); + } else { + $tpl_page .= ' '; + } + $tpl_page .= ''; + if ($line['staffnote'] != '') { + $tpl_page .= htmlentities(stripslashes($line['staffnote'])); + } else { + $tpl_page .= ' '; + } + $tpl_page .= ''. date("F j, Y, g:i a", $line['at']) . ''; + if ($line['until'] == '0') { + $tpl_page .= ''. _gettext('Does not expire') . ''; + } else { + $tpl_page .= date("F j, Y, g:i a", $line['until']); + } + $tpl_page .= ''. $line['by'] . ''.$line['appeal'].':(:)
'; + if ($hiddenbans>0) { + $tpl_page .= sprintf(_gettext('%s bans not shown.'), $hiddenbans) . + ' '. _gettext('View all bans') . ''.' View last 100 bans'; + } + } else { + $tpl_page .= _gettext('There are currently no bans.'); + } + } + } + + /* Search for all posts by a selected IP address and delete them */ + function deletepostsbyip($from_ban = false) { + global $tc_db, $tpl_page, $board_class; + $this->ModeratorsOnly(); + if (!$from_ban) { + $tpl_page .= '

'. _gettext('Delete all posts by IP') . '


'; + } + if (isset($_POST['ip']) || isset($_POST['multiban'])) { + if ($_POST['ip'] != '' || !empty($_POST['multiban'])) { + if (!$from_ban) { + $this->CheckToken($_POST['token']); + } + $deletion_boards = array(); + $deletion_new_boards = array(); + $board_ids = ''; + if (isset($_POST['banfromall'])) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `id`, `name` FROM `" . KU_DBPREFIX . "boards`"); + foreach ($results as $line) { + if (!$this->CurrentUserIsModeratorOfBoard($line['name'], $_SESSION['manageusername'])) { + exitWithErrorPage('/'. $line['name'] . '/: '. _gettext('You can only delete posts from boards you moderate.')); + } + $delete_boards[$line['id']] = $line['name']; + $board_ids .= $line['id'] . ','; + } + } else { + if (empty($_POST['deletefrom'])) { + exitWithErrorPage(_gettext('Please select a board.')); + } + foreach($_POST['deletefrom'] as $board) { + if (!$this->CurrentUserIsModeratorOfBoard($board, $_SESSION['manageusername'])) { + exitWithErrorPage('/'. $board . '/: '. _gettext('You can only delete posts from boards you moderate.')); + } + $id = $tc_db->GetOne("SELECT `id` FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($board)); + $board_ids .= $tc_db->qstr($id) . ','; + $delete_boards[$id] = $board; + } + } + $board_ids = substr($board_ids, 0, -1); + + $i = 0; + if (isset($_POST['multiban'])) + $ips = unserialize($_POST['multiban']); + else + $ips = Array($_POST['ip']); + foreach ($ips as $ip) { + $i = 0; + $post_list = $tc_db->GetAll("SELECT `id`, `boardid` FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` IN (" . $board_ids . ") AND `IS_DELETED` = '0' AND `ipmd5` = '" . md5($ip) . "'"); + if (count($post_list) > 0) { + foreach ($post_list as $post) { + $i++; + $post_class = new Post($post['id'], $delete_boards[$post['boardid']], $post['boardid']); + $post_class->Delete(); + $boards_deleted[$post['boardid']] = $delete_boards[$post['boardid']]; + unset($post_class); + } + + $tpl_page .= _gettext('All threads/posts by that IP in selected boards successfully deleted.') . '
'. $i . ' posts were removed.
'; + management_addlogentry(_gettext('Deleted posts by ip') . ' '. $ip, 7); + } + else { + $tpl_page .= _gettext('No posts for that IP found'); + } + if (isset($boards_deleted)) { + foreach ($boards_deleted as $board) { + $board_class = new Board($board); + $board_class->RegenerateAll(); + unset($board_class); + } + } + } + $tpl_page .= '
'; + } + } + if (!$from_ban) { + $tpl_page .= '
+ +
IP + + + + +


' . + $this->MakeBoardListCheckboxes('deletefrom', $this->BoardList($_SESSION['manageusername'])) . + '
+ + + +
'; + } + } + + /* View recently uploaded images */ + function recentimages() { + global $tc_db, $tpl_page; + $this->ModeratorsOnly(); + + if (!isset($_SESSION['imagesperpage'])) { + $_SESSION['imagesperpage'] = 50; + } + + if (isset($_GET['show'])) { + if ($_GET['show'] == '25' || $_GET['show'] == '50' || $_GET['show'] == '75' || $_GET['show'] == '100') { + $_SESSION['imagesperpage'] = $_GET['show']; + } + } + + $tpl_page .= '

'. _gettext('Recently uploaded images') . '


+ '._gettext('Number of images to show per page').': 25, 50, 75, 100 '._gettext('(note that this is a rough limit, more may be shown)').'
'; + if (isset($_POST['clear'])) { + if ($_POST['clear'] != '') { + $clear_decrypted = md5_decrypt($_POST['clear'], KU_RANDOMSEED); + if ($clear_decrypted != '') { + $clear_unserialized = unserialize($clear_decrypted); + + foreach ($clear_unserialized as $clear_sql) { + $tc_db->Execute($clear_sql); + } + $tpl_page .= _gettext('Successfully marked previous images as reviewed.').'
'; + } + } + } + + $dayago = (time() - 86400); + $imagesshown = 0; + $reviewsql_array = array(); + + if ($imagesshown <= $_SESSION['imagesperpage']) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `" . KU_DBPREFIX . "boards`.`name` AS `boardname`, `" . KU_DBPREFIX . "posts`.`boardid` AS boardid, `" . KU_DBPREFIX . "posts`.`id` AS id, `" . KU_DBPREFIX . "posts`.`parentid` AS parentid, `" . KU_DBPREFIX . "posts`.`file` AS file, `" . KU_DBPREFIX . "posts`.`file_type` AS file_type, `" . KU_DBPREFIX . "posts`.`thumb_w` AS thumb_w, `" . KU_DBPREFIX . "posts`.`thumb_h` AS thumb_h FROM `" . KU_DBPREFIX . "posts`, `" . KU_DBPREFIX ."boards` WHERE (`file_type` = 'jpg' OR `file_type` = 'gif' OR `file_type` = 'png') AND `reviewed` = 0 AND `IS_DELETED` = 0 AND `" . KU_DBPREFIX . "boards`.`id` = `" . KU_DBPREFIX . "posts`.`boardid` ORDER BY `timestamp` DESC LIMIT " . intval($_SESSION['imagesperpage'])); + if (count($results) > 0) { + $reviewsql = "UPDATE `" . KU_DBPREFIX . "posts` SET `reviewed` = 1 WHERE "; + $tpl_page .= ''. "\n"; + foreach ($results as $line) { + $reviewsql .= '(`boardid` = '.$line['boardid'] .' AND `id` = '. $line['id'] . ') OR '; + $real_parentid = ($line['parentid'] == 0) ? $line['id'] : $line['parentid']; + $tpl_page .= ''; + } + $tpl_page .= '
/'. $line['boardname'] . '/'. $line['id'] . '
'; + + $reviewsql = substr($reviewsql, 0, -3); + $reviewsql_array[] = $reviewsql; + $imagesshown += count($results); + } + } + + if ($imagesshown > 0) { + $tpl_page .= '

'. sprintf(_gettext('%s images shown.'), $imagesshown). '
'; + $tpl_page .= '
+ + +

'; + } else { + $tpl_page .= '

'. _gettext('No recent images currently need review.') ; + } + } + + /* View recently posted posts */ + function recentposts() { + global $tc_db, $tpl_page; + $this->ModeratorsOnly(); + + if (!isset($_SESSION['postsperpage'])) { + $_SESSION['postsperpage'] = 50; + } + + if (isset($_GET['show'])) { + if ($_GET['show'] == '25' || $_GET['show'] == '50' || $_GET['show'] == '75' || $_GET['show'] == '100') { + $_SESSION['postsperpage'] = $_GET['show']; + } + } + + $tpl_page .= '

'. _gettext('Recent posts') . '


+ '._gettext('Number of posts to show per page').': 25, 50, 75, 100 '._gettext('(note that this is a rough limit, more may be shown)').'
'; + if (isset($_POST['clear'])) { + if ($_POST['clear'] != '') { + $clear_decrypted = md5_decrypt($_POST['clear'], KU_RANDOMSEED); + if ($clear_decrypted != '') { + $clear_unserialized = unserialize($clear_decrypted); + + foreach ($clear_unserialized as $clear_sql) { + $tc_db->Execute($clear_sql); + } + $tpl_page .= _gettext('Successfully marked previous posts as reviewed.').'
'; + } + } + } + + $dayago = (time() - 86400); + $postsshown = 0; + $reviewsql_array = array(); + + $boardlist = $this->BoardList($_SESSION['manageusername']); + if ($postsshown <= $_SESSION['postsperpage']) { + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `" . KU_DBPREFIX . "boards`.`name` AS `boardname`, `" . KU_DBPREFIX . "posts`.`boardid` AS boardid, `" . KU_DBPREFIX . "posts`.`id` AS id, `" . KU_DBPREFIX . "posts`.`parentid` AS parentid, `" . KU_DBPREFIX . "posts`.`message` AS message, `" . KU_DBPREFIX . "posts`.`ip` AS ip FROM `" . KU_DBPREFIX . "posts`, `" . KU_DBPREFIX ."boards` WHERE `" . KU_DBPREFIX . "posts`.`timestamp` > " . $dayago . " AND `reviewed` = 0 AND `IS_DELETED` = 0 AND `" . KU_DBPREFIX . "boards`.`id` = `" . KU_DBPREFIX . "posts`.`boardid` ORDER BY `timestamp` DESC LIMIT " . intval($_SESSION['postsperpage'])); + if (count($results) > 0) { + $reviewsql = "UPDATE `" . KU_DBPREFIX . "posts` SET `reviewed` = 1 WHERE "; + $tpl_page .= ''. "\n"; + $tpl_page .= ''. "\n"; + foreach ($results as $line) { + $reviewsql .= '(`boardid` = '.$line['boardid'] .' AND `id` = '. $line['id'] . ') OR '; + $real_parentid = ($line['parentid'] == 0) ? $line['id'] : $line['parentid']; + $tpl_page .= ''; + } + $tpl_page .= '
'._gettext('Post Number').''._gettext('Post Message').''._gettext('Poster IP').'
/'. $line['boardname'] . '/'. $line['id'] . ''. stripslashes($line['message']) . ''. md5_decrypt($line['ip'], KU_RANDOMSEED) . '
'; + + $reviewsql = substr($reviewsql, 0, -3) . ' LIMIT '. count($results); + $reviewsql_array[] = $reviewsql; + $postsshown += count($results); + } + } + + if ($postsshown > 0) { + $tpl_page .= '

'. sprintf(_gettext('%s posts shown.'), $postsshown) .'
+
+ + +

'; + } else { + $tpl_page .= '

'. _gettext('No recent posts currently need review.') ; + } + } + + + /* + * +------------------------------------------------------------------------------+ + * Misc Functions + * +------------------------------------------------------------------------------+ + */ + + /* Show APC info */ + function apc() { + global $tpl_page; + + if (KU_APC) { + $apc_info_system = apc_cache_info(); + $apc_info_user = apc_cache_info('user'); + //print_r($apc_info_user); + $tpl_page .= '

APC

'. _gettext('System (File cache)') .'

    '; + $tpl_page .= '
  • Start time: '. date("y/m/d(D)H:i", $apc_info_system['start_time']) . '
  • '; + $tpl_page .= '
  • Hits: '. $apc_info_system['num_hits'] . '
  • '; + $tpl_page .= '
  • Misses: '. $apc_info_system['num_misses'] . '
  • '; + $tpl_page .= '
  • Entries: '. $apc_info_system['num_entries'] . '
  • '; + $tpl_page .= '

User (kusaba)

    '; + $tpl_page .= '
  • Start time: '. date("y/m/d(D)H:i", $apc_info_user['start_time']) . '
  • '; + $tpl_page .= '
  • Hits: '. $apc_info_user['num_hits'] . '
  • '; + $tpl_page .= '
  • Misses: '. $apc_info_user['num_misses'] . '
  • '; + $tpl_page .= '
  • Entries: '. $apc_info_user['num_entries'] . '
  • '; + $tpl_page .= '


Clear APC cache'; + } else { + $tpl_page .= 'APC isn\'t enabled!'; + } + } + + /* Clear the APC cache */ + function clearcache() { + global $tpl_page; + + if (KU_APC) { + apc_clear_cache(); + apc_clear_cache('user'); + $tpl_page .= 'APC cache cleared.'; + management_addlogentry(_gettext('Cleared APC cache'), 0); + } else { + $tpl_page .= 'APC isn\'t enabled!'; + } + } + + /* Generate a list of boards a moderator controls */ + function BoardList($username) { + global $tc_db, $tpl_page; + + $staff_boardsmoderated = array(); + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `boards` FROM `" . KU_DBPREFIX . "staff` WHERE `username` = '" . $username . "' LIMIT 1"); + if ($this->CurrentUserIsAdministrator() || $results[0][0] == 'allboards') { + $resultsboard = $tc_db->GetAll("SELECT HIGH_PRIORITY `id`, `name` FROM `" . KU_DBPREFIX . "boards` ORDER BY `name` ASC"); + foreach ($resultsboard as $lineboard) { + $staff_boardsmoderated = array_merge($staff_boardsmoderated, array(array( 'name' => $lineboard['name'], 'id' => $lineboard['id']))); + } + } else { + if ($results[0][0] != '') { + foreach ($results as $line) { + $array_boards = explode('|', $line['boards']); + } + foreach ($array_boards as $this_board_name) { + $this_board_id = $tc_db->GetOne("SELECT HIGH_PRIORITY `id` FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($this_board_name) . ""); + $staff_boardsmoderated = array_merge($staff_boardsmoderated, array(array('name' => $this_board_name, 'id' => $this_board_id))); + } + } + } + + return $staff_boardsmoderated; + } + + /* Generate a list of boards in query format */ + function sqlboardlist() { + global $tc_db, $tpl_page; + + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `id` FROM `" . KU_DBPREFIX . "boards` ORDER BY `name` ASC"); + $sqlboards = ''; + foreach ($results as $line) { + $sqlboards .= 'posts_'. $line['name'] . ', '; + } + + return substr($sqlboards, 0, -2); + } + + /* Generate a dropdown box from a supplied array of boards */ + function MakeBoardListDropdown($name, $boards, $all = false) { + $output = ''; + + return $output; + } + + /* Generate a series of checkboxes from a supplied array of boards */ + function MakeBoardListCheckboxes($boxname, $boards) { + $output = ''; + + if (!empty($boards)) { + foreach ($boards as $board) { + $output .= ' '."\n"; + } + } + + return $output; + } + + /* Generate a dropdown box for all sections */ + function MakeSectionListDropDown($name, $selected) { + global $tc_db; + + $output = '
'. "\n"; + + return $output; + } + + /* Delete files without their md5 stored in the database */ + function delunusedimages($verbose = false) { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + + $resultsboard = $tc_db->GetAll("SELECT HIGH_PRIORITY `id`, `name` FROM `" . KU_DBPREFIX . "boards`"); + foreach ($resultsboard as $lineboard) { + if ($verbose) { + $tpl_page .= ''. _gettext('Looking for unused images in') .' /'. $lineboard['name'] . '/
'; + } + $file_md5list = array(); + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `file_md5` FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $lineboard['id'] . " AND `IS_DELETED` = 0 AND `file` != '' AND `file` != 'removed' AND `file_md5` != ''"); + foreach ($results as $line) { + $file_md5list[] = $line['file_md5']; + } + $dir = './'. $lineboard['name'] . '/src'; + $files = glob("$dir/{*.jpg, *.png, *.gif, *.swf}", GLOB_BRACE); + if (is_array($files)) { + foreach ($files as $file) { + if (in_array(md5_file(KU_BOARDSDIR . $lineboard['name'] . '/src/'. basename($file)), $file_md5list) == false) { + if (time() - filemtime(KU_BOARDSDIR . $lineboard['name'] . '/src/'. basename($file)) > 120) { + if ($verbose == true) { + $tpl_page .= sprintf(_gettext('A live record for %s was not found; the file has been removed.'), $file).'
'; + } + unlink(KU_BOARDSDIR . $lineboard['name'] . '/src/'. basename($file)); + @unlink(KU_BOARDSDIR . $lineboard['name'] . '/thumb/'. substr(basename($file), 0, -4) . 's'. substr(basename($file), strlen(basename($file)) - 4)); + @unlink(KU_BOARDSDIR . $lineboard['name'] . '/thumb/'. substr(basename($file), 0, -4) . 'c'. substr(basename($file), strlen(basename($file)) - 4)); + } + } + } + } + } + + return true; + } + + /* Delete replies currently not marked as deleted who belong to a thread which is marked as deleted */ + function delorphanreplies($verbose = false) { + global $tc_db, $tpl_page; + $this->AdministratorsOnly(); + + $resultsboard = $tc_db->GetAll("SELECT HIGH_PRIORITY `id`, `name` FROM `" . KU_DBPREFIX . "boards`"); + foreach ($resultsboard as $lineboard) { + if ($verbose) { + $tpl_page .= ''. _gettext('Looking for orphans in') .' /'. $lineboard['name'] . '/
'; + } + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY `id`, `parentid` FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $lineboard['id'] . " AND `parentid` != '0' AND `IS_DELETED` = 0"); + foreach ($results as $line) { + $exists_rows = $tc_db->GetAll("SELECT HIGH_PRIORITY COUNT(*) FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $lineboard['id'] . " AND `id` = '" . $line['parentid'] . "' AND `IS_DELETED` = 0", 1); + if ($exists_rows[0] == 0) { + $post_class = new Post($line['id'], $lineboard['name'], $lineboard['id']); + $post_class->Delete; + unset($post_class); + + if ($verbose) { + $tpl_page .= sprintf(_gettext('Reply #%1$s\'s thread (#%2$s) does not exist! It has been deleted.'),$line['id'],$line['parentid']).'
'; + } + } + } + } + + return true; + } + + function spam() { + global $tpl_page; + $spam = KU_ROOTDIR . 'spam.txt'; + if (!empty($_POST['spam'])) { + $this->CheckToken($_POST['token']); + file_put_contents($spam, $_POST['spam']); + $tpl_page .= '
'. _gettext('Spam.txt successfully edited.') .'
'; + } + $content = htmlspecialchars(file_get_contents(KU_ROOTDIR . 'spam.txt')); + + $tpl_page .= '

'. _gettext('Spam.txt Management') .'


'. "\n" . + '
'. "\n" . + '' . "\n" . + '
' . "\n" . + ''. "\n" . + '
'. "\n"; + } + /* Gets the IP address of a post */ + function getip() { + global $tc_db, $smarty, $tpl_page; + if(!$this->CurrentUserIsModerator() && !$this->CurrentUserIsAdministrator()) { + die(); + } + $results = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($_GET['boarddir'])); + if (count($results) > 0) { + if (!$this->CurrentUserIsModeratorOfBoard($_GET['boarddir'], $_SESSION['manageusername'])) { + die(); + } + $ip = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $tc_db->qstr($results[0]['id']) . " AND `id` = " . $tc_db->qstr($_GET['id'])); + die("dnb-".$_GET['boarddir']."-".$_GET['id']."-".(($ip[0]['parentid'] == 0) ? ("y") : ("n"))."=".md5_decrypt($ip[0]['ip'], KU_RANDOMSEED)); + } + die(); + } +} +?> diff --git a/inc/classes/menu.class.php b/inc/classes/menu.class.php new file mode 100644 index 0000000..87c23d2 --- /dev/null +++ b/inc/classes/menu.class.php @@ -0,0 +1,99 @@ +assign('boardpath', getCLBoardPath()); + + if (KU_MENUTYPE == 'normal') { + $dwoo_data->assign('styles', explode(':', KU_MENUSTYLES)); + } + + if ($savetofile) { + $files = array('menu.html', 'menu_dirs.html'); + } else { + $files = array('menu.php', 'menu.php'); + } + + $dwoo_data->assign('files', $files); + + $sections = Array(); + + $results_boardsexist = $tc_db->GetAll("SELECT `id` FROM `".KU_DBPREFIX."boards` LIMIT 1"); + if (count($results_boardsexist) > 0) { + $sections = $tc_db->GetAll("SELECT * FROM `" . KU_DBPREFIX . "sections` ORDER BY `order` ASC"); + foreach($sections AS $key=>$section) { + $results = $tc_db->GetAll("SELECT * FROM `" . KU_DBPREFIX . "boards` WHERE `section` = '" . $section['id'] . "' ORDER BY `order` ASC, `name` ASC /* MENU.CLASS.PHP */"); + foreach($results AS $line) { + $sections[$key]['boards'][] = $line; + } + } + } + $dwoo_data->assign('boards', $sections); + + for ($i = 0; $i < 2; $i++) { + if ($i == 0) $dwoo_data->assign('showdirs', 0); + else $dwoo_data->assign('showdirs', 1); + if ($savetofile) { + if ($i == 0) { + file_put_contents(KU_ROOTDIR . $files[0], $dwoo->get(KU_TEMPLATEDIR . '/menu.tpl', $dwoo_data)); + } else { + file_put_contents(KU_ROOTDIR . $files[1], $dwoo->get(KU_TEMPLATEDIR . '/menu.tpl', $dwoo_data)); + } + } else { + if ($i == 0) { + $menu_nodirs = $dwoo->get(KU_TEMPLATEDIR . '/menu.tpl', $dwoo_data); + if ($option == 'nodirs') { + return $menu_nodirs; + } + } else { + if ($option == 'dirs') { + $menu_dirs = $dwoo->get(KU_TEMPLATEDIR . '/menu.tpl', $dwoo_data); + return $menu_dirs; + } + } + } + } + + if (isset($menu_nodirs) && isset($menu_dirs)) { + return array($menu_nodirs, $menu_dirs); + } + } + + function Generate() { + return $this->GetMenu(true); + } + + function PrintMenu($option = false) { + if ($option != false) { + return $this->GetMenu(false, $option); + } else { + return $this->GetMenu(false); + } + } +} +?> \ No newline at end of file diff --git a/inc/classes/parse.class.php b/inc/classes/parse.class.php new file mode 100644 index 0000000..2c7286c --- /dev/null +++ b/inc/classes/parse.class.php @@ -0,0 +1,326 @@ +\\1\\2', $txt); + + return $txt; + } + + function BBCode($string){ + $patterns = array( + '`\[b\](.+?)\[/b\]`is', + '`\[i\](.+?)\[/i\]`is', + '`\[u\](.+?)\[/u\]`is', + '`\[s\](.+?)\[/s\]`is', + '`\[aa\](.+?)\[/aa\]`is', + '`\[spoiler\](.+?)\[/spoiler\]`is', + ); + $replaces = array( + '\\1', + '\\1', + '\\1', + '\\1', + '
\\1
', + '\\1', + ); + $string = preg_replace($patterns, $replaces , $string); + $string = preg_replace_callback('`\[code\](.+?)\[/code\]`is', array(&$this, 'code_callback'), $string); + + return $string; + } + + function code_callback($matches) { + $return = '
' + . str_replace('
', '', $matches[1]) . + '
'; + + return $return; + } + + function ColoredQuote($buffer, $boardtype) { + /* Add a \n to keep regular expressions happy */ + if (substr($buffer, -1, 1)!="\n") { + $buffer .= "\n"; + } + + if ($boardtype==1) { + /* The css for text boards use 'quote' as the class for quotes */ + $class = 'quote'; + $linechar = ''; + } else { + /* The css for imageboards use 'unkfunc' (???) as the class for quotes */ + $class = 'unkfunc'; + $linechar = "\n"; + } + $buffer = preg_replace('/^(>[^>](.*))\n/m', '\\1' . $linechar, $buffer); + /* Remove the > from the quoted line if it is a text board */ + if ($boardtype==1) { + $buffer = str_replace('>', '', $buffer); + } + + return $buffer; + } + + function ClickableQuote($buffer, $board, $boardtype, $parentid, $boardid, $ispage = false) { + global $thread_board_return; + $thread_board_return = $board; + $thread_board_id = $boardid; + + /* Add html for links to posts in the board the post was made */ + $buffer = preg_replace_callback('/>>([r]?[l]?[f]?[q]?[0-9,\-,\,]+)/', array(&$this, 'InterthreadQuoteCheck'), $buffer); + + /* Add html for links to posts made in a different board */ + $buffer = preg_replace_callback('/>>\/([a-z]+)\/([0-9]+)/', array(&$this, 'InterboardQuoteCheck'), $buffer); + + return $buffer; + } + + function InterthreadQuoteCheck($matches) { + global $tc_db, $ispage, $thread_board_return, $thread_board_id; + + $lastchar = ''; + // If the quote ends with a , or -, cut it off. + if(substr($matches[0], -1) == "," || substr($matches[0], -1) == "-") { + $lastchar = substr($matches[0], -1); + $matches[1] = substr($matches[1], 0, -1); + $matches[0] = substr($matches[0], 0, -1); + } + if ($this->boardtype != 1 && is_numeric($matches[1])) { + + $query = "SELECT `parentid` FROM `".KU_DBPREFIX."posts` WHERE `boardid` = " . $this->boardid . " AND `id` = ".$tc_db->qstr($matches[1]); + $result = $tc_db->GetOne($query); + if ($result !== '') { + if ($result == 0) { + $realid = $matches[1]; + } else { + $realid = $result; + } + } else { + return $matches[0]; + } + + $return = ''.$matches[0].''.$lastchar; + } else { + $return = $matches[0]; + + $postids = getQuoteIds($matches[1]); + if (count($postids) > 0) { + $realid = $this->parentid; + if ($realid === 0) { + if ($this->id > 0) { + $realid = $this->id; + } + } + if ($realid !== '') { + $return = '' . $matches[0] . ''; + } + } + } + + return $return; + } + + function InterboardQuoteCheck($matches) { + global $tc_db; + + $result = $tc_db->GetAll("SELECT `id`, `type` FROM `".KU_DBPREFIX."boards` WHERE `name` = ".$tc_db->qstr($matches[1]).""); + if ($result[0]["type"] != '') { + $result2 = $tc_db->GetOne("SELECT `parentid` FROM `".KU_DBPREFIX."posts` WHERE `boardid` = " . $result[0]['id'] . " AND `id` = ".$tc_db->qstr($matches[2]).""); + if ($result2 != '') { + if ($result2 == 0) { + $realid = $matches[2]; + } else { + if ($result[0]['type'] != 1) { + $realid = $result2; + } + } + + if ($result[0]["type"] != 1) { + return ''.$matches[0].''; + } else { + return ''.$matches[0].''; + } + } + } + + return $matches[0]; + } + + function Wordfilter($buffer, $board) { + global $tc_db; + + $query = "SELECT * FROM `".KU_DBPREFIX."wordfilter`"; + $results = $tc_db->GetAll($query); + foreach($results AS $line) { + $array_boards = explode('|', $line['boards']); + if (in_array($board, $array_boards)) { + $replace_word = $line['word']; + $replace_replacedby = $line['replacedby']; + + $buffer = ($line['regex'] == 1) ? preg_replace($replace_word, $replace_replacedby, $buffer) : str_ireplace($replace_word, $replace_replacedby, $buffer); + } + } + + return $buffer; + } + + function CheckNotEmpty($buffer) { + $buffer_temp = str_replace("\n", "", $buffer); + $buffer_temp = str_replace("
", "", $buffer_temp); + $buffer_temp = str_replace("
", "", $buffer_temp); + $buffer_temp = str_replace("
", "", $buffer_temp); + + $buffer_temp = str_replace(" ", "", $buffer_temp); + + if ($buffer_temp=="") { + return ""; + } else { + return $buffer; + } + } + + /* From http://us.php.net/wordwrap */ + /*function CutWord($str, $maxLength, $char){ + $wordEndChars = array(" ", "\n", "\r", "\f", "\v", "\0"); + $count = 0; + $newStr = ""; + $openTag = false; + for($i=0; $i' . "\n"; + if($str{$i} == "<"){ + $openTag = true; + continue; + } + if(($openTag) && ($str{$i} == ">")){ + $openTag = false; + continue; + } + + if(!$openTag){ + if(!in_array($str{$i}, $wordEndChars)){//If not word ending char + $count++; + if($count==$maxLength){//if current word max length is reached + $newStr .= $char;//insert word break char + $count = 0; + } + }else{//Else char is word ending, reset word char count + $count = 0; + } + } + + }//End for + die($newStr); + return $newStr; + }*/ + + /*function CutWord($txt, $where) { + if (empty($txt)) return false; + for ($c = 0, $a = 0, $g = 0; $c $where) { + if ($usemb) { + $txt_processed .= mb_substr($txt_segment, 0, $where) . "\n"; + $txt_segment = mb_substr($txt_segment, $where); + + $segment_length = mb_strlen($txt_segment); + } else { + $txt_processed .= substr($txt_segment, 0, $where) . "\n"; + $txt_segment = substr($txt_segment, $where); + + $segment_length = strlen($txt_segment); + } + } + + $txt_processed .= $txt_segment . ' '; + } + + $txt_processed = ($usemb) ? mb_substr($txt_processed, 0, -1) : substr($txt_processed, 0, -1); + $txt_processed .= "\n"; + } + + return $txt_processed; + } + + function ParsePost($message, $board, $boardtype, $parentid, $boardid, $ispage = false) { + $this->boardtype = $boardtype; + $this->parentid = $parentid; + $this->boardid = $boardid; + + $message = trim($message); + $message = $this->CutWord($message, (KU_LINELENGTH / 15)); + $message = htmlspecialchars($message, ENT_QUOTES); + if (KU_MAKELINKS) { + $message = $this->MakeClickable($message); + } + $message = $this->ClickableQuote($message, $board, $boardtype, $parentid, $boardid, $ispage); + $message = $this->ColoredQuote($message, $boardtype); + /*if (KU_MARKDOWN) { + require KU_ROOTDIR . 'lib/markdown/markdown.php'; + $message = Markdown($message); + }*/ + $message = str_replace("\n", '
', $message); + $message = $this->BBCode($message); + $message = $this->Wordfilter($message, $board); + $message = $this->CheckNotEmpty($message); + + return $message; + } +} +?> \ No newline at end of file diff --git a/inc/classes/posting.class.php b/inc/classes/posting.class.php new file mode 100644 index 0000000..3e3cf52 --- /dev/null +++ b/inc/classes/posting.class.php @@ -0,0 +1,343 @@ +board['type'] == '2') { + /* Set the variable to tell the script it is handling an oekaki posting, and the oekaki file which will be posted */ + return KU_CGIDIR . 'kusabaoek/' . $_POST['oekaki'] . '.png'; + } + } + + return ''; + } + + function CheckReplyTime() { + global $tc_db, $board_class; + + /* Get the timestamp of the last time a reply was made by this IP address */ + $results = $tc_db->GetAll("SELECT MAX(timestamp) FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $board_class->board['id'] . " AND `parentid` != 0 AND `ipmd5` = '" . md5($_SERVER['REMOTE_ADDR']) . "' AND `timestamp` > " . (time() - KU_REPLYDELAY)); + /* If they have posted before and it was recorded... */ + if (isset($result)) { + /* If the time was shorter than the minimum time distance */ + if (time() - $line['timestamp'] <= KU_REPLYDELAY) { + exitWithErrorPage(_gettext('Please wait a moment before posting again.'), _gettext('You are currently posting faster than the configured minimum post delay allows.')); + } + } + } + + function CheckNewThreadTime() { + global $tc_db, $board_class; + + /* Get the timestamp of the last time a new thread was made by this IP address */ + $result = $tc_db->GetOne("SELECT MAX(timestamp) FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $board_class->board['id'] . " AND `parentid` = 0 AND `ipmd5` = '" . md5($_SERVER['REMOTE_ADDR']) . "' AND `timestamp` > " . (time() - KU_NEWTHREADDELAY)); + /* If they have posted before and it was recorded... */ + if (isset($result)) { + /* If the time was shorter than the minimum time distance */ + if (time() - $result <= KU_NEWTHREADDELAY) { + exitWithErrorPage(_gettext('Please wait a moment before posting again.'), _gettext('You are currently posting faster than the configured minimum post delay allows.')); + } + } + } + + function UTF8Strings() { + if (function_exists('mb_convert_encoding') && function_exists('mb_check_encoding')) { + if (isset($_POST['name']) && !mb_check_encoding($_POST['name'], 'UTF-8')) { + $_POST['name'] = mb_convert_encoding($_POST['name'], 'UTF-8'); + } + if (isset($_POST['em']) && !mb_check_encoding($_POST['em'], 'UTF-8')) { + $_POST['em'] = mb_convert_encoding($_POST['em'], 'UTF-8'); + } + if (isset($_POST['subject']) && !mb_check_encoding($_POST['subject'], 'UTF-8')) { + $_POST['subject'] = mb_convert_encoding($_POST['subject'], 'UTF-8'); + } + if (isset($_POST['message']) && !mb_check_encoding($_POST['message'], 'UTF-8')) { + $_POST['message'] = mb_convert_encoding($_POST['message'], 'UTF-8'); + } + } + } + + function CheckValidPost($is_oekaki) { + global $tc_db, $board_class; + + if ( + ( /* A message is set, or an image was provided */ + isset($_POST['message']) || + isset($_FILES['imagefile']) + ) || /* It is a validated oekaki posting */ + $is_oekaki || + ( /* It is a text board, meaning only a message is required */ + $board_class->board['type'] == '1' && + isset($_POST['message']) + ) || ( + ( /* It has embedding allowed */ + $board_class->board['uploadtype'] == '1' || + $board_class->board['uploadtype'] == '2' + ) && ( /* An embed ID was provided, or no file was checked and no ID was supplied */ + isset($_POST['embed']) || + ( + $board_class->board['uploadtype'] == '2' && + !isset($_FILES['imagefile']) && + isset($_POST['nofile']) && + $board_class->board['enablenofile'] == true + ) + ) + ) + ) { + return true; + } else { + return false; + } + } + + function CheckMessageLength() { + global $board_class; + + /* If the length of the message is greater than the board's maximum message length... */ + if (strlen($_POST['message']) > $board_class->board['messagelength']) { + /* Kill the script, stopping the posting process */ + exitWithErrorPage(sprintf(_gettext('Sorry, your message is too long. Message length: %d, maximum allowed length: %d'), strlen($_POST['message']), $board_class->board['messagelength'])); + } + } + + function CheckCaptcha() { + global $board_class; + + /* If the board has captcha's enabled... */ + if ($board_class->board['enablecaptcha'] == 1) { + if ($board_class->board['type'] == 1 && $_POST['replythread']) { + /* Check if they entered the correct code. If not... */ + if ($_SESSION['security_code'] != strtolower($_POST['captcha']) || empty($_SESSION['security_code'])) { + /* Kill the script, stopping the posting process */ + exitWithErrorPage(_gettext('Incorrect captcha entered.')); + } + } + else { + require_once(KU_ROOTDIR.'recaptchalib.php'); + $privatekey = "6LdVg8YSAAAAALayugP2r148EEQAogHPfQOSYow-"; + + // was there a reCAPTCHA response? + $resp = recaptcha_check_answer ($privatekey, + $_SERVER["REMOTE_ADDR"], + $_POST["recaptcha_challenge_field"], + $_POST["recaptcha_response_field"] + ); + if (!$resp->is_valid) { + // Show error and give user opportunity to try again. + exitWithErrorPage(_gettext('Incorrect captcha entered.')); + } + } + } + } + + function CheckBannedHash() { + global $tc_db, $board_class, $bans_class; + + /* Banned file hash check */ + if (isset($_FILES['imagefile'])) { + if ($_FILES['imagefile']['name'] != '') { + $results = $tc_db->GetAll("SELECT `bantime` , `description` FROM `" . KU_DBPREFIX . "bannedhashes` WHERE `md5` = " . $tc_db->qstr(md5_file($_FILES['imagefile']['tmp_name'])) . " LIMIT 1"); + if (count($results) > 0) { + $bans_class->BanUser($_SERVER['REMOTE_ADDR'], 'SERVER', '1', $results[0]['bantime'], '', 'Posting a banned file.
' . $results[0]['description'], 0, 0, 1); + $bans_class->BanCheck($_SERVER['REMOTE_ADDR'], $board_class->board['name']); + die(); + } + } + } + } + + function CheckIsReply() { + global $tc_db, $board_class; + + /* If it appears this is a reply to a thread, and not a new thread... */ + if (isset($_POST['replythread'])) { + if ($_POST['replythread'] != '0') { + /* Check if the thread id supplied really exists */ + $results = $tc_db->GetOne("SELECT COUNT(*) FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $board_class->board['id'] . " AND `IS_DELETED` = '0' AND `id` = " . $tc_db->qstr($_POST['replythread']) . " AND `parentid` = '0' LIMIT 1"); + /* If it does... */ + if ($results > 0) { + return true; + /* If it doesn't... */ + } else { + /* Kill the script, stopping the posting process */ + exitWithErrorPage(_gettext('Invalid thread ID.'), _gettext('That thread may have been recently deleted.')); + } + } + } + + return false; + } + + function CheckNotDuplicateSubject($subject) { + global $tc_db, $board_class; + + $result = $tc_db->GetOne("SELECT COUNT(*) FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $board_class->board['id'] . " AND `IS_DELETED` = '0' AND `subject` = " . $tc_db->qstr($subject) . " AND `parentid` = '0'"); + if ($result > 0) { + exitWithErrorPage(_gettext('Duplicate thread subject'), _gettext('Text boards may have only one thread with a unique subject. Please pick another.')); + } + } + + function GetThreadInfo($id) { + global $tc_db, $board_class; + + /* Check if the thread id supplied really exists and if it is locked */ + $results = $tc_db->GetAll("SELECT `id`,`locked` FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $board_class->board['id'] . " AND `IS_DELETED` = '0' AND `id` = " . $tc_db->qstr($id) . " AND `parentid` = '0'"); + /* If it does... */ + if (count($results) > 0) { + /* Get the thread's info */ + $thread_locked = $results[0]['locked']; + $thread_replyto = $results[0]['id']; + /* Get the number of replies */ + $result = $tc_db->GetOne("SELECT COUNT(id) FROM `" . KU_DBPREFIX ."posts` WHERE `boardid` = " . $board_class->board['id'] . " AND `IS_DELETED` = '0' AND `parentid` = " . $tc_db->qstr($id) . ""); + $thread_replies = $result; + + return array($thread_replies, $thread_locked, $thread_replyto); + } else { + /* If it doesn't, kill the script, stopping the posting process */ + exitWithErrorPage(_gettext('Invalid thread ID.'), _gettext('That thread may have been recently deleted.')); + } + } + + function GetFields() { + /* Fetch and process the name, email, and subject fields from the post data */ + $post_name = isset($_POST['name']) ? htmlspecialchars($_POST['name'], ENT_QUOTES) : ''; + $post_email = isset($_POST['em']) ? str_replace('"', '', strip_tags($_POST['em'])) : ''; + /* If the user used a software function, don't store it in the database */ + if ($post_email == 'return' || $post_email == 'noko') $post_email = ''; + $post_subject = isset($_POST['subject']) ? htmlspecialchars($_POST['subject'], ENT_QUOTES) : ''; + + return array($post_name, $post_email, $post_subject); + } + + function GetUserAuthority() { + global $tc_db, $board_class; + + $user_authority = 0; + $flags = ''; + + if (isset($_POST['modpassword'])) { + + $results = $tc_db->GetAll("SELECT `type`, `boards` FROM `" . KU_DBPREFIX . "staff` WHERE `username` = '" . md5_decrypt($_POST['modpassword'], KU_RANDOMSEED) . "' LIMIT 1"); + + if (count($results) > 0) { + if ($results[0][0] == 1) { + $user_authority = 1; // admin + } elseif ($results[0][0] == 2 && in_array($board_class->board['name'], explode('|', $results[0][1]))) { + $user_authority = 2; // mod + } elseif ($results[0][0] == 2 && $results[0][1] == 'allboards') { + $user_authority = 2; + }/* elseif ($results[0][0] == 3) { + $user_authority = 3; // VIP + }*/ + if ($user_authority < 3) { /* set posting flags for mods and admins */ + if (isset($_POST['displaystaffstatus'])) $flags .= 'D'; + if (isset($_POST['lockonpost'])) $flags .= 'L'; + if (isset($_POST['stickyonpost'])) $flags .= 'S'; + if (isset($_POST['rawhtml'])) $flags .= 'RH'; + if (isset($_POST['usestaffname'])) $flags .= 'N'; + } + } + } + + return array($user_authority, $flags); + } + + function CheckBadUnicode($post_name, $post_email, $post_subject, $post_message) { + /* Check for bad characters which can cause the page to deform (right-to-left markers, etc) */ + $bad_ords = array(8235, 8238); + + $ords_name = unistr_to_ords($post_name); + $ords_email = unistr_to_ords($post_email); + $ords_subject = unistr_to_ords($post_subject); + $ords_message = unistr_to_ords($post_message); + $ords_filename = isset($_FILES['imagefile']) ? unistr_to_ords($_FILES['imagefile']['name']) : ''; + foreach ($bad_ords as $bad_ord) { + if ($ords_name != '') { + if (in_array($bad_ord, $ords_name)) { + exitWithErrorPage(_gettext('Your post contains one or more illegal characters.')); + } + } + if ($ords_email != '') { + if (in_array($bad_ord, $ords_email)) { + exitWithErrorPage(_gettext('Your post contains one or more illegal characters.')); + } + } + if ($ords_subject != '') { + if (in_array($bad_ord, $ords_subject)) { + exitWithErrorPage(_gettext('Your post contains one or more illegal characters.')); + } + } + if ($ords_message != '') { + if (in_array($bad_ord, $ords_message)) { + exitWithErrorPage(_gettext('Your post contains one or more illegal characters.')); + } + } + if ($ords_filename != '') { + if (in_array($bad_ord, $ords_filename)) { + exitWithErrorPage(_gettext('Your post contains one or more illegal characters.')); + } + } + } + } + + function GetPostTag() { + global $board_class; + + /* Check for and parse tags if one was provided, and they are enabled */ + $post_tag = ''; + $tags = unserialize(KU_TAGS); + if ($board_class->board['type'] == 3 && $tags != '' && isset($_POST['tag'])) { + if ($_POST['tag'] != '') { + $validtag = false; + while (list($tag, $tag_abbr) = each($tags)) { + if ($tag_abbr == $_POST['tag']) { + $validtag = true; + } + } + if ($validtag) { + $post_tag = $_POST['tag']; + } + } + } + + return $post_tag; + } + + function CheckBlacklistedText() { + global $bans_class, $tc_db; + $badlinks = array_map('rtrim', file(KU_ROOTDIR . 'spam.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)); + + foreach ($badlinks as $badlink) { + if (stripos($_POST['message'], $badlink) !== false) { + /* They included a blacklisted link in their post. Ban them for an hour */ + $bans_class->BanUser($_SERVER['REMOTE_ADDR'], 'board.php', 1, 3600, '', _gettext('Posting a blacklisted link.') . ' (' . $badlink . ')', $_POST['message']); + exitWithErrorPage(sprintf(_gettext('Blacklisted link ( %s ) detected.'), $badlink)); + } + } + } +} + +?> diff --git a/inc/classes/randword.class.php b/inc/classes/randword.class.php new file mode 100644 index 0000000..170a599 --- /dev/null +++ b/inc/classes/randword.class.php @@ -0,0 +1,98 @@ +word .= $this->consonants[array_rand($this->consonants)]; + $const_or_vowel = 2; + break; + case 2: + $this->word .= $this->vowels[array_rand($this->vowels)]; + $const_or_vowel = 1; + break; + } + + if (strlen($this->word) >= $length) + { + $done = true; + } + } + + $this->word = substr($this->word, 0, $length); + + if ($lower_case) + { + $this->word = strtolower($this->word); + } + else if ($ucfirst) + { + $this->word = ucfirst(strtolower($this->word)); + } + else if ($upper_case) + { + $this->word = strtoupper($this->word); + } + return $this->word; + } +} + +?> \ No newline at end of file diff --git a/inc/classes/rss.class.php b/inc/classes/rss.class.php new file mode 100644 index 0000000..b875ee2 --- /dev/null +++ b/inc/classes/rss.class.php @@ -0,0 +1,50 @@ +GetAll("SELECT * FROM `".KU_DBPREFIX."posts` WHERE `boardid` = " . $rssboardid . " AND `IS_DELETED` = '0' ORDER BY `id` DESC LIMIT 15"); + $dwoo_data->assign('posts', $posts); + $dwoo_data->assign('boardname', $rssboard); + $rss = $dwoo->get(KU_TEMPLATEDIR . '/rss_board.tpl', $dwoo_data); + } + return $rss; + } + + function GenerateModLogRSS() { + global $tc_db; + require_once KU_ROOTDIR.'lib/dwoo.php'; + $dwoo = new Dwoo(); + $dwoo_data = new Dwoo_Data(); + $entries = $tc_db->GetAll("SELECT * FROM `".KU_DBPREFIX."modlog` ORDER BY `timestamp` DESC LIMIT 15"); + $dwoo_data->assign('entries', $entries); + $rss = $dwoo->get(KU_TEMPLATEDIR . '/rss_mod.tpl', $dwoo_data); + + return($rss); + } +} +?> diff --git a/inc/classes/svg.class.php b/inc/classes/svg.class.php new file mode 100644 index 0000000..5022fc0 --- /dev/null +++ b/inc/classes/svg.class.php @@ -0,0 +1,51 @@ +width = (string) $xml['width']; + $this->height = (string) $xml['height']; + $this->id = (string) $xml['id']; + $this->version = (string) $xml['version']; + $this->namespaces = $xml->getNamespaces(); + $sodipodi = $xml->attributes($this->namespaces['sodipodi']); + $this->docname = (string) $sodipodi['docname']; + $this->docbase = (string) $sodipodi['docbase']; + $this->sodipodiversion = (string) $sodipodi['version']; + $inkscape = $xml->attributes($this->namespaces['inkscape']); + $this->inkscapeversion = (string) $inkscape['version']; + $this->output_extension = (string) $inkscape['ouput_extension']; + } +} + +?> \ No newline at end of file diff --git a/inc/classes/upload.class.php b/inc/classes/upload.class.php new file mode 100644 index 0000000..c71ddbd --- /dev/null +++ b/inc/classes/upload.class.php @@ -0,0 +1,412 @@ +board['type'] == 0 || $board_class->board['type'] == 2 || $board_class->board['type'] == 3) { + $imagefile_name = isset($_FILES['imagefile']) ? $_FILES['imagefile']['name'] : ''; + if ($imagefile_name != '') { + if (strpos($_FILES['imagefile']['name'], ',') != false) { + exitWithErrorPage(_gettext('Please select only one image to upload.')); + } + + if ($_FILES['imagefile']['size'] > $board_class->board['maximagesize']) { + exitWithErrorPage(sprintf(_gettext('Please make sure your file is smaller than %dB'), $board_class->board['maximagesize'])); + } + + switch ($_FILES['imagefile']['error']) { + case UPLOAD_ERR_OK: + break; + case UPLOAD_ERR_INI_SIZE: + exitWithErrorPage(sprintf(_gettext('The uploaded file exceeds the upload_max_filesize directive (%s) in php.ini.')), ini_get('upload_max_filesize')); + break; + case UPLOAD_ERR_FORM_SIZE: + exitWithErrorPage(sprintf(_gettext('Please make sure your file is smaller than %dB'), $board_class->board['maximagesize'])); + break; + case UPLOAD_ERR_PARTIAL: + exitWithErrorPage(_gettext('The uploaded file was only partially uploaded.')); + break; + case UPLOAD_ERR_NO_FILE: + exitWithErrorPage(_gettext('No file was uploaded.')); + break; + case UPLOAD_ERR_NO_TMP_DIR: + exitWithErrorPage(_gettext('Missing a temporary folder.')); + break; + case UPLOAD_ERR_CANT_WRITE: + exitWithErrorPage(_gettext('Failed to write file to disk')); + break; + default: + exitWithErrorPage(_gettext('Unknown File Error')); + } + + $this->file_type = preg_replace('/.*(\..+)/','\1',$_FILES['imagefile']['name']); + if ($this->file_type == '.jpeg') { + /* Fix for the rarely used 4-char format */ + $this->file_type = '.jpg'; + } + + $pass = true; + if (!is_file($_FILES['imagefile']['tmp_name']) || !is_readable($_FILES['imagefile']['tmp_name'])) { + $pass = false; + } else { + if ($this->file_type == '.jpg' || $this->file_type == '.gif' || $this->file_type == '.png') { + if (!@getimagesize($_FILES['imagefile']['tmp_name'])) { + $pass = false; + } + } + } + if (!$pass) { + exitWithErrorPage(_gettext('File transfer failure. Please go back and try again.')); + } + + $this->file_name = substr(htmlspecialchars(preg_replace('/(.*)\..+/','\1',$_FILES['imagefile']['name']), ENT_QUOTES), 0, 50); + $this->file_name = str_replace('.','_',$this->file_name); + $this->original_file_name = $this->file_name; + $this->file_md5 = md5_file($_FILES['imagefile']['tmp_name']); + + $exists_thread = checkMd5($this->file_md5, $board_class->board['name'], $board_class->board['id']); + if (is_array($exists_thread)) { + exitWithErrorPage(_gettext('Duplicate file entry detected.'), sprintf(_gettext('Already posted %shere%s.'),'','')); + } + + if (strtolower($this->file_type) == 'svg') { + require_once 'svg.class.php'; + $svg = new Svg($_FILES['imagefile']['tmp_name']); + $this->imgWidth = $svg->width; + $this->imgHeight = $svg->height; + } else { + $imageDim = getimagesize($_FILES['imagefile']['tmp_name']); + $this->imgWidth = $imageDim[0]; + $this->imgHeight = $imageDim[1]; + } + + $this->file_type = strtolower($this->file_type); + $this->file_size = $_FILES['imagefile']['size']; + + $filetype_forcethumb = $tc_db->GetOne("SELECT " . KU_DBPREFIX . "filetypes.force_thumb FROM " . KU_DBPREFIX . "boards, " . KU_DBPREFIX . "filetypes, " . KU_DBPREFIX . "board_filetypes WHERE " . KU_DBPREFIX . "boards.id = " . KU_DBPREFIX . "board_filetypes.boardid AND " . KU_DBPREFIX . "filetypes.id = " . KU_DBPREFIX . "board_filetypes.typeid AND " . KU_DBPREFIX . "boards.name = '" . $board_class->board['name'] . "' and " . KU_DBPREFIX . "filetypes.filetype = '" . substr($this->file_type, 1) . "';"); + if ($filetype_forcethumb != '') { + if ($filetype_forcethumb == 0) { + $this->file_name = time() . mt_rand(1, 99); + + /* If this board has a load balance url and password configured for it, attempt to use it */ + if ($board_class->board['loadbalanceurl'] != '' && $board_class->board['loadbalancepassword'] != '') { + require_once KU_ROOTDIR . 'inc/classes/loadbalancer.class.php'; + $loadbalancer = new Load_Balancer; + + $loadbalancer->url = $board_class->board['loadbalanceurl']; + $loadbalancer->password = $board_class->board['loadbalancepassword']; + + $response = $loadbalancer->Send('thumbnail', base64_encode(file_get_contents($_FILES['imagefile']['tmp_name'])), 'src/' . $this->file_name . $this->file_type, 'thumb/' . $this->file_name . 's' . $this->file_type, 'thumb/' . $this->file_name . 'c' . $this->file_type, '', $this->isreply, true); + + if ($response != 'failure' && $response != '') { + $response_unserialized = unserialize($response); + + $this->imgWidth_thumb = $response_unserialized['imgw_thumb']; + $this->imgHeight_thumb = $response_unserialized['imgh_thumb']; + + $imageused = true; + } else { + exitWithErrorPage(_gettext('File was not properly thumbnailed').': ' . $response); + } + /* Otherwise, use this script alone */ + } else { + $this->file_location = KU_BOARDSDIR . $board_class->board['name'] . '/src/' . $this->file_name . $this->file_type; + $this->file_thumb_location = KU_BOARDSDIR . $board_class->board['name'] . '/thumb/' . $this->file_name . 's' . $this->file_type; + $this->file_thumb_cat_location = KU_BOARDSDIR . $board_class->board['name'] . '/thumb/' . $this->file_name . 'c' . $this->file_type; + + if (!move_uploaded_file($_FILES['imagefile']['tmp_name'], $this->file_location)) { + exitWithErrorPage(_gettext('Could not copy uploaded image.')); + } + chmod($this->file_location, 0644); + + if ($_FILES['imagefile']['size'] == filesize($this->file_location)) { + if ((!$this->isreply && ($this->imgWidth > KU_THUMBWIDTH || $this->imgHeight > KU_THUMBHEIGHT)) || ($this->isreply && ($this->imgWidth > KU_REPLYTHUMBWIDTH || $this->imgHeight > KU_REPLYTHUMBHEIGHT))) { + if (!$this->isreply) { + if (!createThumbnail($this->file_location, $this->file_thumb_location, KU_THUMBWIDTH, KU_THUMBHEIGHT)) { + exitWithErrorPage(_gettext('Could not create thumbnail.')); + } + } else { + if (!createThumbnail($this->file_location, $this->file_thumb_location, KU_REPLYTHUMBWIDTH, KU_REPLYTHUMBHEIGHT)) { + exitWithErrorPage(_gettext('Could not create thumbnail.')); + } + } + } else { + if (!createThumbnail($this->file_location, $this->file_thumb_location, $this->imgWidth, $this->imgHeight)) { + exitWithErrorPage(_gettext('Could not create thumbnail.')); + } + } + if (!createThumbnail($this->file_location, $this->file_thumb_cat_location, KU_CATTHUMBWIDTH, KU_CATTHUMBHEIGHT)) { + exitWithErrorPage(_gettext('Could not create thumbnail.')); + } + $imageDim_thumb = getimagesize($this->file_thumb_location); + $this->imgWidth_thumb = $imageDim_thumb[0]; + $this->imgHeight_thumb = $imageDim_thumb[1]; + $imageused = true; + } else { + exitWithErrorPage(_gettext('File was not fully uploaded. Please go back and try again.')); + } + } + } else { + /* Fetch the mime requirement for this special filetype */ + $filetype_required_mime = $tc_db->GetOne("SELECT `mime` FROM `" . KU_DBPREFIX . "filetypes` WHERE `filetype` = " . $tc_db->qstr(substr($this->file_type, 1))); + + $this->file_name = htmlspecialchars_decode($this->file_name, ENT_QUOTES); + $this->file_name = stripslashes($this->file_name); + $this->file_name = str_replace("\x80", " ", $this->file_name); + $this->file_name = str_replace(' ', '_', $this->file_name); + $this->file_name = str_replace('#', '(number)', $this->file_name); + $this->file_name = str_replace('@', '(at)', $this->file_name); + $this->file_name = str_replace('/', '(fwslash)', $this->file_name); + $this->file_name = str_replace('\\', '(bkslash)', $this->file_name); + + /* If this board has a load balance url and password configured for it, attempt to use it */ + if ($board_class->board['loadbalanceurl'] != '' && $board_class->board['loadbalancepassword'] != '') { + require_once KU_ROOTDIR . 'inc/classes/loadbalancer.class.php'; + $loadbalancer = new Load_Balancer; + + $loadbalancer->url = $board_class->board['loadbalanceurl']; + $loadbalancer->password = $board_class->board['loadbalancepassword']; + + if ($filetype_required_mime != '') { + $checkmime = $filetype_required_mime; + } else { + $checkmime = ''; + } + + $response = $loadbalancer->Send('direct', $_FILES['imagefile']['tmp_name'], 'src/' . $this->file_name . $this->file_type, '', '', $checkmime, false, true); + + $this->file_is_special = true; + /* Otherwise, use this script alone */ + } else { + $this->file_location = KU_BOARDSDIR . $board_class->board['name'] . '/src/' . $this->file_name . $this->file_type; + + if (file_exists($this->file_location)) { + exitWithErrorPage(_gettext('A file by that name already exists')); + die(); + } + + if($this->file_type == '.mp3') { + require_once(KU_ROOTDIR . 'lib/getid3/getid3.php'); + + $getID3 = new getID3; + $getID3->analyze($_FILES['imagefile']['tmp_name']); + if (isset($getID3->info['id3v2']['APIC'][0]['data']) && isset($getID3->info['id3v2']['APIC'][0]['image_mime'])) { + $source_data = $getID3->info['id3v2']['APIC'][0]['data']; + $mime = $getID3->info['id3v2']['APIC'][0]['image_mime']; + } + elseif (isset($getID3->info['id3v2']['PIC'][0]['data']) && isset($getID3->info['id3v2']['PIC'][0]['image_mime'])) { + $source_data = $getID3->info['id3v2']['PIC'][0]['data']; + $mime = $getID3->info['id3v2']['PIC'][0]['image_mime']; + } + + if($source_data) { + $im = imagecreatefromstring($source_data); + if (preg_match("/png/", $mime)) { + $ext = ".png"; + imagepng($im,$this->file_location.".tmp",0,PNG_ALL_FILTERS); + } else if (preg_match("/jpg|jpeg/", $mime)) { + $ext = ".jpg"; + imagejpeg($im, $this->file_location.".tmp"); + } else if (preg_match("/gif/", $mime)) { + $ext = ".gif"; + imagegif($im, $this->file_location.".tmp"); + } + $this->file_thumb_location = KU_BOARDSDIR . $board_class->board['name'] . '/thumb/' . $this->file_name .'s'. $ext; + if (!$this->isreply) { + if (!createThumbnail($this->file_location.".tmp", $this->file_thumb_location, KU_THUMBWIDTH, KU_THUMBHEIGHT)) { + exitWithErrorPage(_gettext('Could not create thumbnail.')); + } + } else { + if (!createThumbnail($this->file_location.".tmp", $this->file_thumb_location, KU_REPLYTHUMBWIDTH, KU_REPLYTHUMBHEIGHT)) { + exitWithErrorPage(_gettext('Could not create thumbnail.')); + } + } + $imageDim_thumb = getimagesize($this->file_thumb_location); + $this->imgWidth_thumb = $imageDim_thumb[0]; + $this->imgHeight_thumb = $imageDim_thumb[1]; + $imageused = true; + unlink($this->file_location.".tmp"); + } + + + } + + /* Move the file from the post data to the server */ + if (!move_uploaded_file($_FILES['imagefile']['tmp_name'], $this->file_location)) { + exitWithErrorPage(_gettext('Could not copy uploaded image.')); + } + + /* Check if the filetype provided comes with a MIME restriction */ + if ($filetype_required_mime != '') { + /* Check if the MIMEs don't match up */ + if (mime_content_type($this->file_location) != $filetype_required_mime) { + /* Delete the file we just uploaded and kill the script */ + unlink($this->file_location); + exitWithErrorPage(_gettext('Invalid MIME type for this filetype.')); + } + } + + /* Make sure the entire file was uploaded */ + if ($_FILES['imagefile']['size'] == filesize($this->file_location)) { + $imageused = true; + } else { + exitWithErrorPage(_gettext('File transfer failure. Please go back and try again.')); + } + + /* Flag that the file used isn't an internally supported type */ + $this->file_is_special = true; + } + } + } else { + exitWithErrorPage(_gettext('Sorry, that filetype is not allowed on this board.')); + } + } elseif (isset($_POST['embed'])) { + if ($_POST['embed'] != '') { + $_POST['embed'] = strip_tags(substr($_POST['embed'], 0, 20)); + $video_id = $_POST['embed']; + $this->file_name = $video_id; + + if ($video_id != '' && strpos($video_id, '@') == false && strpos($video_id, '&') == false) { + + $embeds = $tc_db->GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "embeds`"); + $worked = false; + + foreach ($embeds as $line) { + if ((strtolower($_POST['embedtype']) == strtolower($line['name'])) && in_array($line['filetype'], explode(',', $board_class->board['embeds_allowed']))) { + $worked = true; + $videourl_start = $line['videourl']; + $this->file_type = '.' . strtolower($line['filetype']); + } + } + + if (!$worked) { + exitWithErrorPage(_gettext('Invalid video type.')); + } + + $results = $tc_db->GetOne("SELECT COUNT(*) FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $board_class->board['id'] . " AND `file` = " . $tc_db->qstr($video_id) . " AND `IS_DELETED` = 0"); + if ($results[0] == 0) { + $video_check = check_link($videourl_start . $video_id); + switch ($video_check[1]) { + case 404: + exitWithErrorPage(_gettext('Unable to connect to') .': '. $videourl_start . $video_id); + break; + case 303: + exitWithErrorPage(_gettext('Invalid video ID.')); + break; + case 302: + // Continue + break; + case 301: + // Continue + break; + case 200: + // Continue + break; + default: + exitWithErrorPage(_gettext('Invalid response code ') .':'. $video_check[1]); + break; + } + } else { + $results = $tc_db->GetAll("SELECT `id`,`parentid` FROM `" . KU_DBPREFIX . "posts` WHERE `boardid` = " . $board_class->board['id'] . " AND `file` = " . $tc_db->qstr($video_id) . " AND `IS_DELETED` = 0 LIMIT 1"); + foreach ($results as $line) { + $real_threadid = ($line[1] == 0) ? $line[0] : $line[1]; + exitWithErrorPage(sprintf(_gettext('That video ID has already been posted %shere%s.'),'','')); + } + } + } else { + exitWithErrorPage(_gettext('Invalid ID')); + } + } + } + } + } else { + $this->file_name = time() . mt_rand(1, 99); + $this->original_file_name = $this->file_name; + $this->file_md5 = md5_file($oekaki); + $this->file_type = '.png'; + $this->file_size = filesize($oekaki); + $imageDim = getimagesize($oekaki); + $this->imgWidth = $imageDim[0]; + $this->imgHeight = $imageDim[1]; + + if (!copy($oekaki, KU_BOARDSDIR . $board_class->board['name'] . '/src/' . $this->file_name . $this->file_type)) { + exitWithErrorPage(_gettext('Could not copy uploaded image.')); + } + + $oekaki_animation = substr($oekaki, 0, -4) . '.pch'; + if (file_exists($oekaki_animation)) { + if (!copy($oekaki_animation, KU_BOARDSDIR . $board_class->board['name'] . '/src/' . $this->file_name . '.pch')) { + exitWithErrorPage(_gettext('Could not copy animation.')); + } + unlink($oekaki_animation); + } + + $thumbpath = KU_BOARDSDIR . $board_class->board['name'] . '/thumb/' . $this->file_name . 's' . $this->file_type; + $thumbpath_cat = KU_BOARDSDIR . $board_class->board['name'] . '/thumb/' . $this->file_name . 'c' . $this->file_type; + if ( + (!$this->isreply && ($this->imgWidth > KU_THUMBWIDTH || $this->imgHeight > KU_THUMBHEIGHT)) || + ($this->isreply && ($this->imgWidth > KU_REPLYTHUMBWIDTH || $this->imgHeight > KU_REPLYTHUMBHEIGHT)) + ) { + if (!$this->isreply) { + if (!createThumbnail($oekaki, $thumbpath, KU_THUMBWIDTH, KU_THUMBHEIGHT)) { + exitWithErrorPage(_gettext('Could not create thumbnail.')); + } + } else { + if (!createThumbnail($oekaki, $thumbpath, KU_REPLYTHUMBWIDTH, KU_REPLYTHUMBHEIGHT)) { + exitWithErrorPage(_gettext('Could not create thumbnail.')); + } + } + } else { + if (!createThumbnail($oekaki, $thumbpath, $this->imgWidth, $this->imgHeight)) { + exitWithErrorPage(_gettext('Could not create thumbnail.')); + } + } + if (!createThumbnail($oekaki, $thumbpath_cat, KU_CATTHUMBWIDTH, KU_CATTHUMBHEIGHT)) { + exitWithErrorPage(_gettext('Could not create thumbnail.')); + } + + $imgDim_thumb = getimagesize($thumbpath); + $this->imgWidth_thumb = $imgDim_thumb[0]; + $this->imgHeight_thumb = $imgDim_thumb[1]; + unlink($oekaki); + } + } +} +?> diff --git a/inc/embedhelp/Thumbs.db b/inc/embedhelp/Thumbs.db new file mode 100644 index 0000000..ec0bfa1 Binary files /dev/null and b/inc/embedhelp/Thumbs.db differ diff --git a/inc/embedhelp/google.jpg b/inc/embedhelp/google.jpg new file mode 100644 index 0000000..d3785b1 Binary files /dev/null and b/inc/embedhelp/google.jpg differ diff --git a/inc/embedhelp/youtube.jpg b/inc/embedhelp/youtube.jpg new file mode 100644 index 0000000..bc27407 Binary files /dev/null and b/inc/embedhelp/youtube.jpg differ diff --git a/inc/filetypes/Thumbs.db b/inc/filetypes/Thumbs.db new file mode 100644 index 0000000..a769a02 Binary files /dev/null and b/inc/filetypes/Thumbs.db differ diff --git a/inc/filetypes/aboutthisdir.txt b/inc/filetypes/aboutthisdir.txt new file mode 100644 index 0000000..2d4d905 --- /dev/null +++ b/inc/filetypes/aboutthisdir.txt @@ -0,0 +1 @@ +If you wish to allow different filetypes to be uploaded than the default which come with TC, place your own images here and add the filetype in the manage panel. diff --git a/inc/filetypes/audio.gif b/inc/filetypes/audio.gif new file mode 100644 index 0000000..706cea6 Binary files /dev/null and b/inc/filetypes/audio.gif differ diff --git a/inc/filetypes/flash.png b/inc/filetypes/flash.png new file mode 100644 index 0000000..e44e15f Binary files /dev/null and b/inc/filetypes/flash.png differ diff --git a/inc/filetypes/generic.png b/inc/filetypes/generic.png new file mode 100644 index 0000000..21e0d53 Binary files /dev/null and b/inc/filetypes/generic.png differ diff --git a/inc/func/apc.php b/inc/func/apc.php new file mode 100644 index 0000000..0e7cd01 --- /dev/null +++ b/inc/func/apc.php @@ -0,0 +1,22 @@ +Execute("DELETE FROM `" . KU_DBPREFIX . "reports` WHERE `postid` = " . $id . " AND `board` = " . $tc_db->qstr($board)); +} +?> diff --git a/inc/func/calculations.php b/inc/func/calculations.php new file mode 100644 index 0000000..5df63e4 --- /dev/null +++ b/inc/func/calculations.php @@ -0,0 +1,136 @@ + 1) { + $last_posts_to_fetch = substr($postid, 1); + if ($last_posts_to_fetch >= 1) { + $last_posts_to_fetch = min($last_posts_to_fetch, $replies); + $min_posts_to_fetch = max((($replies + 1) - $last_posts_to_fetch), 1); + if ($min_posts_to_fetch > 1) { + $min_posts_to_fetch++; + } + + $lastposts = range($min_posts_to_fetch, ($replies + 1)); + + $key = array_search($postid, $postids, true); + array_insert($postids, $key, $lastposts); + + $key = array_search($postid, $postids, true); + if ($key !== false) { + unset($postids[$key]); + } + } + } + } + if (strpos($postid, '-') !== false) { + $range_processed = Array(); + $rangeids = split('-', $postid); + if (count($rangeids) == 2) { + if(empty($rangeids[1])){ + $postids['BETWEEN'][$i][] = 0; + $postids['BETWEEN'][$i][] = $rangeids[0]; + } + else { + $postids['BETWEEN'][$i][] = $rangeids[0]; + $postids['BETWEEN'][$i][] = $rangeids[1]; + } + $i++; + } + } + + if (strpos($postid, 'r') === 0 && $replies !== false) { + if (strlen($postid) > 1) { + $random_posts_to_fetch = substr($postid, 1); + if ($random_posts_to_fetch >= 1) { + $randposts = array(); + //$random_posts_to_fetch = min($random_posts_to_fetch, $replies); + for ($i=0;$i<$random_posts_to_fetch;$i++) { + $postinserted = false; + + while (!$postinserted) { + $randpost = rand(1, $replies); + //if (!in_array($randpost, $randposts)) { + $randposts[] = $randpost; + $postinserted = true; + //} + } + } + + $key = array_search($postid, $postids, true); + array_insert($postids, $key, $randposts); + + $key = array_search($postid, $postids, true); + if ($key !== false) { + unset($postids[$key]); + } + } + } + } + } + + return $postids; +} + +function array_insert(&$array, $position, $insert_array) { + if (!is_int($position)) { + $i = 0; + foreach ($array as $key => $value) { + if ($key == $position) { + $position = $i; + break; + } + $i++; + } + } + $first_array = array_splice($array, 0, $position); + $array = array_merge($first_array, $insert_array, $array); +} + + +function cleanBoardName($board) { + return trim(str_replace('/', '', str_replace('|', '', str_replace(' ', '', $board)))); +} + +/** + * Convert a board ID to a board name + * + * @param integer $boardid Board ID + * @return string Board directory + */ +function boardid_to_dir($boardid) { + global $tc_db; + + $query = "SELECT `name` FROM `".KU_DBPREFIX."boards` WHERE `id` = ".$tc_db->qstr($boardid).""; + $results = $tc_db->SelectLimit($query, 1); + if (count($results)>0) { + foreach($results AS $line) { + return $line['name']; + } + } +} + +/** + * Calculate the number of pages which will be needed for the supplied number of posts + * + * @param integer $boardtype Board type + * @param integer $numposts Number of posts + * @return integer Number of pages required + */ +function calculatenumpages($boardtype, $numposts) { + if ($boardtype==1) { + return (floor($numposts/KU_THREADSTXT)); + } elseif ($boardtype==3) { + return (floor($numposts/30)); + } + + return (floor($numposts/KU_THREADS)); +} +?> \ No newline at end of file diff --git a/inc/func/custom.php b/inc/func/custom.php new file mode 100644 index 0000000..38c7edb --- /dev/null +++ b/inc/func/custom.php @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/inc/func/directories.php b/inc/func/directories.php new file mode 100644 index 0000000..ee60e4f --- /dev/null +++ b/inc/func/directories.php @@ -0,0 +1,169 @@ +"; + } + else if (is_dir($file) === TRUE) { + /* If this Directory contains a Subdirectory, run this Function on it */ + removeDir($file); + } + } + /* Remove Directory once Files have been removed (If Exists) */ + if (is_dir($path) === TRUE) { + rmdir($path); + echo '
'. _gettext('Removed Directory').': ' . $path . "

"; + } +} + +/** + * Remove a board + * + * @param string $dir Directory to remove + * @return boolean Result + */ +function removeBoard($dir){ + global $tc_db; + + if(!isset($GLOBALS['remerror'])) { + $GLOBALS['remerror'] = false; + } + + if($handle = opendir(KU_BOARDSDIR . $dir)){ /* If the folder exploration is sucsessful, continue */ + while (false !== ($file = readdir($handle))){ /* As long as storing the next file to $file is successful, continue */ + $path = $dir . '/' . $file; + + if(is_file(KU_BOARDSDIR . $path)){ + if(!unlink(KU_BOARDSDIR . $path)){ + echo ''.sprintf(_gettext('"%s" could not be deleted. This may be due to a permissions problem.
Directory cannot be deleted until all files are deleted.'), $path).'

'; + $GLOBALS['remerror'] = true; + return false; + } + } else + if(is_dir(KU_BOARDSDIR . $path) && substr($file, 0, 1) != '.'){ + removeBoard($path); + @rmdir(KU_BOARDSDIR . $path); + } + } + closedir($handle); /* Close the folder exploration */ + } + + if(!$GLOBALS['remerror']) /* If no errors occured, delete the now empty directory */ + if(!rmdir(KU_BOARDSDIR . $dir)){ + echo ''.sprintf(_gettext('Could not remove directory "%s". This may be due to a permissions problem.'),$dir).'
'.$GLOBALS['remerror']; + return false; + } else + return true; + + return false; +} + +/* +------------ lixlpixel recursive PHP functions ------------- +recursive_directory_size( directory, human readable format ) +expects path to directory and optional TRUE / FALSE +PHP has to have the rights to read the directory you specify +and all files and folders inside the directory to count size +if you choose to get human readable format, +the function returns the filesize in bytes, KB and MB +------------------------------------------------------------ +to use this function to get the filesize in bytes, write: +recursive_directory_size('path/to/directory/to/count'); +to use this function to get the size in a nice format, write: +recursive_directory_size('path/to/directory/to/count',TRUE); +*/ + +/** + * Find the size of a directory, including any subdirectories + * + * @param string $directory Directory + * @param boolean $format Format + * @return array Size/number of files + */ +function recursive_directory_size($directory, $format=FALSE) +{ + $size = 0; + $files = 0; + + /* If the path has a slash at the end we remove it here */ + if(substr($directory,-1) == '/') + { + $directory = substr($directory,0,-1); + } + + /* If the path is not valid or is not a directory ... */ + if(!file_exists($directory) || !is_dir($directory) || !is_readable($directory)) + { + /* ... We return -1 and exit the function */ + return -1; + } + /* We open the directory */ + if($handle = opendir($directory)) + { + /* And scan through the items inside */ + while(($file = readdir($handle)) !== false) + { + /* We build the new path */ + $path = $directory.'/'.$file; + + /* If the filepointer is not the current directory or the parent directory */ + if($file != '.' && $file != '..') + { + /* If the new path is a file */ + if(is_file($path)) + { + /* We add the filesize to the total size */ + $size += filesize($path); + $files++; + + /* If the new path is a directory */ + }elseif(is_dir($path)) + { + /* If $format is set to true, follow the directory and recalculate from there */ + if ($format) { + /* We call this function with the new path */ + $handlesize = recursive_directory_size($path); + + if (is_int($handlesize)) { + /* If the function returns more than zero */ + if($handlesize >= 0) + { + /* We add the result to the total size */ + $size += $handlesize; + + /* Else we return -1 and exit the function */ + }else{ + return -1; + } + /* Else we return -1 and exit the function */ + }else{ + return -1; + } + } + } + } + } + /* Close the directory */ + closedir($handle); + } + /* Return the total filesize in bytes */ + return array($size,$files); +} +?> \ No newline at end of file diff --git a/inc/func/encryption.php b/inc/func/encryption.php new file mode 100644 index 0000000..04cbf6a --- /dev/null +++ b/inc/func/encryption.php @@ -0,0 +1,44 @@ + 0) { + $iv .= chr(mt_rand() & 0xff); + } + return $iv; +} +function md5_encrypt($plain_text, $password, $iv_len = 16) { + $plain_text .= "\x13"; + $n = strlen($plain_text); + if ($n % 16) $plain_text .= str_repeat("\0", 16 - ($n % 16)); + $i = 0; + $enc_text = get_rnd_iv($iv_len); + $iv = substr($password ^ $enc_text, 0, 512); + while ($i < $n) { + $block = substr($plain_text, $i, 16) ^ pack('H*', md5($iv)); + $enc_text .= $block; + $iv = substr($block . $iv, 0, 512) ^ $password; + $i += 16; + } + return base64_encode($enc_text); +} +function md5_decrypt($enc_text, $password, $iv_len = 16) { + $enc_text = base64_decode($enc_text); + $n = strlen($enc_text); + $i = $iv_len; + $plain_text = ''; + $iv = substr($password ^ substr($enc_text, 0, $iv_len), 0, 512); + while ($i < $n) { + $block = substr($enc_text, $i, 16); + $plain_text .= $block ^ pack('H*', md5($iv)); + $iv = substr($block . $iv, 0, 512) ^ $password; + $i += 16; + } + return preg_replace('/\\x13\\x00*$/', '', $plain_text); +} +?> \ No newline at end of file diff --git a/inc/func/fetching.php b/inc/func/fetching.php new file mode 100644 index 0000000..707f8d8 --- /dev/null +++ b/inc/func/fetching.php @@ -0,0 +1,107 @@ +GetAll("SELECT * FROM `" . KU_DBPREFIX . "blotter` ORDER BY `id` DESC" . $limit); + if (count($results) > 0) { + if ($all) { + $output .= '
';
+		}
+		foreach ($results as $line) {
+			if ($all && $line['important'] == 1) {
+				$output .= '';
+			} elseif (!$all) {
+				$output .= '';
+			} else {
+				$output .= "\n";
+			}
+			$output .= "\n";
+		}
+		if ($all) {
+			$output .= '
'; + } + } + + if (KU_APC) { + if ($all) { + apc_store('blotter|all', $output); + } else { + apc_store('blotter|last4', $output); + } + } + + return $output; +} + +function getBlotterLastUpdated() { + global $tc_db; + + return $tc_db->GetOne("SELECT `at` FROM `" . KU_DBPREFIX . "blotter` ORDER BY `id` DESC LIMIT 1"); +} + +/** + * Gets information about the filetype provided, which is specified in the manage panel + * + * @param string $filetype Filetype + * @return array Filetype image, width, and height + */ +function getfiletypeinfo($filetype) { + global $tc_db; + + $return = ''; + if (KU_APC) { + $return = apc_fetch('filetype|' . $filetype); + } + + if ($return != '') { + return unserialize($return); + } + + $results = $tc_db->GetAll("SELECT `image`, `image_w`, `image_h` FROM `" . KU_DBPREFIX . "filetypes` WHERE `filetype` = " . $tc_db->qstr($filetype) . " LIMIT 1"); + if (count($results) > 0) { + foreach($results AS $line) { + $return = array($line['image'],$line['image_w'],$line['image_h']); + } + } else { + /* No info was found, return the generic icon */ + $return = array('generic.png',48,48); + } + + if (KU_APC) { + apc_store('filetype|' . $filetype, serialize($return), 600); + } + + return $return; +} +?> \ No newline at end of file diff --git a/inc/func/misc.php b/inc/func/misc.php new file mode 100644 index 0000000..65d2755 --- /dev/null +++ b/inc/func/misc.php @@ -0,0 +1,91 @@ +assign('styles', explode(':', KU_MENUSTYLES)); + $dwoo_data->assign('errormsg', $errormsg); + + if ($extended != '') { + $dwoo_data->assign('errormsgext', '
' . $extended . '
'); + } else { + $dwoo_data->assign('errormsgext', $extended); + } + + + echo $dwoo->get(KU_TEMPLATEDIR . '/error.tpl', $dwoo_data); + + die(); +} + +/** + * Add an entry to the modlog + * + * @param string $entry Entry text + * @param integer $category Category to file under. 0 - No category, 1 - Login, 2 - Cleanup/rebuild boards and html files, 3 - Board adding/deleting, 4 - Board updates, 5 - Locking/stickying, 6 - Staff changes, 7 - Thread deletion/post deletion, 8 - Bans, 9 - News, 10 - Global changes, 11 - Wordfilter + * @param string $forceusername Username to force as the entry username + */ +function management_addlogentry($entry, $category = 0, $forceusername = '') { + global $tc_db; + + $username = ($forceusername == '') ? $_SESSION['manageusername'] : $forceusername; + + if ($entry != '') { + $tc_db->Execute("INSERT INTO `" . KU_DBPREFIX . "modlog` ( `entry` , `user` , `category` , `timestamp` ) VALUES ( " . $tc_db->qstr($entry) . " , '" . $username . "' , " . $tc_db->qstr($category) . " , '" . time() . "' )"); + } + if (KU_RSS) { + require_once(KU_ROOTDIR . 'inc/classes/rss.class.php'); + $rss_class = new RSS(); + + print_page(KU_BOARDSDIR . 'modlogrss.xml', $rss_class->GenerateModLogRSS($entry), ''); + } +} + +function sendStaffMail($subject, $message) { + $emails = split(':', KU_APPEAL); + $expires = ($line['until'] > 0) ? date("F j, Y, g:i a", $line['until']) : 'never'; + foreach ($emails as $email) { + @mail($email, $subject, $message, 'From: "' . KU_NAME . '" ' . "\r\n" . 'Reply-To: kusaba@noreply' . KU_DOMAIN . "\r\n" . 'X-Mailer: kusaba' . KU_VERSION . '/PHP' . phpversion()); + } +} + +/* Depending on the configuration, use either a meta refresh or a direct header */ +function do_redirect($url, $ispost = false, $file = '') { + global $board_class; + $headermethod = true; + + if ($headermethod) { + if ($ispost) { + header('Location: ' . $url); + } else { + die(''); + } + } else { + if ($ispost && $file != '') { + echo sprintf(_gettext('%s uploaded.'), $file) . ' ' . _gettext('Updating pages.'); + } elseif ($ispost) { + echo _gettext('Post added.') . ' ' . _gettext('Updating pages.'); # TEE COME BACK + } else { + echo '---> ---> --->'; + } + die(''); + } +} +?> \ No newline at end of file diff --git a/inc/func/module.php b/inc/func/module.php new file mode 100644 index 0000000..3b18efc --- /dev/null +++ b/inc/func/module.php @@ -0,0 +1,117 @@ +qstr($module)." AND `key` = ".$tc_db->qstr($key)." LIMIT 1"; + $result = $tc_db->GetOne($query); + + return $result; +} + +function module_setting_set($module, $key, $value, $type = 'string') { + global $tc_db; + + $exists = $tc_db->GetOne("SELECT COUNT(*) FROM `".KU_DBPREFIX."module_settings` WHERE `module` = ".$tc_db->qstr($module)." AND `key` = ".$tc_db->qstr($key)." LIMIT 1"); + if ($exists > 0) { + $result = $tc_db->Execute("UPDATE `".KU_DBPREFIX."module_settings` SET `value` = ".$tc_db->qstr($value).") WHERE `module` = ".$tc_db->qstr($module)." AND `key` = ".$tc_db->qstr($key).""); + } else { + $result = $tc_db->Execute("INSERT INTO `".KU_DBPREFIX."module_settings` (`module` , `key` , `value` , `type`) VALUES (".$tc_db->qstr($module).", ".$tc_db->qstr($key).", ".$tc_db->qstr($value).", ".$tc_db->qstr($type).")"); + } + + return $result; +} +?> \ No newline at end of file diff --git a/inc/func/numberformatting.php b/inc/func/numberformatting.php new file mode 100644 index 0000000..9523a6c --- /dev/null +++ b/inc/func/numberformatting.php @@ -0,0 +1,81 @@ += $now) ? $action = '' : $action = 'ago'; + + # Set the periods of time + $periods = array(_gettext('second'), _gettext('minute'), _gettext('hour'), _gettext('day'), _gettext('week'), _gettext('month'), _gettext('year'), _gettext('decade')); + $lengths = array(1, 60, 3600, 86400, 604800, 2630880, 31570560, 315705600); + + $diff = ($action == '' ? $timestamp - $now : $now - $timestamp); + + $prec_key = array_search($precision_level,$periods); + + # round diff to the precision_level + $diff = round(($diff/$lengths[$prec_key]))*$lengths[$prec_key]; + + # if the diff is very small, display for ex "just seconds ago" + if ($diff <= 10) { + $periodago = max(0,$prec_key-1); + $agotxt = $periods[$periodago].'s'; + return "$agotxt $action"; + } + + # Go from decades backwards to seconds + $time = ""; + for ($i = (sizeof($lengths) - 1); $i>=0; $i--) { + if ($i > 0) { + if($diff > $lengths[$i-1] && ($max_detail_levels > 0)) { # if the difference is greater than the length we are checking... continue + $val = floor($diff / $lengths[$i-1]); # 65 / 60 = 1. That means one minute. 130 / 60 = 2. Two minutes.. etc + $time .= $val ." ". $periods[$i-1].($val > 1 ? 's ' : ' '); # The value, then the name associated, then add 's' if plural + $diff -= ($val * $lengths[$i-1]); # subtract the values we just used from the overall diff so we can find the rest of the information + if(!$detailed) { $i = 0; } # if detailed is turn off (default) only show the first set found, else show all information + $max_detail_levels--; + } + } + } + + # Basic error checking. + if($time == "") { + return "Error-- Unable to calculate time."; + } else { + if ($action != '') { + return $time.$action; + } + + return $time; + } +} + +function microtime_float() { + return array_sum(explode(' ', microtime())); +} + +function formatJapaneseNumbers($input) { + $patterns = array('/1/', '/2/', '/3/', '/4/', '/5/', '/6/', '/7/', '/8/', '/9/', '/0/'); + $replace = array('1', '2', '3', '4', '5', '6', '7', '8', '9', '0'); + + return preg_replace($patterns, $replace, $input); +} +?> \ No newline at end of file diff --git a/inc/func/pages.php b/inc/func/pages.php new file mode 100644 index 0000000..63076c6 --- /dev/null +++ b/inc/func/pages.php @@ -0,0 +1,29 @@ + \ No newline at end of file diff --git a/inc/func/paths.php b/inc/func/paths.php new file mode 100644 index 0000000..44e7b28 --- /dev/null +++ b/inc/func/paths.php @@ -0,0 +1,22 @@ + \ No newline at end of file diff --git a/inc/func/posts.php b/inc/func/posts.php new file mode 100644 index 0000000..84c7d6d --- /dev/null +++ b/inc/func/posts.php @@ -0,0 +1,255 @@ +GetAll("SELECT HIGH_PRIORITY * FROM `" . KU_DBPREFIX . "embeds`"); + + $output = '' . "\n"; + + foreach ($results as $line) { + if ($post['file_type'] == $line['filetype']) { + $code = $line['code']; + /*$width = $line['width']; + $height = $line['height'];*/ + $replace = array('SET_HEIGHT', 'SET_WIDTH', 'EMBED_ID'); + $trueval = array($line['height'], $line['width'], $post['file']); + + $code = str_replace($replace, $trueval, $code); + $output .= $code; + } + + } + + $output .= ' ' . "\n"; + + return $output; +} + +/** + * Check if the supplied md5 file hash is currently recorded inside of the database, attached to a non-deleted post + */ +function checkMd5($md5, $board, $boardid) { + global $tc_db; + $matches = $tc_db->GetAll("SELECT `id`, `parentid` FROM `".KU_DBPREFIX."posts` WHERE `boardid` = " . $boardid . " AND `IS_DELETED` = 0 AND `file_md5` = ".$tc_db->qstr($md5)." LIMIT 1"); + if (count($matches) > 0) { + $real_parentid = ($matches[0][1] == 0) ? $matches[0][0] : $matches[0][1]; + + return array($real_parentid, $matches[0][0]); + } + + return false; +} + +/* Image handling */ +/** + * Create a thumbnail + * + * @param string $name File to be thumbnailed + * @param string $filename Path to place the thumbnail + * @param integer $new_w Maximum width + * @param integer $new_h Maximum height + * @return boolean Success/fail + */ +function createThumbnail($name, $filename, $new_w, $new_h) { + if (KU_THUMBMETHOD == 'imagemagick') { + $convert = 'convert ' . escapeshellarg($name); + if (!KU_ANIMATEDTHUMBS) { + $convert .= '[0] '; + } + $convert .= ' -resize ' . $new_w . 'x' . $new_h . ' -quality '; + if (substr($filename, 0, -3) != 'gif') { + $convert .= '70'; + } else { + $convert .= '90'; + } + $convert .= ' ' . escapeshellarg($filename); + exec($convert); + + if (is_file($filename)) { + return true; + } else { + return false; + } + } elseif (KU_THUMBMETHOD == 'gd') { + $system=explode(".", $filename); + $system = array_reverse($system); + if (preg_match("/jpg|jpeg/", $system[0])) { + $src_img=imagecreatefromjpeg($name); + } else if (preg_match("/png/", $system[0])) { + $src_img=imagecreatefrompng($name); + } else if (preg_match("/gif/", $system[0])) { + $src_img=imagecreatefromgif($name); + } else { + return false; + } + + if (!$src_img) { + exitWithErrorPage(_gettext('Unable to read uploaded file during thumbnailing.'), _gettext('A common cause for this is an incorrect extension when the file is actually of a different type.')); + } + $old_x = imageSX($src_img); + $old_y = imageSY($src_img); + if ($old_x > $old_y) { + $percent = $new_w / $old_x; + } else { + $percent = $new_h / $old_y; + } + $thumb_w = round($old_x * $percent); + $thumb_h = round($old_y * $percent); + + $dst_img = ImageCreateTrueColor($thumb_w, $thumb_h); + fastImageCopyResampled($dst_img, $src_img, 0, 0, 0, 0, $thumb_w, $thumb_h, $old_x, $old_y, $system); + + if (preg_match("/png/", $system[0])) { + if (!imagepng($dst_img,$filename,0,PNG_ALL_FILTERS) ) { + echo 'unable to imagepng.'; + return false; + } + } else if (preg_match("/jpg|jpeg/", $system[0])) { + if (!imagejpeg($dst_img, $filename, 70)) { + echo 'unable to imagejpg.'; + return false; + } + } else if (preg_match("/gif/", $system[0])) { + if (!imagegif($dst_img, $filename)) { + echo 'unable to imagegif.'; + return false; + } + } + + imagedestroy($dst_img); + imagedestroy($src_img); + + return true; + } + + return false; +} + +/* Author: Tim Eckel - Date: 12/17/04 - Project: FreeRingers.net - Freely distributable. */ +/** + * Faster method than only calling imagecopyresampled() + * + * @return boolean Success/fail + */ +function fastImageCopyResampled(&$dst_image, &$src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h, $system, $quality = 3) { + /* + Optional "quality" parameter (defaults is 3). Fractional values are allowed, for example 1.5. + 1 = Up to 600 times faster. Poor results, just uses imagecopyresized but removes black edges. + 2 = Up to 95 times faster. Images may appear too sharp, some people may prefer it. + 3 = Up to 60 times faster. Will give high quality smooth results very close to imagecopyresampled. + 4 = Up to 25 times faster. Almost identical to imagecopyresampled for most images. + 5 = No speedup. Just uses imagecopyresampled, highest quality but no advantage over imagecopyresampled. + */ + + if (empty($src_image) || empty($dst_image) || $quality <= 0) { return false; } + + if (preg_match("/png/", $system[0]) || preg_match("/gif/", $system[0])) { + $colorcount = imagecolorstotal($src_image); + if ($colorcount <= 256 && $colorcount != 0) { + imagetruecolortopalette($dst_image,true,$colorcount); + imagepalettecopy($dst_image,$src_image); + $transparentcolor = imagecolortransparent($src_image); + imagefill($dst_image,0,0,$transparentcolor); + imagecolortransparent($dst_image,$transparentcolor); + } + else { + imageAlphaBlending($dst_image, false); + imageSaveAlpha($dst_image, true); //If the image has Alpha blending, lets save it + } + } + + if ($quality < 5 && (($dst_w * $quality) < $src_w || ($dst_h * $quality) < $src_h)) { + $temp = imagecreatetruecolor ($dst_w * $quality + 1, $dst_h * $quality + 1); + if (preg_match("/png/", $system[0])) { + $background = imagecolorallocate($temp, 0, 0, 0); + ImageColorTransparent($temp, $background); // make the new temp image all transparent + imagealphablending($temp, false); // turn off the alpha blending to keep the alpha channel + } + imagecopyresized ($temp, $src_image, 0, 0, $src_x, $src_y, $dst_w * $quality + 1, $dst_h * $quality + 1, $src_w, $src_h); + imagecopyresampled ($dst_image, $temp, $dst_x, $dst_y, 0, 0, $dst_w, $dst_h, $dst_w * $quality, $dst_h * $quality); + imagedestroy ($temp); + } + + else imagecopyresampled ($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h); + + return true; +} + + +/* +Link validator + +Will use cURL to attempt to visit a webpage, and then return based upon how the +request was handled. Used for embedded videos to validate the ID is existant. + +Thanks phadeguy - http://www.zend.com/codex.php?id=1256&single=1 +expects a link url as string +returns an array of three elements: +return_array[0] = HTTP version +return_array[1] = Returned error number (200, 404, etc) +return_array[2] = Returned error text ("OK", "File Not Found", etc) */ +function check_link($link) { + $main = array(); + $ch = curl_init(); + curl_setopt ($ch, CURLOPT_URL, $link); + curl_setopt ($ch, CURLOPT_HEADER, 1); + curl_setopt ($ch, CURLOPT_NOBODY, 1); +// curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, 1); + curl_setopt ($ch, CURLOPT_TIMEOUT, 10); + curl_setopt ($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)"); + ob_start(); + curl_exec ($ch); + $stuff = ob_get_contents(); + ob_end_clean(); + curl_close ($ch); + $parts = split("n",$stuff,2); + $main = split(" ",$parts[0],3); + return $main; +} + +/** + * Trim the threads to the page limit and delete posts which are older than limited + */ +function TrimToPageLimit($board) { + global $tc_db; + + if ($board['maxage'] != 0) { + // If the maximum thread age setting is not zero (do not delete old threads), find posts which are older than the limit, and delete them + $results = $tc_db->GetAll("SELECT `id`, `timestamp` FROM `".KU_DBPREFIX."posts` WHERE `boardid` = " . $board['id'] . " AND `IS_DELETED` = 0 AND `parentid` = 0 AND `stickied` = 0 AND ((`timestamp` + " . ($board['maxage']*3600) . ") < " . time() . ")"); + foreach($results AS $line) { + // If it is older than the limit + $post_class = new Post($line['id'], $board['name'], $board['id']); + $post_class->Delete(true); + } + } + if ($board['maxpages'] != 0) { + // If the maximum pages setting is not zero (do not limit pages), find posts which are over the limit, and delete them + $results = $tc_db->GetAll("SELECT `id`, `stickied` FROM `".KU_DBPREFIX."posts` WHERE `boardid` = " . $board['id'] . " AND `IS_DELETED` = 0 AND `parentid` = 0"); + $results_count = count($results); + if (calculatenumpages($board['type'], $results_count) >= $board['maxpages']) { + $board['maxthreads'] = ($board['maxpages'] * KU_THREADS); + $numthreadsover = ($results_count - $board['maxthreads']); + if ($numthreadsover > 0) { + $resultspost = $tc_db->GetAll("SELECT `id`, `stickied` FROM `".KU_DBPREFIX."posts` WHERE `boardid` = " . $board['id'] . " AND `IS_DELETED` = 0 AND `parentid` = 0 AND `stickied` = 0 ORDER BY `bumped` ASC LIMIT " . $numthreadsover); + foreach($resultspost AS $linepost) { + $post_class = new Post($linepost['id'], $board['name'], $board['id']); + $post_class->Delete(true); + } + } + } + } + // If the thread was marked for deletion more than two hours ago, delete it + $results = $tc_db->GetAll("SELECT `id` FROM `".KU_DBPREFIX."posts` WHERE `boardid` = " . $board['id'] . " AND `IS_DELETED` = 0 AND `parentid` = 0 AND `stickied` = 0 AND `deleted_timestamp` > 0 AND (`deleted_timestamp` <= " . time() . ")"); + foreach($results AS $line) { + // If it is older than the limit + $post_class = new Post($line['id'], $board['name'], $board['id']); + $post_class->Delete(true); + } +} + +?> \ No newline at end of file diff --git a/inc/func/stringformatting.php b/inc/func/stringformatting.php new file mode 100644 index 0000000..1734cd8 --- /dev/null +++ b/inc/func/stringformatting.php @@ -0,0 +1,317 @@ +'; + } + + if ($type == 'post') { + if ($locale == 'ja') { + /* Format the timestamp japanese style */ + $fulldate = strftime ("%Yy%mm%dd(DAYOFWEEK) %HH%MM%SS", $timestamp); + $dayofweek = strftime('%a', $timestamp); + + + /* I don't like this method, but I can't rely on PHP's locale settings to do it for me... */ + switch ($dayofweek) { + case 'Sun': + $dayofweek = '日'; + break; + + case 'Mon': + $dayofweek = '月'; + break; + + case 'Tue': + $dayofweek = '火'; + break; + + case 'Wed': + $dayofweek = '水'; + break; + + case 'Thu': + $dayofweek = '木'; + break; + + case 'Fri': + $dayofweek = '金'; + break; + + case 'Sat': + $dayofweek = '土'; + break; + + default: + // The date must be in the correct language already, so let's convert it to unicode if it isn't already. + $dayofweek = mb_convert_encoding($dayofweek, "UTF-8", "JIS, eucjp-win, sjis-win"); + break; + + } + $fulldate = formatJapaneseNumbers($fulldate); + //Convert the symbols for year, month, etc to unicode equivalents. We couldn't do this above beause the numbers would be formatted to japanese. + $fulldate = str_replace(array("y","m","d","H","M","S"), array("年","月","日","時","分","秒"), $fulldate); + $fulldate = str_replace('DAYOFWEEK', $dayofweek, $fulldate); + return $output.$fulldate.(($email != '') ? ('') : ("")); + } else { + /* Format the timestamp english style */ + return $output.date('y/m/d(D)H:i', $timestamp).(($email != '') ? ('') : ("")); + } + } + + return $output.date('y/m/d(D)H:i', $timestamp).(($email != '') ? ('') : ("")); +} + +/** + * Format the provided input into a reflink, which follows the Japanese locale if it is set. + */ +function formatReflink($post_board, $post_thread_start_id, $post_id, $locale = 'en') { + $return = ' '; + + $reflink_noquote = ''; + + $reflink_quote = ''; + + if ($locale == 'ja') { + $return .= $reflink_quote . formatJapaneseNumbers($post_id) . '' . $reflink_noquote . '番'; + } else { + $return .= $reflink_noquote . 'No. ' . '' . $reflink_quote . $post_id . ''; + } + + return $return . "\n"; +} + +/** + * Calculate the different name and tripcode for the name field provided + * + * @param string $post_name Text entered in the Name field + * @return array Name and tripcode + */ +function calculateNameAndTripcode($post_name) { + global $tc_db; + + if(preg_match("/(#|!)(.*)/", $post_name, $regs)){ + $cap = $regs[2]; + $cap_full = '#' . $regs[2]; + + // {{{ Special tripcode check + + $trips = unserialize(KU_TRIPS); + if (count($trips) > 0) { + if (isset($trips[$cap_full])) { + $forcedtrip = $trips[$cap_full]; + return array(preg_replace("/(#)(.*)/", "", $post_name), $forcedtrip); + } + } + + // }}} + + if (function_exists('mb_convert_encoding')) { + $recoded_cap = mb_convert_encoding($cap, 'SJIS', 'UTF-8'); + if ($recoded_cap != '') { + $cap = $recoded_cap; + } + } + + if (strpos($post_name, '#') === false) { + $cap_delimiter = '!'; + } elseif (strpos($post_name, '!') === false) { + $cap_delimiter = '#'; + } else { + $cap_delimiter = (strpos($post_name, '#') < strpos($post_name, '!')) ? '#' : '!'; + } + + if (preg_match("/(.*)(" . $cap_delimiter . ")(.*)/", $cap, $regs_secure)) { + $cap = $regs_secure[1]; + $cap_secure = $regs_secure[3]; + $is_secure_trip = true; + } else { + $is_secure_trip = false; + } + + $tripcode = ''; + if ($cap != '') { + /* From Futabally */ + $cap = strtr($cap, "&", "&"); + $cap = strtr($cap, ",", ", "); + $salt = substr($cap."H.", 1, 2); + $salt = preg_replace("/[^\.-z]/", ".", $salt); + $salt = strtr($salt, ":;<=>?@[\\]^_`", "ABCDEFGabcdef"); + $tripcode = substr(crypt($cap, $salt), -10); + } + + if ($is_secure_trip) { + if ($cap != '') { + $tripcode .= '!'; + } + + $secure_tripcode = md5($cap_secure . KU_RANDOMSEED); + if (function_exists('base64_encode')) { + $secure_tripcode = base64_encode($secure_tripcode); + } + if (function_exists('str_rot13')) { + $secure_tripcode = str_rot13($secure_tripcode); + } + + $secure_tripcode = substr($secure_tripcode, 2, 10); + + $tripcode .= '!' . $secure_tripcode; + } + + $name = preg_replace("/(" . $cap_delimiter . ")(.*)/", "", $post_name); + + + return array($name, $tripcode); + } + + return $post_name; +} + +/** + * Format a long message to be shortened if it exceeds the allowed length on a page + * + * @param string $message Post message + * @param string $board Board directory + * @param integer $threadid Thread ID + * @param boolean $page Is rendering for a page + * @return string The formatted message + */ +function formatLongMessage($message, $board, $threadid, $page) { + $output = ''; + if ((strlen($message) > KU_LINELENGTH || count(explode('
', $message)) > 15) && $page) { + $message_exploded = explode('
', $message); + $message_shortened = ''; + for ($i = 0; $i <= 14; $i++) { + if (isset($message_exploded[$i])) { + $message_shortened .= $message_exploded[$i] . '
'; + } + } + if (strlen($message_shortened) > KU_LINELENGTH) { + $message_shortened = substr($message_shortened, 0, KU_LINELENGTH); + } + $message_shortened = closeOpenTags($message_shortened); + + if (strrpos($message_shortened,"<") > strrpos($message_shortened,">")) { + //We have a partially opened tag we need to get rid of. + $message_shortened = substr($message_shortened, 0, strrpos($message_shortened,"<")); + } + + $output = $message_shortened . '
' . "\n" . + ' ' . sprintf(_gettext('Message too long. Click %shere%s to view the full text.'), '', '') . "\n" . + '
' . "\n"; + } else { + $output .= $message . "\n"; + } + + return $output; +} + +/* Thanks milianw - php.net */ +/** + * Closes all HTML tags left open + * + * @param string $html HTML to be checked + * @return string HTML with all tags closed + */ +function closeOpenTags($html){ + /* Put all opened tags into an array */ + preg_match_all("#<([a-z]+)( .*)?(?!/)>#iU", $html, $result); + $openedtags=$result[1]; + + /* Put all closed tags into an array */ + preg_match_all("##iU", $html, $result); + $closedtags=$result[1]; + $len_opened = count($openedtags); + /* All tags are closed */ + if(count($closedtags) == $len_opened){ + return $html; + } + $openedtags = array_reverse($openedtags); + /* Close tags */ + for($i=0;$i<$len_opened;$i++) { + if ($openedtags[$i]!='br') { + if (!in_array($openedtags[$i], $closedtags)){ + $html .= ''; + } else { + unset($closedtags[array_search($openedtags[$i], $closedtags)]); + } + } + } + return $html; +} + +/* By Darien Hager, Jan 2007 */ +/** + * Find the string value of a pair of ords + * + * @param string $ords Ords + * @param string $encoding Encoding + * @return string String + */ +function ords_to_unistr($ords, $encoding = 'UTF-8'){ + if (!function_exists('mb_convert_encoding')) { + return false; + } + /* Turns an array of ordinal values into a string of unicode characters */ + $str = ''; + for($i = 0; $i < sizeof($ords); $i++){ + /* Pack this number into a 4-byte string + (Or multiple one-byte strings, depending on context.) */ + $v = $ords[$i]; + $str .= pack("N",$v); + } + $str = mb_convert_encoding($str,$encoding,"UCS-4BE"); + return($str); +} + + +/** + * Find the ord value of a string + * + * @param string $str String + * @param string $encoding Encoding + * @return array Ords + */ +function unistr_to_ords($str, $encoding = 'UTF-8'){ + if (!function_exists('mb_convert_encoding')) { + return false; + } + /* Turns a string of unicode characters into an array of ordinal values, + Even if some of those characters are multibyte. */ + $str = mb_convert_encoding($str,"UCS-4BE",$encoding); + $ords = array(); + + /* Visit each unicode character */ + for($i = 0; $i < mb_strlen($str,"UCS-4BE"); $i++){ + /* Now we have 4 bytes. Find their total numeric value */ + $s2 = mb_substr($str,$i,1,"UCS-4BE"); + $val = unpack("N",$s2); + $ords[] = $val[1]; + } + return($ords); +} + +function processPost($id, $newthreadid, $oldthreadid, $board_from, $board_to, $boardid) { + + global $tc_db; + + $message = $tc_db->GetOne("SELECT `message` FROM " . KU_DBPREFIX . "posts WHERE `boardid` = " . $boardid . " AND `id` = " . $id . " LIMIT 1"); + + if ($message != '') { + $message_new = str_replace('/read.php/' . $board_from . '/' . $oldthreadid, '/read.php/' . $board_to . '/' . $newthreadid, $message); + + if ($message_new != $message) { + $tc_db->GetOne("UPDATE " . KU_DBPREFIX . "posts SET `message` = " . $tc_db->qstr($message) . " WHERE `boardid` = " . $boardid . " AND `id` = " . $id); + } + } +} +?> diff --git a/inc/func/validation.php b/inc/func/validation.php new file mode 100644 index 0000000..3edcbc7 --- /dev/null +++ b/inc/func/validation.php @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/inc/functions.php b/inc/functions.php new file mode 100644 index 0000000..3d4d28e --- /dev/null +++ b/inc/functions.php @@ -0,0 +1,42 @@ + \ No newline at end of file diff --git a/inc/lang/cs/LC_MESSAGES/kusaba.po b/inc/lang/cs/LC_MESSAGES/kusaba.po new file mode 100644 index 0000000..12136c6 --- /dev/null +++ b/inc/lang/cs/LC_MESSAGES/kusaba.po @@ -0,0 +1,457 @@ +msgid "" +msgstr "" +"Project-Id-Version: kusaba\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2007-12-09 03:10+0000\n" +"PO-Revision-Date: 2008-02-22 13:49+0000\n" +"Last-Translator: pcp \n" +"Language-Team: Czech \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2008-03-12 04:24+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +msgid "Add" +msgstr "Přidat" + +msgid "Add board" +msgstr "Přidat nástěnku" + +msgid "Add news" +msgstr "Přidat zprávičku" + +msgid "Admin" +msgstr "Admin" + +msgid "Administration" +msgstr "Administrace" + +msgid "Administrator" +msgstr "Administrátor" + +msgid "Administrators" +msgstr "Administrátoři" + +msgid "All Threads" +msgstr "Všechny vlákna" + +msgid "All boards" +msgstr "Všechny nástěnky" + +msgid "Ban from" +msgstr "Ban od" + +msgid "Ban successfully removed." +msgstr "Ban odstraněn" + +msgid "Board" +msgstr "Board" + +msgid "Board successfully deleted." +msgstr "Nástěnka smazána" + +msgid "Board type:" +msgstr "Typ nástěnky" + +msgid "Boards" +msgstr "Nástěnky" + +msgid "Can be left blank." +msgstr "Nemusí být vyplněno" + +msgid "Can not be left blank." +msgstr "Musí být vyplněno" + +msgid "Cancel" +msgstr "Storno" + +msgid "Cleanup" +msgstr "Vyčistit" + +msgid "Cleanup finished." +msgstr "Čištění dokončeno" + +msgid "Click to show/hide" +msgstr "Zobrazit/Skrýt" + +msgid "Continue" +msgstr "Pokračovat" + +msgid "Date" +msgstr "Datum" + +msgid "Default" +msgstr "Výchozí" + +msgid "Delete" +msgstr "Odstranit" + +msgid "Delete board" +msgstr "Smazat nástěnku" + +msgid "Delete posts" +msgstr "Smazat příspěvky" + +msgid "Deleted" +msgstr "Smazáno" + +msgid "Deleted posts by ip" +msgstr "Smazat příspěvky podle IP" + +msgid "Deleting unused images." +msgstr "Mažu nepoužité obrázky" + +msgid "Description" +msgstr "Popis" + +msgid "Directory" +msgstr "Adresář" + +msgid "Does not expire" +msgstr "Nevyprší" + +msgid "Edit" +msgstr "Úpravy" + +msgid "Email" +msgstr "E-mail" + +msgid "Embed" +msgstr "Vloženo" + +msgid "Error, it appears your file did not transfer properly. Please go back and try again." +msgstr "Chyba při odesílání souboru. Zkuste to znovu." + +msgid "FAQ" +msgstr "FAQ" + +msgid "File" +msgstr "Soubor" + +msgid "File Only" +msgstr "Pouze soubory" + +msgid "File
Removed" +msgstr "Soubor odstraněn" + +msgid "First 100 posts" +msgstr "Prvních 100 příspěvků" + +msgid "From" +msgstr "Od" + +msgid "Global options" +msgstr "Globální volby" + +msgid "Go" +msgstr "Jdi" + +msgid "Height" +msgstr "Výška" + +msgid "ID" +msgstr "ID" + +msgid "IP" +msgstr "IP" + +msgid "Image" +msgstr "Obrázek" + +msgid "Image successfully deleted from your post." +msgstr "Obrázek byl z tvého příspěvku úspěšně smazán" + +msgid "Images" +msgstr "Obrázky" + +msgid "Important" +msgstr "Důležité" + +msgid "Improper filetype." +msgstr "Nepodporovaný formát souboru" + +msgid "Incorrect password." +msgstr "Nesprávné heslo" + +msgid "Incorrect username/password." +msgstr "Nesprávné jméno nebo heslo" + +msgid "Index" +msgstr "Index" + +msgid "Invalid MIME type for this filetype." +msgstr "Neplatný MIME typ pro tento soubor" + +msgid "Invalid thread ID." +msgstr "Neplatné ID vlákna" + +msgid "Last Post" +msgstr "Poslední příspěvek" + +msgid "Lock" +msgstr "Uzamknout" + +msgid "Logged in" +msgstr "Přihlášený" + +msgid "Logo" +msgstr "Logo" + +msgid "Manage" +msgstr "Spravovat" + +msgid "Manage boards" +msgstr "Spravovat nástěnky" + +msgid "Maxmimum thumbnail height" +msgstr "Maximální výška náhledu" + +msgid "Maxmimum thumbnail width" +msgstr "Maximální šířka náhledu" + +msgid "Message" +msgstr "Zpráva" + +msgid "Misc" +msgstr "Různé" + +msgid "Mod" +msgstr "Mod" + +msgid "Moderator" +msgstr "Moderátor" + +msgid "Moderators" +msgstr "Moderátoři" + +msgid "Modify" +msgstr "Upravit" + +msgid "Module settings" +msgstr "Nastavení modulu" + +msgid "Modules" +msgstr "Moduly" + +msgid "Name" +msgstr "Jméno" + +msgid "Never" +msgstr "Nikdy" + +msgid "New Thread" +msgstr "Nové vlákno" + +msgid "New password" +msgstr "Nové heslo" + +msgid "New password again" +msgstr "Heslo znovu" + +msgid "News" +msgstr "Zprávy" + +msgid "Next" +msgstr "Další" + +msgid "No" +msgstr "Ne" + +msgid "No File" +msgstr "Žádný soubor" + +msgid "No threads." +msgstr "Žádná vlákna" + +msgid "None" +msgstr "Nic" + +msgid "Normal imageboard" +msgstr "Obrázky" + +msgid "Online now" +msgstr "Nyní online" + +msgid "Open images in new window" +msgstr "Otevírat obrázky v novém okně" + +msgid "Order" +msgstr "Pořadí" + +msgid "Password" +msgstr "Heslo" + +msgid "Password successfully changed." +msgstr "Heslo bylo úspěšně změněno." + +msgid "Please enter a positive amount of seconds, or zero for a permanent ban." +msgstr "Zadejte počet sekund nebo nulu pro permanentní Ban." + +msgid "Please select only one image to upload." +msgstr "Prosím zvolte pouze jeden obrázek k odeslání" + +msgid "Post" +msgstr "Příspěvek" + +msgid "Post preview" +msgstr "Náhled příspěvku" + +msgid "Post successfully deleted." +msgstr "Příspěvek smazán" + +msgid "Posts" +msgstr "Příspěvky" + +msgid "Preview" +msgstr "Náhled" + +msgid "Previous" +msgstr "Předchozí" + +msgid "Quick Reply" +msgstr "Rychle odpovědět" + +msgid "Reason" +msgstr "Důvod" + +msgid "Reason:" +msgstr "Důvod:" + +msgid "Regular expression" +msgstr "Regulární výraz" + +msgid "Remove" +msgstr "Odstranit" + +msgid "Replies" +msgstr "Odpovědi" + +msgid "Reply" +msgstr "Odpovědět" + +msgid "Rules" +msgstr "Pravidla" + +msgid "Seconds" +msgstr "sekund" + +msgid "Section" +msgstr "Sekce" + +msgid "Show All" +msgstr "Zobrazit vše" + +msgid "Show Directories" +msgstr "Zobrazit adresáře" + +msgid "Show/Hide" +msgstr "Zobrazit/Skrýt" + +msgid "Size" +msgstr "Velikost" + +msgid "Sorry, that filetype is not allowed on this board." +msgstr "Omlouváme se, ale tento souborový formát není na nástěnce podporován" + +msgid "Sorry, this board is locked and can not be posted in." +msgstr "Tato nástěnka je uzamčena a proto není možné přidávat další příspěvky" + +msgid "Statistics" +msgstr "Statistika" + +msgid "Sticky" +msgstr "Přilepit" + +msgid "Subject" +msgstr "Předmět" + +msgid "Submit" +msgstr "Odeslat" + +msgid "Tag" +msgstr "Tag" + +msgid "Text board" +msgstr "Text" + +msgid "That IP has already been banned." +msgstr "Tato IP je již blokována" + +msgid "There was an error in trying to delete your post" +msgstr "Chyba při mazání příspěvku" + +msgid "This post has been deleted." +msgstr "Příspěvek smazán" + +msgid "Thread" +msgstr "Vlákno" + +msgid "Thread successfully locked." +msgstr "Vlákno uzamčeno" + +msgid "Thread successfully unlocked." +msgstr "Vlákno odemčeno" + +msgid "Threads" +msgstr "Vlákna" + +msgid "To" +msgstr "Do" + +msgid "Unable to delete board." +msgstr "Není možné smazat nástěnku" + +msgid "Unlock" +msgstr "Odemknout" + +msgid "Unsticky" +msgstr "Odlepit" + +msgid "Update" +msgstr "Aktualizace" + +msgid "Username" +msgstr "Uživatelské jméno" + +msgid "Welcome" +msgstr "Vítejte" + +msgid "Word" +msgstr "Slovo" + +msgid "Yes" +msgstr "Ano" + +msgid "Your IP address is" +msgstr "Vaše IP adresa je" + +msgid "and" +msgstr "a" + +msgid "for the following reason" +msgstr "z důvodu" + +msgid "forever" +msgstr "navždy" + +msgid "log in" +msgstr "přihlásit se" + +msgid "log out" +msgstr "Odhlásit se" + +msgid "or" +msgstr "nebo" + +msgid "translator-credits" +msgstr "" +"Launchpad Contributions:\n" +" pcp https://launchpad.net/~popcorp86" + +msgid "will expire on" +msgstr "vyprší" + +msgid "will not expire" +msgstr "nevyprší nikdy" + diff --git a/inc/lang/de/LC_MESSAGES/kusaba.po b/inc/lang/de/LC_MESSAGES/kusaba.po new file mode 100644 index 0000000..b37f602 --- /dev/null +++ b/inc/lang/de/LC_MESSAGES/kusaba.po @@ -0,0 +1,1422 @@ +msgid "" +msgstr "" +"Project-Id-Version: trevorchan\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2007-12-09 03:10+0000\n" +"PO-Revision-Date: 2009-05-13 01:08-0800\n" +"Last-Translator: \n" +"Language-Team: German \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2008-03-12 04:24+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +msgid "%s bans not shown." +msgstr "%s Sperren werden nicht gezeigt." + +msgid "%s not implemented." +msgstr "%s nicht implementiert." + +msgid "%s uploaded." +msgstr "%s hochgeladen." + +msgid "(for post and file deletion)" +msgstr "(zum Löschen von Eintrag oder Datei)" + +msgid "

Add News Post

This message will be displayed as it is written, so make sure you add the proper HTML." +msgstr "

Neuigkeiten hinzufügen

Diese Nachricht wird so dargestellt wie sie geschrieben ist, stelle also sicher das Du passendes HTML verwendest." + +msgid "A board with that name already exists." +msgstr "Ein Forum mit diesem Namen existiert bereits." + +msgid "A board with that name does not exist." +msgstr "Ein Forum mit diesem Namen existiert nicht." + +msgid "A common cause for this is an incorrect extension when the file is actually of a different type." +msgstr "Eine allgemeine Ursache dafür ist eine falsche Erweiterung, wenn die Datei eigentlich anderer Art ist." + +msgid "A file is required for a new thread. If embedding is allowed, either a file or embed ID is required." +msgstr "Für ein neues Thema wird eine Datei benötigt. Falls Einbettung erlaubt ist, sind entweder eine Datei oder eine Einbettungs-ID notwendig." + +msgid "A message is required to post without a file." +msgstr "Eine Nachricht wird benötigt um ohne Datei eintragen zu können." + +msgid "A post with that ID does not exist." +msgstr "Ein Eintrag mit dieser ID existiert nicht." + +msgid "A staff member with that ID already exists." +msgstr "Ein Mitglied mit dieser ID existiert bereits." + +msgid "A staff member with that id does not appear to exist." +msgstr "Ein Mitglied mit dieser ID scheint nicht zu existieren." + +msgid "Add" +msgstr "Hinzufügen" + +msgid "Add ban" +msgstr "Sperre hinzufügen" + +msgid "Add board" +msgstr "Forum hinzufügen" + +msgid "Add new blotter entry" +msgstr "Trage neuen Protokollbucheintrag ein" + +msgid "Add news" +msgstr "Neuigkeiten hinzufügen" + +msgid "Add staff member" +msgstr "Mitglied hinzufügen" + +msgid "Add word" +msgstr "Wort hinzufügen" + +msgid "Added a news entry" +msgstr "Neuigkeiten hinzugefügt" + +msgid "Added board" +msgstr "Forum hinzugefügt" + +msgid "Added on" +msgstr "Hinzugefügt" + +msgid "Added staff member" +msgstr "Mitglied hinzugefügt" + +msgid "Admin" +msgstr "Admin" + +msgid "Administration" +msgstr "Administration" + +msgid "Administrator" +msgstr "Administrator" + +msgid "Administrators" +msgstr "Administratoren" + +msgid "All Threads" +msgstr "Alle Themen" + +msgid "All boards" +msgstr "Alle Foren" + +msgid "All threads/posts by that IP in selected boards successfully deleted." +msgstr "Alle Themen/Einträge dieser IP wurden erfolgreich aus den ausgewählten Foren gelöscht." + +msgid "Allowed filetypes" +msgstr "Erlaubte Dateitypen" + +msgid "Already posted %shere%s." +msgstr "Bereits %shier%s veröffentlicht." + +msgid "An image, or message, is required for a reply." +msgstr "Eine Datei, oder Nachricht, wird für eine Antwort benötigt." + +msgid "Anonymous" +msgstr "Anonymous" + +msgid "Appeal Message" +msgstr "Widerspruchsnachricht" + +msgid "Appeal successfully denied." +msgstr "Widerspruch erfolgreich verweigert." + +msgid "Are you absolutely sure you want to delete %s?" +msgstr "Bist Du absolut sicher %s löschen zu wollen?" + +msgid "At" +msgstr "@" + +msgid "Ban from" +msgstr "Sperren von" + +msgid "Ban proxy list" +msgstr "Proxysperren" + +msgid "Ban successfully placed." +msgstr "Sperre erfolgreich angelegt." + +msgid "Ban successfully removed." +msgstr "Sperre erfolgreich entfernt." + +msgid "Banned" +msgstr "Gesperrt" + +msgid "Banned %d IP addresses using an IP address list." +msgstr "Sperrte %d IP-Addressen mittels einer IP-Addressen Liste." + +msgid "Banned from" +msgstr "Gesperrt von" + +msgid "Blotter" +msgstr "Protokollbuch" + +msgid "Blotter entry added." +msgstr "Protokollbucheintrag hinzugefügt." + +msgid "Blotter entry deleted." +msgstr "Protokollbucheintrag gelöscht." + +msgid "Blotter entry updated." +msgstr "Protokollbucheintrag aktualisiert." + +msgid "Blotter is disabled." +msgstr "Protokollbuch ist deaktiviert." + +msgid "Blotter updated" +msgstr "Protokollbuch aktualisiert" + +msgid "Board" +msgstr "Forum" + +msgid "Board options" +msgstr "Forenoptionen" + +msgid "Board successfully added." +msgstr "Forum erfolgreich hinzugefügt." + +msgid "Board successfully deleted." +msgstr "Forum erfolgreich gelöscht." + +msgid "Board type:" +msgstr "Forumstyp:" + +msgid "Boards" +msgstr "Foren" + +msgid "Cache successfully flushed." +msgstr "Zwischenspeicher erfolgreich geleert." + +msgid "Can be left blank." +msgstr "Kann ausgelassen werden." + +msgid "Can not be left blank." +msgstr "Kann nicht ausgelassen werden." + +msgid "Cancel" +msgstr "Abbrechen" + +msgid "Captcha" +msgstr "Bestätigungscode" + +msgid "Catalog Mode" +msgstr "Katalogmodus" + +msgid "Change account password" +msgstr "Kontenpasswort ändern" + +msgid "Check for new version" +msgstr "Auf neue Version prüfen" + +msgid "Choose one" +msgstr "Wähle aus" + +msgid "Cleanup" +msgstr "Säubern" + +msgid "Cleanup finished." +msgstr "Säuberung vollendet." + +msgid "Cleared APC cache" +msgstr "APC Zwischenspeicher geleert" + +msgid "Click Reply to view, or %sexpand%s." +msgstr "Klicke Antworten zum Anzeigen, oder %sexpandiere%s." + +msgid "Click Reply to view." +msgstr "Zum Anzeigen auf Antworten klicken." + +msgid "Click to show/hide" +msgstr "Klick zum zeigen/verstecken" + +msgid "Continue" +msgstr "Fortsetzen" + +msgid "Could not copy uploaded image." +msgstr "Konnte hochgeladenes Bild nicht kopieren." + +msgid "Could not create thumbnail." +msgstr "Konnte kein Vorschaubild erstellen." + +msgid "Current version:" +msgstr "Derzeitige Version:" + +msgid "Date" +msgstr "Datum" + +msgid "Days to keep modlog entries" +msgstr "Aufbewahrung von ModLog Einträgen in Tagen" + +msgid "Default" +msgstr "Voreinstellung" + +msgid "Default style:" +msgstr "Standardstyle:" + +msgid "Delete" +msgstr "Löschen" + +msgid "Delete all posts by IP" +msgstr "Lösche alle Einträge dieser IP" + +msgid "Delete all posts by this IP" +msgstr "Alle Einträge dieser IP löschen" + +msgid "Delete board" +msgstr "Forum löschen" + +msgid "Delete post" +msgstr "Eintrag löschen" + +msgid "Delete posts" +msgstr "Lösche Einträge" + +msgid "Delete thread" +msgstr "Thema löschen" + +msgid "Delete thread/post" +msgstr "Thema/Eintrag löschen" + +msgid "Deleted" +msgstr "Gelöscht" + +msgid "Deleted a VIP code" +msgstr "Lösche einen VIP-Code" + +msgid "Deleted board" +msgstr "Forum gelöscht" + +msgid "Deleted post" +msgstr "Eintrag gelöscht" + +msgid "Deleted posts by ip" +msgstr "Einträge von IP gelöscht" + +msgid "Deleted staff member" +msgstr "Mitglied gelöscht" + +msgid "Deleted thread" +msgstr "Thema gelöscht" + +msgid "Deleting non-deleted replies which belong to deleted threads." +msgstr "Löschung von nicht gelöschten Antworten welche zu gelöschten Themen gehören." + +msgid "Deleting unused images." +msgstr "Lösche unbenutzte Bilder." + +msgid "Denied the ban appeal for" +msgstr "Verweigerte den Sperrenwiderspruch für" + +msgid "Description" +msgstr "Beschreibung" + +msgid "Directory" +msgstr "Verzeichnis" + +msgid "Disk space used" +msgstr "Verwendeter Speicherplatz" + +msgid "Does not expire" +msgstr "Läuft nicht ab" + +msgid "Duplicate file entry detected." +msgstr "Doppelter Dateieintrag entdeckt." + +msgid "Duplicate thread subject" +msgstr "Doppelter Themenbetreff" + +msgid "Edit" +msgstr "Bearbeiten" + +msgid "Edit filetypes" +msgstr "Editiere Dateitypen" + +msgid "Edit sections" +msgstr "Editiere Sektionen" + +msgid "Edit word" +msgstr "Wort bearbeiten" + +msgid "Edited a VIP cod" +msgstr "Editierte einen VIP-Code" + +msgid "Edited a news entry" +msgstr "Nachrichteneintrag editiert" + +msgid "Email" +msgstr "Email" + +msgid "Embed" +msgstr "Einbetten" + +msgid "Embedding only" +msgstr "Nur Einbettung" + +msgid "Enable \"no file\" posting" +msgstr "Erlaube \"Keine Datei\" Einträge" + +msgid "Enable captcha:" +msgstr "Aktiviere CAPTCHA:" + +msgid "Enable reporting:" +msgstr "Ermögliche Berichterstattung:" + +msgid "Enable/disable captcha system for this board. If captcha is enabled, in order for a user to post, they must first correctly enter the text on an image." +msgstr "Aktiviert/Deaktiviert das CAPTCHA-System für dieses Forum. Falls CAPTCHA aktiviert ist, müssen Benutzer zuerst den Text eines Bildes korrekt bestätigen, bevor sie etwas eintragen können." + +msgid "Entire Thread" +msgstr "Ganzes Thema" + +msgid "Error, it appears your file did not transfer properly. Please go back and try again." +msgstr "Fehler: Es scheint das die Datei nicht korrekt übertragen wurde. Bitte wechsle zurück und versuche es erneut." + +msgid "Expand all images" +msgstr "Alle Bilder expandieren" + +msgid "Expires:" +msgstr "Erlischt:" + +msgid "Extension icon displayed, click image to open file." +msgstr "Dateisymbol wird angezeigt, zum Öffnen Bild anklicken." + +msgid "FAQ" +msgstr "FAQ" + +msgid "File" +msgstr "Datei" + +msgid "File Only" +msgstr "Nur Datei" + +msgid "File was not fully uploaded. Please go back and try again." +msgstr "Datei wurde nicht vollständig hochgeladen. Bitte wechsle zurück und versuche es erneut." + +msgid "File
Removed" +msgstr "Datei
Entfernt" + +msgid "Filetype added." +msgstr "Dateityp hinzugefügt." + +msgid "Filetype deleted." +msgstr "Dateityp gelöscht." + +msgid "Filetype updated." +msgstr "Dateityp aktualisiert." + +msgid "First 100 posts" +msgstr "Erste 100 Einträge" + +msgid "First 100 posts shown." +msgstr "Erste 100 Einträge werden angezeigt." + +msgid "First Post ID" +msgstr "Erste Eintrags-ID" + +msgid "Forced anonymous" +msgstr "Anonymous erzwingen" + +msgid "From" +msgstr "Von" + +msgid "Front" +msgstr "Vorderseite" + +msgid "Front Page" +msgstr "Hauptseite" + +msgid "Get posting password" +msgstr "Zeige Eintragspasswort" + +msgid "Global configuration succesfully updated." +msgstr "Allgemeine Konfiguration erfolgreich aktualisiert." + +msgid "Global options" +msgstr "Allgemeine Optionen" + +msgid "Go" +msgstr "Fortfahren" + +msgid "Header image" +msgstr "Titelbild" + +msgid "Height" +msgstr "Höhe" + +msgid "Hide Directories" +msgstr "Verstecke Verzeichnisse" + +msgid "Hide the watched threads box" +msgstr "Verstecke das beobachtete Themen Feld" + +msgid "Home" +msgstr "Hauptseite" + +msgid "ID" +msgstr "ID" + +msgid "IP" +msgstr "IP" + +msgid "If set to yes, new threads will not require an image to be posted." +msgstr "Falls ja, benötigen neue Themen keine Datei um veröffentlicht werden zu können." + +msgid "If set to yes, this board will appear in bold in the menu" +msgstr "Falls ja, wird dieses Forum im Menü fett gedruckt dargestellt" + +msgid "If set to yes, this board will appear in italics in the menu" +msgstr "Falls ja, wird dieses Forum im Menü kursiv dargestellt" + +msgid "If set to yes, users will be redirected to the thread they replied to/posted after posting. If set to no, users will be redirected to the first page of the board." +msgstr "Falls ja, werden Benutzer nach einem Eintrag zu dem Thema, welches sie erstellt oder auf das sie geantwortet haben, weitergeleitet. Falls nein, werden Benutzer auf die erste Seite des Forums weitergeleitet." + +msgid "If set to yes, users will not be allowed to enter a name, making everyone appear as Anonymous" +msgstr "Falls ja, wird es Benutzern nicht erlaubt einen Namen einzutragen, sodass jeder als Anonymous erscheint." + +msgid "Image" +msgstr "Bild" + +msgid "Image successfully deleted from your post." +msgstr "Bild wurde erfolgreich aus Deinem Eintrag gelöscht." + +msgid "Images" +msgstr "Bilder" + +msgid "Images and embedding" +msgstr "Bilder und Einbettung" + +msgid "Important" +msgstr "Wichtig" + +msgid "Improper filetype." +msgstr "Unpassender Dateityp." + +msgid "Include header" +msgstr "Header einbinden" + +msgid "Incorrect captcha entered." +msgstr "Fehlerhafter CAPTCHA eingetragen." + +msgid "Incorrect password." +msgstr "Fehlerhaftes Passwort." + +msgid "Incorrect username/password." +msgstr "Fehlerhafter/s Benutzername/Passwort." + +msgid "Index" +msgstr "Index" + +msgid "Inject" +msgstr "Einspeisen" + +msgid "Inserted SQL" +msgstr "SQL eingefügt" + +msgid "Integer values must be entered correctly." +msgstr "Ganzzahlige Werte müssen korrekt eingetragen werden." + +msgid "Invalid ID" +msgstr "Unzulässige ID" + +msgid "Invalid MIME type for this filetype." +msgstr "Ungültiger MIME Typ für dieses Dateiformat." + +msgid "Invalid ban ID" +msgstr "Unzulässige Sperren ID" + +msgid "Invalid board directory." +msgstr "Unzulässiges Forenverzeichnis." + +msgid "Invalid response code:" +msgstr "Unzulässiger Antwortcode:" + +msgid "Invalid session." +msgstr "Unzulässige Sitzung." + +msgid "Invalid staff ID." +msgstr "Unzulässige Mitglieds ID." + +msgid "Invalid thread ID." +msgstr "Ungültige Themen ID." + +msgid "Invalid thread ID. This may have been caused by the thread recently being deleted." +msgstr "Unzulässige Themen ID. Dies könnte durch eine kürzlich stattgefundene Löschung des Themas verursacht worden sein." + +msgid "Invalid video ID." +msgstr "Unzulässige Video ID." + +msgid "Invalid video type." +msgstr "Unzulässiger Videotyp." + +msgid "Is replaced by" +msgstr "Wird ersetzt durch" + +msgid "Last 50 posts" +msgstr "Letzte 50 Einträge" + +msgid "Last 50 posts shown." +msgstr "Letzte 50 Beiträge werden angezeigt." + +msgid "Last Post" +msgstr "Letzter Eintrag" + +msgid "Last active" +msgstr "Zuletzt aktiv" + +msgid "Lock" +msgstr "Verriegeln" + +msgid "Locked" +msgstr "Geschlossen" + +msgid "Locked thread" +msgstr "Thema geschlossen" + +msgid "Log in again." +msgstr "Erneut einloggen." + +msgid "Logged in" +msgstr "Eingeloggt" + +msgid "Logo" +msgstr "Logo" + +msgid "Manage" +msgstr "Verwalten" + +msgid "Manage boards" +msgstr "Foren verwalten" + +msgid "Manage locked threads" +msgstr "Geschlossene Themen verwalten" + +msgid "Manage stickies" +msgstr "Stickies verwalten" + +msgid "Marked for deletion (old)." +msgstr "Für Löschung markiert (alt)." + +msgid "Maximum board pages" +msgstr "Maximale Forenseiten" + +msgid "Maximum image size" +msgstr "Maximale Dateigröße" + +msgid "Maximum message length" +msgstr "Maximale Nachrichtenlänge" + +msgid "Maximum thread age (Hours)" +msgstr "Maximales Themenalter (Stunden)" + +msgid "Maximum thread replies" +msgstr "Maximale Themenantworten" + +msgid "Maxmimum size of uploaded images, in bytes." +msgstr "Maximale Größe der hochgeladenen Bilder, in Bytes." + +msgid "Maxmimum thumbnail height" +msgstr "Maximale Vorschaubild Höhe" + +msgid "Maxmimum thumbnail width" +msgstr "Maximale Vorschaubild Breite" + +msgid "Message" +msgstr "Nachricht" + +msgid "Message too long. Click %shere%s to view the full text." +msgstr "Nachricht zu lang. Klicke %shier%s um den vollen Text anzuzeigen." + +msgid "Misc" +msgstr "Verschiedenes" + +msgid "Mod" +msgstr "Mod" + +msgid "ModLog" +msgstr "ModLog" + +msgid "Moderates" +msgstr "Moderiert" + +msgid "Moderating boards" +msgstr "Moderierte Foren" + +msgid "Moderation" +msgstr "Moderation" + +msgid "Moderator" +msgstr "Moderator" + +msgid "Moderators" +msgstr "Moderatoren" + +msgid "Modify" +msgstr "Modifizieren" + +msgid "Modify staff member" +msgstr "Mitglied modifizieren" + +msgid "Module settings" +msgstr "Moduleinstellungen" + +msgid "Modules" +msgstr "Module" + +msgid "More" +msgstr "Mehr" + +msgid "Move complete." +msgstr "Verschiebung komplett." + +msgid "Move thread" +msgstr "Thema verschieben" + +msgid "NOTICE: You are using the default administrator account. Anyone can log in to this account, so a second administrator account needs to be created. Create another, log in to it, and delete this one." +msgstr "HINWEIS: Es wird das standardmäßige Administratorkonto benutzt. Jeder kann sich in dieses Konto einloggen, es wird deshalb ein zweites Administratorkonto benötigt. Erstelle ein neues, logge Dich damit ein, und lösche dieses hier." + +msgid "Name" +msgstr "Name" + +msgid "Name to display when a name is not attached to a post." +msgstr "Angezeigter Name falls einem Eintrag kein Name zugeordnet ist." + +msgid "Never" +msgstr "Niemals" + +msgid "New Thread" +msgstr "Neues Thema" + +msgid "New image" +msgstr "Neues Bild" + +msgid "New password" +msgstr "Neues Passwort" + +msgid "New password again" +msgstr "Nochmals neues Passwort" + +msgid "News" +msgstr "Neuigkeiten" + +msgid "News entry successfully added." +msgstr "Neuigkeiten erfolgreich hinzugefügt." + +msgid "Next" +msgstr "Weiter" + +msgid "No" +msgstr "Nein" + +msgid "No File" +msgstr "Keine Datei" + +msgid "No blotter entries." +msgstr "Keine Protokollbucheinträge." + +msgid "No boards" +msgstr "Keine Foren" + +msgid "No embedding" +msgstr "Keine Einbettung" + +msgid "No threads." +msgstr "Keine Themen." + +msgid "No visible boards" +msgstr "Keine sichtbaren Foren" + +msgid "None" +msgstr "Keine" + +msgid "Normal imageboard" +msgstr "Normales Bilderforum" + +msgid "Oekaki imageboard" +msgstr "Oekaki Bilderforum" + +msgid "Old password" +msgstr "Altes Passwort" + +msgid "Online now" +msgstr "Gerade online" + +msgid "Only moderators of the board and admins can make new posts/replies" +msgstr "Nur Moderatoren des Forums und Administratoren können neue Einträge/Antworten erstellen." + +msgid "Only put in the letter(s) of the board directory, no slashes!" +msgstr "Trage nur den/die Buchstaben des Forenverzeichnisses ein, keine Schrägstriche!" + +msgid "Open images in new window" +msgstr "Öffne Bilder in neuem Fenster" + +msgid "Order" +msgstr "Reihenfolge" + +msgid "Order to show board in menu list, in ascending order." +msgstr "Reihenfolge in welcher das Forum in der Menüliste angezeigt wird, in aufsteigender Reihenfolge." + +msgid "Overrides the header set in the config file. Leave blank to use configured global header image. Needs to be a full url including http://. Set to none to show no header image." +msgstr "Überschreibt das Titelbild welches in der Config-Datei festgelegt wurde. Leer lassen um das allgemein konfigurierte Titelbild zu nutzen. Es wird eine volle URL inklusive http:// benötigt. Auf Nichts setzen um kein Titelbild anzuzeigen." + +msgid "Pages" +msgstr "Seiten" + +msgid "Paint with" +msgstr "Male mit" + +msgid "Paint!" +msgstr "Malen!" + +msgid "Password" +msgstr "Passwort" + +msgid "Password successfully changed." +msgstr "Passwort erfolgreich geändert." + +msgid "Placed:" +msgstr "Angelegt:" + +msgid "Please enter a positive amount of seconds, or zero for a permanent ban." +msgstr "Bitte trage eine positive Menge an Sekunden ein, oder Null für eine permanente Sperre." + +msgid "Please enter a search query." +msgstr "Bitte Suchabfrage eintragen." + +msgid "Please fill in all required fields." +msgstr "Bitte alle benötigten Felder ausfüllen." + +msgid "Please make sure your file is smaller than %dB" +msgstr "Datei muß kleiner als %dB sein" + +msgid "Please select a board." +msgstr "Bitte ein Forum auswählen." + +msgid "Please select only one image to upload." +msgstr "Bitte nur eine Datei zum Hochladen auswählen." + +msgid "Please wait a moment before posting again." +msgstr "Bitte warte einen Moment bevor Du wieder einträgst." + +msgid "Popular" +msgstr "Beliebt" + +msgid "Post" +msgstr "Eintrag" + +msgid "Post added." +msgstr "Eintrag hinzugefügt." + +msgid "Post preview" +msgstr "Eintragsvorschau" + +msgid "Post successfully deleted." +msgstr "Eintrag erfolgreich gelöscht." + +msgid "Postbox notice" +msgstr "Briefkastennachricht" + +msgid "Posting a blacklisted link." +msgstr "Eintrag eines auf der Blacklist verzeichneten Links." + +msgid "Posting mode: Reply" +msgstr "Eintragsmodus: Antworten" + +msgid "Posting password" +msgstr "Eintragspasswort" + +msgid "Posting rates (past hour)" +msgstr "Eintragsquoten (letzte Stunde)" + +msgid "Posts" +msgstr "Einträge" + +msgid "Presets" +msgstr "Vorlagen" + +msgid "Preview" +msgstr "Vorschau" + +msgid "Previous" +msgstr "Zurück" + +msgid "Proxy list" +msgstr "Proxyliste" + +msgid "Query" +msgstr "Abfragen" + +msgid "Query executed successfully" +msgstr "Abfrage erfolgreich ausgeführt" + +msgid "Quick Reply" +msgstr "Schnellantwort" + +msgid "Ran cleanup" +msgstr "Säuberung ausgeführt" + +msgid "Raw HTML which will be inserted at the top of each page of the board." +msgstr "Schlichtes HTML das im Titel jeder Seite des Forums angezeigt wird." + +msgid "Read this thread from the beginning" +msgstr "Dieses Thema von Anfang an lesen" + +msgid "Reason" +msgstr "Begründung" + +msgid "Reason:" +msgstr "Begründung:" + +msgid "Rebuild all html files" +msgstr "Erneuere alle HTML Dateien" + +msgid "Rebuild complete. Took %d seconds." +msgstr "Wiederaufbau abgeschlossen. %d Sekunden verstrichen." + +msgid "Rebuilt all boards and threads" +msgstr "Alle Foren und Themen erneuert" + +msgid "Redirect to thread" +msgstr "Zum Thema weiterleiten" + +msgid "Redirecting" +msgstr "Weiterleitung" + +msgid "Refresh watched threads" +msgstr "Erneuere beobachtete Themen" + +msgid "Regenerated %s" +msgstr "%s wiederhergestellt" + +msgid "Regular expression" +msgstr "Regulärer Ausdruck" + +msgid "Remove" +msgstr "Entfernen" + +msgid "Removed word from wordfilter" +msgstr "Wort aus Wortfilter gelöscht" + +msgid "Replacement" +msgstr "Ersatz" + +msgid "Replies" +msgstr "Antworten" + +msgid "Replies displayed per stickied thread (in thread list)" +msgstr "Angezeigte Antworten pro angeheftetem Thema (in Themenliste)" + +msgid "Replies displayed per thread (in thread list)" +msgstr "Angezeigte Antworten pro Thema (in Themenliste)" + +msgid "Reply" +msgstr "Antworten" + +msgid "Report" +msgstr "Melden" + +msgid "Reporting allows users to report posts, adding the post to the report list." +msgstr "Die Berichterstattung erlaubt es Benutzern Einträge zu melden, wobei der Eintrag in die Berichtliste aufgenommen wird." + +msgid "Reports" +msgstr "Meldungen" + +msgid "Restore watched threads" +msgstr "Stelle beobachtete Themen wieder her" + +msgid "Results" +msgstr "Ergebnisse" + +msgid "Return" +msgstr "Zurück" + +msgid "Rules" +msgstr "Regeln" + +msgid "SQL query" +msgstr "SQL Abfrage" + +msgid "Search" +msgstr "Suchen" + +msgid "Search posts" +msgstr "Durchsuche Einträge" + +msgid "Seconds" +msgstr "Sekunden" + +msgid "Section" +msgstr "Sektion" + +msgid "Section added." +msgstr "Sektion hinzugefügt." + +msgid "Section deleted." +msgstr "Sektion gelöscht." + +msgid "Section updated." +msgstr "Sektion aktualisiert." + +msgid "Send Appeal" +msgstr "Sende Widerspruch" + +msgid "Show All" +msgstr "Alles anzeigen" + +msgid "Show Directories" +msgstr "Zeige Verzeichnisse" + +msgid "Show Posting Password" +msgstr "Zeige Eintragspasswort" + +msgid "Show/Hide" +msgstr "Zeige/Verstecke" + +msgid "Shown below" +msgstr "Unten angezeigt" + +msgid "Site Styles" +msgstr "Seitenstile" + +msgid "Size" +msgstr "Größe" + +msgid "Sorry, a generic error has occurred." +msgstr "Entschuldigung, es ist ein allgemeiner Fehler aufgetreten." + +msgid "Sorry, because of your numerous failed logins, you have been locked out from logging in for 20 minutes. Please wait and then try again." +msgstr "Entschuldigung, aufgrund zahlreich gescheiterter Loginversuche wurde die Anmeldung für 20 Minuten gesperrt. Bitte warte und versuche es dann erneut." + +msgid "Sorry, that filetype is not allowed on this board." +msgstr "Entschuldigung, dieser Dateityp ist in diesem Forum nicht erlaubt." + +msgid "Sorry, this board is locked and can not be posted in." +msgstr "Dieses Forum ist geschlossen und erlaubt keine neuen Einträge." + +msgid "Sorry, this thread is locked and can not be replied to." +msgstr "Dieses Thema ist geschlossen und erlaubt keine neuen Antworten." + +msgid "Sorry, your message is too long. Message length: %d, maxmimum allowed length: %d" +msgstr "Entschuldigung, Deine Nachricht ist zu lang. Textlänge: %d, maximal erlaubte Länge: %s" + +msgid "Sorry, your search returned zero results." +msgstr "Entschuldigung, die Suche erbrachte keine Treffer." + +msgid "Source" +msgstr "Quelle" + +msgid "Staff" +msgstr "Team" + +msgid "Staff member successfully added." +msgstr "Mitglied erfolgreich hinzugefügt." + +msgid "Staff rights" +msgstr "Mitgliedsrechte" + +msgid "Staff successfully deleted" +msgstr "Mitglied erfolgreich gelöscht" + +msgid "Staff successfully updated" +msgstr "Mitglied erfolgreich aktualisiert" + +msgid "Statistics" +msgstr "Statistiken" + +msgid "Stickied" +msgstr "Angeheftet" + +msgid "Stickied thread" +msgstr "Thema angeheftet" + +msgid "Sticky" +msgstr "Anheften" + +msgid "Style" +msgstr "Stil" + +msgid "Styles" +msgstr "Stile" + +msgid "Subject" +msgstr "Betreff" + +msgid "Submit" +msgstr "Abschicken" + +msgid "System lockout" +msgstr "Systemaussperrung" + +msgid "Tag" +msgstr "Stichwort" + +msgid "Text board" +msgstr "Textforum" + +msgid "Text boards may have only one thread with a unique subject. Please pick another." +msgstr "Textforen können nur ein Thema mit einem einzigartigen Betreff enthalten. Bitte wähle einen anderen." + +msgid "Text boards only. If enabled, the list of threads displayed on the front page will be formatted differently to be compact." +msgstr "Nur Textforen. Falls aktiviert, wird die Liste der Themen, welche auf der Hauptseite angezeigt wird, unterschiedlich formatiert um kompakt zu sein." + +msgid "That ID does not exist." +msgstr "Diese ID existiert nicht." + +msgid "That ID is a reply, not a thread." +msgstr "Diese ID ist eine Antwort, kein Thema." + +msgid "That IP has already been banned." +msgstr "Diese IP wurde bereits gesperrt." + +msgid "That name is for internal use. Please pick another." +msgstr "Dieser Name ist für interne Benutzung. Bitte wähle einen anderen." + +msgid "That post has been cleared as not requiring any deletion." +msgstr "Dieser Eintrag wurde gesäubert und erfordert keine Löschung." + +msgid "That post is already in the report list." +msgstr "Dieser Eintrag befindet sich bereits in der Berichtliste." + +msgid "That thread has yet to be deleted." +msgstr "Dieses Thema muss erst noch gelöscht werden." + +msgid "That thread may have been recently deleted." +msgstr "Dieses Thema wurde möglicherweise vor kurzem gelöscht." + +msgid "That video ID has already been posted %shere%s." +msgstr "Diese Video ID wurde bereits %shier%s veröffentlicht." + +msgid "That word already exists." +msgstr "Dieses Wort existiert bereits." + +msgid "The 5 newest replies are shown below." +msgstr "Die 5 neuesten Antworten werden unten angezeigt." + +msgid "The change will not be apparent until the html files are rebuilt." +msgstr "Die Veränderung wird nicht sichtbar sein, bis die HTML Dateien erneuert wurden." + +msgid "The directory of the board." +msgstr "Das Verzeichnis des Forums." + +msgid "The first post of this board will recieve this ID." +msgstr "Der erste Eintrag dieses Forums wird diese ID erhalten." + +msgid "The name of the board." +msgstr "Der Name des Forums." + +msgid "The number of replies a thread can have before autosaging to the back of the board." +msgstr "Die Anzahl der Antworten die ein Thema haben kann bevor es automatisch zum hinteren Teil des Forums befördert wird." + +msgid "The old password you provided did not match the current one." +msgstr "Das alte Passwort stimmte nicht mit dem aktuellen überein." + +msgid "The second password did not match the first." +msgstr "Das zweite Passwort stimmte nicht mit dem ersten überein." + +msgid "The section the board is in. This is used for displaying the list of boards on the top and bottom of pages." +msgstr "Die Sektion in welcher sich das Forum befindet. Dadurch wird eine Liste der Foren an Ober- & Unterseite jeder Seite dargestellt." + +msgid "The style which will be set when the user first visits the board." +msgstr "Der Stil welcher festgelegt wird, wenn der Benutzer das Forum zuerst besucht." + +msgid "The type of posts which will be accepted on this board. A normal imageboard will feature image and extended format posts, a text board will have no images, and an Oekaki board will allow users to draw images and use them in their posts." +msgstr "Die Art der Einträge welche in diesem Forum akzeptiert wird. Ein normales Bilderforum erlaubt Bilder- und erweiterte Formateinträge, ein Textforum wird keine Bilder haben, und ein Oekakiforum wird es Benutzern gestatten Bilder zu zeichnen und diese in ihren Einträgen zu verwenden." + +msgid "There are currently no bans." +msgstr "Gegenwärtig sind keine Sperren angelegt." + +msgid "There are currently no filetypes." +msgstr "Es existieren momentan keine Dateitypen." + +msgid "There are currently no sections." +msgstr "Es existieren momentan keine Sektionen." + +msgid "There are currently no threads to display." +msgstr "Es existieren momentan keine Themen zum Anzeigen." + +msgid "There is already a file with that name." +msgstr "Es existiert bereits eine Datei mit diesem Namen." + +msgid "There was an error in trying to delete your post" +msgstr "Es ist ein Fehler beim Löschens Deines Eintrages aufgetreten" + +msgid "This board does not allow post reporting." +msgstr "Dieses Forum erlaubt kein Melden von Einträgen." + +msgid "This post has been deleted." +msgstr "Dieser Eintrag wurde gelöscht." + +msgid "Thread" +msgstr "Thema" + +msgid "Thread successfully deleted." +msgstr "Thema erfolgreich gelöscht." + +msgid "Thread successfully locked." +msgstr "Thema erfolgreich geschlossen." + +msgid "Thread successfully stickied." +msgstr "Thema erfolgreich angeheftet." + +msgid "Thread successfully un-stickied" +msgstr "Thema erfolgreich abgeheftet" + +msgid "Thread successfully unlocked." +msgstr "Thema erfolgreich geöffnet." + +msgid "Threads" +msgstr "Themen" + +msgid "Threads displayed per page (in thread list)" +msgstr "Angezeigte Themen pro Seite (in Themenliste)" + +msgid "Thumbnail displayed, click image for full size." +msgstr "Vorschaubild wird angezeigt, für Volldarstellung Bild anklicken." + +msgid "To" +msgstr "Zu" + +msgid "Trial" +msgstr "Erprobung" + +msgid "Unable to clear cache: you do not have caching enabled." +msgstr "Zwischenspeicher kann nicht geleert werden: Chaching wurde nicht aktiviert." + +msgid "Unable to connect to:" +msgstr "Verbindung nicht etablierbar:" + +msgid "Unable to create directories." +msgstr "Kann Verzeichnisse nicht erstellen." + +msgid "Unable to delete board." +msgstr "Forum kann nicht gelöscht werden." + +msgid "Unable to find record of your IP being banned." +msgstr "Kein Eintrag auffindbar, dass Deine IP gesperrt wurde." + +msgid "Unable to find records of any posts matching that quote syntax." +msgstr "Nicht imstande, Aufzeichnungen irgendwelcher Einträge zu finden, welche zur Zitatsyntax passen." + +msgid "Unable to locate a board named" +msgstr "Forum nicht auffindbar:" + +msgid "Unable to locate a filetype with that ID." +msgstr "Kein Dateityp mit dieser ID auffindbar." + +msgid "Unable to locate a section with that ID." +msgstr "Keine Sektion mit dieser ID auffindbar." + +msgid "Unable to locate that word." +msgstr "Dieses Wort kann nicht gefunden werden." + +msgid "Unable to read uploaded file during thumbnailing." +msgstr "Hochgeladene Datei kann während Miniaturherstellung nicht gelesen werden." + +msgid "Unable to report post. Please go back and try again." +msgstr "Kann Eintrag nicht melden. Bitte wechsle zurück und versuche es erneut." + +msgid "Unbanned" +msgstr "Entsperrt" + +msgid "Unlock" +msgstr "Entriegeln" + +msgid "Unlocked thread" +msgstr "Thema geöffnet" + +msgid "Unstickied thread" +msgstr "Thema abgeheftet" + +msgid "Unsticky" +msgstr "Abheften" + +msgid "Upating pages." +msgstr "Aktualisiere Seiten." + +msgid "Update" +msgstr "Aktualisierung" + +msgid "Update and regenerate board" +msgstr "Forum aktualisieren und regenerieren" + +msgid "Update successful." +msgstr "Aktualisierung erfolgreich." + +msgid "Update without regenerating board" +msgstr "Forum aktualisieren ohne zu regenerieren" + +msgid "Updated board configuration" +msgstr "Forenkonfiguration aktualisiert" + +msgid "Updated global configuration" +msgstr "Allgemeine Konfiguration aktualisiert" + +msgid "Updated staff member" +msgstr "Mitglied aktualisiert" + +msgid "Updated word on wordfilter" +msgstr "Wort in Wortfilter aktualisiert" + +msgid "Upload type:" +msgstr "Uploadtyp:" + +msgid "Use animation?" +msgstr "Animation benutzen?" + +msgid "Username" +msgstr "Benutzername" + +msgid "View Reports" +msgstr "Zeige Meldungen" + +msgid "View all bans" +msgstr "Zeige alle Sperren" + +msgid "View animation" +msgstr "Zeige Animation" + +msgid "View catalog" +msgstr "Zeige Katalog" + +msgid "View deleted thread" +msgstr "Gelöschtes Thema anzeigen" + +msgid "View/Add/Remove bans" +msgstr "Sperren zeigen/hinzufügen/entfernen" + +msgid "Viewed disk space used" +msgstr "Angezeigte Speicherkapazität benutzt" + +msgid "Watched Threads" +msgstr "Beobachtete Themen" + +msgid "Welcome" +msgstr "Willkommen" + +msgid "What filetypes users are allowed to upload." +msgstr "Welche Dateitypen Benutzer hochladen dürfen." + +msgid "Whether or not to allow embedding of videos." +msgstr "Ob das Einbetten von Videos erlaubt werden soll oder nicht." + +msgid "Width" +msgstr "Breite" + +msgid "Word" +msgstr "Wort" + +msgid "Word successfully added." +msgstr "Wort erfolgreich hinzugefügt." + +msgid "Word successfully removed." +msgstr "Wort erfolgreich entfernt." + +msgid "Word successfully updated." +msgstr "Wort erfolgreich aktualisiert." + +msgid "Wordfilter" +msgstr "Wortfilter" + +msgid "YOU ARE BANNED" +msgstr "DU BIST GESPERRT" + +msgid "YOU ARE NOT BANNED!" +msgstr "DU BIST NICHT GESPERRT!" + +msgid "Yes" +msgstr "Ja" + +msgid "You are banned from posting on:" +msgstr "Du bist in folgenden Foren gesperrt:" + +msgid "You are currently posting faster than the configured minimum post delay allows." +msgstr "Momentan trägst Du schneller ein als es das konfigurierte Minimum für Eintragswartezeiten erlaubt." + +msgid "You are not a moderator of this board." +msgstr "Du bist kein Moderator dieses Forums." + +msgid "You can only delete posts from boards you moderate." +msgstr "Du kannst nur Einträge aus Foren löschen welche Du moderierst." + +msgid "You can only make board specific bans to boards which you moderate." +msgstr "Du kannst nur forenspezifische Sperren zu Foren anlegen welche Du moderierst." + +msgid "You have been banned from posting on" +msgstr "Du wurdest aus diesen Foren gesperrt" + +msgid "You have been successfully logged out." +msgstr "Du wurdest erfolgreich ausgeloggt." + +msgid "You may not appeal this ban." +msgstr "Du kannst diese Sperre nicht widerrufen." + +msgid "You may appeal this ban in" +msgstr "Du kannst diese Sperre jetzt dort widerrufen:" + +msgid "You may now appeal this ban." +msgstr "Du kannst diese Sperre jetzt widerrufen." + +msgid "You must enter a subject." +msgstr "Du musst einen Betreff eintragen." + +msgid "You searched for" +msgstr "Du suchtest nach" + +msgid "Your IP address is" +msgstr "Deine IP-Addresse ist" + +msgid "Your appeal is currently pending review." +msgstr "Dein Widerspruch befindet sich momentan in Bearbeitung." + +msgid "Your appeal was reviewed and denied. You may not appeal this ban again." +msgstr "Dein Widerspruch wurde überprüft und verweigert. Du kannst diese Sperre nicht erneut widerrufen." + +msgid "Your image" +msgstr "Dein Bild" + +msgid "Your post already doesn't have an image!" +msgstr "Dein Eintrag hat bereits ein Bild!" + +msgid "Your post contains one or more illegal characters." +msgstr "Dein Beitrag enthält einen oder mehrere unzulässige Zeichen." + +msgid "Your posting password" +msgstr "Dein Eintragspasswort" + +msgid "and" +msgstr "und" + +msgid "for the following reason" +msgstr "aus folgendem Grund" + +msgid "forever" +msgstr "endlos" + +msgid "log in" +msgstr "einloggen" + +msgid "log out" +msgstr "ausloggen" + +msgid "omitted" +msgstr "ausgelassen" + +msgid "or" +msgstr "oder" + +msgid "translator-credits" +msgstr "" +"Launchpad Contributions:\n" +" Guillaume Janssen \n" +" Twilight \n" +" tj9991 \n" +"\n" +"Launchpad Contributions:\n" +" Twilight https://launchpad.net/~twilight" + +msgid "will expire on" +msgstr "verfällt am" + +msgid "will not expire" +msgstr "verfällt nicht" + diff --git a/inc/lang/es/LC_MESSAGES/kusaba.po b/inc/lang/es/LC_MESSAGES/kusaba.po new file mode 100644 index 0000000..7ab9a71 --- /dev/null +++ b/inc/lang/es/LC_MESSAGES/kusaba.po @@ -0,0 +1,1406 @@ +msgid "" +msgstr "" +"Project-Id-Version: trevorchan\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2007-12-09 03:10+0000\n" +"PO-Revision-Date: 2008-02-04 22:06+0000\n" +"Last-Translator: Kiba-Kun \n" +"Language-Team: Spanish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2008-03-12 04:24+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +msgid "%s bans not shown." +msgstr "%s bans no mostrados." + +msgid "%s not implemented." +msgstr "%s no está implementado." + +msgid "%s uploaded." +msgstr "%s subido." + +msgid "(for post and file deletion)" +msgstr "(Para el borrado del post)" + +msgid "

Add News Post

This message will be displayed as it is written, so make sure you add the proper HTML." +msgstr "

Agregar noticia

Este mensaje se mostrará tal como se escribe, así que asegúrate de agregar corréctamente el código HTML." + +msgid "A board with that name already exists." +msgstr "Ya existe un board con ese nombre." + +msgid "A board with that name does not exist." +msgstr "No existe un board con ese nombre." + +msgid "A common cause for this is an incorrect extension when the file is actually of a different type." +msgstr "Una causa común para esto es un archivo con una extensión incorrecta, cuando en realidad el archivo es de un formato diferente." + +msgid "A file is required for a new thread. If embedding is allowed, either a file or embed ID is required." +msgstr "Se requiere de un archivo para crear un hilo nuevo. De estar permitido el incrustar, se sigue requiriendo de un archivo o de un ID incrustado." + +msgid "A message is required to post without a file." +msgstr "Necesitas escribir un mensaje para postear sin un archivo." + +msgid "A post with that ID does not exist." +msgstr "No existe un post con esa ID." + +msgid "A staff member with that ID already exists." +msgstr "Ya existe un miembro del staff con esa ID." + +msgid "A staff member with that id does not appear to exist." +msgstr "No parece que exista in miembro del staff con esa ID." + +msgid "Add" +msgstr "Agregar" + +msgid "Add ban" +msgstr "Agregar ban" + +msgid "Add board" +msgstr "Agregar board" + +msgid "Add new blotter entry" +msgstr "Añadir nueva entrada al boletín" + +msgid "Add news" +msgstr "Agregar noticia" + +msgid "Add staff member" +msgstr "Agregar miembro del staff" + +msgid "Add word" +msgstr "Agregar palabra" + +msgid "Added a news entry" +msgstr "Noticia añadida" + +msgid "Added board" +msgstr "Board añadido" + +msgid "Added on" +msgstr "Añadido el" + +msgid "Added staff member" +msgstr "Miembro del staff añadido" + +msgid "Admin" +msgstr "Admin" + +msgid "Administration" +msgstr "Administración" + +msgid "Administrator" +msgstr "Administrador" + +msgid "Administrators" +msgstr "Administradores" + +msgid "All Threads" +msgstr "Todos los hilos" + +msgid "All boards" +msgstr "Todos los boards" + +msgid "All threads/posts by that IP in selected boards successfully deleted." +msgstr "Todos los hilos/posts de esa IP han sido borrados con éxito de los boards seleccionados." + +msgid "Allowed filetypes" +msgstr "Tipos de archivos permitidos" + +msgid "Already posted %shere%s." +msgstr "Está posteado %saquí%s" + +msgid "An image, or message, is required for a reply." +msgstr "Se requiere de una imagen o mensaje para responder." + +msgid "Anonymous" +msgstr "Anónimo" + +msgid "Appeal Message" +msgstr "Mensaje de apelación" + +msgid "Appeal successfully denied." +msgstr "Apelación rechazada con éxito." + +msgid "Are you absolutely sure you want to delete %s?" +msgstr "¿Estás seguro que quieres eliminar %s?" + +msgid "At" +msgstr "En" + +msgid "Ban from" +msgstr "Banear de" + +msgid "Ban proxy list" +msgstr "Banear lista proxy" + +msgid "Ban successfully placed." +msgstr "Ban colocado con éxito." + +msgid "Ban successfully removed." +msgstr "Ban removido con éxito." + +msgid "Banned" +msgstr "Baneado" + +msgid "Banned %d IP addresses using an IP address list." +msgstr "Direcciones IP baneadas usando una lista de direcciones IP." + +msgid "Banned from" +msgstr "Baneado de" + +msgid "Blotter" +msgstr "Boletín" + +msgid "Blotter entry added." +msgstr "Entrada añadida al boletín." + +msgid "Blotter entry deleted." +msgstr "Entrada eliminada del boletín." + +msgid "Blotter entry updated." +msgstr "Entrada al boletín actualizada." + +msgid "Blotter is disabled." +msgstr "El boletín está desactivado." + +msgid "Blotter updated" +msgstr "Boletín actualizado" + +msgid "Board" +msgstr "Board" + +msgid "Board options" +msgstr "Opciones del board" + +msgid "Board successfully added." +msgstr "Board añadido con éxito." + +msgid "Board successfully deleted." +msgstr "Boar eliminado con éxito." + +msgid "Board type:" +msgstr "Tipo de board:" + +msgid "Boards" +msgstr "Boards" + +msgid "Cache successfully flushed." +msgstr "Caché eliminada con éxito." + +msgid "Can be left blank." +msgstr "Puede quedarse en blanco." + +msgid "Can not be left blank." +msgstr "No puede quedarse en blanco." + +msgid "Cancel" +msgstr "Cancelar" + +msgid "Captcha" +msgstr "Captcha" + +msgid "Catalog Mode" +msgstr "Modo: Catálogo" + +msgid "Change account password" +msgstr "Cambiar mi contraseña" + +msgid "Check for new version" +msgstr "Comprobar nueva versión" + +msgid "Choose one" +msgstr "Escoge uno" + +msgid "Cleanup" +msgstr "Limpiar" + +msgid "Cleanup finished." +msgstr "Limpieza finalizada." + +msgid "Cleared APC cache" +msgstr "Caché APC limpiado" + +msgid "Click Reply to view, or %sexpand%s." +msgstr "Haz click en Responder para ver, o %sexpande%s." + +msgid "Click Reply to view." +msgstr "Haz click en Responder para ver." + +msgid "Click to show/hide" +msgstr "Haz click para mostrar/ocultar" + +msgid "Continue" +msgstr "Continuar" + +msgid "Could not copy uploaded image." +msgstr "No se pudo copiar la imagen subida." + +msgid "Could not create thumbnail." +msgstr "No se pudo crear el thumbnail." + +msgid "Current version:" +msgstr "Versión actual:" + +msgid "Date" +msgstr "Fecha" + +msgid "Days to keep modlog entries" +msgstr "Número de días que se guardan los datos del modlog" + +msgid "Default" +msgstr "Defecto" + +msgid "Default style:" +msgstr "Estilo por defecto:" + +msgid "Delete" +msgstr "Eliminar" + +msgid "Delete all posts by IP" +msgstr "Eliminar posts de IP" + +msgid "Delete all posts by this IP" +msgstr "Eliminar todos los posts de esta IP" + +msgid "Delete board" +msgstr "Eliminar board" + +msgid "Delete post" +msgstr "Eliminar post" + +msgid "Delete posts" +msgstr "Eliminar posts" + +msgid "Delete thread" +msgstr "Eliminar hilo" + +msgid "Delete thread/post" +msgstr "Eliminar hilo/post" + +msgid "Deleted" +msgstr "Eliminado" + +msgid "Deleted a VIP code" +msgstr "Código VIP eliminado" + +msgid "Deleted board" +msgstr "Board eliminado" + +msgid "Deleted post" +msgstr "Post eliminado" + +msgid "Deleted posts by ip" +msgstr "Posts por IP eliminados" + +msgid "Deleted staff member" +msgstr "Miembro del staff eliminado" + +msgid "Deleted thread" +msgstr "Hilo eliminado" + +msgid "Deleting non-deleted replies which belong to deleted threads." +msgstr "Eliminando respuestas no-eliminadas que pertenecen a hilos eliminados." + +msgid "Deleting unused images." +msgstr "Eliminar imágenes sin uso." + +msgid "Denied the ban appeal for" +msgstr "Rechazada la apelación de ban por" + +msgid "Description" +msgstr "Descripción" + +msgid "Directory" +msgstr "Directorio" + +msgid "Disk space used" +msgstr "Espacio utilizado en disco" + +msgid "Does not expire" +msgstr "No caduca" + +msgid "Duplicate file entry detected." +msgstr "Archivo duplicado." + +msgid "Duplicate thread subject" +msgstr "Título de hilo duplicado" + +msgid "Edit" +msgstr "Editar" + +msgid "Edit filetypes" +msgstr "Editar tipos de archivos" + +msgid "Edit sections" +msgstr "Editar secciones" + +msgid "Edit word" +msgstr "Editar texto." + +msgid "Edited a VIP cod" +msgstr "Código VIP editado" + +msgid "Edited a news entry" +msgstr "Noticia editada" + +msgid "Email" +msgstr "Email" + +msgid "Embed" +msgstr "Incrustar" + +msgid "Embedding only" +msgstr "Sólo incrustados" + +msgid "Enable \"no file\" posting" +msgstr "Activar postear \"sin archivo\"" + +msgid "Enable captcha:" +msgstr "Activar captcha:" + +msgid "Enable reporting:" +msgstr "Activar reportar:" + +msgid "Enable/disable captcha system for this board. If captcha is enabled, in order for a user to post, they must first correctly enter the text on an image." +msgstr "Activa/Desactiva el sistema captcha en este board. Si el captcha está activado, para que un usuario pueda postear primero deberá escribir correctamente el texto que aparecerá en una imagen." + +msgid "Entire Thread" +msgstr "Hilo completo" + +msgid "Error, it appears your file did not transfer properly. Please go back and try again." +msgstr "Error, parece que el archivo no se transfirió correctamente. Regresa y vuelve a intentarlo." + +msgid "Expand all images" +msgstr "Expandir todas las imágenes" + +msgid "Expires:" +msgstr "Expira:" + +msgid "Extension icon displayed, click image to open file." +msgstr "Ícono de extensión mostrado, click en la imagen para abrir el archivo." + +msgid "FAQ" +msgstr "FAQ" + +msgid "File" +msgstr "Archivo" + +msgid "File Only" +msgstr "Archivo Solamente" + +msgid "File was not fully uploaded. Please go back and try again." +msgstr "El archivo no se subió por completo. Inténtalo de nuevo." + +msgid "File
Removed" +msgstr "Archivo
Removido" + +msgid "Filetype added." +msgstr "Tipo de archivo añadido." + +msgid "Filetype deleted." +msgstr "Tipo de archivo eliminado." + +msgid "Filetype updated." +msgstr "Tipo de archivo actualizado." + +msgid "First 100 posts" +msgstr "Primeros 100 posts" + +msgid "First 100 posts shown." +msgstr "Primeros 100 posts mostrados." + +msgid "First Post ID" +msgstr "ID del primer post" + +msgid "Forced anonymous" +msgstr "Forzar anónimo" + +msgid "From" +msgstr "De" + +msgid "Front" +msgstr "Frontal" + +msgid "Front Page" +msgstr "Página inicial" + +msgid "Get posting password" +msgstr "Conseguir contraseña de posteo" + +msgid "Global configuration succesfully updated." +msgstr "Configuración global actualizada con éxito." + +msgid "Global options" +msgstr "Opciones globales" + +msgid "Go" +msgstr "Proceder" + +msgid "Header image" +msgstr "Imagen de la cabecera" + +msgid "Height" +msgstr "Alto" + +msgid "Hide Directories" +msgstr "Ocultar directorios" + +msgid "Hide the watched threads box" +msgstr "Esconder los hilos marcados" + +msgid "Home" +msgstr "Inicio" + +msgid "ID" +msgstr "ID" + +msgid "IP" +msgstr "IP" + +msgid "If set to yes, new threads will not require an image to be posted." +msgstr "Si eliges \"SÍ\", los hilos nuevos no requerirán de una imagen para ser posteados." + +msgid "If set to yes, this board will appear in bold in the menu" +msgstr "Si se cambia a sí, este board aparecerá en negritas en el menú" + +msgid "If set to yes, this board will appear in italics in the menu" +msgstr "Si se elige \"Sí\", este board aparecerá en itálicas en el menú" + +msgid "If set to yes, users will be redirected to the thread they replied to/posted after posting. If set to no, users will be redirected to the first page of the board." +msgstr "Si eliges \"Sí\", los usuarios serán redirigidos al hilo que postearon/respondieron después de hacerlo. Si eliges \"No\", los usuiarios serán redirigidos a la primera página del board." + +msgid "If set to yes, users will not be allowed to enter a name, making everyone appear as Anonymous" +msgstr "Si eliges \"SÍ\", los usuarios no podrán usar un nombre, haciendo que todos aparezcan como \"Anónimo\"." + +msgid "Image" +msgstr "Imagen" + +msgid "Image successfully deleted from your post." +msgstr "Imagen eliminada satisfactoriamente del post." + +msgid "Images" +msgstr "Imágenes" + +msgid "Images and embedding" +msgstr "Imagenes e incrustados." + +msgid "Important" +msgstr "Importante" + +msgid "Improper filetype." +msgstr "Tipo de archivo incorrecto." + +msgid "Include header" +msgstr "Incluir cabecera" + +msgid "Incorrect captcha entered." +msgstr "Código captcha incorrecto." + +msgid "Incorrect password." +msgstr "Contraseña incorrecta." + +msgid "Incorrect username/password." +msgstr "Nombre de usuario/contraseña incorrecta." + +msgid "Index" +msgstr "Índice" + +msgid "Inject" +msgstr "Ejecutar" + +msgid "Inserted SQL" +msgstr "SQL insertado" + +msgid "Integer values must be entered correctly." +msgstr "Los valores enteros deben ser introducidos correctamente." + +msgid "Invalid ID" +msgstr "ID no válido" + +msgid "Invalid MIME type for this filetype." +msgstr "MIME inválido para este tipo de archivo. Esto puede deberse a que el archivo tiene una extensión diferente a la real." + +msgid "Invalid ban ID" +msgstr "ID de ban no válida." + +msgid "Invalid board directory." +msgstr "Directorio de board no válido." + +msgid "Invalid response code:" +msgstr "Código de respuesta no válido." + +msgid "Invalid session." +msgstr "Sesíon no válida." + +msgid "Invalid staff ID." +msgstr "ID de staff no válido." + +msgid "Invalid thread ID." +msgstr "ID de hilo no válido." + +msgid "Invalid thread ID. This may have been caused by the thread recently being deleted." +msgstr "ID de hilo no válido. Esto es a causa de que el hilo fue borrado recientemente." + +msgid "Invalid video ID." +msgstr "ID de video no válido." + +msgid "Invalid video type." +msgstr "Tipo de video no válido." + +msgid "Is replaced by" +msgstr "Es sustituda por" + +msgid "Last 50 posts" +msgstr "Últimos 50 posts" + +msgid "Last 50 posts shown." +msgstr "Últimos 50 posts mostrados." + +msgid "Last Post" +msgstr "Último post" + +msgid "Lock" +msgstr "Cerrar" + +msgid "Locked" +msgstr "Cerrado" + +msgid "Locked thread" +msgstr "Hilo cerrado" + +msgid "Log in again." +msgstr "Volver a iniciar sesión." + +msgid "Logged in" +msgstr "Sesión iniciada" + +msgid "Logo" +msgstr "Logo" + +msgid "Manage" +msgstr "Administrar" + +msgid "Manage boards" +msgstr "Administrar boards" + +msgid "Manage locked threads" +msgstr "Administrar hilos cerrados" + +msgid "Manage stickies" +msgstr "Administrar hilos fijos" + +msgid "Marked for deletion (old)." +msgstr "Marcado para su eliminación (antiguo)" + +msgid "Maximum board pages" +msgstr "Máximo de páginas por board" + +msgid "Maximum image size" +msgstr "Tamaño máximo de imagen" + +msgid "Maximum message length" +msgstr "Longitud máxima del mensaje" + +msgid "Maximum thread age (Hours)" +msgstr "Edad máxima del hilo (Horas)" + +msgid "Maximum thread replies" +msgstr "Respuestas máximas por hilo" + +msgid "Maxmimum size of uploaded images, in bytes." +msgstr "Tamaño máximo de las imagenes, en bytes." + +msgid "Maxmimum thumbnail height" +msgstr "Alto máximo del thumbnail" + +msgid "Maxmimum thumbnail width" +msgstr "Ancho máximo del thumbnail" + +msgid "Message" +msgstr "Mensaje" + +msgid "Message too long. Click %shere%s to view the full text." +msgstr "Mensaje demasiado largo. Haz click %saquí%s para ver el texto completo." + +msgid "Misc" +msgstr "Misceláneo" + +msgid "Mod" +msgstr "Mod" + +msgid "ModLog" +msgstr "ModLog" + +msgid "Moderates" +msgstr "Modera" + +msgid "Moderating boards" +msgstr "Moderando boards" + +msgid "Moderation" +msgstr "Moderación" + +msgid "Moderator" +msgstr "Moderador" + +msgid "Moderators" +msgstr "Moderadores" + +msgid "Modify" +msgstr "Modificar" + +msgid "Modify staff member" +msgstr "Modificar miembro del staff" + +msgid "Module settings" +msgstr "Configurar módulos" + +msgid "Modules" +msgstr "Módulos" + +msgid "More" +msgstr "Más" + +msgid "Move complete." +msgstr "Movimiento completado." + +msgid "Move thread" +msgstr "Mover hilo" + +msgid "NOTICE: You are using the default administrator account. Anyone can log in to this account, so a second administrator account needs to be created. Create another, log in to it, and delete this one." +msgstr "AVISO: Estás usando la cuenta de administrador que viene por defecto. Cualquiera puede iniciar sesíon en esta cuenta, por ello es necesario crear una segunda cuenta de administrador. Creala, inicia sesión en ella y elimina esta cuenta." + +msgid "Name" +msgstr "Nombre" + +msgid "Name to display when a name is not attached to a post." +msgstr "Nombre que se mostrará si no se elige uno." + +msgid "Never" +msgstr "Nunca" + +msgid "New Thread" +msgstr "Nuevo hilo" + +msgid "New image" +msgstr "Nueva imagen" + +msgid "New password" +msgstr "Nueva contraseña" + +msgid "New password again" +msgstr "Repetir la nueva contraseña" + +msgid "News" +msgstr "Noticias" + +msgid "News entry successfully added." +msgstr "Noticia añadida con éxito." + +msgid "Next" +msgstr "Siguiente" + +msgid "No" +msgstr "No" + +msgid "No File" +msgstr "No hay archivo" + +msgid "No blotter entries." +msgstr "No hay boletines." + +msgid "No boards" +msgstr "No hay boards" + +msgid "No embedding" +msgstr "No incrustar" + +msgid "No threads." +msgstr "No hay hilos." + +msgid "No visible boards" +msgstr "Boards no visibles" + +msgid "None" +msgstr "Ninguno" + +msgid "Normal imageboard" +msgstr "Imageboard normal" + +msgid "Oekaki imageboard" +msgstr "Oekaki imageboard" + +msgid "Old password" +msgstr "Contraseña actual" + +msgid "Online now" +msgstr "En línea ahora" + +msgid "Only moderators of the board and admins can make new posts/replies" +msgstr "Sólo los moderadores del board y los administradores pueden agregar nuevos posts/respuestas" + +msgid "Only put in the letter(s) of the board directory, no slashes!" +msgstr "Escribe sólo la(s) letra(s) del directorio del board, sin diagonales." + +msgid "Open images in new window" +msgstr "Abrir imágenes en una nueva ventana." + +msgid "Order" +msgstr "Ordenar" + +msgid "Order to show board in menu list, in ascending order." +msgstr "Orden en el que aparecerá el board en la lista del menú, en orden ascendente." + +msgid "Overrides the header set in the config file. Leave blank to use configured global header image. Needs to be a full url including http://. Set to none to show no header image." +msgstr "Se sobrepone a la cabecera que está en el archivo config. Déjalo en blanco para usar la imagen de cabecera de la configuración global. Tiene que ser la url completa, incluyendo http:// . Escribe none para no mostrar ninguna imagen de cabecera." + +msgid "Pages" +msgstr "Páginas" + +msgid "Paint with" +msgstr "Dibujar con" + +msgid "Paint!" +msgstr "¡Dibujar!" + +msgid "Password" +msgstr "Contraseña" + +msgid "Password successfully changed." +msgstr "Contraseña cambiada con éxito." + +msgid "Placed:" +msgstr "Colocado:" + +msgid "Please enter a positive amount of seconds, or zero for a permanent ban." +msgstr "Por favor, escribe el tiempo en segundos, o cero (0) para banear permanentemente." + +msgid "Please enter a search query." +msgstr "Inserta la consulta." + +msgid "Please fill in all required fields." +msgstr "Por favor, llena todos los campos requeridos." + +msgid "Please make sure your file is smaller than %dB" +msgstr "Asegúrate de que el archivo ocupe menos de %dB" + +msgid "Please select a board." +msgstr "Por favor, selecciona un board." + +msgid "Please select only one image to upload." +msgstr "Por favor, seleccione solamente una imagen para subir." + +msgid "Please wait a moment before posting again." +msgstr "Por favor, espera un momento antes de postear de nuevo." + +msgid "Popular" +msgstr "Popular" + +msgid "Post" +msgstr "Post" + +msgid "Post added." +msgstr "Post añadido." + +msgid "Post preview" +msgstr "Previsualizar post" + +msgid "Post successfully deleted." +msgstr "Post eliminado con éxito." + +msgid "Postbox notice" +msgstr "Buzón de noticias" + +msgid "Posting a blacklisted link." +msgstr "Postear un link que está en la lista negra." + +msgid "Posting mode: Reply" +msgstr "Modo: Responder" + +msgid "Posting rates (past hour)" +msgstr "Tasa de posts (a una hora)" + +msgid "Posts" +msgstr "Posts" + +msgid "Presets" +msgstr "Predefinido" + +msgid "Preview" +msgstr "Previsualizar" + +msgid "Previous" +msgstr "Anterior" + +msgid "Proxy list" +msgstr "Lista Proxy" + +msgid "Query" +msgstr "Consulta" + +msgid "Query executed successfully" +msgstr "Consulta ejecutada con éxito" + +msgid "Quick Reply" +msgstr "Respuesta rápida" + +msgid "Ran cleanup" +msgstr "Limpieza ejecutada" + +msgid "Raw HTML which will be inserted at the top of each page of the board." +msgstr "HTML que será insertado en la parte superior de cáda página del board." + +msgid "Read this thread from the beginning" +msgstr "Leer este hilo desde el principio" + +msgid "Reason" +msgstr "Razón" + +msgid "Reason:" +msgstr "Razón:" + +msgid "Rebuild all html files" +msgstr "Reconstruir archivos html" + +msgid "Rebuild complete. Took %d seconds." +msgstr "Reconstrucción completada. Tomó %d segundos." + +msgid "Rebuilt all boards and threads" +msgstr "Reconstruir todos los boards e hilos" + +msgid "Redirect to thread" +msgstr "Redirigir al hilo" + +msgid "Redirecting" +msgstr "Redirigiendo" + +msgid "Refresh watched threads" +msgstr "Actualizar los hilos marcados" + +msgid "Regenerated %s" +msgstr "Regenerado %s" + +msgid "Regular expression" +msgstr "Expresión regular" + +msgid "Remove" +msgstr "Eliminar" + +msgid "Removed word from wordfilter" +msgstr "Palabra removida del filtro de texto" + +msgid "Replacement" +msgstr "Reemplazo" + +msgid "Replies" +msgstr "Respuestas" + +msgid "Replies displayed per stickied thread (in thread list)" +msgstr "Respuestas mostradas por hilo fijo (en la lista del hilo)" + +msgid "Replies displayed per thread (in thread list)" +msgstr "Respuestas mostradas por hilo (en la lista del hilo)" + +msgid "Reply" +msgstr "Responder" + +msgid "Report" +msgstr "Reportar" + +msgid "Reporting allows users to report posts, adding the post to the report list." +msgstr "\"Reportar\" permite que los usuarios reporten posts, agregando el post a la lista de reportes." + +msgid "Reports" +msgstr "Reportes" + +msgid "Restore watched threads" +msgstr "Restaurar los hilos marcados" + +msgid "Results" +msgstr "Resultados" + +msgid "Return" +msgstr "Volver" + +msgid "Rules" +msgstr "Reglas" + +msgid "SQL query" +msgstr "Consulta SQL" + +msgid "Search" +msgstr "Buscar" + +msgid "Search posts" +msgstr "Buscar mensajes" + +msgid "Seconds" +msgstr "Segundos" + +msgid "Section" +msgstr "Sección" + +msgid "Section added." +msgstr "Sección añadida." + +msgid "Section deleted." +msgstr "Sección eliminada." + +msgid "Section updated." +msgstr "Sección actualizada." + +msgid "Send Appeal" +msgstr "Mandar apelación" + +msgid "Show All" +msgstr "Mostrar todo" + +msgid "Show Directories" +msgstr "Mostrar directorios" + +msgid "Show Posting Password" +msgstr "Mostrar contraseña de staff" + +msgid "Show/Hide" +msgstr "Mostrar/Ocultar" + +msgid "Shown below" +msgstr "Mostrado debajo" + +msgid "Site Styles" +msgstr "Estilo del sitio" + +msgid "Size" +msgstr "Tamaño" + +msgid "Sorry, a generic error has occurred." +msgstr "Un error genérico ha ocurrido." + +msgid "Sorry, because of your numerous failed logins, you have been locked out from logging in for 20 minutes. Please wait and then try again." +msgstr "Debido a los numerosos intentos fallidos para iniciar sesión, se te bloqueará el acceso por 20 minutos. Por favor, espera e intenta de nuevo." + +msgid "Sorry, that filetype is not allowed on this board." +msgstr "Este tipo de archivo no está permitido en este board." + +msgid "Sorry, this board is locked and can not be posted in." +msgstr "Este board está cerrado y no se puede postear en él." + +msgid "Sorry, this thread is locked and can not be replied to." +msgstr "Este hilo está cerrado y no se pueden agregar respuestas en él." + +msgid "Sorry, your message is too long. Message length: %d, maxmimum allowed length: %d" +msgstr "Tu mensaje es demasiado largo. Longitud del mensaje: %d, longitud máxima permitida: %d" + +msgid "Sorry, your search returned zero results." +msgstr "Lo sentimos, tu búsqueda no arrojó resultados." + +msgid "Source" +msgstr "Fuente" + +msgid "Staff" +msgstr "Staff" + +msgid "Staff member successfully added." +msgstr "Miembro del staff añadido con éxito" + +msgid "Staff rights" +msgstr "Derechos del staff" + +msgid "Staff successfully deleted" +msgstr "Staff eliminado con éxito" + +msgid "Staff successfully updated" +msgstr "Staff actualizado con éxito" + +msgid "Statistics" +msgstr "Estadísticas" + +msgid "Stickied" +msgstr "Hilo fijado" + +msgid "Stickied thread" +msgstr "Hilo fijado" + +msgid "Sticky" +msgstr "Fijar hilo" + +msgid "Style" +msgstr "Estilo" + +msgid "Styles" +msgstr "Estilos" + +msgid "Subject" +msgstr "Tema" + +msgid "Submit" +msgstr "Enviar" + +msgid "System lockout" +msgstr "Cierre del sistema" + +msgid "Tag" +msgstr "Marca" + +msgid "Text board" +msgstr "Board textual" + +msgid "Text boards may have only one thread with a unique subject. Please pick another." +msgstr "En los boards textuales, los hilos tienen un título único. Por favor, elije otro." + +msgid "Text boards only. If enabled, the list of threads displayed on the front page will be formatted differently to be compact." +msgstr "Solamente para los boards de texto. Si se activa, la lista de hilos que se muestra en la página frontal, tendrá un formato diferente y se verá más compacta." + +msgid "That ID does not exist." +msgstr "Esa ID no existe." + +msgid "That ID is a reply, not a thread." +msgstr "Esa ID es una respuesta, no un hilo." + +msgid "That IP has already been banned." +msgstr "Esta IP ya ha sido baneada." + +msgid "That name is for internal use. Please pick another." +msgstr "Ese nombre es para uso interno. Por favor, elige otro." + +msgid "That post has been cleared as not requiring any deletion." +msgstr "Este post ha sido marcado como que no requiere ninguna eliminación." + +msgid "That post is already in the report list." +msgstr "Ese post ya está en la lista de reportes." + +msgid "That thread has yet to be deleted." +msgstr "Este hilo aún tiene que ser eliminado." + +msgid "That thread may have been recently deleted." +msgstr "Ese hilo pudo haber sido eliminado recientemente." + +msgid "That video ID has already been posted %shere%s." +msgstr "Esa ID de video ya fue posteada %saquí%s." + +msgid "That word already exists." +msgstr "Ya existe esa palabra." + +msgid "The 5 newest replies are shown below." +msgstr "Las 5 respuestas más nuevas se muestran debajo." + +msgid "The change will not be apparent until the html files are rebuilt." +msgstr "Los cambios no serán visibles hasta que reconstruyas los archivos html." + +msgid "The directory of the board." +msgstr "Directorio del board." + +msgid "The first post of this board will recieve this ID." +msgstr "El primer post de este board recibirá esta ID." + +msgid "The name of the board." +msgstr "Nombre del board." + +msgid "The number of replies a thread can have before autosaging to the back of the board." +msgstr "Número de respuestas que un hilo puede tener antes de quedarse al final del board." + +msgid "The old password you provided did not match the current one." +msgstr "La contraseña actual que escribiste no es correcta." + +msgid "The second password did not match the first." +msgstr "La segunda contraseña no concuerda con la primera." + +msgid "The section the board is in. This is used for displaying the list of boards on the top and bottom of pages." +msgstr "Sección en la que se encuentra el board. Esto se usa para mostrar la lista de boards en la parte superior e inferior de las páginas. Las secciones deben ser creadas antes en Editar secciones" + +msgid "The style which will be set when the user first visits the board." +msgstr "Estilo que verá el usuario en su primera visita al board." + +msgid "The type of posts which will be accepted on this board. A normal imageboard will feature image and extended format posts, a text board will have no images, and an Oekaki board will allow users to draw images and use them in their posts." +msgstr "Tipo de posts que serán aceptados en este board. Un imageboard normal mostrará imagenes y posts de formato extendido; un board textual no tendrá imagenes; Un board de Oekaki permitirá a los usuarios dibujar imagenes y usarlas en sus posts." + +msgid "There are currently no bans." +msgstr "Actualmene no hay ningún ban." + +msgid "There are currently no filetypes." +msgstr "Actualmente no existen tipos de archivo." + +msgid "There are currently no sections." +msgstr "Actualmente no existen secciones." + +msgid "There are currently no threads to display." +msgstr "Actualmente no hay hilos para mostrar" + +msgid "There is already a file with that name." +msgstr "Ya existe un archivo con ese nombre." + +msgid "There was an error in trying to delete your post" +msgstr "Hubo un error al intentar eliminar el post." + +msgid "This board does not allow post reporting." +msgstr "Este board no permite reportar posts." + +msgid "This post has been deleted." +msgstr "Este post ha sido eliminado." + +msgid "Thread" +msgstr "Hilo" + +msgid "Thread successfully deleted." +msgstr "hilo eliminado con éxito" + +msgid "Thread successfully locked." +msgstr "Hilo cerrado con éxito." + +msgid "Thread successfully stickied." +msgstr "Hilo fijado con éxito." + +msgid "Thread successfully un-stickied" +msgstr "Hilo despegado con éxito" + +msgid "Thread successfully unlocked." +msgstr "Hilo abierto con éxito." + +msgid "Threads" +msgstr "Hilos" + +msgid "Threads displayed per page (in thread list)" +msgstr "Hilos mostrados por página (en la lista del hilo)" + +msgid "Thumbnail displayed, click image for full size." +msgstr "Thumbnail mostrado, haz click en la imagen para verla en tamaño completo." + +msgid "To" +msgstr "Para" + +msgid "Trial" +msgstr "Prueba" + +msgid "Unable to clear cache: you do not have caching enabled." +msgstr "No se puede limpiar la caché: la caché no está activada." + +msgid "Unable to connect to:" +msgstr "No se puede conectar a:" + +msgid "Unable to create directories." +msgstr "No se pueden crear directorios." + +msgid "Unable to delete board." +msgstr "No se puede eliminar el board." + +msgid "Unable to find record of your IP being banned." +msgstr "Imposible encontrar registros de que tu IP haya sido baneada" + +msgid "Unable to find records of any posts matching that quote syntax." +msgstr "No se pueden encontrar datos en ningún post que concuerden con esa sintaxis." + +msgid "Unable to locate a board named" +msgstr "No se encuentra ningún board llamado" + +msgid "Unable to locate a filetype with that ID." +msgstr "No se puede localizar ningún tipo de archivo con esa ID." + +msgid "Unable to locate a section with that ID." +msgstr "No se puede localizar una sección con esa ID." + +msgid "Unable to locate that word." +msgstr "No se localizó el texto" + +msgid "Unable to read uploaded file during thumbnailing." +msgstr "No se pudo leer el archivo subido durante la creación del thumbnail." + +msgid "Unable to report post. Please go back and try again." +msgstr "No se puede reportar el post. por favor, regresa e intenta de nuevo." + +msgid "Unbanned" +msgstr "Ban retirado" + +msgid "Unlock" +msgstr "Abrir" + +msgid "Unlocked thread" +msgstr "Hilo abierto" + +msgid "Unstickied thread" +msgstr "Hilo despegado" + +msgid "Unsticky" +msgstr "Despegar hilo" + +msgid "Upating pages." +msgstr "Actualizando páginas." + +msgid "Update" +msgstr "Guardar cambios" + +msgid "Update and regenerate board" +msgstr "Actualizar y regenerar el board" + +msgid "Update successful." +msgstr "Actualización exitosa." + +msgid "Update without regenerating board" +msgstr "Actualizar sin regenerar el board" + +msgid "Updated board configuration" +msgstr "Configuración del board actualizada" + +msgid "Updated global configuration" +msgstr "Configuración global actualizada" + +msgid "Updated staff member" +msgstr "Miembro del staff actualizado" + +msgid "Updated word on wordfilter" +msgstr "Palabra actualizada en el filtro de texto" + +msgid "Upload type:" +msgstr "Tipo de subida:" + +msgid "Use animation?" +msgstr "¿Usar animación?" + +msgid "Username" +msgstr "Nombre de Usuario" + +msgid "View Reports" +msgstr "Ver Reportes" + +msgid "View all bans" +msgstr "Ver todos los bans" + +msgid "View animation" +msgstr "Ver animación" + +msgid "View catalog" +msgstr "Ver catálogo" + +msgid "View deleted thread" +msgstr "Ver hilo eliminado" + +msgid "View/Add/Remove bans" +msgstr "Ver/Agregar/Remover bans" + +msgid "Viewed disk space used" +msgstr "Espacio usado en el disco visto" + +msgid "Watched Threads" +msgstr "Hilos marcados" + +msgid "Welcome" +msgstr "Bienvenido" + +msgid "What filetypes users are allowed to upload." +msgstr "Tipos de archivos permitidos para subir." + +msgid "Whether or not to allow embedding of videos." +msgstr "Permitir o no incrustar videos." + +msgid "Width" +msgstr "Ancho" + +msgid "Word" +msgstr "Palabra" + +msgid "Word successfully added." +msgstr "Texto añadido con éxito." + +msgid "Word successfully removed." +msgstr "Texto eliminado con éxito." + +msgid "Word successfully updated." +msgstr "Texto actualizado con éxito." + +msgid "Wordfilter" +msgstr "Filtro de texto" + +msgid "YOU ARE BANNED" +msgstr "ESTÁS BANEADO" + +msgid "YOU ARE NOT BANNED!" +msgstr "¡NO ESTÁS BANEADO!" + +msgid "Yes" +msgstr "Sí" + +msgid "You are banned from posting on:" +msgstr "Estás baneado a causa de un post en:" + +msgid "You are currently posting faster than the configured minimum post delay allows." +msgstr "Estás posteando más rápido que el mímimo permitido" + +msgid "You are not a moderator of this board." +msgstr "No eres moderador de este board." + +msgid "You can only delete posts from boards you moderate." +msgstr "Sólo puedes eliminar posts de los boards que moderes." + +msgid "You can only make board specific bans to boards which you moderate." +msgstr "Sólo puedes elegir los boards que moderes para que sean afectados por el ban." + +msgid "You have been banned from posting on" +msgstr "Se te baneó de" + +msgid "You have been successfully logged out." +msgstr "Has finalizado sesión con éxito." + +msgid "You may not appeal this ban." +msgstr "NO puedes apelar este ban." + +msgid "You may appeal this ban in" +msgstr "Puedes apelar este ban en" + +msgid "You may now appeal this ban." +msgstr "Puedes apelar este ban." + +msgid "You must enter a subject." +msgstr "Debes escribir el título." + +msgid "You searched for" +msgstr "Buscabas" + +msgid "Your IP address is" +msgstr "Tu dirección IP es" + +msgid "Your appeal is currently pending review." +msgstr "Tu apelación está pendiente de revisión." + +msgid "Your appeal was reviewed and denied. You may not appeal this ban again." +msgstr "Tu apelación fue revisada y rechazada. NO puedes apelar este ban de nuevo." + +msgid "Your image" +msgstr "Tu imagen" + +msgid "Your post already doesn't have an image!" +msgstr "¡Todavía no has elegido una imagen!" + +msgid "Your post contains one or more illegal characters." +msgstr "Tu post contiene uno o más caracteres ilegales." + +msgid "Your posting password" +msgstr "Tu contraseña de posteo" + +msgid "and" +msgstr "y" + +msgid "for the following reason" +msgstr "por la siguiente razón" + +msgid "forever" +msgstr "permanente" + +msgid "log in" +msgstr "iniciar sesión" + +msgid "log out" +msgstr "Finalizar sesíon" + +msgid "omitted" +msgstr "omitido" + +msgid "or" +msgstr "o" + +msgid "will expire on" +msgstr "expirará el" + +msgid "will not expire" +msgstr "no expirará" + diff --git a/inc/lang/et/LC_MESSAGES/kusaba.po b/inc/lang/et/LC_MESSAGES/kusaba.po new file mode 100644 index 0000000..65f9b5e --- /dev/null +++ b/inc/lang/et/LC_MESSAGES/kusaba.po @@ -0,0 +1,1408 @@ +msgid "" +msgstr "" +"Project-Id-Version: kusaba\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2007-12-09 03:10+0000\n" +"PO-Revision-Date: 2007-11-10 19:32+0000\n" +"Last-Translator: m0rra \n" +"Language-Team: Estonian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2008-03-12 04:24+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +msgid "%s bans not shown." +msgstr "%s tõkendit mitte näidatud." + +msgid "%s not implemented." +msgstr "%s ei ole võimalik." + +msgid "%s uploaded." +msgstr "%s üles laetud." + +msgid "(for post and file deletion)" +msgstr "(postituse ja faili kustutamiseks)" + +msgid "

Add News Post

This message will be displayed as it is written, so make sure you add the proper HTML." +msgstr "

Lisa uudiste postitus

Seda teadet näidatakse nii, nagu see on kirjutatud, seega tuleb kasutada õiget HTML-i." + +msgid "A board with that name already exists." +msgstr "Selle nimega tahvel on juba olemas." + +msgid "A board with that name does not exist." +msgstr "Selle nimega tahvlit pole olemas." + +msgid "A common cause for this is an incorrect extension when the file is actually of a different type." +msgstr "Tavaline põhjus selle jaoks on vale faililaiend, kui fail on tegelikult teist tüüpi." + +msgid "A file is required for a new thread. If embedding is allowed, either a file or embed ID is required." +msgstr "Uue lõnga loomiseks on vajalik fail. Kui manustamine on lubatud, siis on nõutud kas fail või manuse ID." + +msgid "A message is required to post without a file." +msgstr "Failita postitamiseks on vaja teksti." + +msgid "A post with that ID does not exist." +msgstr "Sellise ID-ga postitust ei ole olemas." + +msgid "A staff member with that ID already exists." +msgstr "Selle ID-ga meeskonnaliige on juba olemas." + +msgid "A staff member with that id does not appear to exist." +msgstr "Selle ID-ga meeskonnaliiget ei ole olemas." + +msgid "Add" +msgstr "Lisa" + +msgid "Add ban" +msgstr "Lisa tõkend" + +msgid "Add board" +msgstr "Lisa tahvel" + +msgid "Add new blotter entry" +msgstr "Lisa uus blotteri sissekanne." + +msgid "Add news" +msgstr "Lisa uudised" + +msgid "Add staff member" +msgstr "Lisas meeskonnaliikme" + +msgid "Add word" +msgstr "Lisa sõna" + +msgid "Added a news entry" +msgstr "Lisas uudistepostituse" + +msgid "Added board" +msgstr "Lisasin tahvli" + +msgid "Added on" +msgstr "Lisatud" + +msgid "Added staff member" +msgstr "Lisasin meeskonnaliikme" + +msgid "Admin" +msgstr "Administraator" + +msgid "Administration" +msgstr "Haldamine" + +msgid "Administrator" +msgstr "Haldur" + +msgid "Administrators" +msgstr "Haldurid" + +msgid "All Threads" +msgstr "Kõik lõngad" + +msgid "All boards" +msgstr "Kõik tahvlid" + +msgid "All threads/posts by that IP in selected boards successfully deleted." +msgstr "Kõik sellelt IP-lt tehtud lõngad/postitused valitud tahvlitelt edukalt kustutatud." + +msgid "Allowed filetypes" +msgstr "Lubatud failitüübid" + +msgid "Already posted %shere%s." +msgstr "See on juba postitatud %ssiia%s." + +msgid "An image, or message, is required for a reply." +msgstr "Lõngale vastamiseks on vaja vähemalt pilti või teksti." + +msgid "Anonymous" +msgstr "Anonüümne" + +msgid "Appeal Message" +msgstr "Appellatsiooni sõnum" + +msgid "Appeal successfully denied." +msgstr "Appellatsioon õnnestunult tagasi lükatud." + +msgid "Are you absolutely sure you want to delete %s?" +msgstr "Oled sa täiesti kindel, et soovid kustutada %s?" + +msgid "At" +msgstr "Kohas" + +msgid "Ban from" +msgstr "Tõkesta tahvlilt" + +msgid "Ban proxy list" +msgstr "Tõkendatud proxyde nimekiri" + +msgid "Ban successfully placed." +msgstr "Tõkend edukalt paigaldatud." + +msgid "Ban successfully removed." +msgstr "Tõkend edukalt eemaldatud." + +msgid "Banned" +msgstr "Seadis tõkendi" + +msgid "Banned %d IP addresses using an IP address list." +msgstr "Tõkendas %d IP aadressi kasutades IP aadresside nimekirja." + +msgid "Banned from" +msgstr "Tõkendatud tahvlilt" + +msgid "Blotter" +msgstr "Blotter" + +msgid "Blotter entry added." +msgstr "Blotteri sissekanne lisatud." + +msgid "Blotter entry deleted." +msgstr "Blotteri sissekanne kustutatud." + +msgid "Blotter entry updated." +msgstr "Blotteri postitus uuendatud." + +msgid "Blotter is disabled." +msgstr "Blotter blokeeritud." + +msgid "Blotter updated" +msgstr "Blotter uuendatud" + +msgid "Board" +msgstr "Tahvel" + +msgid "Board options" +msgstr "Tahvli seaded" + +msgid "Board successfully added." +msgstr "Tahvel edukalt lisatud." + +msgid "Board successfully deleted." +msgstr "Tahvel edukalt kustutatud." + +msgid "Board type:" +msgstr "Tahvli tüüp:" + +msgid "Boards" +msgstr "Tahvlid" + +msgid "Cache successfully flushed." +msgstr "Vahemälu edukalt tühjendatud." + +msgid "Can be left blank." +msgstr "Võib tühjaks jätta." + +msgid "Can not be left blank." +msgstr "Ei või tühjaks jätta." + +msgid "Cancel" +msgstr "Loobu" + +msgid "Captcha" +msgstr "Captcha" + +msgid "Catalog Mode" +msgstr "Kataloogi viis" + +msgid "Change account password" +msgstr "Muuda konto parool" + +msgid "Check for new version" +msgstr "Kontrolli uue versiooni olemasolu" + +msgid "Choose one" +msgstr "Vali üks" + +msgid "Cleanup" +msgstr "Koristamine" + +msgid "Cleanup finished." +msgstr "Koristamine lõpetatud." + +msgid "Cleared APC cache" +msgstr "Kustutas APC vahemälu" + +msgid "Click Reply to view, or %sexpand%s." +msgstr "Klikka Vasta vaatamiseks, või %ssuurendamiseks%s." + +msgid "Click Reply to view." +msgstr "Klikka Vasta vaatamiseks." + +msgid "Click to show/hide" +msgstr "Klikka näitamiseks/peitmiseks" + +msgid "Continue" +msgstr "Jätka" + +msgid "Could not copy uploaded image." +msgstr "Ei suutnud üles laetud pilti kopeerida." + +msgid "Could not create thumbnail." +msgstr "Pisipildi loomine ebaõnnestus." + +msgid "Current version:" +msgstr "Hetkel kasutuses olev versioon:" + +msgid "Date" +msgstr "Kuupäev" + +msgid "Days to keep modlog entries" +msgstr "Päevi moderaatori logi kirjete alles hoidmiseks" + +msgid "Default" +msgstr "Vaikimisi" + +msgid "Default style:" +msgstr "Vaikestiil:" + +msgid "Delete" +msgstr "Kustuta" + +msgid "Delete all posts by IP" +msgstr "Kustuta kõik postitused IP-lt" + +msgid "Delete all posts by this IP" +msgstr "Kustuta kõik postitused IP-lt" + +msgid "Delete board" +msgstr "Kustuta tahvel" + +msgid "Delete post" +msgstr "Kustuta postitus" + +msgid "Delete posts" +msgstr "Kustuta postitused" + +msgid "Delete thread" +msgstr "Kustuta lõng" + +msgid "Delete thread/post" +msgstr "Kustuta lõng/postitus" + +msgid "Deleted" +msgstr "Kustutatud" + +msgid "Deleted a VIP code" +msgstr "Kustus VIP koodi" + +msgid "Deleted board" +msgstr "Eemaldasin tahvli" + +msgid "Deleted post" +msgstr "Kustutas postituse" + +msgid "Deleted posts by ip" +msgstr "Kustutasin postitused IP-lt" + +msgid "Deleted staff member" +msgstr "Eemaldasin meeskonnaliikme" + +msgid "Deleted thread" +msgstr "Kustutas lõnga" + +msgid "Deleting non-deleted replies which belong to deleted threads." +msgstr "Kustutan kustutamata vastuseid, mis kuuluvad kustutatud lõngadesse." + +msgid "Deleting unused images." +msgstr "Kustutan kasutamata pilte." + +msgid "Denied the ban appeal for" +msgstr "Keelas tõkendi appellatsiooni" + +msgid "Description" +msgstr "Kirjeldus" + +msgid "Directory" +msgstr "Kaust" + +msgid "Disk space used" +msgstr "Kasutatud kettaruum" + +msgid "Does not expire" +msgstr "Ei aegu" + +msgid "Duplicate file entry detected." +msgstr "See fail on juba olemas." + +msgid "Duplicate thread subject" +msgstr "Selle teemaga lõng on juba olemas." + +msgid "Edit" +msgstr "Toimeta" + +msgid "Edit filetypes" +msgstr "Muuda failitüüpe" + +msgid "Edit sections" +msgstr "Muuda osakondi" + +msgid "Edit word" +msgstr "Muuda sõne" + +msgid "Edited a VIP cod" +msgstr "Muutis VIP koodi" + +msgid "Edited a news entry" +msgstr "Toimetas uudistepostitust" + +msgid "Email" +msgstr "E-mail" + +msgid "Embed" +msgstr "Manus" + +msgid "Embedding only" +msgstr "Ainult lisamine" + +msgid "Enable \"no file\" posting" +msgstr "Võimalda faili puudumisel postitamine" + +msgid "Enable captcha:" +msgstr "Nõua captcha kasutamist:" + +msgid "Enable reporting:" +msgstr "Teatamisest lubamine:" + +msgid "Enable/disable captcha system for this board. If captcha is enabled, in order for a user to post, they must first correctly enter the text on an image." +msgstr "Luba/ära luba captcha süsteemi selle tahvli jaoks. Kui captchat nõutakse, siis peab kasutaja postitamiseks kõigepealt pildil oleva teksti õigesti sisestama." + +msgid "Entire Thread" +msgstr "Terve lõng" + +msgid "Error, it appears your file did not transfer properly. Please go back and try again." +msgstr "Viga, fail ei ole korralikult üles laetud. Palun mine tagasi ja proovi uuesti." + +msgid "Expand all images" +msgstr "Suurenda kõik pildid" + +msgid "Expires:" +msgstr "Aegub:" + +msgid "Extension icon displayed, click image to open file." +msgstr "Laienduse ikoon näidatud, klikka pildil faili avamiseks." + +msgid "FAQ" +msgstr "KKK" + +msgid "File" +msgstr "Fail" + +msgid "File Only" +msgstr "Ainult fail" + +msgid "File was not fully uploaded. Please go back and try again." +msgstr "Faili ei laetud tervenisti üles. Palun mine tagasi ja proovi uuesti." + +msgid "File
Removed" +msgstr "Fail
eemaldatud" + +msgid "Filetype added." +msgstr "Failitüüp lisatud." + +msgid "Filetype deleted." +msgstr "Failitüüp kustutatud." + +msgid "Filetype updated." +msgstr "Failitüüp uuendatud." + +msgid "First 100 posts" +msgstr "Esimesed 100 postitust" + +msgid "First 100 posts shown." +msgstr "Esimesed 100 postitust näidatud." + +msgid "First Post ID" +msgstr "Esimese postituse ID" + +msgid "Forced anonymous" +msgstr "Sunnitud anonüümsus" + +msgid "From" +msgstr "Alates" + +msgid "Front" +msgstr "Esileht" + +msgid "Front Page" +msgstr "Esileht" + +msgid "Get posting password" +msgstr "Leia postitamise parool" + +msgid "Global configuration succesfully updated." +msgstr "Üldised seaded edukalt uuendatud." + +msgid "Global options" +msgstr "Üldised seaded" + +msgid "Go" +msgstr "Liikumine" + +msgid "Header image" +msgstr "Päisepilt" + +msgid "Height" +msgstr "Kõrgus" + +msgid "Hide Directories" +msgstr "Peida kaustad" + +msgid "Hide the watched threads box" +msgstr "Peida jälgitud lõngade kast" + +msgid "Home" +msgstr "Kodu" + +msgid "ID" +msgstr "ID" + +msgid "IP" +msgstr "IP" + +msgid "If set to yes, new threads will not require an image to be posted." +msgstr "Kui seatud, siis ei ole uute lõngade alustamiseks pilti vaja." + +msgid "If set to yes, this board will appear in bold in the menu" +msgstr "Kui seatud, siis ilmub tahvel menüüs rasvaselt" + +msgid "If set to yes, this board will appear in italics in the menu" +msgstr "Kui seatud, siis ilmub tahvel menüüs kaldkirjas." + +msgid "If set to yes, users will be redirected to the thread they replied to/posted after posting. If set to no, users will be redirected to the first page of the board." +msgstr "Kui seatud, siis suunatakse kasutajad lõnga, kuhu nad postitasid peale postitamist. Kui seadmata, siis suunatakse kasutajad tahvli esimesele lehele." + +msgid "If set to yes, users will not be allowed to enter a name, making everyone appear as Anonymous" +msgstr "Kui seatud, siis ei saa kasutajad nime sisestada, pannes kõik ilmuma Anonüümsena." + +msgid "Image" +msgstr "Pilt" + +msgid "Image successfully deleted from your post." +msgstr "Postitusest pildi eemaldamine õnnestus." + +msgid "Images" +msgstr "Pildid" + +msgid "Images and embedding" +msgstr "Pildid ja lisamine" + +msgid "Important" +msgstr "Tähtis" + +msgid "Improper filetype." +msgstr "Ebaõige failitüüp." + +msgid "Include header" +msgstr "Lisa päis" + +msgid "Incorrect captcha entered." +msgstr "Vale captcha." + +msgid "Incorrect password." +msgstr "Vale parool." + +msgid "Incorrect username/password." +msgstr "Vale kasutajanimi või parool." + +msgid "Index" +msgstr "Indeks" + +msgid "Inject" +msgstr "Süsti" + +msgid "Inserted SQL" +msgstr "Sisestas SQL-i" + +msgid "Integer values must be entered correctly." +msgstr "Täisarvulised väärtused peavad olema õigesti sisestatud." + +msgid "Invalid ID" +msgstr "Vale ID" + +msgid "Invalid MIME type for this filetype." +msgstr "Vale MIME tüüp selle failitüübi jaoks." + +msgid "Invalid ban ID" +msgstr "Vigane tõkendi ID" + +msgid "Invalid board directory." +msgstr "Vale tahvli kaust." + +msgid "Invalid response code:" +msgstr "Vigane vastuse kood:" + +msgid "Invalid session." +msgstr "Aegunud sessioon." + +msgid "Invalid staff ID." +msgstr "Vale meeskonna ID." + +msgid "Invalid thread ID." +msgstr "Vale lõnga ID." + +msgid "Invalid thread ID. This may have been caused by the thread recently being deleted." +msgstr "Vale lõnga ID. See võib olla põhjustatud lõnga hiljutisest kustutamisest." + +msgid "Invalid video ID." +msgstr "Vigane video ID." + +msgid "Invalid video type." +msgstr "Vigane video tüüp." + +msgid "Is replaced by" +msgstr "on asendatud" + +msgid "Last 50 posts" +msgstr "Viimased 50 postitust" + +msgid "Last 50 posts shown." +msgstr "Viimased 50 postitust näidatud." + +msgid "Last Post" +msgstr "Viimane postitus" + +msgid "Lock" +msgstr "Lukusta" + +msgid "Locked" +msgstr "Lukus" + +msgid "Locked thread" +msgstr "Lukustas lõnga" + +msgid "Log in again." +msgstr "Logi uuesti sisse." + +msgid "Logged in" +msgstr "Sisse logitud" + +msgid "Logo" +msgstr "Logo" + +msgid "Manage" +msgstr "Halda" + +msgid "Manage boards" +msgstr "Halda tahvleid" + +msgid "Manage locked threads" +msgstr "Halda lukustatud lõngu" + +msgid "Manage stickies" +msgstr "Halda kleebiseid" + +msgid "Marked for deletion (old)." +msgstr "Märgitud kustutamiseks (vana)." + +msgid "Maximum board pages" +msgstr "Maksimaalne arv lehti tahvlil" + +msgid "Maximum image size" +msgstr "Maksimaalne pildi suurus" + +msgid "Maximum message length" +msgstr "Maksimaalne teksti pikkus" + +msgid "Maximum thread age (Hours)" +msgstr "Maksimaalne lõnga aeg (tunde)" + +msgid "Maximum thread replies" +msgstr "Maksimaalne vastuste arv lõngale" + +msgid "Maxmimum size of uploaded images, in bytes." +msgstr "Maksimaalne üles laetavate piltide suurus, baitides." + +msgid "Maxmimum thumbnail height" +msgstr "Maksimaalne pisipildi kõrgus" + +msgid "Maxmimum thumbnail width" +msgstr "Maksimaalne pisipildi laius" + +msgid "Message" +msgstr "Teade" + +msgid "Message too long. Click %shere%s to view the full text." +msgstr "Tekst on liiga pikk. Klikka %ssiia%s teksti täies pikkuses nägemiseks." + +msgid "Misc" +msgstr "Muu" + +msgid "Mod" +msgstr "Moderaator" + +msgid "ModLog" +msgstr "Moderaatori logi" + +msgid "Moderates" +msgstr "Modereerib" + +msgid "Moderating boards" +msgstr "Tahvlite modereerimine" + +msgid "Moderation" +msgstr "Modereerimine" + +msgid "Moderator" +msgstr "Moderaator" + +msgid "Moderators" +msgstr "Moderaatorid" + +msgid "Modify" +msgstr "Muuda" + +msgid "Modify staff member" +msgstr "Muuda meeskonnaliikme seadeid" + +msgid "Module settings" +msgstr "Moodulite seaded" + +msgid "Modules" +msgstr "Moodulid" + +msgid "More" +msgstr "Rohkem" + +msgid "Move complete." +msgstr "Liigutamine lõpetatud." + +msgid "Move thread" +msgstr "Liiguta lõnga" + +msgid "NOTICE: You are using the default administrator account. Anyone can log in to this account, so a second administrator account needs to be created. Create another, log in to it, and delete this one." +msgstr "TÄHELEPANU: Sa kasutad vaikimisi loodud administraatori kontot. Igaüks saab siia sisse logida, seega on vajalik teise administraatori konto loomine. Loo teine, logi tollega sisse ja kustuta see konto." + +msgid "Name" +msgstr "Nimi" + +msgid "Name to display when a name is not attached to a post." +msgstr "Nimi, mida näidata, kui postitusele ei ole nime lisatud." + +msgid "Never" +msgstr "Mitte kunagi" + +msgid "New Thread" +msgstr "Uus lõng" + +msgid "New image" +msgstr "UUs pilt" + +msgid "New password" +msgstr "Uus parool" + +msgid "New password again" +msgstr "Uus parool uuesti" + +msgid "News" +msgstr "Uudised" + +msgid "News entry successfully added." +msgstr "Uudiste sissekanne edukalt lisatud." + +msgid "Next" +msgstr "Järgmine" + +msgid "No" +msgstr "Ei" + +msgid "No File" +msgstr "Fail puudub" + +msgid "No blotter entries." +msgstr "Blotteri sisekanded puuduvad." + +msgid "No boards" +msgstr "Tahvlid puuduvad" + +msgid "No embedding" +msgstr "Lisamine pole lubatud" + +msgid "No threads." +msgstr "Lõngad puuduvad." + +msgid "No visible boards" +msgstr "Nähtavad tahvlid puuduvad" + +msgid "None" +msgstr "Puudub" + +msgid "Normal imageboard" +msgstr "Tavaline pilditahvel" + +msgid "Oekaki imageboard" +msgstr "Oekaki joonistustahvel" + +msgid "Old password" +msgstr "Vana parool" + +msgid "Only moderators of the board and admins can make new posts/replies" +msgstr "Ainult selle tahvli moderaatorid ja administraatorid saavad siia teha uusi postitusi/vastuseid" + +msgid "Only put in the letter(s) of the board directory, no slashes!" +msgstr "Sisesta ainult tahvli kausta täht/tähed, ilma kaldkriipsudeta!" + +msgid "Open images in new window" +msgstr "Ava pildid uues aknas" + +msgid "Order" +msgstr "Järjekord" + +msgid "Order to show board in menu list, in ascending order." +msgstr "Tahvlite menüüs näitamise järjekord, kasvavas järjekorras." + +msgid "Overrides the header set in the config file. Leave blank to use configured global header image. Needs to be a full url including http://. Set to none to show no header image." +msgstr "Kirjutab üle konfiguratsioonifailis seatud päise. Jäta tühjaks konfiguratsioonifailis seatud üldise päise pildi kasutamiseks. Peab olema täispikk URL koos http://-ga. Jäta tühjaks päise mitte näitamiseks." + +msgid "Pages" +msgstr "Lehed" + +msgid "Paint with" +msgstr "Joonista kasutades" + +msgid "Paint!" +msgstr "Joonista!" + +msgid "Password" +msgstr "Parool" + +msgid "Password successfully changed." +msgstr "Parool edukalt muudetud." + +msgid "Placed:" +msgstr "Pandud:" + +msgid "Please enter a positive amount of seconds, or zero for a permanent ban." +msgstr "Palun sisesta naturaalarvuline sekundite väärtus või 0 igavesti tõkendamiseks." + +msgid "Please enter a search query." +msgstr "Palun sisesta otsing." + +msgid "Please fill in all required fields." +msgstr "Palun täida kõik nõutud väljad." + +msgid "Please make sure your file is smaller than %dB" +msgstr "Palun kontrolli, et fail oleks väiksem kui %dB" + +msgid "Please select a board." +msgstr "Palun vali tahvel." + +msgid "Please select only one image to upload." +msgstr "Palun vali üleslaadimiseks ainult üks pilt." + +msgid "Please wait a moment before posting again." +msgstr "Palun oota natuke enne uuesti postitamist." + +msgid "Popular" +msgstr "Populaarne" + +msgid "Post" +msgstr "Postitus" + +msgid "Post added." +msgstr "Postitus lisatud." + +msgid "Post preview" +msgstr "Postita eelvaade" + +msgid "Post successfully deleted." +msgstr "Postituse kustutamine õnnestus." + +msgid "Postbox notice" +msgstr "Postituskasti märge" + +msgid "Posting a blacklisted link." +msgstr "Postitan mustas nimekirjas olevat linki." + +msgid "Posting mode: Reply" +msgstr "Postitamise viis: vastamine" + +msgid "Posting rates (past hour)" +msgstr "Postitusi viimase tunni jooksul" + +msgid "Posts" +msgstr "Postitused" + +msgid "Presets" +msgstr "Eelseaded" + +msgid "Preview" +msgstr "Eelvaade" + +msgid "Previous" +msgstr "Eelmine" + +msgid "Proxy list" +msgstr "Proxyde nimekiri" + +msgid "Query" +msgstr "Päring" + +msgid "Query executed successfully" +msgstr "Päring edukalt sooritatud." + +msgid "Quick Reply" +msgstr "Kiirvastus" + +msgid "Ran cleanup" +msgstr "Koristas" + +msgid "Raw HTML which will be inserted at the top of each page of the board." +msgstr "Puhas HTML, mida näidatakse tahvli iga lehekülje päises." + +msgid "Read this thread from the beginning" +msgstr "Loe seda lõnga algusest" + +msgid "Reason" +msgstr "Põhjus" + +msgid "Reason:" +msgstr "Põhjus:" + +msgid "Rebuild all html files" +msgstr "Ehita kõik .html failid uuesti" + +msgid "Rebuild complete. Took %d seconds." +msgstr "Uuesti ehitamine lõpetatud. Võttis %d sekundit." + +msgid "Rebuilt all boards and threads" +msgstr "Ehitasin uuesti kõik tahvlid ja lõngad" + +msgid "Redirect to thread" +msgstr "Suuna lõnga" + +msgid "Redirecting" +msgstr "Suunan ümber" + +msgid "Refresh watched threads" +msgstr "Uuenda jälgitud lõngu" + +msgid "Regenerated %s" +msgstr "Lõin uuesti %s" + +msgid "Regular expression" +msgstr "Regulaaravaldis" + +msgid "Remove" +msgstr "Kustuta" + +msgid "Removed word from wordfilter" +msgstr "Eemaldasin sõna sõnefiltrist" + +msgid "Replacement" +msgstr "Asendus" + +msgid "Replies" +msgstr "Vastused" + +msgid "Replies displayed per stickied thread (in thread list)" +msgstr "Vastused näidatud kleebitud lõnga kohta (lõngade loetelus)" + +msgid "Replies displayed per thread (in thread list)" +msgstr "Vastused näidatud lõnga kohta (lõngade loetelus)" + +msgid "Reply" +msgstr "Vasta" + +msgid "Report" +msgstr "Teate" + +msgid "Reporting allows users to report posts, adding the post to the report list." +msgstr "Teatamine lubab kasutajatel postitustest teatada, lisades postituse teadete nimekirja." + +msgid "Reports" +msgstr "Teated" + +msgid "Restore watched threads" +msgstr "Taasta jälgitud lõngad" + +msgid "Results" +msgstr "Tulemused" + +msgid "Return" +msgstr "Tagasi" + +msgid "Rules" +msgstr "Reeglid" + +msgid "SQL query" +msgstr "SQL päring" + +msgid "Search" +msgstr "Otsing" + +msgid "Search posts" +msgstr "Otsi postitusi" + +msgid "Seconds" +msgstr "Sekundit" + +msgid "Section" +msgstr "Osa" + +msgid "Section added." +msgstr "Osa lisatud." + +msgid "Section deleted." +msgstr "Osa kustutatud." + +msgid "Section updated." +msgstr "Osa uuendatud." + +msgid "Send Appeal" +msgstr "Saada appellatsioon" + +msgid "Show All" +msgstr "Näita kõiki" + +msgid "Show Directories" +msgstr "Näita kaustu" + +msgid "Show Posting Password" +msgstr "Näita postitamise parooli" + +msgid "Show/Hide" +msgstr "Näita/Peida" + +msgid "Shown below" +msgstr "Allpool näidatud" + +msgid "Site Styles" +msgstr "Lehekülje kujundused" + +msgid "Size" +msgstr "Suurus" + +msgid "Sorry, a generic error has occurred." +msgstr "Vabandame, on tekkinud viga." + +msgid "Sorry, because of your numerous failed logins, you have been locked out from logging in for 20 minutes. Please wait and then try again." +msgstr "Vabandame, aga jätkuvate ebaõnnestunud sisselogimiskatsete tõttu on logimiskatsed 20 minutiks peatatud. Palun oota ja proovi hiljem uuesti." + +msgid "Sorry, that filetype is not allowed on this board." +msgstr "Vabandame, sellel tahvlil ei ole see failitüüp lubatud." + +msgid "Sorry, this board is locked and can not be posted in." +msgstr "Vabandame, see tahvel on lukus ja siia ei saa postitada." + +msgid "Sorry, this thread is locked and can not be replied to." +msgstr "Vabandame, see lõng on lukus ja siia ei saa vastata." + +msgid "Sorry, your message is too long. Message length: %d, maxmimum allowed length: %d" +msgstr "Vabandust, tekst on liiga pikk. Teksti pikkus: %d, maksimaalne lubatud pikkus: %d" + +msgid "Sorry, your search returned zero results." +msgstr "Vabandame, otsing ei tagastanud ühtki tulemust." + +msgid "Source" +msgstr "Lähtekood" + +msgid "Staff" +msgstr "Meeskond" + +msgid "Staff member successfully added." +msgstr "Meeskonnaliige edukalt lisatud." + +msgid "Staff rights" +msgstr "Meeskonna õigused" + +msgid "Staff successfully deleted" +msgstr "Meeskond edukalt kustutatud" + +msgid "Staff successfully updated" +msgstr "Meeskond edukalt uuendatud" + +msgid "Statistics" +msgstr "Statistika" + +msgid "Stickied" +msgstr "Kleebitud" + +msgid "Stickied thread" +msgstr "Kleepis lõnga" + +msgid "Sticky" +msgstr "Kleebi" + +msgid "Style" +msgstr "Kujundus" + +msgid "Styles" +msgstr "Kujundused" + +msgid "Subject" +msgstr "Teema" + +msgid "Submit" +msgstr "Saada" + +msgid "System lockout" +msgstr "Süsteemi lukustamine" + +msgid "Tag" +msgstr "Silt" + +msgid "Text board" +msgstr "Tekstitahvel" + +msgid "Text boards may have only one thread with a unique subject. Please pick another." +msgstr "Tekstitahvlitel peab igal lõngas olema erinev teema. Palun vali uus." + +msgid "Text boards only. If enabled, the list of threads displayed on the front page will be formatted differently to be compact." +msgstr "Ainult tekstitahvlid. Kui seatud, siis esilehel näidatud nimekiri lõngadest kujundatakse erinevalt kompaktsuse jaoks." + +msgid "That ID does not exist." +msgstr "Sellist ID-d ei ole olemas." + +msgid "That ID is a reply, not a thread." +msgstr "See on vastuse, mitte lõnga ID." + +msgid "That IP has already been banned." +msgstr "See IP on juba tõkendatud." + +msgid "That name is for internal use. Please pick another." +msgstr "See nimi on sisemiseks kasutuseks. Palun vali teine." + +msgid "That post has been cleared as not requiring any deletion." +msgstr "See postitus on üle vaadatud ja ei vaja kustutamist." + +msgid "That post is already in the report list." +msgstr "Sellest postitusest on juba teatatud." + +msgid "That thread has yet to be deleted." +msgstr "See lõng ei ole veel kustutatud." + +msgid "That thread may have been recently deleted." +msgstr "See lõng võib olla hiljuti kustutatud." + +msgid "That video ID has already been posted %shere%s." +msgstr "Selle video ID on juba %ssiia%s postitatud." + +msgid "That word already exists." +msgstr "See sõne on juba olemas." + +msgid "The 5 newest replies are shown below." +msgstr "5 uusimat vastust on allpool näidatud." + +msgid "The change will not be apparent until the html files are rebuilt." +msgstr "Muudatus ei ilmne kuni .hmtl falid on ümber ehitatud." + +msgid "The directory of the board." +msgstr "Tahvli kataloog." + +msgid "The first post of this board will recieve this ID." +msgstr "Tahvli esimene postitus saab selle ID." + +msgid "The name of the board." +msgstr "Tahvli nimi." + +msgid "The number of replies a thread can have before autosaging to the back of the board." +msgstr "Vastuste arv, mis lõng võib omada enne automaatset tahvli taha mainamist." + +msgid "The old password you provided did not match the current one." +msgstr "Sisestatud vana parool ei klappinud praeguse parooliga." + +msgid "The second password did not match the first." +msgstr "Teine parool ei klappinud esimesega." + +msgid "The section the board is in. This is used for displaying the list of boards on the top and bottom of pages." +msgstr "Osa, millel tahvel on. See on kasutatud tahvlite nimekirja näitamiseks lehekülgede üla- ja alaservas." + +msgid "The style which will be set when the user first visits the board." +msgstr "See stiil säetakse tahvli esimesel külastusel." + +msgid "The type of posts which will be accepted on this board. A normal imageboard will feature image and extended format posts, a text board will have no images, and an Oekaki board will allow users to draw images and use them in their posts." +msgstr "Postituste tüüp, mis on sellel tahvlil lubatud. Tavaline pilditahvel lubab pilte ja laiendatud formaadiga postitusi, tekstitahvlil ei ole pilte ja Oekaki tahvel lubab kasutajatel joonistada pilte ja kasutada neid postitustes." + +msgid "There are currently no bans." +msgstr "Hetkel tõkendid puuduvad." + +msgid "There are currently no filetypes." +msgstr "Hetkel failitüübid puuduvad." + +msgid "There are currently no sections." +msgstr "Hetkel osad puuduvad." + +msgid "There are currently no threads to display." +msgstr "Hetkel ei ole ühtki lõnga näidata." + +msgid "There is already a file with that name." +msgstr "Selle nimega fail on juba olemas." + +msgid "There was an error in trying to delete your post" +msgstr "Postituse kustutamisel tekkis viga" + +msgid "This board does not allow post reporting." +msgstr "Sellel tahvlil ei ole postitustest teatamine lubatud." + +msgid "This post has been deleted." +msgstr "See postitus on kustutatud." + +msgid "Thread" +msgstr "Lõng" + +msgid "Thread successfully deleted." +msgstr "Lõng edukalt kustutatud." + +msgid "Thread successfully locked." +msgstr "Lõng edukalt lukustatud." + +msgid "Thread successfully stickied." +msgstr "Lõng on edukalt kleebitud." + +msgid "Thread successfully un-stickied" +msgstr "Lõng on edukalt maha kraabitud" + +msgid "Thread successfully unlocked." +msgstr "Lõng edukalt lukust lahti võetud." + +msgid "Threads" +msgstr "Lõngad" + +msgid "Threads displayed per page (in thread list)" +msgstr "Lõngu näidatud lehekülje kohta (lõngade loetelus)" + +msgid "Thumbnail displayed, click image for full size." +msgstr "Pisipilt näidatud, klikka pildil täissuuruses vaatamiseks." + +msgid "To" +msgstr "Kuni" + +msgid "Trial" +msgstr "Proov" + +msgid "Unable to clear cache: you do not have caching enabled." +msgstr "Ei suutnud vahemälu tühjendada: sul ei ole vahemälu lubatud." + +msgid "Unable to connect to:" +msgstr "Ei suutnud luua ühendust::" + +msgid "Unable to create directories." +msgstr "Ei suutnud kaustu luua." + +msgid "Unable to delete board." +msgstr "Ei suutnud tahvlit kustutada." + +msgid "Unable to find record of your IP being banned." +msgstr "Ei suutnud leida kirjet sinu IP tõkendamise kohta." + +msgid "Unable to find records of any posts matching that quote syntax." +msgstr "Ei suutnud leida vasteid sellele tsitaadi süntaksile vastavale postitusele." + +msgid "Unable to locate a board named" +msgstr "Ei suutnud leida tahvlit nimega" + +msgid "Unable to locate a filetype with that ID." +msgstr "Ei suutnud selle ID-ga failitüüpi leida." + +msgid "Unable to locate a section with that ID." +msgstr "Ei suutnud selle ID-ga osa leida." + +msgid "Unable to locate that word." +msgstr "Ei suutnud seda sõnet leida." + +msgid "Unable to read uploaded file during thumbnailing." +msgstr "Ei suutnud pisipildi loomise ajal üles laetud faili lugeda." + +msgid "Unable to report post. Please go back and try again." +msgstr "Ei suutnud postitusest teatada. Palun mine tagasi ja proovi uuesti." + +msgid "Unbanned" +msgstr "Võttis tõkendi maha" + +msgid "Unlock" +msgstr "Lukust lahti" + +msgid "Unlocked thread" +msgstr "Võttis lõnga lahti" + +msgid "Unstickied thread" +msgstr "Kraapis lõnga maha" + +msgid "Unsticky" +msgstr "Kraabi maha" + +msgid "Upating pages." +msgstr "Uuendan lehti." + +msgid "Update" +msgstr "Uuenda" + +msgid "Update and regenerate board" +msgstr "Uuenda ja loo tahvel uuesti" + +msgid "Update successful." +msgstr "Uuendamine õnnestus." + +msgid "Update without regenerating board" +msgstr "Uuenda tahvlit uuesti loomata" + +msgid "Updated board configuration" +msgstr "Uuendasin tahvli seadeid" + +msgid "Updated global configuration" +msgstr "Uuendasin üldisi seadeid" + +msgid "Updated staff member" +msgstr "Uuendasin meeskonnaliikme" + +msgid "Updated word on wordfilter" +msgstr "Uuendasin sõnet sõnefiltris" + +msgid "Upload type:" +msgstr "Üles laadimise tüüp:" + +msgid "Use animation?" +msgstr "Kasuta animatsiooni?" + +msgid "Username" +msgstr "Kasutajaunnus" + +msgid "View Reports" +msgstr "Vaata teateid" + +msgid "View all bans" +msgstr "Näida kõiki tõkendeid." + +msgid "View animation" +msgstr "Vaata animatsiooni" + +msgid "View catalog" +msgstr "Vaata kausta" + +msgid "View deleted thread" +msgstr "Vaata kustutatud lõnga" + +msgid "View/Add/Remove bans" +msgstr "Vaata/lisa/eemalda tõkendeid" + +msgid "Viewed disk space used" +msgstr "Vaatas kasutatud kettaruumi" + +msgid "Watched Threads" +msgstr "Jälgitud lõngad" + +msgid "Welcome" +msgstr "Tere tulemast" + +msgid "What filetypes users are allowed to upload." +msgstr "Failitüübid, mis on üles laadimiseks lubatud." + +msgid "Whether or not to allow embedding of videos." +msgstr "Kas lubada või mitte videote lisamist." + +msgid "Width" +msgstr "Laius" + +msgid "Word" +msgstr "Sõna" + +msgid "Word successfully added." +msgstr "Sõne edukalt lisatud." + +msgid "Word successfully removed." +msgstr "Sõne edukalt eemaldatud." + +msgid "Word successfully updated." +msgstr "Sõne edukalt uuendatud." + +msgid "Wordfilter" +msgstr "Sõnade filter" + +msgid "YOU ARE BANNED" +msgstr "SA OLED BÄNNITUD" + +msgid "YOU ARE NOT BANNED!" +msgstr "SA EI OLE BÄNNITUD!" + +msgid "Yes" +msgstr "Jah" + +msgid "You are banned from posting on:" +msgstr "Sa oled tõkestatud postitamast:" + +msgid "You are currently posting faster than the configured minimum post delay allows." +msgstr "Sa postitad hetkel kiiremini kui konfiguratsioonis lubatud." + +msgid "You are not a moderator of this board." +msgstr "Sa ei ole selle tahvli moderaator." + +msgid "You can only delete posts from boards you moderate." +msgstr "Sa võid ainult kustutada postitusi enda poolt modereeritud tahvlist." + +msgid "You can only make board specific bans to boards which you moderate." +msgstr "Sa saad tõkendada ainult tahvlilt, mida sa ise modereerid." + +msgid "You have been banned from posting on" +msgstr "Sa oled tõkestatud postitamast alates" + +msgid "You have been successfully logged out." +msgstr "Edukalt välja logitud." + +msgid "You may not appeal this ban." +msgstr "Sa ei või tõkendust apelleerida." + +msgid "You may appeal this ban in" +msgstr "Sa võid seda tõkendit appelleerida" + +msgid "You may now appeal this ban." +msgstr "Sa võida seda tõkendit nüüd appelleerida." + +msgid "You must enter a subject." +msgstr "Sa pead sisestama teema." + +msgid "You searched for" +msgstr "Otsing oli" + +msgid "Your IP address is" +msgstr "Sinu IP on" + +msgid "Your appeal is currently pending review." +msgstr "Sinu appellatsioon on hetkel läbivaatamisel." + +msgid "Your appeal was reviewed and denied. You may not appeal this ban again." +msgstr "Sinu appellatsioon vaadati läbi ja keelduti. Sa ei või seda tõkendit uuesti appelleerida." + +msgid "Your image" +msgstr "Sinu pilt" + +msgid "Your post already doesn't have an image!" +msgstr "Postitusel juba puudub pilt!" + +msgid "Your post contains one or more illegal characters." +msgstr "Postitus sisaldab ühe või rohkem lubamatuid tähemärke." + +msgid "Your posting password" +msgstr "Postitamise parool" + +msgid "and" +msgstr "ja" + +msgid "for the following reason" +msgstr "järgneval põhjusel" + +msgid "forever" +msgstr "igavesti" + +msgid "log in" +msgstr "logi sisse" + +msgid "log out" +msgstr "logi välja" + +msgid "omitted" +msgstr "vahele jäetud" + +msgid "or" +msgstr "või" + +msgid "translator-credits" +msgstr "" +"Launchpad Contributions:\n" +" m0rra https://launchpad.net/~operations-hot" + +msgid "will expire on" +msgstr "aegub" + +msgid "will not expire" +msgstr "ei aegu" + diff --git a/inc/lang/fi/LC_MESSAGES/kusaba.po b/inc/lang/fi/LC_MESSAGES/kusaba.po new file mode 100644 index 0000000..f477de4 --- /dev/null +++ b/inc/lang/fi/LC_MESSAGES/kusaba.po @@ -0,0 +1,1414 @@ +msgid "" +msgstr "" +"Project-Id-Version: kusaba\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2007-12-09 03:10+0000\n" +"PO-Revision-Date: 2008-02-24 23:11+0000\n" +"Last-Translator: Jebula \n" +"Language-Team: Finnish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2008-03-12 04:24+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +msgid "%s bans not shown." +msgstr "%s bannia ei näkynyt" + +msgid "%s not implemented." +msgstr "%s ei ole välinöity." + +msgid "%s uploaded." +msgstr "lähetetty." + +msgid "(for post and file deletion)" +msgstr "(viestin ja tiedoston poistamiseen)" + +msgid "

Add News Post

This message will be displayed as it is written, so make sure you add the proper HTML." +msgstr "

Lisää uutinen

Tämä viesti näkyy siten kuin se on kirjoitettu. Kirjoita kunnollista HTML -koodia." + +msgid "A board with that name already exists." +msgstr "Boardi tuolla nimellä on jo luotu." + +msgid "A board with that name does not exist." +msgstr "Boardia antamallasi nimellä ei ole olemassa." + +msgid "A common cause for this is an incorrect extension when the file is actually of a different type." +msgstr "Yleisin syy tälläiselle on viallinen laajennus, kun tiedosto eri tyyppiä." + +msgid "A file is required for a new thread. If embedding is allowed, either a file or embed ID is required." +msgstr "Uuden aiheen aloittamiseen vaadittu tiedosto puuttuu.. Jos upotus on sallittua, joko tiedosto tai upotteen ID on vaadittu." + +msgid "A message is required to post without a file." +msgstr "Viesti on vaadittu postaamiseen ilman kvaa" + +msgid "A post with that ID does not exist." +msgstr "Viestio tuolla ID:llä ei ole olemassa." + +msgid "A staff member with that ID already exists." +msgstr "Henkilökunnan jäsen tuolla ID:llä on jo olemassa." + +msgid "A staff member with that id does not appear to exist." +msgstr "Lisää henkilökuntaan jäsen, ID:llä jota ei vielä ole." + +msgid "Add" +msgstr "Lisää" + +msgid "Add ban" +msgstr "Bannaa joku" + +msgid "Add board" +msgstr "Lisää boardi" + +msgid "Add new blotter entry" +msgstr "Lisää uusi merkintä ilmoitukseen." + +msgid "Add news" +msgstr "Lisää uutinen" + +msgid "Add staff member" +msgstr "Lisää henkilökuntaan jäsen" + +msgid "Add word" +msgstr "Lisää sana" + +msgid "Added a news entry" +msgstr "Lisätty uutinen" + +msgid "Added board" +msgstr "Lisätty boardi" + +msgid "Added on" +msgstr "Lisätty" + +msgid "Added staff member" +msgstr "Lisätty henkilökuntaan jäsen" + +msgid "Admin" +msgstr "Ylläpitäjä" + +msgid "Administration" +msgstr "Hallinta" + +msgid "Administrator" +msgstr "Ylläpito" + +msgid "Administrators" +msgstr "Ylläpitäjät" + +msgid "All Threads" +msgstr "Kaikki keskustelut" + +msgid "All boards" +msgstr "Kaikki boardit" + +msgid "All threads/posts by that IP in selected boards successfully deleted." +msgstr "Kaikki keskustelut/viestit joihin on postattu valitulla IP:llä, on poistettu onnistuneesti." + +msgid "Allowed filetypes" +msgstr "Sallitut tiedostontyypit" + +msgid "Already posted %shere%s." +msgstr "Jo postattu %stänne%s." + +msgid "An image, or message, is required for a reply." +msgstr "Kuva tai viesti on vaadittu vastaamiseen." + +msgid "Anonymous" +msgstr "Anonyymi" + +msgid "Appeal Message" +msgstr "Valitusviesti" + +msgid "Appeal successfully denied." +msgstr "Anomus onnistuneesti kumottu." + +msgid "Are you absolutely sure you want to delete %s?" +msgstr "Oletko aivan varma että haluat poistaa %s?" + +msgid "At" +msgstr "At" + +msgid "Ban from" +msgstr "Bannattu" + +msgid "Ban proxy list" +msgstr "Bannattyjen proxyjen lista" + +msgid "Ban successfully placed." +msgstr "Banni onnistuneesti laitettu." + +msgid "Ban successfully removed." +msgstr "Banni onnistuneesti poistettu" + +msgid "Banned" +msgstr "Bannattu, B&!" + +msgid "Banned %d IP addresses using an IP address list." +msgstr "Bannittu %d IP osoite, bannittiin käyttäen IP osoite listaa" + +msgid "Banned from" +msgstr "Bannattu" + +msgid "Blotter" +msgstr "Ilmoitus" + +msgid "Blotter entry added." +msgstr "Ilmoitukseen on lisätty merkintä." + +msgid "Blotter entry deleted." +msgstr "Ilmoituksen merkintä poistettu." + +msgid "Blotter entry updated." +msgstr "Ilmoituksen merkintää päivitetty." + +msgid "Blotter is disabled." +msgstr "Ilmoitus poistettu" + +msgid "Blotter updated" +msgstr "Ilmoitus päivitetty" + +msgid "Board" +msgstr "Boardi" + +msgid "Board options" +msgstr "Boardin asetukset" + +msgid "Board successfully added." +msgstr "Boardi lisätty onnistuneesti" + +msgid "Board successfully deleted." +msgstr "Boardi onnistuneesti poistettu" + +msgid "Board type:" +msgstr "Boardin tyyppi:" + +msgid "Boards" +msgstr "Boardit" + +msgid "Cache successfully flushed." +msgstr "Välimuisti onnistuneesti tyhjennetty.." + +msgid "Can be left blank." +msgstr "Voi jättää tyhjäksi" + +msgid "Can not be left blank." +msgstr "Ei voi jättää tyhjäksi" + +msgid "Cancel" +msgstr "Peruuta" + +msgid "Captcha" +msgstr "Kuvavarmennus" + +msgid "Catalog Mode" +msgstr "Catalogi modi" + +msgid "Change account password" +msgstr "Vaihda käyttäjäntunnuksen salasana" + +msgid "Check for new version" +msgstr "Tarkista uuden version saatavuus" + +msgid "Choose one" +msgstr "Valise yksi" + +msgid "Cleanup" +msgstr "Puhdista" + +msgid "Cleanup finished." +msgstr "Siivoaminen suoritettu." + +msgid "Cleared APC cache" +msgstr "APC-välimuisti tyhjennetty" + +msgid "Click Reply to view, or %sexpand%s." +msgstr "Klikkaa Vastaa katsellaksesi, tai %sexpand%s." + +msgid "Click Reply to view." +msgstr "Klikkaa Vastaa katsellaksesi" + +msgid "Click to show/hide" +msgstr "Paina näytä/piiloita" + +msgid "Continue" +msgstr "Jatka" + +msgid "Could not copy uploaded image." +msgstr "En voinut kopioida uploadattua kuvaa." + +msgid "Could not create thumbnail." +msgstr "En voinut tehdä thumbnailia" + +msgid "Current version:" +msgstr "Tämänhetkinen versio" + +msgid "Date" +msgstr "Päivämäärä" + +msgid "Days to keep modlog entries" +msgstr "Päivät joiden aikana moderaattorilokin kirjaukset säilytetään" + +msgid "Default" +msgstr "Vakio" + +msgid "Default style:" +msgstr "Vakio tyyli:" + +msgid "Delete" +msgstr "poista" + +msgid "Delete all posts by IP" +msgstr "Poista kaikki viestit tältä IP:ltä" + +msgid "Delete all posts by this IP" +msgstr "Poista kaikki viestit tästä IP:stä" + +msgid "Delete board" +msgstr "Poista boardi" + +msgid "Delete post" +msgstr "Poista viesti" + +msgid "Delete posts" +msgstr "Poista viesrti" + +msgid "Delete thread" +msgstr "Poista keskustelu" + +msgid "Delete thread/post" +msgstr "Poista keskustelu/viesti" + +msgid "Deleted" +msgstr "Poistettu" + +msgid "Deleted a VIP code" +msgstr "Poista VIP koodi" + +msgid "Deleted board" +msgstr "Poistettu boardi" + +msgid "Deleted post" +msgstr "Poistettu viesti" + +msgid "Deleted posts by ip" +msgstr "Poistettu kaikki viestit tältä IP:ltä" + +msgid "Deleted staff member" +msgstr "Poistettu henkilökunnasta jäsen" + +msgid "Deleted thread" +msgstr "Poistettu keskustelu" + +msgid "Deleting non-deleted replies which belong to deleted threads." +msgstr "Poistan ei poistettua vastausta joka kuuluu poistettuihin keskusteluihin." + +msgid "Deleting unused images." +msgstr "Poistetaan ei-käytettyjä kuvia." + +msgid "Denied the ban appeal for" +msgstr "Kumottu bannien valitus koska" + +msgid "Description" +msgstr "kuvaus" + +msgid "Directory" +msgstr "Hakemisto" + +msgid "Disk space used" +msgstr "Käytetty levytila" + +msgid "Does not expire" +msgstr "Ei vanhene" + +msgid "Duplicate file entry detected." +msgstr "Saman tiedoston lähettäminen uudelleen estetty." + +msgid "Duplicate thread subject" +msgstr "Kopioi threadin aihe" + +msgid "Edit" +msgstr "Muokkaa" + +msgid "Edit filetypes" +msgstr "Muokkaa tiedostotyyppejä" + +msgid "Edit sections" +msgstr "Muokkaa alueita" + +msgid "Edit word" +msgstr "Muokkaa sanaa" + +msgid "Edited a VIP cod" +msgstr "Muokattu VIP koodi" + +msgid "Edited a news entry" +msgstr "Muokattu uutisartikkeli" + +msgid "Email" +msgstr "Sähköposti" + +msgid "Embed" +msgstr "Upote" + +msgid "Embedding only" +msgstr "Pelkkä upotus" + +msgid "Enable \"no file\" posting" +msgstr "Salli \"Ei tiedostoa\" postaaminen" + +msgid "Enable captcha:" +msgstr "Salli kuvantunnistus:" + +msgid "Enable reporting:" +msgstr "Salli ilmiantaminen:" + +msgid "Enable/disable captcha system for this board. If captcha is enabled, in order for a user to post, they must first correctly enter the text on an image." +msgstr "Salli/estä kuvantunnistus järjestelmä tälle boardille. Jos kuvantunnistus on laitettu päälle, käyttäjän pitää tunnistaa ja kirjoittaa kuvassa näkyvä tekstinpätkä oikein postatakseen viestinsä." + +msgid "Entire Thread" +msgstr "Koko keskustelu" + +msgid "Error, it appears your file did not transfer properly. Please go back and try again." +msgstr "Virhe, tiedostoasi ei nähtävästi saatu lähetettyä oikein. Mene takaisin ja kokeile uudelleen." + +msgid "Expand all images" +msgstr "Laajenna kaikki kuvat." + +msgid "Expires:" +msgstr "Vanhentuu:" + +msgid "Extension icon displayed, click image to open file." +msgstr "Laajennus kuvake, klikkaa kuvaa aukaistaksesi tiedosto." + +msgid "FAQ" +msgstr "UKK" + +msgid "File" +msgstr "Tiedosto" + +msgid "File Only" +msgstr "Vain tiedosto" + +msgid "File was not fully uploaded. Please go back and try again." +msgstr "Tiedostoa ei saatu kokonaan uploadattua, mene takaisin ja kokeile uudelleen." + +msgid "File
Removed" +msgstr "Tiedosto
Poistettu" + +msgid "Filetype added." +msgstr "Tiedostotyyppi lisätty" + +msgid "Filetype deleted." +msgstr "Tiedostotyyppi poistettu" + +msgid "Filetype updated." +msgstr "Tiedostotyyppi päivitetty" + +msgid "First 100 posts" +msgstr "Ensimmäiset 100 viestiä" + +msgid "First 100 posts shown." +msgstr "Ensimmäiset 100 viestiä näytetään." + +msgid "First Post ID" +msgstr "Ensimmäisen viestin ID" + +msgid "Forced anonymous" +msgstr "Pakotettu Anonyymiksi" + +msgid "From" +msgstr "Lähettäjä:" + +msgid "Front" +msgstr "Etupuoli" + +msgid "Front Page" +msgstr "Etusivu" + +msgid "Get posting password" +msgstr "Anna postaus salasana" + +msgid "Global configuration succesfully updated." +msgstr "Globaali kokoonpano päivitetty onnistuneesti!" + +msgid "Global options" +msgstr "Globaalit asetukset" + +msgid "Go" +msgstr "Mene" + +msgid "Header image" +msgstr "Otsakekuva" + +msgid "Height" +msgstr "Korkeus" + +msgid "Hide Directories" +msgstr "Piiloita kansiot" + +msgid "Hide the watched threads box" +msgstr "Piilota seurattujen keskusteluiden laatikko." + +msgid "Home" +msgstr "Etusivu" + +msgid "ID" +msgstr "ID" + +msgid "IP" +msgstr "IP" + +msgid "If set to yes, new threads will not require an image to be posted." +msgstr "Jos asetettu \"kyllä\", uusi keskustelu ei vaadi kuvaa postattavaksi." + +msgid "If set to yes, this board will appear in bold in the menu" +msgstr "Jos asetettu \"kyllä\", tämä boardi nakyy boldattuna menussa" + +msgid "If set to yes, this board will appear in italics in the menu" +msgstr "Jos asetettu \"kyllä\", tämä boardi näyttää 'italics':it menussa" + +msgid "If set to yes, users will be redirected to the thread they replied to/posted after posting. If set to no, users will be redirected to the first page of the board." +msgstr "Jos asetettu \"kyllä\", käyttäjät uudelleenohjautuu keskusteluun johonka hän vastasi. Jos taas asetettu \"Ei\" käyttäjät uudelleenohjataan boardin etusivulle." + +msgid "If set to yes, users will not be allowed to enter a name, making everyone appear as Anonymous" +msgstr "Jos asetettu \"kyllä\" käyttäjät eivät voi käyttää omaa nimeä, vaan kaikki ovat Anonyymejä :-D" + +msgid "Image" +msgstr "kuva" + +msgid "Image successfully deleted from your post." +msgstr "Kuva saatiin onnistuneesti poistettua viestistäsi." + +msgid "Images" +msgstr "kuvat" + +msgid "Images and embedding" +msgstr "Kuvat ja upotus" + +msgid "Important" +msgstr "Tärkeä" + +msgid "Improper filetype." +msgstr "Kelvoton tiedostotyyppi!" + +msgid "Include header" +msgstr "sisällytä otsake" + +msgid "Incorrect captcha entered." +msgstr "Viallinen kuvanvarmennus annettu." + +msgid "Incorrect password." +msgstr "Virheellinen salasana." + +msgid "Incorrect username/password." +msgstr "Virheellinen käyttäjäntunnus tai salasana." + +msgid "Index" +msgstr "Index" + +msgid "Inject" +msgstr "Ruiskuttaa" + +msgid "Inserted SQL" +msgstr "Lisätty SQL" + +msgid "Integer values must be entered correctly." +msgstr "Kokonaislukuarvot pitää syöttää oikein!" + +msgid "Invalid ID" +msgstr "Invaliidi ID" + +msgid "Invalid MIME type for this filetype." +msgstr "Invaliidi MIME tyyppi tälle tiedostotyypille." + +msgid "Invalid ban ID" +msgstr "Invaliidi Ban ID" + +msgid "Invalid board directory." +msgstr "Invaliidi boardin hakemisto." + +msgid "Invalid response code:" +msgstr "Invaliidi vastauskoodi:" + +msgid "Invalid session." +msgstr "Invaliidi sessio!" + +msgid "Invalid staff ID." +msgstr "Invaliidi henkilökunta ID" + +msgid "Invalid thread ID." +msgstr "Invaliidi keskustelun ID." + +msgid "Invalid thread ID. This may have been caused by the thread recently being deleted." +msgstr "Invaliidi keskustelun ID. Syy voi olla siinä jos ketju on juuri poistettu." + +msgid "Invalid video ID." +msgstr "Invaliidi video ID" + +msgid "Invalid video type." +msgstr "Invaliidi videotyyppi." + +msgid "Is replaced by" +msgstr "On asetettu uudelleen johdosta:" + +msgid "Last 50 posts" +msgstr "viimeiset 50 viestiä" + +msgid "Last 50 posts shown." +msgstr "Viimeiset 50 viestiä näytetään." + +msgid "Last Post" +msgstr "Viimeinen viesti" + +msgid "Last active" +msgstr "Viimeisin aktiivinen" + +msgid "Lock" +msgstr "Lukittu" + +msgid "Locked" +msgstr "Lukittu" + +msgid "Locked thread" +msgstr "Lukittu keskustelu" + +msgid "Log in again." +msgstr "Kirjaudu uudelleen sisään" + +msgid "Logged in" +msgstr "Kirjautunut sisään" + +msgid "Logo" +msgstr "Logo" + +msgid "Manage" +msgstr "Hallitse" + +msgid "Manage boards" +msgstr "Hallitse boardeja" + +msgid "Manage locked threads" +msgstr "Hallitse lukitettuja keskusteluita" + +msgid "Manage stickies" +msgstr "Hallitse nastoitettuja keskusteluita" + +msgid "Marked for deletion (old)." +msgstr "Merkitty poistettavaksi (vanha)" + +msgid "Maximum board pages" +msgstr "Suurin sallittu määrä boardin sivuja" + +msgid "Maximum image size" +msgstr "Suurin sallittu tiedoston koko" + +msgid "Maximum message length" +msgstr "Suurin sallittu viestin pituus" + +msgid "Maximum thread age (Hours)" +msgstr "Suurin sallittu keskustelun ikä (Tuntia)" + +msgid "Maximum thread replies" +msgstr "Suurin sallittu keskustelunu pituus" + +msgid "Maxmimum size of uploaded images, in bytes." +msgstr "Suurin sallittu koko uploadatuille kuville," + +msgid "Maxmimum thumbnail height" +msgstr "Suurin sallittu thumbnailin korkeus" + +msgid "Maxmimum thumbnail width" +msgstr "Suurin sallittu thumbnailin leveys" + +msgid "Message" +msgstr "Viesti" + +msgid "Message too long. Click %shere%s to view the full text." +msgstr "Viesti on liian pitkä. Paina %tästä% nähdäksesi loput tekstistä." + +msgid "Misc" +msgstr "Sekalaista" + +msgid "Mod" +msgstr "Mod" + +msgid "ModLog" +msgstr "Moderaattoriloki" + +msgid "Moderates" +msgstr "Moderoi" + +msgid "Moderating boards" +msgstr "Moderoi boardeja" + +msgid "Moderation" +msgstr "Moderointi" + +msgid "Moderator" +msgstr "Moderaattori" + +msgid "Moderators" +msgstr "Moderaattorit" + +msgid "Modify" +msgstr "Muokkaa" + +msgid "Modify staff member" +msgstr "Muokkaa henkilökunnan jäsentä" + +msgid "Module settings" +msgstr "Moduli asetukset" + +msgid "Modules" +msgstr "Modulit" + +msgid "More" +msgstr "Enemmän" + +msgid "Move complete." +msgstr "Siirto suoritettu." + +msgid "Move thread" +msgstr "Siirrä keskustelu" + +msgid "NOTICE: You are using the default administrator account. Anyone can log in to this account, so a second administrator account needs to be created. Create another, log in to it, and delete this one." +msgstr "HUOMIO: Jos käytät vielä vakioasetuksella ollutta admin accounttia, kuka vain voi kirjautua sisään. Luo siis itse uusi ja poista vanha." + +msgid "Name" +msgstr "Nimi" + +msgid "Name to display when a name is not attached to a post." +msgstr "Nimi joka näkyy, jos nimeä ei ole annettu." + +msgid "Never" +msgstr "Ei koskaan." + +msgid "New Thread" +msgstr "Uusi keskustelu" + +msgid "New image" +msgstr "Uusi kuva" + +msgid "New password" +msgstr "Uusi salasana" + +msgid "New password again" +msgstr "Uusi salasana uudelleen" + +msgid "News" +msgstr "Uutiset" + +msgid "News entry successfully added." +msgstr "Uutinen lisätty onnistuneesti" + +msgid "Next" +msgstr "Seuraava" + +msgid "No" +msgstr "Ei" + +msgid "No File" +msgstr "Ei tiedostoa" + +msgid "No blotter entries." +msgstr "Ei merkintöjä ilmoituksessa." + +msgid "No boards" +msgstr "Ei boardeja" + +msgid "No embedding" +msgstr "Ei upotusta" + +msgid "No threads." +msgstr "Ei keskusteluita." + +msgid "No visible boards" +msgstr "Ei boardeja näkyvillä" + +msgid "None" +msgstr "Ei mitään" + +msgid "Normal imageboard" +msgstr "Tavallinen imageboardi" + +msgid "Oekaki imageboard" +msgstr "Oekaki imageboardi" + +msgid "Old password" +msgstr "Vanha salasana" + +msgid "Online now" +msgstr "Onlinessä nyt" + +msgid "Only moderators of the board and admins can make new posts/replies" +msgstr "Vain boardin moderaattorit ja adminit voivat tehdä uusia viestejä ja vastata niihin" + +msgid "Only put in the letter(s) of the board directory, no slashes!" +msgstr "Laita vain kirjain tai pari kuvaamaan boardin kansiota (esim. b) Ei kauttaviivoja!!" + +msgid "Open images in new window" +msgstr "Avaa kuvat uuteen ikkunaan" + +msgid "Order" +msgstr "Järjestys" + +msgid "Order to show board in menu list, in ascending order." +msgstr "Näyttää boardin menulistassa, nousevassa järjestyksessä" + +msgid "Overrides the header set in the config file. Leave blank to use configured global header image. Needs to be a full url including http://. Set to none to show no header image." +msgstr "Menee config.php:ssä asetetun header imagen edelle, jätä tyhjäksi jos haluat pitää sen tällä boardilla. Pitää olla koko url mukaanlukien http://" + +msgid "Pages" +msgstr "Sivut" + +msgid "Paint with" +msgstr "Maalaa" + +msgid "Paint!" +msgstr "Piirrä!" + +msgid "Password" +msgstr "Salasana:" + +msgid "Password successfully changed." +msgstr "Salasanan vaihto onnistui." + +msgid "Placed:" +msgstr "Asetettu:" + +msgid "Please enter a positive amount of seconds, or zero for a permanent ban." +msgstr "Laita positiivinen määrä sekunteja tai nolla, jos haluat antaa elinikäiset bannit." + +msgid "Please enter a search query." +msgstr "Käytä hakua" + +msgid "Please fill in all required fields." +msgstr "Ole hyvä ja täytä kaikki vaaditut kentät" + +msgid "Please make sure your file is smaller than %dB" +msgstr "Varmista että tiedostosi on pienempi kuin %dB" + +msgid "Please select a board." +msgstr "Ole hyvä ja valitse boardi." + +msgid "Please select only one image to upload." +msgstr "Valitse vain yksi kuva uploadattavaksi." + +msgid "Please wait a moment before posting again." +msgstr "Odota hetki ennen kuin postaat uudelleen." + +msgid "Popular" +msgstr "Suosittu" + +msgid "Post" +msgstr "Lähetä" + +msgid "Post added." +msgstr "Viesti lisätty." + +msgid "Post preview" +msgstr "Viestin esikatselu" + +msgid "Post successfully deleted." +msgstr "Viesti poistettu onnistuneesti!" + +msgid "Postbox notice" +msgstr "Postbox merkinnät" + +msgid "Posting a blacklisted link." +msgstr "Lähetit linkin mustaltalistalta." + +msgid "Posting mode: Reply" +msgstr "Postaustyyli: Vastaus" + +msgid "Posting password" +msgstr "Postauksen salasana" + +msgid "Posting rates (past hour)" +msgstr "Viestien määrä (viime tunti)" + +msgid "Posts" +msgstr "Viestit" + +msgid "Presets" +msgstr "Esiasetetut" + +msgid "Preview" +msgstr "Esikatselu" + +msgid "Previous" +msgstr "Edellinen" + +msgid "Proxy list" +msgstr "Proxylista" + +msgid "Query" +msgstr "Kysely" + +msgid "Query executed successfully" +msgstr "Tiedustelu pantu toimeen onnistuneesti." + +msgid "Quick Reply" +msgstr "Vastaa heti" + +msgid "Ran cleanup" +msgstr "juokse siivous" + +msgid "Raw HTML which will be inserted at the top of each page of the board." +msgstr "Raaka HTML, joka on laitettu joka sivun ylälaitaan boardilla." + +msgid "Read this thread from the beginning" +msgstr "Lue tämä keskustelu alusta" + +msgid "Reason" +msgstr "Syy" + +msgid "Reason:" +msgstr "Syy:" + +msgid "Rebuild all html files" +msgstr "Rakenna uudelleen kaikki HTML tiedostot" + +msgid "Rebuild complete. Took %d seconds." +msgstr "uudelleen rakentaminen valmista. Se vei %d sekuntia." + +msgid "Rebuilt all boards and threads" +msgstr "Rakenna klaikki boardit ja keskustelut uudelleen" + +msgid "Redirecting" +msgstr "Uudelleenohjataan" + +msgid "Refresh watched threads" +msgstr "Päivitä seuratut keskustelut" + +msgid "Regenerated %s" +msgstr "Regeneroi %s" + +msgid "Regular expression" +msgstr "Säännöllinen lauseke" + +msgid "Remove" +msgstr "Poista" + +msgid "Removed word from wordfilter" +msgstr "Poistettu sana sanafiltteristä" + +msgid "Replacement" +msgstr "Korvaus" + +msgid "Replies" +msgstr "Vastaukset" + +msgid "Replies displayed per stickied thread (in thread list)" +msgstr "Vastausta näytetty per nastoitettu keskustelu." + +msgid "Replies displayed per thread (in thread list)" +msgstr "Viestejä näytetty per sivu. (keskustelulistassa)" + +msgid "Reply" +msgstr "Vastaa" + +msgid "Report" +msgstr "Ilmianna" + +msgid "Reporting allows users to report posts, adding the post to the report list." +msgstr "Ilmiantaminen antaa käyttäjien lähettää ilmiantoviestejä, lisätä viesti ilmiantolistalle." + +msgid "Reports" +msgstr "Ilmiannot" + +msgid "Restore watched threads" +msgstr "Palauta seuratut keskustelut." + +msgid "Results" +msgstr "Tulokset" + +msgid "Return" +msgstr "Takaisin" + +msgid "Rules" +msgstr "Säännöt" + +msgid "SQL query" +msgstr "SQL-kysely" + +msgid "Search" +msgstr "Etsi" + +msgid "Search posts" +msgstr "Etsi viesti" + +msgid "Seconds" +msgstr "Sekuntia" + +msgid "Section" +msgstr "Osio" + +msgid "Section added." +msgstr "Alue listätty" + +msgid "Section deleted." +msgstr "Alue poistettu" + +msgid "Section updated." +msgstr "Aluetta päivitetty" + +msgid "Send Appeal" +msgstr "Lähetä valitus" + +msgid "Show All" +msgstr "Näytä kaikki" + +msgid "Show Directories" +msgstr "Näytä kansiot" + +msgid "Show Posting Password" +msgstr "Näytä postaus-salasana" + +msgid "Show/Hide" +msgstr "Näytä/Piilota" + +msgid "Shown below" +msgstr "Näkyy alempana" + +msgid "Site Styles" +msgstr "Sivun tyylit" + +msgid "Size" +msgstr "Koko" + +msgid "Sorry, a generic error has occurred." +msgstr "Pahoittelen, geneerinen virhe havaittu." + +msgid "Sorry, because of your numerous failed logins, you have been locked out from logging in for 20 minutes. Please wait and then try again." +msgstr "Pahoittelen, koska epäonnistuit sisäänkirjautumisessa monesti, sinut on bannattu 20min sisäänkirjautumiselta.. Ole hyvä ja odota hetki, kokeile sitten uudelleen." + +msgid "Sorry, that filetype is not allowed on this board." +msgstr "Sorry, tuota tiedostotyyppiä ei tueta tällä boardilla." + +msgid "Sorry, this board is locked and can not be posted in." +msgstr "Pahoittelen, tämä boardi on lukittu etkä voi postata sinne." + +msgid "Sorry, this thread is locked and can not be replied to." +msgstr "Pahoittelen, tämä boardi on lukittu etkä voi vastata sinne." + +msgid "Sorry, your message is too long. Message length: %d, maxmimum allowed length: %d" +msgstr "Pahoittelen, viestisi on liian pitkä. Viestin pituus: %d, maxmimum allowed length: %d" + +msgid "Sorry, your search returned zero results." +msgstr "Haullasi ei löytynyt mitään. :-(" + +msgid "Source" +msgstr "Lähde" + +msgid "Staff" +msgstr "Ylläpito" + +msgid "Staff member successfully added." +msgstr "Henkilökunnan jäsen onnistuneesti lisätty" + +msgid "Staff rights" +msgstr "Ylläpidon oikeudet" + +msgid "Staff successfully deleted" +msgstr "Henkilökunta(a) onnistuneesti poistettu!" + +msgid "Staff successfully updated" +msgstr "Henkilökuntaa onnistuneesti päivitetty!" + +msgid "Statistics" +msgstr "Tilastot" + +msgid "Stickied" +msgstr "Nastoitettu" + +msgid "Stickied thread" +msgstr "Nastoitettu keskustelu" + +msgid "Sticky" +msgstr "Nastoitettu" + +msgid "Style" +msgstr "Tyyli" + +msgid "Styles" +msgstr "Tyylit" + +msgid "Subject" +msgstr "Aihe" + +msgid "Submit" +msgstr "Lähetä" + +msgid "System lockout" +msgstr "Järjestelmän työsulku" + +msgid "Tag" +msgstr "Merkitse" + +msgid "Text board" +msgstr "Tekstiboardi" + +msgid "Text boards may have only one thread with a unique subject. Please pick another." +msgstr "txt-boardeilla voi olla vain yksi uniikki aihe per keskustelu. Valitse toinen." + +msgid "Text boards only. If enabled, the list of threads displayed on the front page will be formatted differently to be compact." +msgstr "Vain teksti-boardit. Jos hyväksytty, keskusteluiden lista jotka on näytetty etusivulla, formatoidaan erilailla jotta se ne olisivat kompakteja." + +msgid "That ID does not exist." +msgstr "Tuo ID ei ole olemassa." + +msgid "That ID is a reply, not a thread." +msgstr "Tuo ID on vastaus, ei keskustelu." + +msgid "That IP has already been banned." +msgstr "Henkilö tuosta IP:stä on jo bannittu." + +msgid "That name is for internal use. Please pick another." +msgstr "Tuo nimi on vain sisäiseen käyttöön. Valitse joku toinen." + +msgid "That post has been cleared as not requiring any deletion." +msgstr "Tuo viesti on puhdistettu." + +msgid "That post is already in the report list." +msgstr "Se viesti on jo ilmiantolistalla." + +msgid "That thread has yet to be deleted." +msgstr "Se keskustelu on jo poistettu." + +msgid "That thread may have been recently deleted." +msgstr "Voi olla että hakemasi keskustelu on juuri poistettu." + +msgid "That video ID has already been posted %shere%s." +msgstr "Tuo video ID on jo postattu %stänne%s." + +msgid "That word already exists." +msgstr "Tuo sana on jo olemassa" + +msgid "The 5 newest replies are shown below." +msgstr "5 uusinta viestiä näkyy alapuolella" + +msgid "The change will not be apparent until the html files are rebuilt." +msgstr "Muutos näkyy vasta, kun kaikki html-tiedostot on rakennettu uudelleen." + +msgid "The directory of the board." +msgstr "Boardin hakemisto" + +msgid "The first post of this board will recieve this ID." +msgstr "Ensimmäinen viesti tällä boardilla saa tämän ID:n." + +msgid "The name of the board." +msgstr "Boardin nimi" + +msgid "The number of replies a thread can have before autosaging to the back of the board." +msgstr "Kuinka monta vastausta keskustelussa voi olla ennen autosagea." + +msgid "The old password you provided did not match the current one." +msgstr "vanha salasana jonka annoit ei täsmää." + +msgid "The second password did not match the first." +msgstr "Salasanat eivät täsmää" + +msgid "The section the board is in. This is used for displaying the list of boards on the top and bottom of pages." +msgstr "Alue jossa boardi on. Tätä käytetään näyttämään lista kaikista boardeista ylä- ja alasivuilla." + +msgid "The style which will be set when the user first visits the board." +msgstr "Tyyli joka on asetettu, kun käviä kävi boardilla ensikertaa." + +msgid "The type of posts which will be accepted on this board. A normal imageboard will feature image and extended format posts, a text board will have no images, and an Oekaki board will allow users to draw images and use them in their posts." +msgstr "Viestin tyyppi, joka sallitaan tällä boardilla. Tavalliselle imageboardille voidaan lähettää kuvia, Tekstiboardille ei hyväksytä ollenkaan kuvia ja Oekaki imageboardilla kävijät saavat itse piirtää kuvia." + +msgid "There are currently no bans." +msgstr "Ei banneja tällä hetkellä!" + +msgid "There are currently no filetypes." +msgstr "Siellä ei ole tällä hetkellä tiedostotyyppejä" + +msgid "There are currently no sections." +msgstr "Ei tällä hetkellä löydy alueita" + +msgid "There are currently no threads to display." +msgstr "Tällä hetkellä ei ole keskusteluita näytettäväksi" + +msgid "There is already a file with that name." +msgstr "Siellä on jo tiedosto tuolla nimellä!" + +msgid "There was an error in trying to delete your post" +msgstr "Virhe ilmeni viestiäsi poistettaessa.." + +msgid "This board does not allow post reporting." +msgstr "Tämä boardi ei salli ilmiantoa." + +msgid "This post has been deleted." +msgstr "Tämä viesti on poistettu" + +msgid "Thread" +msgstr "Keskustelu" + +msgid "Thread successfully deleted." +msgstr "Keskustelu poistettu onnistuneesti" + +msgid "Thread successfully locked." +msgstr "Keskustelu onnistuneesti lukittu!" + +msgid "Thread successfully stickied." +msgstr "Keskustelu nastoitettu onnistuneesti!" + +msgid "Thread successfully un-stickied" +msgstr "Keskustelun nasta poistettu onnistuneesti." + +msgid "Thread successfully unlocked." +msgstr "Keskustelun lukko onnistuneesti poistettu." + +msgid "Threads" +msgstr "Keskustelut" + +msgid "Threads displayed per page (in thread list)" +msgstr "Keskusteluja näytetty per sivu" + +msgid "Thumbnail displayed, click image for full size." +msgstr "Thumbnail, klikkaa suuremmaksi." + +msgid "To" +msgstr "Vastaanottaja:" + +msgid "Trial" +msgstr "Trial" + +msgid "Unable to clear cache: you do not have caching enabled." +msgstr "Kykenemätön tyhjentämään välimuistia: sinulla ei ole välimuistia käytössä" + +msgid "Unable to connect to:" +msgstr "En kyennyt yhdistää:" + +msgid "Unable to create directories." +msgstr "En kykene luomaan hakemistoa." + +msgid "Unable to delete board." +msgstr "En kykene poistamaan boardia" + +msgid "Unable to find record of your IP being banned." +msgstr "En kyennyt löytää tallenteita siitä että IP:si olisi bannissa." + +msgid "Unable to find records of any posts matching that quote syntax." +msgstr "Kykenemätön löytämään arkistoja yhdestäkään viestistä, joka viittaisi tuohon syntaxiin." + +msgid "Unable to locate a board named" +msgstr "En kykene paikantamaan boardi joka on nimetty:" + +msgid "Unable to locate a filetype with that ID." +msgstr "En kyennyt paikantamaan tiedostotyyppiä tuolla ID:llä" + +msgid "Unable to locate a section with that ID." +msgstr "En kyennyt paikantamaan aluetta tuolla ID:llä" + +msgid "Unable to locate that word." +msgstr "En pysty paikantamaan tuota sanaa" + +msgid "Unable to read uploaded file during thumbnailing." +msgstr "Kykenemätön lukemaan lähetettyä kuvaa thumbnailatessa." + +msgid "Unable to report post. Please go back and try again." +msgstr "En pystynyt ilmiantaa viestiä. Mene takaisin ja kokeile uudelleen." + +msgid "Unbanned" +msgstr "Ei-bannattu" + +msgid "Unlock" +msgstr "Poista lukitus" + +msgid "Unlocked thread" +msgstr "Ei-lukitut keskustelut" + +msgid "Unstickied thread" +msgstr "Ei-nastoitettu keskustelu" + +msgid "Unsticky" +msgstr "Poista nasta" + +msgid "Upating pages." +msgstr "Päivitetään sivua." + +msgid "Update" +msgstr "Päivitys" + +msgid "Update and regenerate board" +msgstr "Päivitä ja regeneroi boardi" + +msgid "Update successful." +msgstr "Päivitetty onnistuneesti" + +msgid "Update without regenerating board" +msgstr "Päivitä ilman boardi regenerointia" + +msgid "Updated board configuration" +msgstr "Päivitetty boardin kokoonpanoa" + +msgid "Updated global configuration" +msgstr "Päivitettu globaalia kokoonpanoa" + +msgid "Updated staff member" +msgstr "Päivitetty henkilökunnan jäsen" + +msgid "Updated word on wordfilter" +msgstr "Päivitetty sana sanafiltteriin" + +msgid "Upload type:" +msgstr "Upload tyyppi:" + +msgid "Use animation?" +msgstr "Käytetäänkö animaatiota?" + +msgid "Username" +msgstr "Käyttäjätunnus" + +msgid "View Reports" +msgstr "Katsele selostetia" + +msgid "View all bans" +msgstr "Näytä kaikki bannit" + +msgid "View animation" +msgstr "Näytä animaatio" + +msgid "View catalog" +msgstr "Näytä catalogi" + +msgid "View deleted thread" +msgstr "Katsele poistettuja keskusteluita" + +msgid "View/Add/Remove bans" +msgstr "Katsele/Lisää/Poista banneja" + +msgid "Viewed disk space used" +msgstr "Katso kuinka paljon levytilaa on käytetty" + +msgid "Watched Threads" +msgstr "Seuratut keskustelut" + +msgid "Welcome" +msgstr "Tervetuloa" + +msgid "What filetypes users are allowed to upload." +msgstr "Mitä tiedostotyyppejä kävijöiden on sallittua uploadata" + +msgid "Whether or not to allow embedding of videos." +msgstr "joko tai ei, salli videoiden upotus." + +msgid "Width" +msgstr "Leveys" + +msgid "Word" +msgstr "Sana" + +msgid "Word successfully added." +msgstr "Sana onnistuneesti lisätty." + +msgid "Word successfully removed." +msgstr "Sana onnistuneesti poistettu" + +msgid "Word successfully updated." +msgstr "Sana onnistuneesti päivitetty" + +msgid "Wordfilter" +msgstr "Sanafiltteri" + +msgid "YOU ARE BANNED" +msgstr "OLET BANNITTY TÄLTÄ BOARDILTA" + +msgid "YOU ARE NOT BANNED!" +msgstr "ET OLE BANNISSA!" + +msgid "Yes" +msgstr "Kyllä" + +msgid "You are banned from posting on:" +msgstr "Sinut on bannatty postaamastasi:" + +msgid "You are currently posting faster than the configured minimum post delay allows." +msgstr "Postailet yli annetun minimi odotusajan." + +msgid "You are not a moderator of this board." +msgstr "Et ole tämän boardin moderaattori!" + +msgid "You can only delete posts from boards you moderate." +msgstr "Voit poistaa viestin vain boardilta jossa olet moderaattori." + +msgid "You can only make board specific bans to boards which you moderate." +msgstr "Voit laittaa vain boardi kohtaiset bannit, sinne missä olet moderaattori." + +msgid "You have been banned from posting on" +msgstr "Sait bannit koska lähetit" + +msgid "You have been successfully logged out." +msgstr "Kirjauduit ulos onnistuneesti!" + +msgid "You may not appeal this ban." +msgstr "Sinulla ei ole oikeutta valittaa näistä banneista." + +msgid "You may appeal this ban in" +msgstr "Voit valittaa näistä banneista" + +msgid "You may now appeal this ban." +msgstr "Voit nyt valittaa näistä banneista." + +msgid "You must enter a subject." +msgstr "Sinun täytyy lisätä aihe!" + +msgid "You searched for" +msgstr "Sinä etsit" + +msgid "Your IP address is" +msgstr "Sinun IP osoitteesi on" + +msgid "Your appeal is currently pending review." +msgstr "Sinun valituksesi on vireillä." + +msgid "Your appeal was reviewed and denied. You may not appeal this ban again." +msgstr "Valituksesi luettiin ja hylättiin. Sinä et voi valittaa näistä banneista enään." + +msgid "Your image" +msgstr "Kuvasi" + +msgid "Your post already doesn't have an image!" +msgstr "Viestissäsi ei vielä ole kuvaa!" + +msgid "Your post contains one or more illegal characters." +msgstr "Viestissäsi on yksi tai enemmän epäkelpoja kirjainta." + +msgid "Your posting password" +msgstr "Salasanasi viestille" + +msgid "and" +msgstr "ja" + +msgid "for the following reason" +msgstr "Seuraavasta syystä" + +msgid "forever" +msgstr "Ikuisesti" + +msgid "log in" +msgstr "kirjaudu sisään" + +msgid "log out" +msgstr "Kirjaudu ulos" + +msgid "omitted" +msgstr "poisjätetty" + +msgid "or" +msgstr "tai" + +msgid "translator-credits" +msgstr "" +"Launchpad Contributions:\n" +" Jebula https://launchpad.net/~jebula" + +msgid "will expire on" +msgstr "päättyy" + +msgid "will not expire" +msgstr "ei pääty" + diff --git a/inc/lang/it/LC_MESSAGES/kusaba.po b/inc/lang/it/LC_MESSAGES/kusaba.po new file mode 100644 index 0000000..1203f3a --- /dev/null +++ b/inc/lang/it/LC_MESSAGES/kusaba.po @@ -0,0 +1,465 @@ +msgid "" +msgstr "" +"Project-Id-Version: trevorchan\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2007-12-09 03:10+0000\n" +"PO-Revision-Date: 2008-02-14 04:34+0000\n" +"Last-Translator: Emanuele Gentili \n" +"Language-Team: Italian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2008-03-12 04:24+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +msgid "A board with that name already exists." +msgstr "Esiste già una board con questo nome." + +msgid "A board with that name does not exist." +msgstr "Non esiste una board con questo nome" + +msgid "Add" +msgstr "Aggiungere" + +msgid "Add board" +msgstr "Aggiungi board" + +msgid "Add news" +msgstr "Aggiungi notizie" + +msgid "Add staff member" +msgstr "Aggiungi un membro dello staff" + +msgid "Add word" +msgstr "Aggiungi parola" + +msgid "Added on" +msgstr "Aggiunto" + +msgid "Added staff member" +msgstr "Membro dello staff aggiunto" + +msgid "Administration" +msgstr "Amministrazione" + +msgid "Administrator" +msgstr "Amministratore" + +msgid "Administrators" +msgstr "Amministratori" + +msgid "All Threads" +msgstr "Tutti i thread" + +msgid "An image, or message, is required for a reply." +msgstr "Per una risposta è richiesta un immagine, o un messaggio." + +msgid "Banned" +msgstr "Bannato" + +msgid "Board" +msgstr "Board" + +msgid "Board successfully added." +msgstr "Board aggiunta con successo." + +msgid "Board successfully deleted." +msgstr "Board cancellata con successo" + +msgid "Board type:" +msgstr "Tipo di board:" + +msgid "Can be left blank." +msgstr "Può essere lasciato in bianco." + +msgid "Can not be left blank." +msgstr "Non può essere lasciato in bianco." + +msgid "Change account password" +msgstr "Cambia password dell'account" + +msgid "Check for new version" +msgstr "Controlla per nuova versione" + +msgid "Cleanup" +msgstr "Pulisci" + +msgid "Continue" +msgstr "Continuare" + +msgid "Current version:" +msgstr "Versione corrente:" + +msgid "Default" +msgstr "Predefinito" + +msgid "Default style:" +msgstr "Stile predefinito" + +msgid "Delete" +msgstr "Cancella" + +msgid "Delete all posts by this IP" +msgstr "Cancella tutti i post di questo IP" + +msgid "Delete board" +msgstr "Cancella board" + +msgid "Delete posts" +msgstr "Cancella i post" + +msgid "Deleted staff member" +msgstr "Membro dello staff cancellato" + +msgid "Directory" +msgstr "Directory" + +msgid "Disk space used" +msgstr "Spazio disco usato" + +msgid "Edit" +msgstr "Modifica" + +msgid "Email" +msgstr "Email" + +msgid "Error, it appears your file did not transfer properly. Please go back and try again." +msgstr "Errore, sembra che il file non sia stato trasferito correttamente. Perfavore tornare indietro e riprovare." + +msgid "File" +msgstr "File" + +msgid "File was not fully uploaded. Please go back and try again." +msgstr "Il file non è stato completamente caricato. Perfavore tornare indietro e riprovare." + +msgid "First 100 posts" +msgstr "Primi 100 post" + +msgid "Global options" +msgstr "Opzioni globali" + +msgid "Go" +msgstr "Vai" + +msgid "ID" +msgstr "ID" + +msgid "IP" +msgstr "IP" + +msgid "Incorrect password." +msgstr "Password errata." + +msgid "Incorrect username/password." +msgstr "nome utente/password errate" + +msgid "Index" +msgstr "Indice" + +msgid "Invalid ID" +msgstr "ID non valido" + +msgid "Invalid session." +msgstr "Sessione non valida." + +msgid "Invalid video ID." +msgstr "ID video non valido." + +msgid "Invalid video type." +msgstr "Tipo di video non valido." + +msgid "Last 50 posts" +msgstr "Ultimi 50 post" + +msgid "Last Post" +msgstr "Ultimo post" + +msgid "Lock" +msgstr "Blocca" + +msgid "Locked" +msgstr "Bloccato" + +msgid "Manage" +msgstr "Amministra" + +msgid "Manage boards" +msgstr "Amministra le board" + +msgid "Maximum image size" +msgstr "Grandezza massima dell'immagine" + +msgid "Maximum message length" +msgstr "Lunghezza massima del messaggio" + +msgid "Message" +msgstr "Messaggio" + +msgid "Misc" +msgstr "Misto" + +msgid "Moderates" +msgstr "Moderato" + +msgid "Moderation" +msgstr "Moderazione" + +msgid "Moderator" +msgstr "Moderatore" + +msgid "Moderators" +msgstr "Moderatori" + +msgid "Modify staff member" +msgstr "Modifica membro dello staff" + +msgid "Module settings" +msgstr "Impostazioni del modulo" + +msgid "Modules" +msgstr "Moduli" + +msgid "Name" +msgstr "Nome" + +msgid "New Thread" +msgstr "Nuovo thread" + +msgid "New password" +msgstr "Nuova password" + +msgid "New password again" +msgstr "Ripetere nuova password" + +msgid "Next" +msgstr "Prossimo" + +msgid "No" +msgstr "No" + +msgid "No File" +msgstr "Nessun File" + +msgid "No boards" +msgstr "Nessuna tavola" + +msgid "None" +msgstr "Nessuno" + +msgid "Old password" +msgstr "Vecchia password" + +msgid "Only moderators of the board and admins can make new posts/replies" +msgstr "Solo i moderatori della board e gli amministratori possono creare nuovi post/risposte" + +msgid "Open images in new window" +msgstr "Aprire immagini in una nuova finestra" + +msgid "Order" +msgstr "Ordina" + +msgid "Password" +msgstr "Password" + +msgid "Please make sure your file is smaller than %dB" +msgstr "Perfavore assicurarsi che il file sia più piccolo di %dB" + +msgid "Please select a board." +msgstr "Perfavore selezionare una board" + +msgid "Please select only one image to upload." +msgstr "Perfavore selezionare solo un immagine da caricare." + +msgid "Popular" +msgstr "Popolare" + +msgid "Post preview" +msgstr "Anteprima del post" + +msgid "Previous" +msgstr "Indietro" + +msgid "Quick Reply" +msgstr "Risposta veloce" + +msgid "Reason" +msgstr "Motivo" + +msgid "Reason:" +msgstr "Motivo:" + +msgid "Rebuild all html files" +msgstr "Ripristina tutti i file html" + +msgid "Rebuilt all boards and threads" +msgstr "Ripristina tutte le board ed i thread" + +msgid "Remove" +msgstr "Rimuovere" + +msgid "Replies" +msgstr "Risposte" + +msgid "Reply" +msgstr "Risposta" + +msgid "Results" +msgstr "Risultati" + +msgid "Return" +msgstr "Indietro" + +msgid "Search" +msgstr "Ricerca" + +msgid "Search posts" +msgstr "Cerca post" + +msgid "Seconds" +msgstr "Secondi" + +msgid "Section" +msgstr "Sezione" + +msgid "Section deleted." +msgstr "Sezione eliminata." + +msgid "Show Directories" +msgstr "Mostra cartelle" + +msgid "Shown below" +msgstr "Indicato sotto" + +msgid "Sorry, a generic error has occurred." +msgstr "Spiacente, si è verificato un errore generico." + +msgid "Sorry, that filetype is not allowed on this board." +msgstr "Spiacente, quel tipo di file non è ammesso in questa board" + +msgid "Sorry, your message is too long. Message length: %d, maxmimum allowed length: %d" +msgstr "Spiacente, il messaggio è troppo lungo. Lunghezza messaggio: %d, massima lunghezza consentita: %d" + +msgid "Sorry, your search returned zero results." +msgstr "Spiacente, la ricerca ha restituito zero risultati." + +msgid "Staff" +msgstr "Staff" + +msgid "Staff member successfully added." +msgstr "Aggiunto con successo un membro dello staff" + +msgid "Staff successfully deleted" +msgstr "Staff cancellatto con successo" + +msgid "Staff successfully updated" +msgstr "Staff aggiornato con successo" + +msgid "Submit" +msgstr "Invio" + +msgid "The name of the board." +msgstr "Il nome della board" + +msgid "There are currently no sections." +msgstr "Attualmente non ci sono sezioni." + +msgid "There is already a file with that name." +msgstr "C'è già un file con questo nome." + +msgid "Thread" +msgstr "Thread" + +msgid "Thread successfully locked." +msgstr "Thread bloccato con successo." + +msgid "Thread successfully unlocked." +msgstr "Thread sbloccato con successo." + +msgid "Threads" +msgstr "Thread" + +msgid "Unable to connect to:" +msgstr "Impossibile connetersi a:" + +msgid "Unable to delete board." +msgstr "Impossibile cancellare la board." + +msgid "Unable to locate a board named" +msgstr "Impossibile localizzare il nome della board" + +msgid "Unable to locate a section with that ID." +msgstr "Impossible localizzare una sezione con questo ID." + +msgid "Unable to locate that word." +msgstr "Impossibile localizzare questa parola." + +msgid "Unlock" +msgstr "Sblocca" + +msgid "Unlocked thread" +msgstr "Sblocca thread" + +msgid "Update" +msgstr "Aggiornare" + +msgid "Update and regenerate board" +msgstr "Aggiornare e rigenerare la board" + +msgid "Update successful." +msgstr "Aggiornamento riuscito." + +msgid "Update without regenerating board" +msgstr "Aggiornare senza rigenerare la board" + +msgid "Updated board configuration" +msgstr "Configurazione board aggiornata" + +msgid "Updated global configuration" +msgstr "Configurazione globale aggiornata" + +msgid "Updated staff member" +msgstr "Membro dello staff aggiornato" + +msgid "Username" +msgstr "Nome utente" + +msgid "View catalog" +msgstr "Visualiza catalogo" + +msgid "View deleted thread" +msgstr "Visualizza thread cancellati" + +msgid "Welcome" +msgstr "Benevenuto" + +msgid "Word" +msgstr "Parola" + +msgid "Word successfully added." +msgstr "Parola aggiunta con successo." + +msgid "YOU ARE BANNED" +msgstr "TU SEI BANNATO" + +msgid "Yes" +msgstr "Si" + +msgid "You are not a moderator of this board." +msgstr "Non sei un moderatore di questa board." + +msgid "You must enter a subject." +msgstr "Devi inserire un oggetto." + +msgid "forever" +msgstr "per sempre" + +msgid "translator-credits" +msgstr "" +"Launchpad Contributions:\n" +" tj9991 \n" +"\n" +"Launchpad Contributions:\n" +" Emanuele Gentili https://launchpad.net/~emgent\n" +" Paolo Naldini https://launchpad.net/~hattory\n" +" tj9991 https://launchpad.net/~tslocum" + diff --git a/inc/lang/ja/LC_MESSAGES/kusaba.po b/inc/lang/ja/LC_MESSAGES/kusaba.po new file mode 100644 index 0000000..0682c0a --- /dev/null +++ b/inc/lang/ja/LC_MESSAGES/kusaba.po @@ -0,0 +1,210 @@ +msgid "" +msgstr "" +"Project-Id-Version: trevorchan\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2007-12-09 03:10+0000\n" +"PO-Revision-Date: 2008-03-10 04:45+0000\n" +"Last-Translator: tj9991 \n" +"Language-Team: Japanese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2008-03-12 04:24+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +msgid "(for post and file deletion)" +msgstr "(記事の削除用)" + +msgid "Add" +msgstr "追加" + +msgid "Administration" +msgstr "管理" + +msgid "Administrator" +msgstr "管理者" + +msgid "Administrators" +msgstr "管理者" + +msgid "All boards" +msgstr "全ての板" + +msgid "Board" +msgstr "板" + +msgid "Boards" +msgstr "板" + +msgid "Captcha" +msgstr "Captcha" + +msgid "Catalog Mode" +msgstr "カタログモード" + +msgid "Click Reply to view." +msgstr "全て読むには返信ボタンを押してください。" + +msgid "Date" +msgstr "日付" + +msgid "Delete" +msgstr "削除" + +msgid "Delete post" +msgstr "記事削除" + +msgid "Email" +msgstr "E-メール" + +msgid "Embed" +msgstr "埋め込み" + +msgid "File" +msgstr "画像ファイル名" + +msgid "Home" +msgstr "ホーム" + +msgid "Image" +msgstr "画像" + +msgid "Images" +msgstr "画像" + +msgid "Incorrect password." +msgstr "パスワードが違います。" + +msgid "Incorrect username/password." +msgstr "ユーザー名またはパスワードが違います。" + +msgid "Invalid session." +msgstr "無効なセッションです。" + +msgid "Lock" +msgstr "ロック" + +msgid "Log in again." +msgstr "再度ログインしてください。" + +msgid "Manage" +msgstr "管理" + +msgid "Message" +msgstr "内容" + +msgid "Misc" +msgstr "その他" + +msgid "Moderates" +msgstr "モデレート" + +msgid "Moderating boards" +msgstr "板をモデレートする" + +msgid "Moderation" +msgstr "モデレーション" + +msgid "Moderator" +msgstr "モダレータ" + +msgid "Moderators" +msgstr "モデレータ" + +msgid "Name" +msgstr "名前" + +msgid "Next" +msgstr "次に" + +msgid "No" +msgstr "いいえ" + +msgid "No File" +msgstr "ファイルなし" + +msgid "No boards" +msgstr "板無し" + +msgid "Password" +msgstr "パスワード" + +msgid "Post" +msgstr "投稿" + +msgid "Posting mode: Reply" +msgstr "レス送信モード" + +msgid "Posts" +msgstr "投稿" + +msgid "Preview" +msgstr "プレビュー" + +msgid "Previous" +msgstr "前" + +msgid "Quick Reply" +msgstr "簡単な返信" + +msgid "Remove" +msgstr "削除" + +msgid "Replies" +msgstr "返信" + +msgid "Reply" +msgstr "返信" + +msgid "Return" +msgstr "戻る" + +msgid "Size" +msgstr "サイズ" + +msgid "Sorry, a generic error has occurred." +msgstr "すいません、一般的なエラーが発生しました。" + +msgid "Subject" +msgstr "題名" + +msgid "Submit" +msgstr "送信" + +msgid "Tag" +msgstr "タグ" + +msgid "Thread" +msgstr "スレッド" + +msgid "Threads" +msgstr "スレッド" + +msgid "Username" +msgstr "ユーザー名" + +msgid "Yes" +msgstr "はい" + +msgid "and" +msgstr "と" + +msgid "log in" +msgstr "ログイン" + +msgid "log out" +msgstr "ログアウト" + +msgid "omitted" +msgstr "省略" + +msgid "translator-credits" +msgstr "" +"Launchpad Contributions:\n" +" p \n" +" tj9991 \n" +"\n" +"Launchpad Contributions:\n" +" Nazo https://launchpad.net/~lovesyao\n" +" tj9991 https://launchpad.net/~tslocum" + diff --git a/inc/lang/nb/LC_MESSAGES/kusaba.po b/inc/lang/nb/LC_MESSAGES/kusaba.po new file mode 100644 index 0000000..dfa8638 --- /dev/null +++ b/inc/lang/nb/LC_MESSAGES/kusaba.po @@ -0,0 +1,1051 @@ +msgid "" +msgstr "" +"Project-Id-Version: kusaba\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2007-12-09 03:10+0000\n" +"PO-Revision-Date: 2007-12-09 14:37+0000\n" +"Last-Translator: Jonas Braathen \n" +"Language-Team: Norwegian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2008-03-12 04:24+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +msgid "%s not implemented." +msgstr "%s ikke implementert." + +msgid "(for post and file deletion)" +msgstr "(for innleggs- og filsletting)" + +msgid "

Add News Post

This message will be displayed as it is written, so make sure you add the proper HTML." +msgstr "

Legg til nyhet

Denne meldingen vil vises slik den er skrevet, så vær sikker på at du legger til riktig HTML." + +msgid "A board with that name already exists." +msgstr "En kategori med det navnet finnes allerede." + +msgid "A board with that name does not exist." +msgstr "En kategori med det navnet finnes ikke." + +msgid "A message is required to post without a file." +msgstr "En melding er nødvendig for å sende et innlegg uten en fil." + +msgid "A post with that ID does not exist." +msgstr "Et inlegg med den ID-en finnes ikke." + +msgid "A staff member with that ID already exists." +msgstr "En ansatt med den ID-en finnes allerede." + +msgid "A staff member with that id does not appear to exist." +msgstr "En ansatt med den ID-en ser ikke ut til å eksistere." + +msgid "Add" +msgstr "Legg til" + +msgid "Add ban" +msgstr "Legg til utestengelse" + +msgid "Add board" +msgstr "Legg til kategori" + +msgid "Add news" +msgstr "Legg til nyhet" + +msgid "Add staff member" +msgstr "Legg til ansatt" + +msgid "Add word" +msgstr "Legg til ord" + +msgid "Added a news entry" +msgstr "La til en nyhet" + +msgid "Added board" +msgstr "La til kategori" + +msgid "Added on" +msgstr "Lagt til" + +msgid "Added staff member" +msgstr "La til en ansatt" + +msgid "Admin" +msgstr "Admin" + +msgid "Administration" +msgstr "Administrering" + +msgid "Administrator" +msgstr "Administrator" + +msgid "Administrators" +msgstr "Administratorer" + +msgid "All Threads" +msgstr "Alle temaer" + +msgid "All boards" +msgstr "Alle kategorier" + +msgid "All threads/posts by that IP in selected boards successfully deleted." +msgstr "Slettingen av alle temaene/innleggene lagt til med den IP-en var vellykket." + +msgid "Already posted %shere%s." +msgstr "Allerede lagt til %sher%s." + +msgid "An image, or message, is required for a reply." +msgstr "Et bilde eller en melding er påkrevet for et svar." + +msgid "Anonymous" +msgstr "Anonym" + +msgid "Ban from" +msgstr "Utesteng fra" + +msgid "Ban successfully placed." +msgstr "Utestengelse satt." + +msgid "Ban successfully removed." +msgstr "Utestengelse fjernet." + +msgid "Banned" +msgstr "Utestengt" + +msgid "Banned from" +msgstr "Utestengt fra" + +msgid "Board" +msgstr "Kategori" + +msgid "Board options" +msgstr "Kategoriopsjoner" + +msgid "Board successfully added." +msgstr "Kategori lagt til." + +msgid "Board type:" +msgstr "Kategoritype:" + +msgid "Boards" +msgstr "Kategorier" + +msgid "Cache successfully flushed." +msgstr "Mellomlagring slettet." + +msgid "Can be left blank." +msgstr "Kan forbli blank." + +msgid "Can not be left blank." +msgstr "Kan ikke forbli blank." + +msgid "Cancel" +msgstr "Avbryt" + +msgid "Captcha" +msgstr "Captcha" + +msgid "Change account password" +msgstr "Endre passord på konto" + +msgid "Check for new version" +msgstr "Sjekk for ny versjon." + +msgid "Cleanup" +msgstr "Rydd opp" + +msgid "Cleanup finished." +msgstr "Opprydning ferdig" + +msgid "Click Reply to view." +msgstr "Klikk for å vise" + +msgid "Click to show/hide" +msgstr "Klikk for å vise/skjule" + +msgid "Continue" +msgstr "Fortsett" + +msgid "Could not copy uploaded image." +msgstr "Kunne ikke kopiere det opplastede bildet" + +msgid "Could not create thumbnail." +msgstr "Kunne ikke lage miniatyrbilde." + +msgid "Current version:" +msgstr "Nåværende versjon:" + +msgid "Date" +msgstr "Dato" + +msgid "Days to keep modlog entries" +msgstr "Dager moderatorlogger skal beholdes" + +msgid "Default" +msgstr "Standard" + +msgid "Default style:" +msgstr "Standar stil:" + +msgid "Delete" +msgstr "Slett" + +msgid "Delete all posts by IP" +msgstr "Slett alle innlegg etter IP" + +msgid "Delete all posts by this IP" +msgstr "Slett alle poster med denne IP-en" + +msgid "Delete board" +msgstr "Slett kategori" + +msgid "Delete post" +msgstr "Slett innlegg" + +msgid "Delete posts" +msgstr "Slett innlegg" + +msgid "Delete thread" +msgstr "Slett emne" + +msgid "Delete thread/post" +msgstr "Slett emne/innlegg" + +msgid "Deleted board" +msgstr "Slettet kategori" + +msgid "Deleted post" +msgstr "Slettet innlegg" + +msgid "Deleted posts by ip" +msgstr "Slettet innlegg etter IP" + +msgid "Deleted staff member" +msgstr "slettet en ansatt" + +msgid "Deleted thread" +msgstr "Slettet emne" + +msgid "Description" +msgstr "Beskrivelse" + +msgid "Directory" +msgstr "Katalog" + +msgid "Disk space used" +msgstr "Diskforbruk" + +msgid "Does not expire" +msgstr "Utgår ikke" + +msgid "Duplicate file entry detected." +msgstr "To like filer detektert." + +msgid "Edit" +msgstr "Rediger" + +msgid "Edit word" +msgstr "Editer ord" + +msgid "Email" +msgstr "E-post" + +msgid "Embed" +msgstr "Innfell" + +msgid "Embedding only" +msgstr "Kunn innfelte" + +msgid "Enable \"no file\" posting" +msgstr "Sett til «ingen fil» innlegg" + +msgid "Enable captcha:" +msgstr "Skru på CAPTCHA:" + +msgid "Enable reporting:" +msgstr "Skru på rapportering:" + +msgid "Enable/disable captcha system for this board. If captcha is enabled, in order for a user to post, they must first correctly enter the text on an image." +msgstr "Skru på/av CAPTCHA-systemet for denne kategorien. Hvis CAPTCHA er på, for å sende inn et innlegg, må de først gjengi teksten i bildet korrekt." + +msgid "Error, it appears your file did not transfer properly. Please go back and try again." +msgstr "Feil: Det virker som om filen din ikke ble overført riktig. Vennligst gå tilbake og prøv igjen." + +msgid "Expires:" +msgstr "Utgår:" + +msgid "Extension icon displayed, click image to open file." +msgstr "Filtypeikon vist, klikk på bildet for å åpne filen." + +msgid "File" +msgstr "Fil" + +msgid "File Only" +msgstr "Kun fil" + +msgid "File was not fully uploaded. Please go back and try again." +msgstr "Filen ble ikke fullstendig opplastet. Vennligst gå tilbake og prøv igjen." + +msgid "Filetype added." +msgstr "Filtype lagt til." + +msgid "Filetype deleted." +msgstr "Filtype slettet." + +msgid "Filetype updated." +msgstr "Filtype oppdatert." + +msgid "Forced anonymous" +msgstr "Tvunget anonymitet" + +msgid "Front Page" +msgstr "Forsiden" + +msgid "Get posting password" +msgstr "Få innleggspassord" + +msgid "Global configuration succesfully updated." +msgstr "Global konfigurasjon oppdatert." + +msgid "Global options" +msgstr "Globale opsjoner" + +msgid "Go" +msgstr "Utfør" + +msgid "Header image" +msgstr "Overskriftsbilde" + +msgid "Hide Directories" +msgstr "Skjul kataloger" + +msgid "Home" +msgstr "Hjem" + +msgid "ID" +msgstr "ID" + +msgid "IP" +msgstr "IP" + +msgid "If set to yes, new threads will not require an image to be posted." +msgstr "Hvis satt til ja vil nye emner ikke kreve et bilde." + +msgid "If set to yes, this board will appear in bold in the menu" +msgstr "Hvis satt til ja vil denne kategorien vises i uthevet skrift" + +msgid "If set to yes, this board will appear in italics in the menu" +msgstr "Hvis satt til ja vil denne kategorien vises i kursiv skrift" + +msgid "If set to yes, users will be redirected to the thread they replied to/posted after posting. If set to no, users will be redirected to the first page of the board." +msgstr "Hvis satt til ja vil brukere bli redirigert til emnet de svarte på etter at det er sendt inn. Hvis satt til nei vil brukere bli redirigert til den første siden i kategorien." + +msgid "If set to yes, users will not be allowed to enter a name, making everyone appear as Anonymous" +msgstr "Hvis satt til ja vil brukere ikke kunne sette inn et navn, noe som får alle til å virke anonyme." + +msgid "Image" +msgstr "Bilde" + +msgid "Image successfully deleted from your post." +msgstr "Bildesletting vellykket." + +msgid "Images" +msgstr "Bilder" + +msgid "Images and embedding" +msgstr "Bilder og innfelling" + +msgid "Improper filetype." +msgstr "Ugyldig filtype." + +msgid "Include header" +msgstr "Overskriftsinkludering" + +msgid "Incorrect password." +msgstr "Ugyldig passord." + +msgid "Incorrect username/password." +msgstr "Ugyldig brukernavn/passord." + +msgid "Index" +msgstr "Indeks" + +msgid "Inject" +msgstr "Injiser" + +msgid "Integer values must be entered correctly." +msgstr "Numeriske verdier må være skrevet korrekt." + +msgid "Invalid ID" +msgstr "Ugyldig ID" + +msgid "Invalid ban ID" +msgstr "Ugildig utestengelsesid" + +msgid "Invalid board directory." +msgstr "Ugyldig kategorikatalog." + +msgid "Invalid response code:" +msgstr "Ugyldig responskode." + +msgid "Invalid session." +msgstr "Ugyldig sesjon" + +msgid "Invalid staff ID." +msgstr "Ugyldig ansattes ID." + +msgid "Invalid thread ID. This may have been caused by the thread recently being deleted." +msgstr "Ugyldig tema-ID. Dette kan ha vært forårsaket av at temaet nylig ble slettet." + +msgid "Invalid video ID." +msgstr "Ugildig video-ID" + +msgid "Invalid video type." +msgstr "Ugyldig videotype." + +msgid "Is replaced by" +msgstr "Er erstattet av" + +msgid "Last Post" +msgstr "Siste innlegg" + +msgid "Lock" +msgstr "Lås" + +msgid "Locked" +msgstr "Låst" + +msgid "Locked thread" +msgstr "Låste emne" + +msgid "Log in again." +msgstr "Logg inn igjen." + +msgid "Logged in" +msgstr "Logget inn" + +msgid "Logo" +msgstr "Logo" + +msgid "Manage boards" +msgstr "Administrer kategorier." + +msgid "Manage locked threads" +msgstr "Moderer låste emner" + +msgid "Manage stickies" +msgstr "Moderer prioriterte emner" + +msgid "Maximum board pages" +msgstr "Maksimum antall kategorisider" + +msgid "Maximum image size" +msgstr "Maksimum bildestørelse" + +msgid "Maximum message length" +msgstr "Maksimum innlegsslengde" + +msgid "Maximum thread age (Hours)" +msgstr "Maksimum emnealder (Timer)" + +msgid "Maximum thread replies" +msgstr "Maksimum emnesvar." + +msgid "Maxmimum size of uploaded images, in bytes." +msgstr "Maksimum størelse på de opplastede bildene i bytes" + +msgid "Maxmimum thumbnail height" +msgstr "Maksmimum miniatyrbildehøyde" + +msgid "Maxmimum thumbnail width" +msgstr "Maksimum miniatyrbildebredde" + +msgid "Message" +msgstr "Melding" + +msgid "Misc" +msgstr "Diverse" + +msgid "Mod" +msgstr "Mod" + +msgid "ModLog" +msgstr "Moderatorlogg" + +msgid "Moderates" +msgstr "Modererer" + +msgid "Moderating boards" +msgstr "Modererer kategorier" + +msgid "Moderation" +msgstr "Moderering" + +msgid "Moderator" +msgstr "Moderator" + +msgid "Moderators" +msgstr "Moderatorer" + +msgid "Modify staff member" +msgstr "Modifiser ansatt" + +msgid "More" +msgstr "Flere" + +msgid "NOTICE: You are using the default administrator account. Anyone can log in to this account, so a second administrator account needs to be created. Create another, log in to it, and delete this one." +msgstr "MERK: Du bruker den standar administratorkontoen. Alle kan logge inn på denne, så en administratorkonto nummer to må lages. Lag en ny, logg inn, og slett denne." + +msgid "Name" +msgstr "Navn" + +msgid "Never" +msgstr "Aldri" + +msgid "New Thread" +msgstr "Nytt tema" + +msgid "New password" +msgstr "Nytt passord" + +msgid "New password again" +msgstr "Nytt passord igjen" + +msgid "News" +msgstr "Nyheter" + +msgid "News entry successfully added." +msgstr "Nyhet lagt til." + +msgid "Next" +msgstr "Neste" + +msgid "No" +msgstr "Nei" + +msgid "No File" +msgstr "Ingen fil" + +msgid "No boards" +msgstr "Ingen kategorier" + +msgid "No embedding" +msgstr "Ingen innfelling" + +msgid "No visible boards" +msgstr "Ingen synlige kategorier" + +msgid "None" +msgstr "Ingen" + +msgid "Normal imageboard" +msgstr "Normal bildekategori" + +msgid "Oekaki imageboard" +msgstr "Oekakibildekategori" + +msgid "Old password" +msgstr "Gammelt passord" + +msgid "Only moderators of the board and admins can make new posts/replies" +msgstr "Kun moderatorene over kategoriene og administratorene kan lage nye innlegg." + +msgid "Open images in new window" +msgstr "Åpne bilder i et nytt vindu" + +msgid "Order" +msgstr "Rekkefølge" + +msgid "Order to show board in menu list, in ascending order." +msgstr "Rekkefølgen som kategoriene skal vises i, i stigende rekkefølge." + +msgid "Overrides the header set in the config file. Leave blank to use configured global header image. Needs to be a full url including http://. Set to none to show no header image." +msgstr "Overskrider overskriften som er i konfigurasjonsfilen. La den være blank for å bruke den globale overskriften. Må være en full URL inkludert «http://». Sett til ingen for å ikke vise et overskriftsbilde." + +msgid "Password" +msgstr "Passord" + +msgid "Password successfully changed." +msgstr "Endring av passord fullført." + +msgid "Placed:" +msgstr "Satt:" + +msgid "Please enter a positive amount of seconds, or zero for a permanent ban." +msgstr "Vennligst sett inn et positivt antall sekunder, eller null for en permanent utestengelse." + +msgid "Please enter a search query." +msgstr "Vennligst sett inn en søkestreng." + +msgid "Please fill in all required fields." +msgstr "Vennligst fyll inn alle nødvendige felt." + +msgid "Please make sure your file is smaller than %dB" +msgstr "Vennligst sjekk at filen din er mindre enn %dB" + +msgid "Please select a board." +msgstr "Vennligst velg en kategori." + +msgid "Please select only one image to upload." +msgstr "Vennligst velg kun ett bilde for opplasting." + +msgid "Popular" +msgstr "Populær" + +msgid "Post" +msgstr "Innlegg" + +msgid "Post preview" +msgstr "Forhåndsvisning av innlegg" + +msgid "Post successfully deleted." +msgstr "Innlegg slettet." + +msgid "Postbox notice" +msgstr "Bostboks notis" + +msgid "Posting a blacklisted link." +msgstr "Postet en svartelistet link." + +msgid "Posting mode: Reply" +msgstr "Innleggsmodus: Svar" + +msgid "Posting rates (past hour)" +msgstr "Innleggsrater (forrige time)" + +msgid "Posts" +msgstr "Innlegg" + +msgid "Presets" +msgstr "Forhåndsvalg" + +msgid "Preview" +msgstr "Forhåndsvisning" + +msgid "Previous" +msgstr "Forrige" + +msgid "Query" +msgstr "Spørring" + +msgid "Query executed successfully" +msgstr "Spørring gjennomført" + +msgid "Quick Reply" +msgstr "Hurtigsvar" + +msgid "Ran cleanup" +msgstr "Kjørte opprydning" + +msgid "Raw HTML which will be inserted at the top of each page of the board." +msgstr "Rå HTML som skal settes på toppen av hver side." + +msgid "Read this thread from the beginning" +msgstr "Les dette emnet fra begynnelsen" + +msgid "Reason" +msgstr "Årsak" + +msgid "Reason:" +msgstr "Årsak:" + +msgid "Rebuild complete. Took %d seconds." +msgstr "Gjenoppbygging ferdig. Tok %d sekunder." + +msgid "Rebuilt all boards and threads" +msgstr "Gjenoppbygget alle kategoriene og emnene" + +msgid "Redirect to thread" +msgstr "Rediriger til emne" + +msgid "Redirecting" +msgstr "Redirigerer" + +msgid "Regenerated %s" +msgstr "Regenererte %s" + +msgid "Remove" +msgstr "Fjern" + +msgid "Removed word from wordfilter" +msgstr "Fjernet et ord i ordfilteret" + +msgid "Replies" +msgstr "Svar" + +msgid "Replies displayed per stickied thread (in thread list)" +msgstr "Svar vist per prioriterte emne (i emnelisten)" + +msgid "Replies displayed per thread (in thread list)" +msgstr "Svar vist per emne (i emnelisten)" + +msgid "Reply" +msgstr "Svar" + +msgid "Report" +msgstr "Rapporter" + +msgid "Reporting allows users to report posts, adding the post to the report list." +msgstr "Rapportering tillater brukere å rapportere innlegg, noe som legger til innleggene på rapporteringslisten." + +msgid "Results" +msgstr "Resultater" + +msgid "Return" +msgstr "Returner" + +msgid "SQL query" +msgstr "SQL-spørring" + +msgid "Search" +msgstr "Søk" + +msgid "Search posts" +msgstr "Søk i innleggene" + +msgid "Seconds" +msgstr "Sekunder" + +msgid "Section" +msgstr "Seksjon" + +msgid "Section added." +msgstr "Seksjon lagt til." + +msgid "Section deleted." +msgstr "Seksjon slettet." + +msgid "Section updated." +msgstr "Seksjon oppdatert." + +msgid "Show Directories" +msgstr "Vis kataloger" + +msgid "Show Posting Password" +msgstr "Vis innlegspassordet" + +msgid "Shown below" +msgstr "Vist nedenfor" + +msgid "Size" +msgstr "Størrelse" + +msgid "Sorry, a generic error has occurred." +msgstr "Beklager, en ukjent feil oppstod." + +msgid "Sorry, because of your numerous failed logins, you have been locked out from logging in for 20 minutes. Please wait and then try again." +msgstr "Beklager, grunnet dine gjentatte innloggingsforsøk har du nå blitt utestengt i 20 minutter. Vennligst vent til da og prøv igjen." + +msgid "Sorry, that filetype is not allowed on this board." +msgstr "Beklager, den filtypen er ikke tillat i denne kategorien." + +msgid "Sorry, this board is locked and can not be posted in." +msgstr "Beklager, denne kategorien er låst og kan ikke bli postet i." + +msgid "Sorry, this thread is locked and can not be replied to." +msgstr "Beklager, dette temaet er låst og kan ikke bli svart på." + +msgid "Sorry, your message is too long. Message length: %d, maxmimum allowed length: %d" +msgstr "Beklager, meldingen din er for lang. Din melding: %d, maksimum meldingslengde: %d" + +msgid "Sorry, your search returned zero results." +msgstr "Beklager, søket ditt returnerte null resultater." + +msgid "Staff" +msgstr "Ansatte" + +msgid "Staff member successfully added." +msgstr "Ansatt lagt til." + +msgid "Staff rights" +msgstr "Ansattes rettigheter" + +msgid "Staff successfully deleted" +msgstr "Ansatt slettet" + +msgid "Staff successfully updated" +msgstr "Oppdatering av ansatte vellykket." + +msgid "Stickied" +msgstr "Prioritert" + +msgid "Stickied thread" +msgstr "Prioriterte emnet" + +msgid "Sticky" +msgstr "Prioriter" + +msgid "Subject" +msgstr "Tittel" + +msgid "Tag" +msgstr "Tag" + +msgid "Text board" +msgstr "Tekstkategori" + +msgid "That ID does not exist." +msgstr "Den ID-en finnes ikke." + +msgid "That ID is a reply, not a thread." +msgstr "Den ID-en er et innlegg, ikke et tema." + +msgid "That IP has already been banned." +msgstr "Den IP-en er allerede utestengt." + +msgid "That post has been cleared as not requiring any deletion." +msgstr "Det innlegget har allerede blitt klarert og krevde ikke sletting." + +msgid "That post is already in the report list." +msgstr "Det innlegget er allerede i rapporteringslisten." + +msgid "That thread has yet to be deleted." +msgstr "Det temaet er ikke slettet enda." + +msgid "That video ID has already been posted %shere%s." +msgstr "Den video-ID-en har allerede blitt lagt til %sher%s." + +msgid "That word already exists." +msgstr "Det ordet finnes allerede." + +msgid "The 5 newest replies are shown below." +msgstr "De 5 nyeste innleggene er vist under." + +msgid "The directory of the board." +msgstr "Katalogen til kategorien." + +msgid "The name of the board." +msgstr "Navnet på kategorien." + +msgid "The number of replies a thread can have before autosaging to the back of the board." +msgstr "Antall svar et emne kan ha før det autosages til slutten av kategorien." + +msgid "The old password you provided did not match the current one." +msgstr "Det gamle passordet du oppgav stemmer ikke overens med det du har nå." + +msgid "The second password did not match the first." +msgstr "Det andre passordet stemmer ikke overens med det første." + +msgid "The section the board is in. This is used for displaying the list of boards on the top and bottom of pages." +msgstr "Seksjonen kategorien er i. Dette er brukt for å vise listen over kategoriene på toppen og bunnen av sidene." + +msgid "The style which will be set when the user first visits the board." +msgstr "Den stilen som vil bli benyttet når en bruker besøker kategorien for første gang." + +msgid "The type of posts which will be accepted on this board. A normal imageboard will feature image and extended format posts, a text board will have no images, and an Oekaki board will allow users to draw images and use them in their posts." +msgstr "Typer innlegg som vil bli akseptert i denne kategorien. En normal bildekategori vil inneholde bilder og formaterte innlegg, en tekstkategori vil ha ingen bilder, og en Oekakikategori vil tillate brukere å tegne bilder og bruke dem i innleggene sine." + +msgid "There are currently no bans." +msgstr "Det er foreløpig ingen utestengelser." + +msgid "There are currently no filetypes." +msgstr "Det er foreløpig ingen filtyper." + +msgid "There are currently no sections." +msgstr "det er foreløpig ingen seksjoner." + +msgid "There are currently no threads to display." +msgstr "Det er foreløpig ingen emner å vise" + +msgid "There is already a file with that name." +msgstr "Det finnes allerede en fil med det navnet." + +msgid "There was an error in trying to delete your post" +msgstr "Det skjedde en feil i forsøket på å slettet ditt innlegg" + +msgid "This board does not allow post reporting." +msgstr "Denne kategorien tillater ikke at innlegg blir rapportert." + +msgid "This post has been deleted." +msgstr "Dette innlegget har blitt slettet." + +msgid "Thread" +msgstr "Tråd" + +msgid "Thread successfully deleted." +msgstr "Emne slettet." + +msgid "Thread successfully locked." +msgstr "Emne låst." + +msgid "Thread successfully stickied." +msgstr "Emnet ble prioritert." + +msgid "Thread successfully un-stickied" +msgstr "Emnet ble deprioritert" + +msgid "Thread successfully unlocked." +msgstr "Emne låst opp." + +msgid "Threads" +msgstr "Tråder" + +msgid "Threads displayed per page (in thread list)" +msgstr "Emner vist per side (i emnelisten)" + +msgid "Thumbnail displayed, click image for full size." +msgstr "Miniatyrbilde vist. Klikk for å vise det i full størelse." + +msgid "Trial" +msgstr "På prøve" + +msgid "Unable to clear cache: you do not have caching enabled." +msgstr "Kunne ikke slette mellomlagringen: Du har ikke mellomlagring skrudd på." + +msgid "Unable to connect to:" +msgstr "Kunne ikke koble til:" + +msgid "Unable to create directories." +msgstr "Kunne ikke lage katalogene." + +msgid "Unable to find record of your IP being banned." +msgstr "Kunne ikke finne noe som tyder på at din IP er utestengt." + +msgid "Unable to locate a board named" +msgstr "Kunne ikke lokalisere en kategori med navn" + +msgid "Unable to locate a filetype with that ID." +msgstr "Kunne ikke lokalisere en filtype med den ID-en." + +msgid "Unable to locate a section with that ID." +msgstr "Kunne ikke lokalisere en seksjon med den ID-en." + +msgid "Unable to locate that word." +msgstr "Kunne ikke lokalisere det ordet." + +msgid "Unable to report post. Please go back and try again." +msgstr "Kunne ikke rapportere innlegget. Vennligst gå tilbake og prøv igjen." + +msgid "Unbanned" +msgstr "Tilgitt" + +msgid "Unlock" +msgstr "Lås opp" + +msgid "Unlocked thread" +msgstr "Låste opp emnet" + +msgid "Unstickied thread" +msgstr "Deprioriterte emnet" + +msgid "Unsticky" +msgstr "De-prioriter" + +msgid "Update" +msgstr "Oppdater" + +msgid "Update successful." +msgstr "Oppdatering vellykket." + +msgid "Updated board configuration" +msgstr "Oppdaterte kategorikonfigurasjon" + +msgid "Updated global configuration" +msgstr "Oppdaterte global konfigurasjon" + +msgid "Updated staff member" +msgstr "Oppdaterte en ansatt" + +msgid "Updated word on wordfilter" +msgstr "Oppdaterte et ord i ordfileter" + +msgid "Upload type:" +msgstr "Opplastningstype:" + +msgid "Username" +msgstr "Brukernavn" + +msgid "View deleted thread" +msgstr "Vis slettede emner" + +msgid "View/Add/Remove bans" +msgstr "Vis/Legg til/Fjern utestengelser" + +msgid "Welcome" +msgstr "Velkommen" + +msgid "What filetypes users are allowed to upload." +msgstr "Hvilke filtyper brukerene kan laste opp." + +msgid "Whether or not to allow embedding of videos." +msgstr "Om det skal godkjennes innfellte videoer." + +msgid "Word" +msgstr "Ord" + +msgid "Word successfully added." +msgstr "Ord lagt til." + +msgid "Word successfully removed." +msgstr "Ord fjernet" + +msgid "Word successfully updated." +msgstr "Ord oppdatert." + +msgid "Wordfilter" +msgstr "Ordfilter" + +msgid "YOU ARE BANNED" +msgstr "DU ER UTESTENGT" + +msgid "YOU ARE NOT BANNED!" +msgstr "DU ER UTESTENGT!" + +msgid "Yes" +msgstr "Ja" + +msgid "You are banned from posting on:" +msgstr "Du er utestengt fra:" + +msgid "You are not a moderator of this board." +msgstr "du er ikke en moderator for denne kategorien." + +msgid "You can only delete posts from boards you moderate." +msgstr "Du kan bare slette innlegg fra kategorier du modererer." + +msgid "You can only make board specific bans to boards which you moderate." +msgstr "Du kan bare lage kategorispesifiserte utestengelser for kategorier du modererer." + +msgid "You have been successfully logged out." +msgstr "Utlogging vellykket." + +msgid "You must enter a subject." +msgstr "Du må skrive et tema." + +msgid "You searched for" +msgstr "Du søkte etter" + +msgid "Your post already doesn't have an image!" +msgstr "Ditt innlegg har ingen bilder å slette!" + +msgid "Your posting password" +msgstr "Ditt passord" + +msgid "and" +msgstr "og" + +msgid "forever" +msgstr "for alltid" + +msgid "log in" +msgstr "Logg inn." + +msgid "log out" +msgstr "Logg ut" + +msgid "omitted" +msgstr "hoppet over" + +msgid "or" +msgstr "eller" + +msgid "translator-credits" +msgstr "" +"Launchpad Contributions:\n" +" Amethana \n" +" tj9991 \n" +"\n" +"Launchpad Contributions:\n" +" Amethana https://launchpad.net/~amethana\n" +" Jonas Braathen https://launchpad.net/~braathen\n" +" Praetox https://launchpad.net/~xern01" + diff --git a/inc/lang/nl/LC_MESSAGES/kusaba.po b/inc/lang/nl/LC_MESSAGES/kusaba.po new file mode 100644 index 0000000..371e9e2 --- /dev/null +++ b/inc/lang/nl/LC_MESSAGES/kusaba.po @@ -0,0 +1,1054 @@ +msgid "" +msgstr "" +"Project-Id-Version: kusaba\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2007-12-09 03:10+0000\n" +"PO-Revision-Date: 2007-08-30 11:15+0000\n" +"Last-Translator: tj9991 \n" +"Language-Team: Dutch \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2008-03-12 04:24+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +msgid "%s bans not shown." +msgstr "%s bans niet getoond." + +msgid "%s not implemented." +msgstr "%s niet geimplementeerd." + +msgid "(for post and file deletion)" +msgstr "(voor post- en bestandsverwijdering)" + +msgid "

Add News Post

This message will be displayed as it is written, so make sure you add the proper HTML." +msgstr "

Voeg nieuwsbericht toe

Dit bericht wordt zichtbaar terwijl het wordt ingetypt, zorg er dus voor dat je de juiste HTML codes gebruikt." + +msgid "A board with that name already exists." +msgstr "Een board met die naam bestaat al." + +msgid "A board with that name does not exist." +msgstr "Een board met die naam bestaat niet." + +msgid "A message is required to post without a file." +msgstr "Een berichttekst is verplicht om te kunnen posten zonder bestand." + +msgid "A post with that ID does not exist." +msgstr "Een post met die ID bestaat niet." + +msgid "A staff member with that ID already exists." +msgstr "Een lid van de leiding met die ID bestaat al." + +msgid "A staff member with that id does not appear to exist." +msgstr "Een lid van de leiding met die ID lijkt niet te bestaan." + +msgid "Add" +msgstr "Voeg toe" + +msgid "Add ban" +msgstr "Voeg ban toe" + +msgid "Add board" +msgstr "Voeg board toe" + +msgid "Add news" +msgstr "Voeg nieuws toe" + +msgid "Add staff member" +msgstr "Voeg lid van de leiding toe" + +msgid "Add word" +msgstr "Voeg woord toe" + +msgid "Added a news entry" +msgstr "Nieuwsbericht toegevoegd" + +msgid "Added board" +msgstr "Board toegevoegd" + +msgid "Added on" +msgstr "Toegevoegd op" + +msgid "Added staff member" +msgstr "Lid van de leiding toegevoegd" + +msgid "Admin" +msgstr "Administrator" + +msgid "Administration" +msgstr "Beheer" + +msgid "Administrator" +msgstr "Beheerder" + +msgid "Administrators" +msgstr "Beheerders" + +msgid "All Threads" +msgstr "Alle discussies" + +msgid "All boards" +msgstr "Alle boards" + +msgid "All threads/posts by that IP in selected boards successfully deleted." +msgstr "Alle discussies / posts met die IP zijn succesvol verwijderd in de geselecteerde boards." + +msgid "Already posted %shere%s." +msgstr "Is %shier%s al gepost." + +msgid "An image, or message, is required for a reply." +msgstr "Een afbeelding of berichttekst is verplicht om een reaktie te kunnen plaatsen." + +msgid "Anonymous" +msgstr "Anoniem" + +msgid "Are you absolutely sure you want to delete %s?" +msgstr "Weet je zeker dat je %s wilt verwijderen?" + +msgid "Ban from" +msgstr "Ban van" + +msgid "Ban proxy list" +msgstr "Ban proxylijst" + +msgid "Ban successfully placed." +msgstr "Ban succesvol geplaatst." + +msgid "Ban successfully removed." +msgstr "Ban succesvol verwijderd." + +msgid "Banned" +msgstr "Gebanned" + +msgid "Banned from" +msgstr "Gebanned van" + +msgid "Board" +msgstr "Board" + +msgid "Board options" +msgstr "Board opties" + +msgid "Board successfully added." +msgstr "Board succesvol toegevoegd." + +msgid "Board successfully deleted." +msgstr "Board succesvol verwijderd." + +msgid "Board type:" +msgstr "Boardtype:" + +msgid "Boards" +msgstr "Boards" + +msgid "Cache successfully flushed." +msgstr "Cache succesvol gespoeld." + +msgid "Can be left blank." +msgstr "Kan worden leeggelaten." + +msgid "Can not be left blank." +msgstr "Kan niet worden leeggelaten." + +msgid "Captcha" +msgstr "Captcha" + +msgid "Catalog Mode" +msgstr "Catalogusmode" + +msgid "Change account password" +msgstr "Wijzig account wachtwoord" + +msgid "Check for new version" +msgstr "Controleer of er een nieuwe versie beschikbaar is." + +msgid "Cleanup" +msgstr "Opschoning" + +msgid "Cleanup finished." +msgstr "Opschoning voltooid." + +msgid "Click Reply to view, or %sexpand%s." +msgstr "Klik op Reageer" + +msgid "Click Reply to view." +msgstr "Klik op Reageer om te bekijken." + +msgid "Click to show/hide" +msgstr "Klik om te tonen of verbergen" + +msgid "Continue" +msgstr "Doorgaan" + +msgid "Could not copy uploaded image." +msgstr "Kon de geuploade afbeelding niet kopieren." + +msgid "Could not create thumbnail." +msgstr "Kon geen overzichtsafbeelding aanmaken." + +msgid "Current version:" +msgstr "Huidige versie:" + +msgid "Days to keep modlog entries" +msgstr "Aantal dagen om modlogberichten te bewaren" + +msgid "Default" +msgstr "Standaard" + +msgid "Default style:" +msgstr "Standaardstijl:" + +msgid "Delete" +msgstr "verwijder" + +msgid "Delete all posts by IP" +msgstr "Verwijder alle posts per IP" + +msgid "Delete all posts by this IP" +msgstr "Verwijder alle posts per IP" + +msgid "Delete board" +msgstr "Verwijder board" + +msgid "Delete post" +msgstr "Verwijder post" + +msgid "Delete posts" +msgstr "verwijder posts" + +msgid "Delete thread" +msgstr "Verwijder discussie" + +msgid "Delete thread/post" +msgstr "Verwijder discussie / post" + +msgid "Deleted board" +msgstr "Board verwijderd" + +msgid "Deleted post" +msgstr "Verwijderde post" + +msgid "Deleted posts by ip" +msgstr "Posts per IP verwijderd" + +msgid "Deleted staff member" +msgstr "Lid van de leiding verwijderd" + +msgid "Deleted thread" +msgstr "Verwijderde discussie" + +msgid "Deleting unused images." +msgstr "Bezig met verwijderen van ongebruikte afbeeldingen." + +msgid "Description" +msgstr "Omschrijving" + +msgid "Directory" +msgstr "Directory" + +msgid "Disk space used" +msgstr "Gebruikte diskruimte:" + +msgid "Does not expire" +msgstr "Verloopt nooit" + +msgid "Duplicate file entry detected." +msgstr "Dubbel bestand gevonden" + +msgid "Edit" +msgstr "Bewerken" + +msgid "Edit filetypes" +msgstr "Wijzig bestandstypes." + +msgid "Edit sections" +msgstr "Wijzig secties" + +msgid "Edit word" +msgstr "Wijzig woord" + +msgid "Email" +msgstr "E-mail" + +msgid "Embedding only" +msgstr "Alleen embedding" + +msgid "Enable \"no file\" posting" +msgstr "Sta het plaatsen van posts zonder bestanden toe" + +msgid "Enable captcha:" +msgstr "Schakel CAPTCHA in:" + +msgid "Enable reporting:" +msgstr "Schakel rapporteren in." + +msgid "Enable/disable captcha system for this board. If captcha is enabled, in order for a user to post, they must first correctly enter the text on an image." +msgstr "Schakel CAPTCHA in of uit voor dit board. Indien CAPTCHA aanstaat, dient een gebruiker een code in te voeren alvorens hij een bericht kan plaatsen." + +msgid "Entire Thread" +msgstr "Gehele discussie" + +msgid "Error, it appears your file did not transfer properly. Please go back and try again." +msgstr "Fout: het lijkt erop dat je bestand niet juist werd verzonden. Ga aub terug en probeer het nog eens." + +msgid "Expires:" +msgstr "Vervalt:" + +msgid "Extension icon displayed, click image to open file." +msgstr "Extensie-icoon weergegeven. Klik op het icoon om het bestand te openen." + +msgid "File" +msgstr "Bestand" + +msgid "File Only" +msgstr "Alleen bestand" + +msgid "File was not fully uploaded. Please go back and try again." +msgstr "Bestand werd niet volledig geupload. Ga aub terug en probeer het opnieuw." + +msgid "Filetype added." +msgstr "Filetype toegevoegd." + +msgid "Filetype deleted." +msgstr "Bestandstype verwijderd." + +msgid "Filetype updated." +msgstr "Bestandstype geupdate." + +msgid "First 100 posts" +msgstr "Eerste 100 posts" + +msgid "Forced anonymous" +msgstr "Geforceerd anoniem" + +msgid "Front Page" +msgstr "Voorpagina" + +msgid "Get posting password" +msgstr "Bemachtig posting wachtwoord" + +msgid "Global configuration succesfully updated." +msgstr "Globale configuratie succesvol geupdate." + +msgid "Global options" +msgstr "Globale opties" + +msgid "Go" +msgstr "Ga" + +msgid "Header image" +msgstr "Header-afbeelding" + +msgid "Hide Directories" +msgstr "Verberg directories" + +msgid "Home" +msgstr "Hoofdmenu" + +msgid "ID" +msgstr "ID" + +msgid "IP" +msgstr "IP" + +msgid "If set to yes, new threads will not require an image to be posted." +msgstr "Indien hier \"ja\" staat, kunnne nieuwe discussies geplaatst worden zonder dat een afbeelding is bijgevoegd." + +msgid "If set to yes, this board will appear in bold in the menu" +msgstr "Indien hier \"ja\" staat, verschijnt de naam van dit board vetgedrukt in het menu" + +msgid "If set to yes, this board will appear in italics in the menu" +msgstr "Indien hier \"ja\" staat, verschijnt de naam van dit board cursief in het menu." + +msgid "If set to yes, users will be redirected to the thread they replied to/posted after posting. If set to no, users will be redirected to the first page of the board." +msgstr "Indien hier \"ja\" staat, zullen gebruikers na het plaatsen van een reaktie, doorverwezen worden naar de discussie waarin zij hun reaktie plaatsen. Indien hier \"nee\" staat, worden zij na het plaatsen van een reaktie, doorverwezen naar de eerste pagina van het board." + +msgid "If set to yes, users will not be allowed to enter a name, making everyone appear as Anonymous" +msgstr "Indien hier \"ja\" staat, mogen gebruikers geen naam ingeven, waardoor iedereen anoniem wordt" + +msgid "Image successfully deleted from your post." +msgstr "Afbeelding succesvol verwijderd uit je submit." + +msgid "Images and embedding" +msgstr "Afbeeldingen en embedding" + +msgid "Improper filetype." +msgstr "Ongeldig bestandsformaat." + +msgid "Include header" +msgstr "Sluit header erbij in" + +msgid "Incorrect password." +msgstr "Ongeldig wachtwoord." + +msgid "Incorrect username/password." +msgstr "Ongeldige gebruikersnaam / ongeldig wachtwoord." + +msgid "Index" +msgstr "Index" + +msgid "Inject" +msgstr "Injecteer" + +msgid "Integer values must be entered correctly." +msgstr "Integerwaardes moeten op de juiste wijze worden ingegeven" + +msgid "Invalid ID" +msgstr "Ongeldige ID" + +msgid "Invalid MIME type for this filetype." +msgstr "Ongeldig MIME formaat voor dit bestandstype." + +msgid "Invalid ban ID" +msgstr "Ongeldige ban ID" + +msgid "Invalid board directory." +msgstr "Ongeldige boarddirectory." + +msgid "Invalid response code:" +msgstr "Ongeldige antwoordcode:" + +msgid "Invalid session." +msgstr "Ongeldige sessie." + +msgid "Invalid staff ID." +msgstr "Ongeldige leiding ID." + +msgid "Invalid thread ID. This may have been caused by the thread recently being deleted." +msgstr "Ongeldige discussie ID. Dit kan veroorzaakt zijn doordat de discussie recentelijk is verwijderd." + +msgid "Invalid video ID." +msgstr "Ongeldige video ID." + +msgid "Invalid video type." +msgstr "Ongeldig videoformaat." + +msgid "Is replaced by" +msgstr "Is vervangen door" + +msgid "Last 50 posts" +msgstr "Laatste 50 posts" + +msgid "Last Post" +msgstr "Laatste post" + +msgid "Lock" +msgstr "Vergrendel" + +msgid "Locked" +msgstr "Vergrendeld" + +msgid "Locked thread" +msgstr "Vergrendelde discussie" + +msgid "Log in again." +msgstr "Log opnieuw in." + +msgid "Logged in" +msgstr "Ingelogd" + +msgid "Manage boards" +msgstr "Berichtenboards" + +msgid "Manage locked threads" +msgstr "Onderhoud vergrendelde discussies" + +msgid "Manage stickies" +msgstr "Beheer stickies" + +msgid "Maximum board pages" +msgstr "Maximaal aanta boardpagina's" + +msgid "Maximum image size" +msgstr "Maximale afbeeldingsgrootte" + +msgid "Maximum message length" +msgstr "Maximale berichtlengte" + +msgid "Maximum thread age (Hours)" +msgstr "Maximale discussieleeftijd (Uren)" + +msgid "Maximum thread replies" +msgstr "Maximaal aantal reakties per discussie" + +msgid "Maxmimum size of uploaded images, in bytes." +msgstr "Maimale grootte van geuploade afbeeldingen in bytes." + +msgid "Maxmimum thumbnail height" +msgstr "Maximum hoogte van overzichtsafbeelding" + +msgid "Maxmimum thumbnail width" +msgstr "Maximum breedte van overzichtsafbeelding" + +msgid "Message" +msgstr "Bericht" + +msgid "Misc" +msgstr "Diversen" + +msgid "Mod" +msgstr "Mod" + +msgid "ModLog" +msgstr "ModLog" + +msgid "Moderates" +msgstr "Modereert" + +msgid "Moderating boards" +msgstr "Moderatieboards" + +msgid "Moderation" +msgstr "Moderatie" + +msgid "Moderator" +msgstr "Moderator" + +msgid "Moderators" +msgstr "Moderators" + +msgid "Modify staff member" +msgstr "Wijzig lid van de leiding" + +msgid "Module settings" +msgstr "Module-instellingen" + +msgid "Modules" +msgstr "Modules" + +msgid "NOTICE: You are using the default administrator account. Anyone can log in to this account, so a second administrator account needs to be created. Create another, log in to it, and delete this one." +msgstr "ATTENTIE: Je gebruikt momenteel het standaard beheerdersaccount. Iedereen kan met dit account inloggen. Maak dus een ander beheerdersaccount aan, log daarmee in en verwijder dit standaardaccount." + +msgid "Name" +msgstr "Naam" + +msgid "Never" +msgstr "Nooit" + +msgid "New Thread" +msgstr "Nieuwe discussie" + +msgid "New password" +msgstr "Nieuw wachtwoord" + +msgid "New password again" +msgstr "Nieuw wachtwoord nogmaals" + +msgid "News" +msgstr "Nieuws" + +msgid "News entry successfully added." +msgstr "Nieuwsbericht succesvol toegevoegd." + +msgid "Next" +msgstr "Volgende" + +msgid "No" +msgstr "Nee" + +msgid "No File" +msgstr "Geen bestand" + +msgid "No boards" +msgstr "Geen boards" + +msgid "No embedding" +msgstr "Geen embedding" + +msgid "No visible boards" +msgstr "Geen zichtbare boards" + +msgid "None" +msgstr "Geen" + +msgid "Normal imageboard" +msgstr "Normaal afbeeldingenboard" + +msgid "Oekaki imageboard" +msgstr "Oekaki afbeeldingenboard" + +msgid "Old password" +msgstr "Oud wachtwoord" + +msgid "Only moderators of the board and admins can make new posts/replies" +msgstr "Alleen moderators van dit board en administrators mogen nieuwe posts en reakties plaatsen." + +msgid "Open images in new window" +msgstr "Open afbeeldingen in een nieuw venster" + +msgid "Order" +msgstr "Volgorde" + +msgid "Order to show board in menu list, in ascending order." +msgstr "De volgorde waarin de boards in oplopende volgorde in de menulijst verschijnen." + +msgid "Overrides the header set in the config file. Leave blank to use configured global header image. Needs to be a full url including http://. Set to none to show no header image." +msgstr "Overschrijft de globale standaardheader die gedefineerd staat in het configuratiebestand. Laat dit veld leeg om die globale standaardheader te gebruiken. Indien dit veld gebruikt wordt, dient een volledige URL naar het te gebruiken bestand ingevuld te worden, inclusief HTTP://. Plaats de waarde \"none\" om helemaal geen header te tonen." + +msgid "Password" +msgstr "Wachtwoord" + +msgid "Password successfully changed." +msgstr "Wachtwoord succesvol gewijzigd." + +msgid "Placed:" +msgstr "Geplaatst:" + +msgid "Please enter a positive amount of seconds, or zero for a permanent ban." +msgstr "Voer aub een positief aantal seconden in, of voer het cijfer nul in voor een permanente ban." + +msgid "Please enter a search query." +msgstr "Voer aub een zoekopdracht in." + +msgid "Please fill in all required fields." +msgstr "Vul aub alle vereiste velden in." + +msgid "Please make sure your file is smaller than %dB" +msgstr "Zorg er aub voor dat je bestand kleiner is dan %dB." + +msgid "Please select a board." +msgstr "Selecteer een board aub." + +msgid "Please select only one image to upload." +msgstr "Selecteer aub slechts een afbeelding om te uploaden." + +msgid "Popular" +msgstr "Populair" + +msgid "Post" +msgstr "Submit" + +msgid "Post successfully deleted." +msgstr "Submit succesvol verwijderd." + +msgid "Postbox notice" +msgstr "Postbus indicator" + +msgid "Posting a blacklisted link." +msgstr "Bezig met posten van een link die op de zwarte lijst staat." + +msgid "Posting mode: Reply" +msgstr "Posting mode: Reageer" + +msgid "Posting rates (past hour)" +msgstr "Vertalerskrediet" + +msgid "Posts" +msgstr "Submits" + +msgid "Presets" +msgstr "Voorinstellingen" + +msgid "Previous" +msgstr "Vorige" + +msgid "Proxy list" +msgstr "Proxylijst" + +msgid "Query" +msgstr "Opdracht" + +msgid "Query executed successfully" +msgstr "Opdracht succesvol uitgevoerd" + +msgid "Quick Reply" +msgstr "Spoedreaktie" + +msgid "Ran cleanup" +msgstr "Heb opschoning uitgevoerd" + +msgid "Raw HTML which will be inserted at the top of each page of the board." +msgstr "Ruwe HTML die ingevoegd zal worden aan het begin van elke pagina van dit board." + +msgid "Read this thread from the beginning" +msgstr "Lees deze discussie vanaf het begin" + +msgid "Reason" +msgstr "Reden" + +msgid "Reason:" +msgstr "Reden:" + +msgid "Rebuild all html files" +msgstr "Rebuild alle HTML bestanden" + +msgid "Rebuild complete. Took %d seconds." +msgstr "Rebuild compleet. Duurde %d seconden." + +msgid "Rebuilt all boards and threads" +msgstr "Rebuild van alle boards en discussies voltooid." + +msgid "Redirect to thread" +msgstr "Doorverwijzen naar discussie" + +msgid "Redirecting" +msgstr "Bezig met doorverwijzen" + +msgid "Regenerated %s" +msgstr "%s geregenereerd" + +msgid "Regular expression" +msgstr "Reguliere expressie" + +msgid "Remove" +msgstr "Verwijder" + +msgid "Removed word from wordfilter" +msgstr "Woord uit woordfilter verwijderd" + +msgid "Replies" +msgstr "Reakties" + +msgid "Replies displayed per stickied thread (in thread list)" +msgstr "Reakties weergegeven per stickied discussie (in discussielijst)" + +msgid "Replies displayed per thread (in thread list)" +msgstr "Reakties weergegeven per discussie (in discussielijst)" + +msgid "Reply" +msgstr "Reaktie" + +msgid "Reporting allows users to report posts, adding the post to the report list." +msgstr "Rapporteren staat gebruikers toe om posts te rapporteren. Hierdoor wordt de betreffende post toegevoegd aan de rapportenlijst." + +msgid "Results" +msgstr "Resultaten" + +msgid "Return" +msgstr "Keer terug" + +msgid "SQL query" +msgstr "SQL query" + +msgid "Search posts" +msgstr "Zoek posts" + +msgid "Seconds" +msgstr "Seconden" + +msgid "Section" +msgstr "Sectie" + +msgid "Section added." +msgstr "Sectie toegevoegd" + +msgid "Section deleted." +msgstr "Sectie verwijderd" + +msgid "Section updated." +msgstr "Sectie geupdate" + +msgid "Show Directories" +msgstr "Toon directories" + +msgid "Show Posting Password" +msgstr "Toon posting wachtwoord" + +msgid "Shown below" +msgstr "Beneden getoond" + +msgid "Sorry, a generic error has occurred." +msgstr "Sorry, er is een algemene fout opgetreden." + +msgid "Sorry, because of your numerous failed logins, you have been locked out from logging in for 20 minutes. Please wait and then try again." +msgstr "Sorry, maar vanwege je veelvuldige foutieve loginpogingen ben je de komende 20 minuten buitensgesloten. Wacht aub en probeer het daarna opnieuw." + +msgid "Sorry, that filetype is not allowed on this board." +msgstr "Sorry, dat bestandsformaat wordt niet ondersteund op dit board." + +msgid "Sorry, this board is locked and can not be posted in." +msgstr "Sorry, dit board is vergrendeld. Er kunnen geen berichten in worden geplaatst." + +msgid "Sorry, this thread is locked and can not be replied to." +msgstr "Sorry, deze discussie is vergrendeld. Er kan niet in worden gereageerd." + +msgid "Sorry, your message is too long. Message length: %d, maxmimum allowed length: %d" +msgstr "Sorry, maar je bericht is te lang. De lengte is %d, het maximum is echter %d" + +msgid "Sorry, your search returned zero results." +msgstr "Sorry, maar je zoekopdracht leverde geen resultaten op." + +msgid "Staff" +msgstr "Leiding" + +msgid "Staff member successfully added." +msgstr "Lid van de leiding succesvol toegevoegd." + +msgid "Staff rights" +msgstr "Rechten van de leiding" + +msgid "Staff successfully deleted" +msgstr "Leiding succesvol verwijderd" + +msgid "Staff successfully updated" +msgstr "Lid van de leiding succesvol geupdate" + +msgid "Stickied" +msgstr "Stickied" + +msgid "Stickied thread" +msgstr "Stickied discussie" + +msgid "Sticky" +msgstr "Sticky" + +msgid "Subject" +msgstr "Onderwerp" + +msgid "Text board" +msgstr "Tekstboard" + +msgid "That ID does not exist." +msgstr "Die ID bestaat niet." + +msgid "That ID is a reply, not a thread." +msgstr "Die ID hoort bij reaktie, niet bij een discussie." + +msgid "That IP has already been banned." +msgstr "Die IP is al gebanned." + +msgid "That post has been cleared as not requiring any deletion." +msgstr "Bij die post staat aangegeven dat deze niet verwijderd hoeft te worden." + +msgid "That post is already in the report list." +msgstr "Die post is al in de rapportenlijst geplaatst." + +msgid "That thread has yet to be deleted." +msgstr "Die discussie moet nog worden verwijderd" + +msgid "That video ID has already been posted %shere%s." +msgstr "Die video ID is %shier%s al gepost." + +msgid "That word already exists." +msgstr "Dat woord bestaat al." + +msgid "The 5 newest replies are shown below." +msgstr "De laatste 5 reakties worden hier beneden weergegeven." + +msgid "The directory of the board." +msgstr "De directory van het board." + +msgid "The name of the board." +msgstr "De naam van het board." + +msgid "The number of replies a thread can have before autosaging to the back of the board." +msgstr "Het aantal reakties dat een discussie kan bevatten, voordat de discussie verplaatst wordt naar de laatste pagina van het board." + +msgid "The old password you provided did not match the current one." +msgstr "Het wachtwoord (oude) dat je invoerde, komt niet overeen met het wachtwoord dat je momenteel gebruikt." + +msgid "The second password did not match the first." +msgstr "De beide entries voor het nieuwe wachtwoord komen niet met elkaar overeen." + +msgid "The section the board is in. This is used for displaying the list of boards on the top and bottom of pages." +msgstr "De sectie waarin dit board zich bevind. DIt wordt gebruikt voor het weergeven van de boardlijst aan de boven- en onderzijde van de pagina's." + +msgid "The style which will be set when the user first visits the board." +msgstr "De stijl die ingesteld wordt wanneer de gebruiker dit board voor het eerst bezoekt." + +msgid "The type of posts which will be accepted on this board. A normal imageboard will feature image and extended format posts, a text board will have no images, and an Oekaki board will allow users to draw images and use them in their posts." +msgstr "Het type berichten dat geaccepteert wordt op dit board. Een normaal afbeeldingenboard accepteert afbeeldingen en berichten met uitgebreid tekstformaat. In een tekstboard kunnen geen afbeeldingen worden geplaatst en in een Oekakiboard mogen gebruikers zelf online tekeningen maken en in hun berichten plaatsen." + +msgid "There are currently no bans." +msgstr "Er zijn momenteel geen bans." + +msgid "There are currently no filetypes." +msgstr "Er zijn momenteel geen bestandstypes" + +msgid "There are currently no sections." +msgstr "Er zijn momenteel geen secties." + +msgid "There are currently no threads to display." +msgstr "Er zijn momenteel geen discussies om weer te geven." + +msgid "There is already a file with that name." +msgstr "Een bestand met die naam bestaat al." + +msgid "There was an error in trying to delete your post" +msgstr "Er trad een fout op tijdens het verwijderen van je submit" + +msgid "This board does not allow post reporting." +msgstr "Op dit board is het rapporteren van posts niet toegestaan." + +msgid "This post has been deleted." +msgstr "Deze post is verwijderd." + +msgid "Thread" +msgstr "Discussie" + +msgid "Thread successfully deleted." +msgstr "Discussie succesvol verwijderd." + +msgid "Thread successfully locked." +msgstr "Discussie succesvol vergrendeld." + +msgid "Thread successfully stickied." +msgstr "Discussie succesvol gestickied." + +msgid "Thread successfully un-stickied" +msgstr "Discussie succesvol ontstickied." + +msgid "Thread successfully unlocked." +msgstr "Discussie succesvol ontgrendeld." + +msgid "Threads" +msgstr "Discussies" + +msgid "Threads displayed per page (in thread list)" +msgstr "Discussies weergegeven per pagina (in discussielijst)" + +msgid "Thumbnail displayed, click image for full size." +msgstr "Overzichtsafbeelding weergegeven. Klik op afbeelding voor de volledige grootte." + +msgid "Trial" +msgstr "Proef" + +msgid "Unable to clear cache: you do not have caching enabled." +msgstr "Kan cache niet leegmaken: caching staat uit." + +msgid "Unable to connect to:" +msgstr "Kan geen verbinding maken met:" + +msgid "Unable to create directories." +msgstr "Kan geen directories aanmaken." + +msgid "Unable to delete board." +msgstr "Kan board niet verwijderen." + +msgid "Unable to find record of your IP being banned." +msgstr "Kan geen record vinden met daarin een vermelding dat je IP is gebanned." + +msgid "Unable to locate a board named" +msgstr "Kan geen board vinden genaamd" + +msgid "Unable to locate a filetype with that ID." +msgstr "Kan geen bestandstype vinden met die ID." + +msgid "Unable to locate a section with that ID." +msgstr "Kan geen sectie vinden met die ID." + +msgid "Unable to locate that word." +msgstr "Kan dat woord niet vinden." + +msgid "Unable to report post. Please go back and try again." +msgstr "Kan post niet rapporteren. Ga aub terug en probeer het opnieuw." + +msgid "Unbanned" +msgstr "Unbanned" + +msgid "Unlock" +msgstr "Ontgrendel" + +msgid "Unlocked thread" +msgstr "Ontgrendelde discussie" + +msgid "Unstickied thread" +msgstr "Unstickied discussie" + +msgid "Unsticky" +msgstr "Unsticky" + +msgid "Update" +msgstr "Update" + +msgid "Update successful." +msgstr "Update succesvol." + +msgid "Updated board configuration" +msgstr "Boardconfiguratie geupdate" + +msgid "Updated global configuration" +msgstr "Globale configuratie geupdate" + +msgid "Updated staff member" +msgstr "Lid van de leiding geupdate" + +msgid "Updated word on wordfilter" +msgstr "Woord in woordfilter geupdate." + +msgid "Upload type:" +msgstr "Upload type:" + +msgid "Username" +msgstr "Gebruikersnaam" + +msgid "View all bans" +msgstr "Bekijk alle bans" + +msgid "View deleted thread" +msgstr "Bijkijk verwijderde discussie" + +msgid "View/Add/Remove bans" +msgstr "Bekijk / Voeg toe / Verwijder bans" + +msgid "Welcome" +msgstr "Welkom" + +msgid "What filetypes users are allowed to upload." +msgstr "Welke bestandstypes gebruikers mogen uploaden." + +msgid "Whether or not to allow embedding of videos." +msgstr "Of het wel of niet is toegestaan om video's te embedden." + +msgid "Word" +msgstr "Woord" + +msgid "Word successfully added." +msgstr "Woord succesvol toegevoegd." + +msgid "Word successfully removed." +msgstr "Woord succesvol verwijderd." + +msgid "Word successfully updated." +msgstr "Woord succesvol geupdate." + +msgid "Wordfilter" +msgstr "Woordfilter" + +msgid "YOU ARE BANNED" +msgstr "JE HEBT EEN BAN" + +msgid "YOU ARE NOT BANNED!" +msgstr "JE HEBT GEEN BAN" + +msgid "Yes" +msgstr "Ja" + +msgid "You are banned from posting on:" +msgstr "je bent gebanned van het plaatsen van posts in:" + +msgid "You are not a moderator of this board." +msgstr "Je bent geen moderator van dit board." + +msgid "You can only delete posts from boards you moderate." +msgstr "Je mag alleen posts verwijderen van boards waarin je mag modereren." + +msgid "You can only make board specific bans to boards which you moderate." +msgstr "Je kunt alleen board-specifieke bans plaatsen, in de boards waarin je mag modereren." + +msgid "You have been successfully logged out." +msgstr "Je bent succesvol uitgelogd." + +msgid "You must enter a subject." +msgstr "Je moet een onderwerp ingeven." + +msgid "You searched for" +msgstr "Je zocht voor" + +msgid "Your post already doesn't have an image!" +msgstr "Je submit heeft al geen afbeelding." + +msgid "Your posting password" +msgstr "Je berichtenwachtwoord" + +msgid "forever" +msgstr "voor altijd" + +msgid "log out" +msgstr "Log uit" + +msgid "translator-credits" +msgstr "" +"Launchpad Contributions:\n" +" tj9991 https://launchpad.net/~tslocum" + diff --git a/inc/lang/pl/LC_MESSAGES/kusaba.po b/inc/lang/pl/LC_MESSAGES/kusaba.po new file mode 100644 index 0000000..0a76a60 --- /dev/null +++ b/inc/lang/pl/LC_MESSAGES/kusaba.po @@ -0,0 +1,1070 @@ +msgid "" +msgstr "" +"Project-Id-Version: trevorchan\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2007-12-09 03:10+0000\n" +"PO-Revision-Date: 2007-09-08 03:23+0000\n" +"Last-Translator: phar \n" +"Language-Team: Polish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2008-03-12 04:24+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +msgid "%s bans not shown." +msgstr "Nie pokazano %s banów." + +msgid "%s not implemented." +msgstr "%s jest nieobsługiwany." + +msgid "(for post and file deletion)" +msgstr "(do usuwania postów i plików)" + +msgid "

Add News Post

This message will be displayed as it is written, so make sure you add the proper HTML." +msgstr "

Dodaj newsa

Wiadomość będzie wyświetlona tak, jak została napisana - upewnij się więc co do poprawnej składni HTML." + +msgid "A board with that name already exists." +msgstr "Board o tej nazwie już istnieje." + +msgid "A board with that name does not exist." +msgstr "Board o tej nazwie nie istnieje." + +msgid "A message is required to post without a file." +msgstr "Postując bez pliku, należy wpisać wiadomość" + +msgid "A post with that ID does not exist." +msgstr "Post o tym ID nie istnieje." + +msgid "A staff member with that ID already exists." +msgstr "Członek ekipy o podanym ID już istnieje." + +msgid "A staff member with that id does not appear to exist." +msgstr "Członek ekipy o podanym ID nie istnieje." + +msgid "Add" +msgstr "Dodaj" + +msgid "Add ban" +msgstr "Dodaj ban" + +msgid "Add board" +msgstr "Dodaj board" + +msgid "Add news" +msgstr "Dodaj news" + +msgid "Add staff member" +msgstr "Dodaj członka ekipy" + +msgid "Add word" +msgstr "Dodaj słowo" + +msgid "Added a news entry" +msgstr "Dodano newsa" + +msgid "Added board" +msgstr "Dodano board" + +msgid "Added on" +msgstr "Dodano:" + +msgid "Added staff member" +msgstr "Dodano członka ekipy" + +msgid "Admin" +msgstr "Admin" + +msgid "Administration" +msgstr "Administracj" + +msgid "Administrator" +msgstr "Administrator" + +msgid "Administrators" +msgstr "Administratorzy" + +msgid "All Threads" +msgstr "Wszystkie tematy" + +msgid "All boards" +msgstr "Wszystkie boardy" + +msgid "All threads/posts by that IP in selected boards successfully deleted." +msgstr "Wszystkie tematy/posty wysłane z tego IP zostały usunięte." + +msgid "Allowed filetypes" +msgstr "Dozwolone typy plików" + +msgid "Already posted %shere%s." +msgstr "To już zostało zapostowane %stutaj%s." + +msgid "An image, or message, is required for a reply." +msgstr "Obrazek lub wiadomość jest wymagana przy odpowiedzi!" + +msgid "Anonymous" +msgstr "Anonim" + +msgid "Are you absolutely sure you want to delete %s?" +msgstr "Czy jesteś pewien, że chcesz usunąć %s?" + +msgid "Ban from" +msgstr "Ban na" + +msgid "Ban proxy list" +msgstr "Banuj listę proxy" + +msgid "Ban successfully placed." +msgstr "Pomyślnie zbanowano." + +msgid "Ban successfully removed." +msgstr "Ban pomyślnie usunięto." + +msgid "Banned" +msgstr "Zbanowano" + +msgid "Banned from" +msgstr "Ban na" + +msgid "Board" +msgstr "Board" + +msgid "Board options" +msgstr "Opcje boardu" + +msgid "Board successfully added." +msgstr "Pomyślnie dodano board." + +msgid "Board successfully deleted." +msgstr "Pomyślnie usunięto board." + +msgid "Board type:" +msgstr "Typ boardu:" + +msgid "Boards" +msgstr "Boardy" + +msgid "Cache successfully flushed." +msgstr "Cache pomyślnie usunięte." + +msgid "Can be left blank." +msgstr "Można pozostawić puste" + +msgid "Can not be left blank." +msgstr "Nie można pozostawić pustego" + +msgid "Captcha" +msgstr "Captcha" + +msgid "Catalog Mode" +msgstr "Tryb katalogu" + +msgid "Change account password" +msgstr "Zmień hasło do konta" + +msgid "Check for new version" +msgstr "Sprawdź, czy jest nowa wersja" + +msgid "Cleanup" +msgstr "Czyszczenie" + +msgid "Cleanup finished." +msgstr "Czyszczenie zakończone." + +msgid "Click Reply to view, or %sexpand%s." +msgstr "Kliknij na odpowiedź, by zobaczyć, lub %srozwiń%s" + +msgid "Click Reply to view." +msgstr "Kliknij na Odpowiedź, by zobaczyć." + +msgid "Click to show/hide" +msgstr "Kliknij, by pokazać/ukryć" + +msgid "Continue" +msgstr "Kontynuuj" + +msgid "Could not copy uploaded image." +msgstr "Nie można skopiować wysłanego obrazka." + +msgid "Could not create thumbnail." +msgstr "Nie można było utworzyć miniaturki." + +msgid "Current version:" +msgstr "Obecna wersja:" + +msgid "Days to keep modlog entries" +msgstr "Dni, przez które trzymane są logi moderacji" + +msgid "Default style:" +msgstr "Domyślny styl:" + +msgid "Delete" +msgstr "Usuń" + +msgid "Delete all posts by IP" +msgstr "Usuń wszystkie posty z tego IP" + +msgid "Delete all posts by this IP" +msgstr "Usuń wszystkie posty z tego IP" + +msgid "Delete board" +msgstr "Usuń board" + +msgid "Delete post" +msgstr "Usuń post" + +msgid "Delete posts" +msgstr "Usuń posty" + +msgid "Delete thread" +msgstr "Usuń temat" + +msgid "Delete thread/post" +msgstr "Usuń temat/post" + +msgid "Deleted board" +msgstr "Usunięto board" + +msgid "Deleted post" +msgstr "Usunięto post" + +msgid "Deleted posts by ip" +msgstr "Usunięto post z IP" + +msgid "Deleted staff member" +msgstr "Usunięto członka ekipy" + +msgid "Deleted thread" +msgstr "Usunięto temat" + +msgid "Deleting non-deleted replies which belong to deleted threads." +msgstr "Usuwanie nieusuniętych odpowiedzi w usuniętych tematach." + +msgid "Deleting unused images." +msgstr "Usuwanie nieużywanych obrazów." + +msgid "Description" +msgstr "Opis" + +msgid "Directory" +msgstr "Katalog" + +msgid "Disk space used" +msgstr "Użyte miejsce" + +msgid "Does not expire" +msgstr "Nie wygasa" + +msgid "Duplicate file entry detected." +msgstr "Wykryto zduplikowany plik (ktoś go wysłał już wcześniej)" + +msgid "Edit" +msgstr "Edytuj" + +msgid "Edit filetypes" +msgstr "Edytuj typy plików" + +msgid "Edit sections" +msgstr "Edytuj sekcję" + +msgid "Edit word" +msgstr "Edytuj słowo" + +msgid "Email" +msgstr "Email" + +msgid "Embedding only" +msgstr "Tylko zagnieżdżanie" + +msgid "Enable \"no file\" posting" +msgstr "Włącz postowanie bez pliku" + +msgid "Enable captcha:" +msgstr "Włącz captcha:" + +msgid "Enable reporting:" +msgstr "Włącz możliwość zgłaszania:" + +msgid "Enable/disable captcha system for this board. If captcha is enabled, in order for a user to post, they must first correctly enter the text on an image." +msgstr "Włącz/wyłącz system captcha dla tego boardu. Jeżeli captcha jest włączona, w celach wysłania posta, użytkownik będzie musiał każdorazowo przepisywać kod z obrazka." + +msgid "Entire Thread" +msgstr "Cały temat" + +msgid "Error, it appears your file did not transfer properly. Please go back and try again." +msgstr "Wystąpił błąd przy przesyłaniu obrazka. Prosimy spróbować ponownie." + +msgid "Expires:" +msgstr "Przedawnia się:" + +msgid "Extension icon displayed, click image to open file." +msgstr "Wyświetlono ikonę rozszerzenia, kliknij na nią, by otworzyć plik" + +msgid "File" +msgstr "Plik" + +msgid "File Only" +msgstr "Tylko plik" + +msgid "File was not fully uploaded. Please go back and try again." +msgstr "Plik nie został wysłany w całości. Prosimy spróbować ponownie." + +msgid "Filetype added." +msgstr "Dodano typ pliku." + +msgid "Filetype deleted." +msgstr "Usunięto typ pliku." + +msgid "Filetype updated." +msgstr "Zaktualizowano typ pliku." + +msgid "First 100 posts" +msgstr "Pierwsze 100 postów" + +msgid "Forced anonymous" +msgstr "Wymuszona anonimowość" + +msgid "Front Page" +msgstr "Strona główna" + +msgid "Get posting password" +msgstr "Odkryj hasło postowania" + +msgid "Global configuration succesfully updated." +msgstr "Globalna konfiguracaja pomyślnie zaktualizowana." + +msgid "Global options" +msgstr "Globalne opcje" + +msgid "Go" +msgstr "Idź" + +msgid "Header image" +msgstr "Obrazek nagłówka" + +msgid "Hide Directories" +msgstr "Usuń katalogi" + +msgid "Home" +msgstr "Strona główna" + +msgid "ID" +msgstr "ID" + +msgid "IP" +msgstr "IP" + +msgid "If set to yes, new threads will not require an image to be posted." +msgstr "Jeśli ustawiono na tak, nowe tematy będą wymagały załączenia obrazka." + +msgid "If set to yes, this board will appear in bold in the menu" +msgstr "Jeśli ustawiono na tak, board ten pokaże się w menu porgrubiony" + +msgid "If set to yes, this board will appear in italics in the menu" +msgstr "Jeśli ustawiono na tak, board ten pokaże się w menu kursywą" + +msgid "If set to yes, users will be redirected to the thread they replied to/posted after posting. If set to no, users will be redirected to the first page of the board." +msgstr "Jeśli ustawiono na tak, użytkownicy zostaną przekierowani do tematu w którym odpowiedzieli/zapostowali. Jeśli ustawiono na nie, użytkownicy będą przekierowani na spis tematów." + +msgid "If set to yes, users will not be allowed to enter a name, making everyone appear as Anonymous" +msgstr "Jeśli ustawiono na tak, użytkownicy nie będą mogli wpisać swojego imienia. Wszyscy będą figurować jako Anonim" + +msgid "Image successfully deleted from your post." +msgstr "Obraz został pomyślnie usunięty z twojego postu." + +msgid "Images and embedding" +msgstr "Obrazki i zagnieżdżanie" + +msgid "Improper filetype." +msgstr "Niedozwolony typ pliku." + +msgid "Include header" +msgstr "Dołącz nagłówek" + +msgid "Incorrect password." +msgstr "Nieprawidłowe hasło." + +msgid "Incorrect username/password." +msgstr "Nieprawidłowa nazwa użytkownika/hasło." + +msgid "Index" +msgstr "Indeks" + +msgid "Inject" +msgstr "Wyślij" + +msgid "Integer values must be entered correctly." +msgstr "Należy wpisać poprawną liczbę całkowitą." + +msgid "Invalid ID" +msgstr "Nieprawidłowy ID" + +msgid "Invalid MIME type for this filetype." +msgstr "Nieprawidłowy wpis MIME dla tego typu pliku." + +msgid "Invalid ban ID" +msgstr "Nieprawidłowy ID bana" + +msgid "Invalid board directory." +msgstr "Nieprawidłowy katalog boardu." + +msgid "Invalid response code:" +msgstr "Nieprawidłowy kod odpowiedzi:" + +msgid "Invalid session." +msgstr "Nieprawidłowa sesja." + +msgid "Invalid staff ID." +msgstr "Nieprawidłowy ID ekipy" + +msgid "Invalid thread ID. This may have been caused by the thread recently being deleted." +msgstr "Błąd: nie odnaleziono tematu. Być może został niedawno usunięty." + +msgid "Invalid video ID." +msgstr "ieprawidłowy ID pliku wideo." + +msgid "Invalid video type." +msgstr "Nieprawidłowy typ pliku wideo." + +msgid "Is replaced by" +msgstr "zamień na" + +msgid "Last 50 posts" +msgstr "Ostatnie 50 postów" + +msgid "Last Post" +msgstr "Ostatni post" + +msgid "Lock" +msgstr "Zablokuj" + +msgid "Locked" +msgstr "Zablokowany" + +msgid "Locked thread" +msgstr "Zablokowano temat" + +msgid "Log in again." +msgstr "Zaloguj się ponownie." + +msgid "Logged in" +msgstr "Zalogowano" + +msgid "Manage" +msgstr "Zarządzaj" + +msgid "Manage boards" +msgstr "Zarządzaj boardami" + +msgid "Manage locked threads" +msgstr "Zarządzaj zablokowanymi" + +msgid "Manage stickies" +msgstr "Zarządzaj przyklejonymi" + +msgid "Marked for deletion (old)." +msgstr "Oznaczone do usunięcia (stary temat)" + +msgid "Maximum board pages" +msgstr "Maksymalna ilość stron boardu" + +msgid "Maximum image size" +msgstr "Maksymalny rozmiar obrazka" + +msgid "Maximum message length" +msgstr "Maksymalna długość posta" + +msgid "Maximum thread age (Hours)" +msgstr "Maksymalny wiek tematu (godz.)" + +msgid "Maximum thread replies" +msgstr "Maksymalna ilość odpowiedzi w jednym temacie" + +msgid "Maxmimum size of uploaded images, in bytes." +msgstr "Maksymalny rozmiar wysyłanego obrazka, w bajtach." + +msgid "Maxmimum thumbnail height" +msgstr "Maksymalna wysokość miniaturki" + +msgid "Maxmimum thumbnail width" +msgstr "Maksymalna szerokość miniaturki" + +msgid "Message" +msgstr "Wiadomość" + +msgid "Misc" +msgstr "różne" + +msgid "Mod" +msgstr "Mod" + +msgid "ModLog" +msgstr "Log moderacji" + +msgid "Moderates" +msgstr "Moderuje" + +msgid "Moderating boards" +msgstr "Moderuje boardy:" + +msgid "Moderation" +msgstr "Moderacja" + +msgid "Moderator" +msgstr "Moderator" + +msgid "Moderators" +msgstr "Moderatorz" + +msgid "Modify staff member" +msgstr "Edytuj członka ekipy" + +msgid "Module settings" +msgstr "Ustawienia modułów" + +msgid "Modules" +msgstr "Moduły" + +msgid "NOTICE: You are using the default administrator account. Anyone can log in to this account, so a second administrator account needs to be created. Create another, log in to it, and delete this one." +msgstr "UWAGA: Używasz domyślnego konta administratora - oznacza to, że każdy może się teraz na nie zalogować. Należy utworzyć nowe konto administratora, zalogować się na nie, a następnie to usunąć." + +msgid "Name" +msgstr "Imię" + +msgid "Never" +msgstr "Nigdy" + +msgid "New Thread" +msgstr "Nowy temat" + +msgid "New password" +msgstr "Nowe hasło" + +msgid "New password again" +msgstr "Powtórz nowe hasło" + +msgid "News" +msgstr "Newsy" + +msgid "News entry successfully added." +msgstr "Pomyślnie dodano newsa." + +msgid "Next" +msgstr "Dalej" + +msgid "No File" +msgstr "Brak pliku" + +msgid "No boards" +msgstr "Brak boardów" + +msgid "No embedding" +msgstr "Bez zagnieżdżania" + +msgid "No visible boards" +msgstr "Brak widocznych boardów" + +msgid "Normal imageboard" +msgstr "Zwykły imageboard" + +msgid "Oekaki imageboard" +msgstr "Board oekaki" + +msgid "Old password" +msgstr "Stare hasło" + +msgid "Only moderators of the board and admins can make new posts/replies" +msgstr "Tylko moderatorzy tego boardu i admini mogą zakładać nowe tematy/odpowiadać" + +msgid "Open images in new window" +msgstr "Otwieraj obrazki w nowym oknie" + +msgid "Order" +msgstr "Porządek" + +msgid "Order to show board in menu list, in ascending order." +msgstr "Porządek w jakim pokazywane są boardy w menu, rosnąco" + +msgid "Overrides the header set in the config file. Leave blank to use configured global header image. Needs to be a full url including http://. Set to none to show no header image." +msgstr "Zastępuje obrazek nagłówka w pliku konfiguracyjnym. Pozostaw puste, jeśli chcesz użyć domyślnego. Musi to być pełen url, razem z http://. Ustaw na brak, by nie używać nagłówka." + +msgid "Password" +msgstr "Hasło" + +msgid "Password successfully changed." +msgstr "Hasło pomyślnie zmieniono." + +msgid "Placed:" +msgstr "Wymierzył:" + +msgid "Please enter a positive amount of seconds, or zero for a permanent ban." +msgstr "Proszę wpisać dodatnią liczbę sekund lub zero dla permamentnego bana." + +msgid "Please enter a search query." +msgstr "Proszę wpisać zapytanie do wyszukania." + +msgid "Please fill in all required fields." +msgstr "Proszę wypełnić wszystkie wymagane pola." + +msgid "Please make sure your file is smaller than %dB" +msgstr "Upewnij się, że twój obrazek jest mniejszy niż %dB" + +msgid "Please select a board." +msgstr "Proszę wybrać board." + +msgid "Please select only one image to upload." +msgstr "Proszę wybrać tylko jeden obrazek do wysłania." + +msgid "Popular" +msgstr "Popularny" + +msgid "Post" +msgstr "Post" + +msgid "Post successfully deleted." +msgstr "Post został pomyślnie usunięty." + +msgid "Postbox notice" +msgstr "Powiadomienie na pocztę" + +msgid "Posting a blacklisted link." +msgstr "Próba zapostowania linku na czarnej liście." + +msgid "Posting mode: Reply" +msgstr "Tryb postowania: Odpowiedź" + +msgid "Posting rates (past hour)" +msgstr "Częstotliwość postowania (godz.)" + +msgid "Posts" +msgstr "Posty" + +msgid "Presets" +msgstr "Domyślne" + +msgid "Previous" +msgstr "Wstecz" + +msgid "Proxy list" +msgstr "Lista proxy" + +msgid "Query" +msgstr "Zapytanie" + +msgid "Query executed successfully" +msgstr "Zapytanie wykonano pomyślnie" + +msgid "Quick Reply" +msgstr "Szybka odpowiedź" + +msgid "Ran cleanup" +msgstr "Wykonano czyszczenie" + +msgid "Raw HTML which will be inserted at the top of each page of the board." +msgstr "Kod HTML, który będzie dołączony do góry i dołu każdego boarda." + +msgid "Read this thread from the beginning" +msgstr "Czytaj ten temat od początku" + +msgid "Reason" +msgstr "Powód" + +msgid "Reason:" +msgstr "Powód:" + +msgid "Rebuild all html files" +msgstr "Odbuduj wszystkie pliki html" + +msgid "Rebuild complete. Took %d seconds." +msgstr "Odbudowa ukończona. Zabrało to %d sekund." + +msgid "Rebuilt all boards and threads" +msgstr "Odbudowano wszyskie boardy i thready" + +msgid "Redirect to thread" +msgstr "Przekieruj do tematu" + +msgid "Redirecting" +msgstr "Przekierowywanie..." + +msgid "Regenerated %s" +msgstr "Zregenerowano %s" + +msgid "Regular expression" +msgstr "Wyrażenie potoczne" + +msgid "Removed word from wordfilter" +msgstr "Usunięto słowo z filtra" + +msgid "Replies" +msgstr "Odpowiedzi" + +msgid "Replies displayed per stickied thread (in thread list)" +msgstr "Odpowiedzi wyświetlanych w przyklejonym temacie (na spisie tematow)" + +msgid "Replies displayed per thread (in thread list)" +msgstr "Odpowiedzi wyświetlanych w temacie (na spisie tematów)" + +msgid "Reply" +msgstr "Odpowiedź" + +msgid "Report" +msgstr "Zgłoś" + +msgid "Reporting allows users to report posts, adding the post to the report list." +msgstr "Zgłaszanie pozwala użytkownikom na wysyłanie postów do moderatorów w celach przyszłego rozpatrzenia" + +msgid "Reports" +msgstr "Zgłoszenia" + +msgid "Results" +msgstr "Wyniki" + +msgid "Return" +msgstr "Powrót" + +msgid "SQL query" +msgstr "Zapytanie SQL" + +msgid "Search" +msgstr "Szukaj" + +msgid "Search posts" +msgstr "Przeszukaj posty" + +msgid "Seconds" +msgstr "Sekund" + +msgid "Section" +msgstr "Sekcja" + +msgid "Section added." +msgstr "Dodano sekcję." + +msgid "Section deleted." +msgstr "Usunięto sekcję." + +msgid "Section updated." +msgstr "Zaktualizowano sekcję." + +msgid "Show Directories" +msgstr "Pokaż katalogi" + +msgid "Show Posting Password" +msgstr "Pokaż hasło postowania" + +msgid "Shown below" +msgstr "Poniżej" + +msgid "Sorry, because of your numerous failed logins, you have been locked out from logging in for 20 minutes. Please wait and then try again." +msgstr "Przepraszamy, ale z powodu powtarzających się nieudanych prób logowania została wyłączona jego możliwość na 20 minut. Proszę poczekać i spróbować ponownie." + +msgid "Sorry, that filetype is not allowed on this board." +msgstr "Przepraszamy, ale podany typ pliku nie jest obsługiwany na tym boardzie." + +msgid "Sorry, this board is locked and can not be posted in." +msgstr "Przepraszamy, ale ten board jest zablokowany i nie można w nim postować." + +msgid "Sorry, this thread is locked and can not be replied to." +msgstr "Przepraszamy, ale ten temat jest zablokowany i nie można w nim odpowiadać." + +msgid "Sorry, your message is too long. Message length: %d, maxmimum allowed length: %d" +msgstr "Przepraszamy, ale długość twojej wiadomości (%d) przekracza %d znaków" + +msgid "Sorry, your search returned zero results." +msgstr "Przepraszamy, nic nie znaleziono." + +msgid "Staff" +msgstr "Ekipa" + +msgid "Staff member successfully added." +msgstr "Członek ekipy pomyślnie dodany" + +msgid "Staff rights" +msgstr "Przywileje" + +msgid "Staff successfully deleted" +msgstr "Członek pomyślnie usunięty" + +msgid "Staff successfully updated" +msgstr "Ekipa pomyślnie zaktualizowana" + +msgid "Stickied thread" +msgstr "Przyklejono temat" + +msgid "Sticky" +msgstr "Przyklejony" + +msgid "Style" +msgstr "Styl" + +msgid "Subject" +msgstr "Temat" + +msgid "Submit" +msgstr "Wyślij" + +msgid "Text board" +msgstr "Board tekstowy" + +msgid "That ID does not exist." +msgstr "Ten ID nie istnieje." + +msgid "That ID is a reply, not a thread." +msgstr "Pod tym ID znajduje się odpowiedź, nie temat." + +msgid "That IP has already been banned." +msgstr "To IP już zostało zbanowane." + +msgid "That name is for internal use. Please pick another." +msgstr "Ta nazwa jest zarezerwowana do użycia wewnątrz. Proszę wybrać inną." + +msgid "That post has been cleared as not requiring any deletion." +msgstr "Wpis o tym poście został usunięty - post nie wymaga usunięcia." + +msgid "That post is already in the report list." +msgstr "Ten post został już zgłoszony." + +msgid "That thread has yet to be deleted." +msgstr "Ten temat będzie usunięty." + +msgid "That video ID has already been posted %shere%s." +msgstr "Plik wideo o tym ID został już zapostowany %stutaj%s." + +msgid "That word already exists." +msgstr "To słowo już istnieje." + +msgid "The 5 newest replies are shown below." +msgstr "Pokazano najnowsze 5 odpowiedzi." + +msgid "The directory of the board." +msgstr "Katalog boardu." + +msgid "The name of the board." +msgstr "Nazwa boardu." + +msgid "The number of replies a thread can have before autosaging to the back of the board." +msgstr "Ilość odpowiedzi w temacie przed wypchaniem na koniec boardu." + +msgid "The old password you provided did not match the current one." +msgstr "Stare hasło jest nieprawidłowe." + +msgid "The second password did not match the first." +msgstr "Podane nowe hasła nie są identyczne." + +msgid "The section the board is in. This is used for displaying the list of boards on the top and bottom of pages." +msgstr "Sekcja, w której jest board. Używane do wyświetlania listy boardów na górze i dole strony" + +msgid "The style which will be set when the user first visits the board." +msgstr "Styl, który zostanie użyty, gdy użytkownik poraz pierwszy odwiedzi board." + +msgid "The type of posts which will be accepted on this board. A normal imageboard will feature image and extended format posts, a text board will have no images, and an Oekaki board will allow users to draw images and use them in their posts." +msgstr "Typ postów akceptowanych na tym boardzie. Zwykły imageboard będzie obsługiwał obrazy i rozszerzone formaty, board tekstowy nie będzie miał możliwości wysłania obrazków, a board Oekaki pozwala użytkownikom na rysosowanie obrazów w przeglądarce i załączanie ich do postów." + +msgid "There are currently no bans." +msgstr "Obecnie nie ma żadnych banów." + +msgid "There are currently no filetypes." +msgstr "Obecnie nie ma żadnych typów pliku." + +msgid "There are currently no sections." +msgstr "Obecnie nie ma żadnych sekcji." + +msgid "There are currently no threads to display." +msgstr "Nie ma obecnie żadnych tematów do wyświetlenia." + +msgid "There is already a file with that name." +msgstr "Istnieje już plik o tej nazwie." + +msgid "There was an error in trying to delete your post" +msgstr "Wystąpił błąd przy próbie usunięcia twojego postu." + +msgid "This board does not allow post reporting." +msgstr "Ten board nie zezwala na zgłaszanie postów." + +msgid "This post has been deleted." +msgstr "Ten post został usunięty." + +msgid "Thread" +msgstr "Temat" + +msgid "Thread successfully deleted." +msgstr "Temat pomyślnie usunięto." + +msgid "Thread successfully locked." +msgstr "Temat pomyślnie zablokowano." + +msgid "Thread successfully stickied." +msgstr "Temat pomyślnie przyklejono." + +msgid "Thread successfully un-stickied" +msgstr "Temat pomyślnie odklejono." + +msgid "Thread successfully unlocked." +msgstr "Temat pomyślnie odblokowano." + +msgid "Threads" +msgstr "Tematy" + +msgid "Threads displayed per page (in thread list)" +msgstr "Tematy wyświetlane na stronę (na liście tematów)" + +msgid "Thumbnail displayed, click image for full size." +msgstr "Wyświetlono miniaturkę, kliknij na nią, by zobaczyć w pełnym rozmiarze" + +msgid "Trial" +msgstr "Próbny" + +msgid "Unable to clear cache: you do not have caching enabled." +msgstr "Nie można usunąć cache - jego obsługa jest obecnie wyłączona." + +msgid "Unable to connect to:" +msgstr "Nie można połączyć z:" + +msgid "Unable to create directories." +msgstr "Nie można utworzyć katalogów." + +msgid "Unable to delete board." +msgstr "Nie można usunąć boardu." + +msgid "Unable to find record of your IP being banned." +msgstr "Nie odnaleziono wpisu o twoim adresie IP." + +msgid "Unable to locate a board named" +msgstr "Nie odnaleziono boardu o nazwie" + +msgid "Unable to locate a filetype with that ID." +msgstr "Nie odnaleziono typu pliku o tym ID." + +msgid "Unable to locate a section with that ID." +msgstr "Nie odnaleziono sekcji o tym ID." + +msgid "Unable to locate that word." +msgstr "Nie odnaleziono tego słowa." + +msgid "Unable to report post. Please go back and try again." +msgstr "Nie udało się zgłosić postu. Prosimy spróbować ponownie." + +msgid "Unbanned" +msgstr "Odbanowano" + +msgid "Unlock" +msgstr "Odblokuj" + +msgid "Unlocked thread" +msgstr "Odblokowano tema" + +msgid "Unstickied thread" +msgstr "Odklejono temat" + +msgid "Unsticky" +msgstr "Nieprzyklejony" + +msgid "Update successful." +msgstr "Aktualizacja przebiegła pomyślnie." + +msgid "Updated board configuration" +msgstr "Zaktualizowano konfigurację boardu" + +msgid "Updated global configuration" +msgstr "Zaktualizowano globalną konfigurację" + +msgid "Updated staff member" +msgstr "Zaktualizowano członka ekipy" + +msgid "Updated word on wordfilter" +msgstr "Zaktualizowano słowo w filtrze" + +msgid "Upload type:" +msgstr "Typ wysyłania:" + +msgid "Username" +msgstr "Nazwa użytkownika" + +msgid "View all bans" +msgstr "Zobacz wszystkie bany" + +msgid "View catalog" +msgstr "Zobacz katalog obrazów" + +msgid "View deleted thread" +msgstr "Zobacz usunięte tematy" + +msgid "View/Add/Remove bans" +msgstr "Zobacz/Dodaj/Usuń bany" + +msgid "Watched Threads" +msgstr "Obserwowane tematy" + +msgid "Welcome" +msgstr "Witaj" + +msgid "What filetypes users are allowed to upload." +msgstr "Jakie są dozwolone typy plików." + +msgid "Whether or not to allow embedding of videos." +msgstr "Czy zezwolić na zagnieżdżanie plików wideo." + +msgid "Word" +msgstr "Słowo" + +msgid "Word successfully added." +msgstr "Pomyślnie dodano słowo." + +msgid "Word successfully removed." +msgstr "Pomyślnie usunięto słowo." + +msgid "Word successfully updated." +msgstr "Pomyślnie zaktualizowano słowo." + +msgid "Wordfilter" +msgstr "Filtr słów" + +msgid "YOU ARE BANNED" +msgstr "JESTEŚ ZBANOWANY" + +msgid "YOU ARE NOT BANNED!" +msgstr "NIE JESTEŚ ZBANOWANY!" + +msgid "You are banned from posting on:" +msgstr "Dostałeś bana za postowanie na:" + +msgid "You are not a moderator of this board." +msgstr "Nie jesteś moderatorem tego boardu." + +msgid "You can only delete posts from boards you moderate." +msgstr "Możesz kasować posty jedynie w tych boardach, które moderujesz." + +msgid "You can only make board specific bans to boards which you moderate." +msgstr "Możesz banować jedynie na boardach do których masz uprawnienia." + +msgid "You have been successfully logged out." +msgstr "Pomyślnie się wylogowałeś." + +msgid "You must enter a subject." +msgstr "Musisz wpisać temat." + +msgid "You searched for" +msgstr "Szukana fraza:" + +msgid "Your post already doesn't have an image!" +msgstr "Twój post nie ma obrazka!" + +msgid "Your posting password" +msgstr "Twoje hasło" + +msgid "forever" +msgstr "zawsze" + +msgid "log out" +msgstr "wyloguj" + +msgid "translator-credits" +msgstr "" +"Launchpad Contributions:\n" +" tj9991 \n" +"\n" +"Launchpad Contributions:\n" +" phar https://launchpad.net/~phariseus-gmail\n" +" tj9991 https://launchpad.net/~tslocum" + diff --git a/inc/lang/pt/LC_MESSAGES/kusaba.po b/inc/lang/pt/LC_MESSAGES/kusaba.po new file mode 100644 index 0000000..fe68dd7 --- /dev/null +++ b/inc/lang/pt/LC_MESSAGES/kusaba.po @@ -0,0 +1,385 @@ +msgid "" +msgstr "" +"Project-Id-Version: kusaba\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2007-12-09 03:10+0000\n" +"PO-Revision-Date: 2008-03-10 18:31+0000\n" +"Last-Translator: Tiago Silva \n" +"Language-Team: Portuguese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2008-03-12 04:24+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +msgid "Add" +msgstr "Adicionar" + +msgid "Add news" +msgstr "Adicionar notícias" + +msgid "Add word" +msgstr "Adicionar palavra" + +msgid "Administration" +msgstr "Administração" + +msgid "Administrator" +msgstr "Administrador" + +msgid "Administrators" +msgstr "Administradores" + +msgid "All boards" +msgstr "Todos os conselhos" + +msgid "An image, or message, is required for a reply." +msgstr "É necessário uma imagem ou mensagem para enviar uma resposta." + +msgid "Anonymous" +msgstr "Anónimo" + +msgid "Banned" +msgstr "Banido" + +msgid "Board" +msgstr "Conselho" + +msgid "Boards" +msgstr "Conselhos" + +msgid "Cancel" +msgstr "Cancelar" + +msgid "Catalog Mode" +msgstr "Modo de Catálogo" + +msgid "Change account password" +msgstr "Mudar senha de conta" + +msgid "Continue" +msgstr "Continuar" + +msgid "Could not create thumbnail." +msgstr "Não foi possível criar uma miniatura." + +msgid "Date" +msgstr "Data" + +msgid "Description" +msgstr "Descrição" + +msgid "Directory" +msgstr "Directório" + +msgid "Edit sections" +msgstr "Editar secções" + +msgid "Edit word" +msgstr "Editar palavra" + +msgid "Email" +msgstr "Correio Electrónico" + +msgid "Expand all images" +msgstr "Expandir todas as imagens" + +msgid "File" +msgstr "Ficheiro" + +msgid "File
Removed" +msgstr "" +"Copy text \t\r\n" +"Ficheiro
Removido" + +msgid "From" +msgstr "De" + +msgid "Global options" +msgstr "Opções globais" + +msgid "Height" +msgstr "Altura" + +msgid "Hide Directories" +msgstr "Ocultar Directórios" + +msgid "IP" +msgstr "IP" + +msgid "Image" +msgstr "Imagem" + +msgid "Images" +msgstr "Imagens" + +msgid "Important" +msgstr "Importante" + +msgid "Improper filetype." +msgstr "Tipo de ficheiro impróprio." + +msgid "Include header" +msgstr "Incluir cabeçalho" + +msgid "Incorrect password." +msgstr "Senha incorrecta." + +msgid "Incorrect username/password." +msgstr "Nome de utilizador/senha incorrectos." + +msgid "Index" +msgstr "Índice" + +msgid "Invalid MIME type for this filetype." +msgstr "Tipo MIME inválido para este tipo de ficheiro." + +msgid "Invalid response code:" +msgstr "Código de resposta inválido:" + +msgid "Invalid session." +msgstr "Sessão inválida." + +msgid "Invalid video type." +msgstr "Tipo de vídeo inválido." + +msgid "Lock" +msgstr "Bloquear" + +msgid "Logo" +msgstr "Logótipo" + +msgid "Manage" +msgstr "Gerir" + +msgid "Message" +msgstr "Mensagem" + +msgid "Message too long. Click %shere%s to view the full text." +msgstr "Mensagem demasiado longa. Pressione %aquis%s para ver o texto na íntegra." + +msgid "Misc" +msgstr "Vários" + +msgid "Moderates" +msgstr "Modera" + +msgid "Moderating boards" +msgstr "Conselhos de moderação" + +msgid "Moderation" +msgstr "Moderação" + +msgid "Moderator" +msgstr "Moderador" + +msgid "Moderators" +msgstr "Moderadores" + +msgid "Modify" +msgstr "Modificar" + +msgid "Modules" +msgstr "Módulos" + +msgid "More" +msgstr "Mais" + +msgid "Name" +msgstr "Nome" + +msgid "Never" +msgstr "Nunca" + +msgid "New image" +msgstr "Nova imagem" + +msgid "News" +msgstr "Notícias" + +msgid "Next" +msgstr "Seguinte" + +msgid "No" +msgstr "Não" + +msgid "No boards" +msgstr "Não há conselhos" + +msgid "Pages" +msgstr "Páginas" + +msgid "Paint with" +msgstr "Pintar com" + +msgid "Password" +msgstr "Senha" + +msgid "Password successfully changed." +msgstr "Senha alterada com sucesso." + +msgid "Please fill in all required fields." +msgstr "Por favor, preencha todos os campos requeridos" + +msgid "Popular" +msgstr "Popular" + +msgid "Post" +msgstr "Publicar" + +msgid "Preview" +msgstr "Previsualizar" + +msgid "Previous" +msgstr "Anterior" + +msgid "Quick Reply" +msgstr "Resposta Rápida" + +msgid "Reason" +msgstr "Motivo" + +msgid "Reason:" +msgstr "Motivo:" + +msgid "Regular expression" +msgstr "Expressão regular" + +msgid "Remove" +msgstr "Remover" + +msgid "Replies" +msgstr "Respostas" + +msgid "Reply" +msgstr "Resposta" + +msgid "Reports" +msgstr "Relatórios" + +msgid "Results" +msgstr "Resultados" + +msgid "Rules" +msgstr "Regras" + +msgid "Seconds" +msgstr "Segundos" + +msgid "Section" +msgstr "Secção" + +msgid "Section added." +msgstr "Secção adicionada." + +msgid "Section deleted." +msgstr "Secção eliminada." + +msgid "Section updated." +msgstr "Secção actualizada." + +msgid "Show Directories" +msgstr "Mostrar Directórios" + +msgid "Size" +msgstr "Tamanho" + +msgid "Sorry, a generic error has occurred." +msgstr "Lamento, ocorreu um erro genérico." + +msgid "Sorry, your message is too long. Message length: %d, maxmimum allowed length: %d" +msgstr "Lamento, mas a sua mensagem é demasiado extensa: %d, comprimento máximo permitido: %d" + +msgid "Statistics" +msgstr "Estatísticas" + +msgid "Style" +msgstr "Estilo" + +msgid "Styles" +msgstr "Estilos" + +msgid "Subject" +msgstr "Assunto" + +msgid "Submit" +msgstr "Submeter" + +msgid "Tag" +msgstr "Etiqueta" + +msgid "That name is for internal use. Please pick another." +msgstr "Este nome é para uso interno. Por favor, escolha outro." + +msgid "The second password did not match the first." +msgstr "A segunda senha não coincidiu com a primeira." + +msgid "There is already a file with that name." +msgstr "Já existe um ficheiro com esse nome." + +msgid "Thread" +msgstr "Tópico" + +msgid "Threads" +msgstr "Tópicos" + +msgid "To" +msgstr "Para" + +msgid "Unlock" +msgstr "Desbloquear" + +msgid "Update" +msgstr "Actualizar" + +msgid "Use animation?" +msgstr "Usar animação?" + +msgid "Username" +msgstr "Nome de utilizador" + +msgid "View Reports" +msgstr "Ver Relatórios" + +msgid "View animation" +msgstr "Ver animação" + +msgid "View catalog" +msgstr "Ver catálogo" + +msgid "Width" +msgstr "Largura" + +msgid "YOU ARE NOT BANNED!" +msgstr "VOCÊ NÃO ESTÁ BANIDO!" + +msgid "Yes" +msgstr "Sim" + +msgid "Your IP address is" +msgstr "O seu endereço de IP é" + +msgid "Your image" +msgstr "A sua imagem" + +msgid "and" +msgstr "e" + +msgid "forever" +msgstr "para sempre" + +msgid "or" +msgstr "ou" + +msgid "translator-credits" +msgstr "" +"Launchpad Contributions:\n" +" André Malafaya Baptista https://launchpad.net/~malafaya\n" +" Tiago Silva https://launchpad.net/~tiagosilva" + +msgid "will expire on" +msgstr "irá expirar em" + +msgid "will not expire" +msgstr "não irá expirar" + diff --git a/inc/lang/pt_BR/LC_MESSAGES/kusaba.po b/inc/lang/pt_BR/LC_MESSAGES/kusaba.po new file mode 100644 index 0000000..2e4605d --- /dev/null +++ b/inc/lang/pt_BR/LC_MESSAGES/kusaba.po @@ -0,0 +1,1416 @@ +msgid "" +msgstr "" +"Project-Id-Version: trevorchan\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2007-12-09 03:10+0000\n" +"PO-Revision-Date: 2008-01-30 11:50+0000\n" +"Last-Translator: Tiago Silva \n" +"Language-Team: Brazilian Portuguese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2008-03-12 04:24+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +msgid "%s bans not shown." +msgstr "%s expulsões não mostradas." + +msgid "%s not implemented." +msgstr "%s não está implementado." + +msgid "%s uploaded." +msgstr "%s transferidos." + +msgid "(for post and file deletion)" +msgstr "(para apagar posts ou arquivos)" + +msgid "

Add News Post

This message will be displayed as it is written, so make sure you add the proper HTML." +msgstr "

Adicionar notícia

Esta mensagem será exibida como é escrita, então certifique-se de que você adicionou o código HTML apropriado." + +msgid "A board with that name already exists." +msgstr "Um fórum com este nome já existe." + +msgid "A board with that name does not exist." +msgstr "Um fórum com este nome não existe." + +msgid "A common cause for this is an incorrect extension when the file is actually of a different type." +msgstr "Uma causa comum para isso é uma extensão incorreta quando o arquivo na verdade é de um tipo diferente." + +msgid "A file is required for a new thread. If embedding is allowed, either a file or embed ID is required." +msgstr "Um arquivo é necessário para um novo tópico. Se for permitido embutir algo, um arquivo ou o ID do objeto embutido é requerido." + +msgid "A message is required to post without a file." +msgstr "Uma mensagem é necessária para postar sem um arquivo" + +msgid "A post with that ID does not exist." +msgstr "Não existe uma mensagem com esse ID." + +msgid "A staff member with that ID already exists." +msgstr "Já existe um membro da equipe com este ID." + +msgid "A staff member with that id does not appear to exist." +msgstr "Não existe nenhum membro da equipe com este ID." + +msgid "Add" +msgstr "Adicionar" + +msgid "Add ban" +msgstr "Adicionar expulsão" + +msgid "Add board" +msgstr "Adicionar fórum" + +msgid "Add new blotter entry" +msgstr "Adicionar nova entrada ao registro." + +msgid "Add news" +msgstr "Adicionar notícia" + +msgid "Add staff member" +msgstr "Adicionar membro da equipe" + +msgid "Add word" +msgstr "Adicionar palavra" + +msgid "Added a news entry" +msgstr "Adicionou uma notícia" + +msgid "Added board" +msgstr "Fórum adicionado" + +msgid "Added on" +msgstr "Adicionado em" + +msgid "Added staff member" +msgstr "Membro da equipe adicionado" + +msgid "Admin" +msgstr "Administrador" + +msgid "Administration" +msgstr "Administração" + +msgid "Administrator" +msgstr "Administrador" + +msgid "Administrators" +msgstr "Administradores" + +msgid "All Threads" +msgstr "Todos os tópicos" + +msgid "All boards" +msgstr "Todos os fóruns" + +msgid "All threads/posts by that IP in selected boards successfully deleted." +msgstr "Todos os tópicos/mensagens feitos por esse IP nos fóruns selecionados foram apagados com sucesso." + +msgid "Allowed filetypes" +msgstr "Tipos de arquivos permitidos" + +msgid "Already posted %shere%s." +msgstr "Já foi postado %saqui%s." + +msgid "An image, or message, is required for a reply." +msgstr "Uma imagem, ou mensagem, é necessária para a resposta." + +msgid "Anonymous" +msgstr "Anônimo" + +msgid "Appeal Message" +msgstr "Mensagem de recurso" + +msgid "Appeal successfully denied." +msgstr "Recurso negado com sucesso." + +msgid "Are you absolutely sure you want to delete %s?" +msgstr "Você tem certeza absoluta de que quer apagar %s?" + +msgid "At" +msgstr "Arroba" + +msgid "Ban from" +msgstr "Expulso de" + +msgid "Ban proxy list" +msgstr "Lista de proxies expulsos" + +msgid "Ban successfully placed." +msgstr "Expulsão feita com sucesso." + +msgid "Ban successfully removed." +msgstr "Expulsão removida com sucesso." + +msgid "Banned" +msgstr "Expulso" + +msgid "Banned %d IP addresses using an IP address list." +msgstr "Expulsou %d endereços IP usando uma lista de endereços" + +msgid "Banned from" +msgstr "Expulso de" + +msgid "Blotter" +msgstr "Registro" + +msgid "Blotter entry added." +msgstr "Entrada no registro adicionada." + +msgid "Blotter entry deleted." +msgstr "Entrada no registro apagada." + +msgid "Blotter entry updated." +msgstr "Entrada no registro atualizada." + +msgid "Blotter is disabled." +msgstr "O registro está desligado." + +msgid "Blotter updated" +msgstr "Registro atualizado" + +msgid "Board" +msgstr "Fórum" + +msgid "Board options" +msgstr "Opções do fórum" + +msgid "Board successfully added." +msgstr "Fórum adicionado com sucesso." + +msgid "Board successfully deleted." +msgstr "Fórum apagado com sucesso." + +msgid "Board type:" +msgstr "Tipo do fórum." + +msgid "Boards" +msgstr "Fóruns" + +msgid "Cache successfully flushed." +msgstr "Cache esvaziado com sucesso" + +msgid "Can be left blank." +msgstr "Pode ser deixado em branco." + +msgid "Can not be left blank." +msgstr "Não pode ser deixado em branco." + +msgid "Cancel" +msgstr "Cancelar" + +msgid "Captcha" +msgstr "Captcha" + +msgid "Catalog Mode" +msgstr "Modo de Catálogo" + +msgid "Change account password" +msgstr "Mudar a senha da conta" + +msgid "Check for new version" +msgstr "Checar se há uma nova versão" + +msgid "Choose one" +msgstr "Escolha uma" + +msgid "Cleanup" +msgstr "Limpeza" + +msgid "Cleanup finished." +msgstr "Limpeza concluída." + +msgid "Cleared APC cache" +msgstr "Limpou o cache APC" + +msgid "Click Reply to view, or %sexpand%s." +msgstr "Clique em Responder para visualizar, ou %sexpand%s." + +msgid "Click Reply to view." +msgstr "Clique em Responder para visualizar" + +msgid "Click to show/hide" +msgstr "Clique para mostrar/ocultar" + +msgid "Continue" +msgstr "Continuar" + +msgid "Could not copy uploaded image." +msgstr "Não foi possível copiar a imagem." + +msgid "Could not create thumbnail." +msgstr "Não foi possível criar o thumbnail." + +msgid "Current version:" +msgstr "Versão atual:" + +msgid "Date" +msgstr "Data" + +msgid "Days to keep modlog entries" +msgstr "Dias para modificar as entradas no modlog." + +msgid "Default" +msgstr "Padrão" + +msgid "Default style:" +msgstr "Estilo padrão:" + +msgid "Delete" +msgstr "Apagar" + +msgid "Delete all posts by IP" +msgstr "Apagar todos os posts por IP" + +msgid "Delete all posts by this IP" +msgstr "Apagar todos os posts feitos por este IP" + +msgid "Delete board" +msgstr "Apagar fórum" + +msgid "Delete post" +msgstr "Apagar a mensagem" + +msgid "Delete posts" +msgstr "Apagar mensagens." + +msgid "Delete thread" +msgstr "Apagar o tópico" + +msgid "Delete thread/post" +msgstr "Apagar o tópico/mensagem" + +msgid "Deleted" +msgstr "Removido" + +msgid "Deleted a VIP code" +msgstr "Um código VIP foi apagado" + +msgid "Deleted board" +msgstr "Fórum apagado" + +msgid "Deleted post" +msgstr "Mensagem apagada." + +msgid "Deleted posts by ip" +msgstr "Mensagens do IP apagadas" + +msgid "Deleted staff member" +msgstr "Membro da equipe apagado" + +msgid "Deleted thread" +msgstr "Tópico apagado" + +msgid "Deleting non-deleted replies which belong to deleted threads." +msgstr "Apagando respostas não-apagadas pertencentes a tópicos apagados." + +msgid "Deleting unused images." +msgstr "Apagando imagens não utilizadas." + +msgid "Denied the ban appeal for" +msgstr "Negado o recurso de expulsão para" + +msgid "Description" +msgstr "Descrição" + +msgid "Directory" +msgstr "Diretório" + +msgid "Disk space used" +msgstr "Espaço em disco utilizado" + +msgid "Does not expire" +msgstr "Não expira" + +msgid "Duplicate file entry detected." +msgstr "Arquivo duplicado detectado." + +msgid "Duplicate thread subject" +msgstr "Assunto do tópico duplicado." + +msgid "Edit" +msgstr "Editar" + +msgid "Edit filetypes" +msgstr "Editar tipos de arquivos" + +msgid "Edit sections" +msgstr "Editar seções" + +msgid "Edit word" +msgstr "Editar a palavra" + +msgid "Edited a VIP cod" +msgstr "Um código VIP foi editado" + +msgid "Edited a news entry" +msgstr "Editou uma notícia" + +msgid "Email" +msgstr "Email" + +msgid "Embed" +msgstr "Embutir" + +msgid "Embedding only" +msgstr "Somente embutidos" + +msgid "Enable \"no file\" posting" +msgstr "Habilitar a postagem \"sem arquivo\"" + +msgid "Enable captcha:" +msgstr "Habilitar captcha:" + +msgid "Enable reporting:" +msgstr "Permitir denúncias:" + +msgid "Enable/disable captcha system for this board. If captcha is enabled, in order for a user to post, they must first correctly enter the text on an image." +msgstr "Habilitar/desabilitar o sistema de captchas para este fórum. Caso habilitado, para que um usuário poste, ele precisa primeira inserir o texto presente em uma imagem" + +msgid "Entire Thread" +msgstr "Tópico inteiro" + +msgid "Error, it appears your file did not transfer properly. Please go back and try again." +msgstr "Erro, aparenetemente seu arquivo não foi transferido corretamente. Por favor volte e tente novamente." + +msgid "Expand all images" +msgstr "Expandir todas as imagens" + +msgid "Expires:" +msgstr "Expira em:" + +msgid "Extension icon displayed, click image to open file." +msgstr "Ícone da extensão exibido, clique na imagem para abrir o arquivo" + +msgid "FAQ" +msgstr "Perguntas Freqüentes" + +msgid "File" +msgstr "Arquivo" + +msgid "File Only" +msgstr "Somente o arquivo" + +msgid "File was not fully uploaded. Please go back and try again." +msgstr "O arquivo não foi totalmente copiado. Por favor volte e tente novamente." + +msgid "File
Removed" +msgstr "Arquivo
Removido." + +msgid "Filetype added." +msgstr "Tipo de arquivo adicionado." + +msgid "Filetype deleted." +msgstr "Tipo de arquivo apagado." + +msgid "Filetype updated." +msgstr "Tipo de arquivo atualizado." + +msgid "First 100 posts" +msgstr "Primeiros 100 posts" + +msgid "First 100 posts shown." +msgstr "Primeiros 100 posts exibidos" + +msgid "First Post ID" +msgstr "ID da primeira mensagem" + +msgid "Forced anonymous" +msgstr "Anônimo forçado" + +msgid "From" +msgstr "De" + +msgid "Front" +msgstr "Frente" + +msgid "Front Page" +msgstr "Primeira Página" + +msgid "Get posting password" +msgstr "Obter a senha da mensagem" + +msgid "Global configuration succesfully updated." +msgstr "Configuração global atualizada com sucesso." + +msgid "Global options" +msgstr "Opções globais" + +msgid "Go" +msgstr "Ir" + +msgid "Header image" +msgstr "Imagem do cabeçalho" + +msgid "Height" +msgstr "Altura" + +msgid "Hide Directories" +msgstr "Ocultar diretórios" + +msgid "Hide the watched threads box" +msgstr "Ocultar a caixa de tópicos observados." + +msgid "Home" +msgstr "Início" + +msgid "ID" +msgstr "ID" + +msgid "IP" +msgstr "IP" + +msgid "If set to yes, new threads will not require an image to be posted." +msgstr "Caso configurado com \"sim\", novos tópicos não precisarão de uma imagem" + +msgid "If set to yes, this board will appear in bold in the menu" +msgstr "Caso selecionado \"sim\", o fórum aparecerá em negrito no menu" + +msgid "If set to yes, this board will appear in italics in the menu" +msgstr "Caso selecionado \"sim\", o fórum aparecerá em itálico no menu" + +msgid "If set to yes, users will be redirected to the thread they replied to/posted after posting. If set to no, users will be redirected to the first page of the board." +msgstr "Se configurado como \"sim\", os usuários serão redirecionados para o tópico a cada vez que reponderem ou ao postarem-no. Caso contrário, os usuários serão redirecionados para a primeira página do fórum." + +msgid "If set to yes, users will not be allowed to enter a name, making everyone appear as Anonymous" +msgstr "Se configurado como \"sim\", os usuários não poderão especificar um nome, fazendo com que todos apareçam como Anonymous." + +msgid "Image" +msgstr "Imagem" + +msgid "Image successfully deleted from your post." +msgstr "Imagem apagada com sucesso da sua mensagem." + +msgid "Images" +msgstr "Imagens" + +msgid "Images and embedding" +msgstr "Imagens e embutidos" + +msgid "Important" +msgstr "Importante" + +msgid "Improper filetype." +msgstr "Tipo de arquivo impróprio." + +msgid "Include header" +msgstr "Incluir cabeçalho" + +msgid "Incorrect captcha entered." +msgstr "Captcha incorreto" + +msgid "Incorrect password." +msgstr "Senha incorreta." + +msgid "Incorrect username/password." +msgstr "Nome de usuário/senha incorreta." + +msgid "Index" +msgstr "Índice" + +msgid "Inject" +msgstr "Injetar" + +msgid "Inserted SQL" +msgstr "Inseriu SQL" + +msgid "Integer values must be entered correctly." +msgstr "Valores inteiros devem ser inseridos corretamente." + +msgid "Invalid ID" +msgstr "ID inválido" + +msgid "Invalid MIME type for this filetype." +msgstr "Tipo MIME inválido para este tipo de arquivo." + +msgid "Invalid ban ID" +msgstr "ID da expulsão inválido" + +msgid "Invalid board directory." +msgstr "Diretório de fóruns inválido." + +msgid "Invalid response code:" +msgstr "Código de resposta inválido" + +msgid "Invalid session." +msgstr "Sessão inválida" + +msgid "Invalid staff ID." +msgstr "ID de equipe incorreto." + +msgid "Invalid thread ID." +msgstr "ID do tópico inválida." + +msgid "Invalid thread ID. This may have been caused by the thread recently being deleted." +msgstr "ID do tópico incorreto. Isso pode ter sido causado pela deleção recente do tópico." + +msgid "Invalid video ID." +msgstr "ID de vídeo inválido." + +msgid "Invalid video type." +msgstr "Tipo de vídeo inválido" + +msgid "Is replaced by" +msgstr "É substituída por" + +msgid "Last 50 posts" +msgstr "Últimos 50 posts" + +msgid "Last 50 posts shown." +msgstr "Últimos 50 posts exibidos" + +msgid "Last Post" +msgstr "Último Post" + +msgid "Last active" +msgstr "Ativo pela última vez em" + +msgid "Lock" +msgstr "Trancar" + +msgid "Locked" +msgstr "Trancado" + +msgid "Locked thread" +msgstr "Tópico trancado" + +msgid "Log in again." +msgstr "Entre novamente" + +msgid "Logged in" +msgstr "Autenticado" + +msgid "Logo" +msgstr "Logo" + +msgid "Manage" +msgstr "Gerenciar" + +msgid "Manage boards" +msgstr "Gerenciar fóruns." + +msgid "Manage locked threads" +msgstr "Administrar tópicos trancados" + +msgid "Manage stickies" +msgstr "Administrar tópicos fixos" + +msgid "Marked for deletion (old)." +msgstr "Marcado para remoção (antigo)" + +msgid "Maximum board pages" +msgstr "Número máximo de páginas do fórum." + +msgid "Maximum image size" +msgstr "Tamanho máximo da imagem." + +msgid "Maximum message length" +msgstr "Tamanho máximo da mensagem." + +msgid "Maximum thread age (Hours)" +msgstr "Idade máxima dos tópicos (horas)" + +msgid "Maximum thread replies" +msgstr "Número máximo de respostas ao tópico" + +msgid "Maxmimum size of uploaded images, in bytes." +msgstr "Tamando máximo das imagens enviadas, em bytes" + +msgid "Maxmimum thumbnail height" +msgstr "Tamanho mínimo da miniatura." + +msgid "Maxmimum thumbnail width" +msgstr "Tamanho máximo da miniatura." + +msgid "Message" +msgstr "Mensagem" + +msgid "Message too long. Click %shere%s to view the full text." +msgstr "Mensagem muito longa. Clique Click %saqui%s para ver o texto completo." + +msgid "Misc" +msgstr "Miscelânea" + +msgid "Mod" +msgstr "Moderador" + +msgid "ModLog" +msgstr "ModLog" + +msgid "Moderating boards" +msgstr "Moderando os fóruns" + +msgid "Moderation" +msgstr "Moderação" + +msgid "Moderator" +msgstr "Moderador" + +msgid "Moderators" +msgstr "Moderadores" + +msgid "Modify" +msgstr "Modificar" + +msgid "Modify staff member" +msgstr "Modificar membro da equipe" + +msgid "Module settings" +msgstr "Opções dos módulos" + +msgid "Modules" +msgstr "Módulos" + +msgid "More" +msgstr "Mais" + +msgid "Move complete." +msgstr "Movido com sucesso." + +msgid "Move thread" +msgstr "Mover o tópico" + +msgid "NOTICE: You are using the default administrator account. Anyone can log in to this account, so a second administrator account needs to be created. Create another, log in to it, and delete this one." +msgstr "AVISO: Você está usando a conta padrão de administrador. Qualquer um pode entrar nesta conta, então uma segunda conta de administrador precisa ser criada. Crie outra, entre nela, e apague esta." + +msgid "Name" +msgstr "Nome" + +msgid "Name to display when a name is not attached to a post." +msgstr "Nome para exibir quando um nome não está associado a um post." + +msgid "Never" +msgstr "Nunca" + +msgid "New Thread" +msgstr "Novo tópico" + +msgid "New image" +msgstr "Nova imagem" + +msgid "New password" +msgstr "Nova senha" + +msgid "New password again" +msgstr "Repita a nova senha" + +msgid "News" +msgstr "Notícias" + +msgid "News entry successfully added." +msgstr "Notícia adicionada com sucesso." + +msgid "Next" +msgstr "Próximo" + +msgid "No" +msgstr "Não" + +msgid "No File" +msgstr "Nenhum Arquivo" + +msgid "No blotter entries." +msgstr "Sem entradas no registro." + +msgid "No boards" +msgstr "Nenhum fórum" + +msgid "No embedding" +msgstr "Sem embutidos" + +msgid "No threads." +msgstr "Sem Tópicos" + +msgid "No visible boards" +msgstr "Sem fóruns visíveis" + +msgid "None" +msgstr "Nenhum" + +msgid "Normal imageboard" +msgstr "Fórum de imagens normal" + +msgid "Oekaki imageboard" +msgstr "Fórum de imagens oekaki" + +msgid "Old password" +msgstr "Senha antiga" + +msgid "Online now" +msgstr "Online agora" + +msgid "Only moderators of the board and admins can make new posts/replies" +msgstr "Somente os moderadores desse fórum e os administradores podem enviar novas mensagens/respostas." + +msgid "Only put in the letter(s) of the board directory, no slashes!" +msgstr "Coloque somente a(s) letra(s) do diretório do fórum, sem barras!" + +msgid "Open images in new window" +msgstr "Abrir as imagens em uma nova janela." + +msgid "Order" +msgstr "Ordenar" + +msgid "Order to show board in menu list, in ascending order." +msgstr "Posição para mostrar o fórum no menu, em ordem ascendente." + +msgid "Overrides the header set in the config file. Leave blank to use configured global header image. Needs to be a full url including http://. Set to none to show no header image." +msgstr "Ignora o cabeçalho existente no arquivo de configuração. Deixe em branco para utilizar a imagem de cabeçalho configurada globalmente. Precisa ser uma URL completa que inclua http://. Insira none para não mostrar nenhuma imagem no cabeçalho." + +msgid "Pages" +msgstr "Páginas" + +msgid "Paint with" +msgstr "Pintar com" + +msgid "Paint!" +msgstr "Pintar!" + +msgid "Password" +msgstr "Senha" + +msgid "Password successfully changed." +msgstr "Senha modificada com sucesso." + +msgid "Placed:" +msgstr "Em:" + +msgid "Please enter a positive amount of seconds, or zero for a permanent ban." +msgstr "Por favor informe uma quantidade positiva de segundos, ou zero para uma expulsão permanente." + +msgid "Please enter a search query." +msgstr "Por favor informe um termo para a busca" + +msgid "Please fill in all required fields." +msgstr "Por favor preencha todos os dados necessários." + +msgid "Please make sure your file is smaller than %dB" +msgstr "Por favor certifique-se de que seu arquivo é menor que %dB" + +msgid "Please select a board." +msgstr "Por favor escolha um fórum." + +msgid "Please select only one image to upload." +msgstr "Por favor selecione somente uma imagem." + +msgid "Please wait a moment before posting again." +msgstr "Por favor aguarde um momento antes de postar novamente" + +msgid "Popular" +msgstr "Popular" + +msgid "Post" +msgstr "Postar" + +msgid "Post added." +msgstr "Mensagem adicionada." + +msgid "Post preview" +msgstr "Pós-visualização" + +msgid "Post successfully deleted." +msgstr "Mensagem apagada com sucesso." + +msgid "Postbox notice" +msgstr "Aviso da caixa de mensagens" + +msgid "Posting a blacklisted link." +msgstr "Postando um link da lista negra." + +msgid "Posting mode: Reply" +msgstr "Modo de mensagem: Resposta" + +msgid "Posting password" +msgstr "Senha para postagem." + +msgid "Posting rates (past hour)" +msgstr "Taxa de mensagem (hora passada)" + +msgid "Posts" +msgstr "Mensagens" + +msgid "Presets" +msgstr "Predefinições" + +msgid "Preview" +msgstr "Pré-visualização" + +msgid "Previous" +msgstr "Anterior" + +msgid "Proxy list" +msgstr "Lista de proxies" + +msgid "Query" +msgstr "Consulta" + +msgid "Query executed successfully" +msgstr "Comando executado com sucesso." + +msgid "Quick Reply" +msgstr "Resposta Rápida" + +msgid "Ran cleanup" +msgstr "Executar limpeza" + +msgid "Raw HTML which will be inserted at the top of each page of the board." +msgstr "HTML puro que será inserido no topo de cada página do fórum." + +msgid "Read this thread from the beginning" +msgstr "Leia este tópico desde o início." + +msgid "Reason" +msgstr "Motivo" + +msgid "Reason:" +msgstr "Motivo:" + +msgid "Rebuild all html files" +msgstr "Reconstruir todos os arquivos html" + +msgid "Rebuild complete. Took %d seconds." +msgstr "Reconstrução completa. Demorou %d segundos." + +msgid "Rebuilt all boards and threads" +msgstr "Reconstruir todos os fóruns e tópicos" + +msgid "Redirect to thread" +msgstr "Redirecionar para o tópico" + +msgid "Redirecting" +msgstr "Redirecionando" + +msgid "Refresh watched threads" +msgstr "Atualizar tópicos observados." + +msgid "Regenerated %s" +msgstr "%s regerado" + +msgid "Regular expression" +msgstr "Expressão Regular" + +msgid "Remove" +msgstr "Remover" + +msgid "Removed word from wordfilter" +msgstr "Palavra removida do filtro" + +msgid "Replacement" +msgstr "Substituição" + +msgid "Replies" +msgstr "Respostas" + +msgid "Replies displayed per stickied thread (in thread list)" +msgstr "Repostas apresentadas por tópico fixo (na lista de tópicos)" + +msgid "Replies displayed per thread (in thread list)" +msgstr "Respostas apresentadas por tópico (na lista de tópicos)" + +msgid "Reply" +msgstr "Responder" + +msgid "Report" +msgstr "Denunciar" + +msgid "Reporting allows users to report posts, adding the post to the report list." +msgstr "As denúncias permitem que os usuários denunciem posts, adicionando-os à lista de denúncias." + +msgid "Reports" +msgstr "Denunciados" + +msgid "Restore watched threads" +msgstr "Restaurar tópicos observados." + +msgid "Results" +msgstr "Resultados" + +msgid "Return" +msgstr "Retornar" + +msgid "Rules" +msgstr "Regras" + +msgid "SQL query" +msgstr "Consulta SQL" + +msgid "Search" +msgstr "Pesquisa" + +msgid "Search posts" +msgstr "Buscar mensagens" + +msgid "Seconds" +msgstr "Segundos" + +msgid "Section" +msgstr "Seção" + +msgid "Section added." +msgstr "Seção adicionada." + +msgid "Section deleted." +msgstr "Seção removida." + +msgid "Section updated." +msgstr "Seção atualizada." + +msgid "Send Appeal" +msgstr "Enviar recurso" + +msgid "Show All" +msgstr "Mostrar todos" + +msgid "Show Directories" +msgstr "Mostrar Diretórios" + +msgid "Show Posting Password" +msgstr "Mostrar a senha para enviar mensagens" + +msgid "Show/Hide" +msgstr "Mostrar/Ocultar" + +msgid "Shown below" +msgstr "Mostrado abaixo" + +msgid "Site Styles" +msgstr "Estilos" + +msgid "Size" +msgstr "Tamanho" + +msgid "Sorry, a generic error has occurred." +msgstr "Desculpe, ocorreu um erro genérico." + +msgid "Sorry, because of your numerous failed logins, you have been locked out from logging in for 20 minutes. Please wait and then try again." +msgstr "Desculpe, em razão de suas inúmeras tentativas frustradas de entrar, você foi impedido de tentar novamente por 20 minutos. Por favor espere e tente novamente." + +msgid "Sorry, that filetype is not allowed on this board." +msgstr "Desculpe, este tipo de arquivo não é permitido neste fórum." + +msgid "Sorry, this board is locked and can not be posted in." +msgstr "Desculpe, este fórum está trancado e não pode receber mensagens." + +msgid "Sorry, this thread is locked and can not be replied to." +msgstr "Desculpe, este tópico está trancado e não pode ser respondido." + +msgid "Sorry, your message is too long. Message length: %d, maxmimum allowed length: %d" +msgstr "Desculpe, a sua mensagem é muito longa. Tamanho da mensagem: %d, tamanho máximo permitido: %d" + +msgid "Sorry, your search returned zero results." +msgstr "Desculpe, a sua busca não retornou resultados." + +msgid "Source" +msgstr "Fonte" + +msgid "Staff" +msgstr "Equipe" + +msgid "Staff member successfully added." +msgstr "Membro da equipe adicionado com sucesso." + +msgid "Staff rights" +msgstr "Direitos da equipe" + +msgid "Staff successfully deleted" +msgstr "Equipe apagada com sucesso" + +msgid "Staff successfully updated" +msgstr "Equipe atualizada com sucesso" + +msgid "Statistics" +msgstr "Estatísticas" + +msgid "Stickied" +msgstr "Afixado" + +msgid "Stickied thread" +msgstr "Tópico afixado" + +msgid "Sticky" +msgstr "Fixo" + +msgid "Style" +msgstr "Estilo" + +msgid "Styles" +msgstr "Estilos" + +msgid "Subject" +msgstr "Assunto" + +msgid "Submit" +msgstr "Enviar" + +msgid "System lockout" +msgstr "Travamento do sistema" + +msgid "Tag" +msgstr "Marcador" + +msgid "Text board" +msgstr "Fórum de texto" + +msgid "Text boards may have only one thread with a unique subject. Please pick another." +msgstr "Fóruns de texto devem ter somente uma thread com um assunto único. Por favor selecione outro." + +msgid "Text boards only. If enabled, the list of threads displayed on the front page will be formatted differently to be compact." +msgstr "Fóruns de texto somente. Se ligado, a lista de tópicos exibida na primeira página será formatada de maneira diferente, mais compacta." + +msgid "That ID does not exist." +msgstr "Esse ID não existe." + +msgid "That ID is a reply, not a thread." +msgstr "Esta ID é de uma resposta, e não de um tópico." + +msgid "That IP has already been banned." +msgstr "Este IP já está expulso." + +msgid "That name is for internal use. Please pick another." +msgstr "Este nome está reservado para uso interno. Por favor escolha outro." + +msgid "That post is already in the report list." +msgstr "Este post já está na lista de denúncias" + +msgid "That thread has yet to be deleted." +msgstr "Este tópico ainda não foi apagado." + +msgid "That thread may have been recently deleted." +msgstr "Esse tópico pode ter sido apagado recentemente" + +msgid "That video ID has already been posted %shere%s." +msgstr "O vídeo com este ID já foi postado %saqui%s." + +msgid "That word already exists." +msgstr "Esta palavra já existe." + +msgid "The 5 newest replies are shown below." +msgstr "As 5 últimas respostas são mostradas abaixo" + +msgid "The change will not be apparent until the html files are rebuilt." +msgstr "A mudança não será aparente até que as páginas html sejam reconstruídas" + +msgid "The directory of the board." +msgstr "O diretório do fórum." + +msgid "The first post of this board will recieve this ID." +msgstr "A primeira mensagem deste fórum receberá este ID." + +msgid "The name of the board." +msgstr "O nome do fórum." + +msgid "The number of replies a thread can have before autosaging to the back of the board." +msgstr "O número de respostas que um tópico pode ter antes se ser enviada ao fim do fórum (autosage)." + +msgid "The old password you provided did not match the current one." +msgstr "A senha antiga informada não coincide com a atual" + +msgid "The second password did not match the first." +msgstr "A segunda senha não coincide com a primeira." + +msgid "The section the board is in. This is used for displaying the list of boards on the top and bottom of pages." +msgstr "A seção em que o fórum está. Usado para na lista de fóruns do topo e final das páginas." + +msgid "The style which will be set when the user first visits the board." +msgstr "O estilo que será apresentado na primeira visita ao fórum." + +msgid "The type of posts which will be accepted on this board. A normal imageboard will feature image and extended format posts, a text board will have no images, and an Oekaki board will allow users to draw images and use them in their posts." +msgstr "O tipo de posts que serão aceitos neste fórum. Um fórum de imagens normal aceitará posts de imagens e alguns formatos, um fórum de texto não terá imagens, e um oekaki permitirá que os usuários desenhem imagens e as usem em seus posts." + +msgid "There are currently no bans." +msgstr "Não existe nenhuma expulsão atualmente" + +msgid "There are currently no filetypes." +msgstr "Atualmente não há nenhum tipo de arquivo." + +msgid "There are currently no sections." +msgstr "Não existem seções atualmente." + +msgid "There are currently no threads to display." +msgstr "Atualmente não existem tópicos para exibir" + +msgid "There is already a file with that name." +msgstr "Já existe um arquivo com este nome." + +msgid "There was an error in trying to delete your post" +msgstr "Ocorreu um erro ao tentar apagar sua mensagem." + +msgid "This board does not allow post reporting." +msgstr "Esse fórum não permite a denúncia de posts." + +msgid "This post has been deleted." +msgstr "Este post foi apagado." + +msgid "Thread" +msgstr "Tópico" + +msgid "Thread successfully deleted." +msgstr "Tópico apagado com sucesso." + +msgid "Thread successfully locked." +msgstr "Tópico trancado com sucesso." + +msgid "Thread successfully stickied." +msgstr "Tópico afixado com sucesso." + +msgid "Thread successfully un-stickied" +msgstr "Tópico des-afixado com sucesso." + +msgid "Thread successfully unlocked." +msgstr "Tópico destrancado com sucesso." + +msgid "Threads" +msgstr "Tópicos" + +msgid "Threads displayed per page (in thread list)" +msgstr "Tópicos apresentados por página (na lista de tópicos)" + +msgid "Thumbnail displayed, click image for full size." +msgstr "Miniatura exibida, clique na imagem para o tamanho completo." + +msgid "To" +msgstr "Para" + +msgid "Trial" +msgstr "Temporário" + +msgid "Unable to clear cache: you do not have caching enabled." +msgstr "Não foi possível limpar o cache: você não o habilitou" + +msgid "Unable to connect to:" +msgstr "Não possível se conectar a" + +msgid "Unable to create directories." +msgstr "Não foi possível criar os diretórios." + +msgid "Unable to delete board." +msgstr "Não foi possível apagar o fórum." + +msgid "Unable to find record of your IP being banned." +msgstr "Não foi possível achar registros de que seu IP tenha sido expulso." + +msgid "Unable to find records of any posts matching that quote syntax." +msgstr "Não foi possível achar registros de nenhuma mensagem que coincida com a citação." + +msgid "Unable to locate a board named" +msgstr "Não foi possível achar um fórum chamado" + +msgid "Unable to locate a filetype with that ID." +msgstr "Impossível localizar um tipo de arquivo com aquele ID." + +msgid "Unable to locate a section with that ID." +msgstr "Não foi possível localizar uma seção com aquele ID." + +msgid "Unable to locate that word." +msgstr "Não foi possível localizar a palavra." + +msgid "Unable to read uploaded file during thumbnailing." +msgstr "Não foi possível ler o arquivo copiado durante a criação do thumbnail." + +msgid "Unable to report post. Please go back and try again." +msgstr "Não foi possível denunciar o post. Por favor volte e tente novamente." + +msgid "Unbanned" +msgstr "Des-expulso" + +msgid "Unlock" +msgstr "Destrancar" + +msgid "Unlocked thread" +msgstr "Tópico destrancado" + +msgid "Unstickied thread" +msgstr "Tópico des-afixado" + +msgid "Unsticky" +msgstr "Desfixar" + +msgid "Upating pages." +msgstr "Atualizando as páginas." + +msgid "Update" +msgstr "Atualizar" + +msgid "Update and regenerate board" +msgstr "Atualizar e refazer o fórum" + +msgid "Update successful." +msgstr "Atualização bem sucedida." + +msgid "Update without regenerating board" +msgstr "Atualizar sem refazer o fórum" + +msgid "Updated board configuration" +msgstr "Configuração do fórum atualizada" + +msgid "Updated global configuration" +msgstr "Configuração global atualizada" + +msgid "Updated staff member" +msgstr "Membro da equipe atualizado" + +msgid "Updated word on wordfilter" +msgstr "Palavra atualizada no filtro" + +msgid "Upload type:" +msgstr "Tipo de upload:" + +msgid "Use animation?" +msgstr "Usar animação?" + +msgid "Username" +msgstr "Nome de usuário" + +msgid "View Reports" +msgstr "Ver denúncias" + +msgid "View all bans" +msgstr "Ver todas as expulsões" + +msgid "View animation" +msgstr "Ver animação" + +msgid "View catalog" +msgstr "Ver catálogo" + +msgid "View deleted thread" +msgstr "Ver tópico apagado" + +msgid "View/Add/Remove bans" +msgstr "Ver/Adicionar/Remover expulsões" + +msgid "Viewed disk space used" +msgstr "Visualizou o espaço em disco utilizado" + +msgid "Watched Threads" +msgstr "Tópicos observados." + +msgid "Welcome" +msgstr "Bem-vindo" + +msgid "What filetypes users are allowed to upload." +msgstr "Quais tipos de arquivos os usuários podem enviar." + +msgid "Whether or not to allow embedding of videos." +msgstr "Aceitar ou não o embutimento de vídeos" + +msgid "Width" +msgstr "Largura" + +msgid "Word" +msgstr "Palavra" + +msgid "Word successfully added." +msgstr "Palavra adicionada com sucesso." + +msgid "Word successfully removed." +msgstr "Palavra removida com sucesso." + +msgid "Word successfully updated." +msgstr "Palavra atualizada com sucesso." + +msgid "Wordfilter" +msgstr "Filtro de palavras" + +msgid "YOU ARE BANNED" +msgstr "VOCÊ ESTÁ EXPULSO" + +msgid "YOU ARE NOT BANNED!" +msgstr "VOCÊ NÃO ESTÁ EXPULSO!" + +msgid "Yes" +msgstr "Sim" + +msgid "You are banned from posting on:" +msgstr "Você está expulso de:" + +msgid "You are currently posting faster than the configured minimum post delay allows." +msgstr "Você está postando mais rápido do que o período mínimo entre posts permite" + +msgid "You are not a moderator of this board." +msgstr "Você não é um moderador deste fórum." + +msgid "You can only delete posts from boards you moderate." +msgstr "Você só pode apagar mensagens de fóruns onde você é moderador." + +msgid "You can only make board specific bans to boards which you moderate." +msgstr "Você só pode fazer expulsões específicas em fóruns moderados por você." + +msgid "You have been banned from posting on" +msgstr "Você foi banido de" + +msgid "You have been successfully logged out." +msgstr "Você saiu com sucesso." + +msgid "You may not appeal this ban." +msgstr "Você não pode recorrer desta expulsão." + +msgid "You may appeal this ban in" +msgstr "Você pode recorrer desta expulsão em" + +msgid "You may now appeal this ban." +msgstr "Você não pode recorrer desta expulsão." + +msgid "You must enter a subject." +msgstr "Você precisa especificar um assunto." + +msgid "You searched for" +msgstr "Você buscou" + +msgid "Your IP address is" +msgstr "Seu endereço IP é" + +msgid "Your appeal is currently pending review." +msgstr "Seu pedido de revisão está pendente." + +msgid "Your appeal was reviewed and denied. You may not appeal this ban again." +msgstr "Seu pedido de revisão foi negado. Você não pode recorrer desta expulsão novamente." + +msgid "Your image" +msgstr "Sua imagem" + +msgid "Your post already doesn't have an image!" +msgstr "A sua mensagem já não tem uma imagem!" + +msgid "Your post contains one or more illegal characters." +msgstr "O seu post contém um ou mais caracteres inválidos." + +msgid "Your posting password" +msgstr "Sua senha para postagem." + +msgid "and" +msgstr "e" + +msgid "for the following reason" +msgstr "pelo seguinte motivo" + +msgid "forever" +msgstr "para sempre" + +msgid "log in" +msgstr "entrar" + +msgid "log out" +msgstr "sair" + +msgid "omitted" +msgstr "omitidos" + +msgid "or" +msgstr "ou" + +msgid "translator-credits" +msgstr "" +"Launchpad Contributions:\n" +" tj9991 \n" +"\n" +"Launchpad Contributions:\n" +" Tiago Silva https://launchpad.net/~tiagosilva\n" +" seabeast https://launchpad.net/~augusto-cesar\n" +" tj9991 https://launchpad.net/~tslocum" + +msgid "will expire on" +msgstr "irá expirar em" + +msgid "will not expire" +msgstr "não irá expirar" + diff --git a/inc/lang/ro/LC_MESSAGES/kusaba.po b/inc/lang/ro/LC_MESSAGES/kusaba.po new file mode 100644 index 0000000..6f3e11b --- /dev/null +++ b/inc/lang/ro/LC_MESSAGES/kusaba.po @@ -0,0 +1,2337 @@ +msgid "" +msgstr "" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Project-Id-Version: Kusaba X\n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: !Rocky \n" +"Language-Team: ROchan \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: Romanian\n" +"X-Poedit-Country: ROMANIA\n" +"X-Poedit-SourceCharset: utf-8\n" + +msgid "%d Boards" +msgstr "%d forumuri" + +msgid "%s bans not shown." +msgstr "%s banuri neafişate." + +msgid "%s images shown." +msgstr "%s imagini afişate." + +msgid "%s posts shown." +msgstr "%s mesaje afişate." + +msgid "%s not implemented." +msgstr "%s neimplementat." + +msgid "%s uploaded." +msgstr "%s uploadat." + +msgid "(for post and file deletion)" +msgstr "(pentru ştergerea mesajului)" + +msgid "(note that this is a rough limit, more may be shown)" +msgstr "(limită relativă; pot fi afișate mai multe)" + +msgid "

Add News Post

This message will be displayed as it is written, so make sure you add the proper HTML." +msgstr "

Adaugă ştire

Mesajul va fi afişat aşa cum e scris, deci vezi să bagi HTML corect." + +msgid "A board with that name already exists." +msgstr "Deja există acest forum." + +msgid "A board with that name does not exist." +msgstr "Nu există acest forum." + +msgid "A common cause for this is an incorrect extension when the file is actually of a different type." +msgstr "Asta înseamnă că extensia fişierului e diferită de tipul fişierului." + +msgid "A file is required for a new thread. If embedding is allowed, either a file or embed ID is required." +msgstr "Pentru o discuţie nouă, ai nevoie de un fişier (sau de un embed, dacă opţiunea e activată)." + +msgid "A live record for %s was not found; the file has been removed." +msgstr "Nu am găsit %s; fişierul a fost şters." + +msgid "A message is required to post without a file." +msgstr "Ca să postezi fără fişier, trebuie să scrii ceva." + +msgid "A post with that ID does not exist." +msgstr "Nu există acest mesaj." + +msgid "A staff member with that ID already exists." +msgstr "Alt membru al staff-ului are acest ID." + +msgid "A staff member with that id does not appear to exist." +msgstr "Nu există un membru al staff-ului cu acest ID." + +msgid "Abbreviation (less then 10 characters)" +msgstr "Prescurtarea secţiunii (maxim 10 caractere)" + +msgid "Abbreviation" +msgstr "Prescurtare" + +msgid "Action" +msgstr "Acţiune" + +msgid "Ad Edited" +msgstr "Reclamă editată" + +msgid "Ad Management" +msgstr "Administrarea reclamelor" + +msgid "Add ban message" +msgstr "Adaugă mesajul pentru ban" + +msgid "Add ban" +msgstr "Adaugă ban" + +msgid "Add Board" +msgstr "Adaugă forumul" + +msgid "Add board" +msgstr "Adaugă un forum" + +msgid "Add filetype" +msgstr "Adaugă un tip de fişier" + +msgid "Add new blotter entry" +msgstr "Buletin nou" + +msgid "Add news" +msgstr "Adaugă o ştire" + +msgid "Add Results" +msgstr "Rezultat" + +msgid "Add section" +msgstr "Adaugă o secţiune" + +msgid "Add staff member" +msgstr "Adaugă membru nou în staff" + +msgid "Add word" +msgstr "Adaugă un cuvânt" + +msgid "Add" +msgstr "Adaugă" + +msgid "Add/Delete boards" +msgstr "Adaugă / şterge forumuri" + +msgid "Added a FAQ entry" +msgstr "Adăugat un FAQ" + +msgid "Added a news entry" +msgstr "Adăugat ştirea" + +msgid "Added a Rule entry" +msgstr "Adăugat o regulă" + +msgid "Added an announcement" +msgstr "Adăugat anunţ" + +msgid "Added an Embed" +msgstr "Adăugat un embed" + +msgid "Added board" +msgstr "Adăugat forumul" + +msgid "Added By" +msgstr "Adăugat de" + +msgid "Added on" +msgstr "Adăugat pe" + +msgid "Added staff member" +msgstr "Adăugat membru" + +msgid "Added word to wordfilter: %s - Changes to: %s - Boards: /%s/" +msgstr "Adăugat filtru: %s - Înlocuit de: %s - Forumuri: /%s/" + +msgid "Added" +msgstr "Adăugat" + +msgid "Admin" +msgstr "Admin" + +msgid "Administration" +msgstr "Administraţie" + +msgid "Administrator" +msgstr "Administrator" + +msgid "Administrators" +msgstr "Administratori" + +msgid "All Boards" +msgstr "Toate forumurile" + +msgid "All boards" +msgstr "Toate forumurile" + +msgid "All threads on /%s/" +msgstr "Toate discuţiile de pe /%s/" + +msgid "All Threads" +msgstr "Toate discuţiile" + +msgid "All threads/posts by that IP in selected boards successfully deleted." +msgstr "Toate discuţiile / mesajele de pe acest IP au fost şterse." + +msgid "Allow read" +msgstr "Se permite citirea?" + +msgid "Allowed embeds" +msgstr "Embeduri permise" + +msgid "Allowed filetypes" +msgstr "Fişiere permise" + +msgid "Already posted %shere%s." +msgstr "Postat %saici%s." + +msgid "An image, or message, is required for a reply." +msgstr "Ca să răspunzi, ai nevoie de un mesaj sau de-o imagine." + +msgid "An invalid applet was specified. Save a screenshot of your work in case of continued failure." +msgstr "Applet invalid. Fă un screenshot la ce-ai făcut, în caz că pică appletul de tot." + +msgid "and" +msgstr "şi" + +msgid "Announcement edited" +msgstr "Anunţ editat" + +msgid "Announcement Management" +msgstr "Administrare anunţuri" + +msgid "Announcement successfully added." +msgstr "Anunţ adăugat." + +msgid "Announcement successfully deleted" +msgstr "Anunţ şters" + +msgid "Announcements" +msgstr "Anunţuri" + +msgid "Anonymous" +msgstr "Anonim" + +msgid "Anything can go here, such as banners, links, etc. It doesn't have to be just ads." +msgstr "Aici poţi pune orice (bannere, linkuri, etc.). Nu trebuie să fie neapărat reclame." + +msgid "Appeal (days)" +msgstr "Cerere de debanare (zile)" + +msgid "Appeal Message" +msgstr "Cerere de debanare" + +msgid "Appeal successfully denied." +msgstr "Cerere de debanare respinsă." + +msgid "Appeal:" +msgstr "Cerere de debanare:" + +msgid "Appeals" +msgstr "Cereri de debanare:" + +msgid "Archive" +msgstr "Arhivă" + +msgid "Are you absolutely sure you want to delete %s?" +msgstr "Sigur vrei să ştergi %s?" + +msgid "Are you sure you want to delete and ban this poster?" +msgstr "Sigur vrei să ştergi şi să banezi acest user?" + +msgid "Are you sure you want to delete this thread/post?" +msgstr "Sigur vrei să ştergi această discuţie / mesaj?" + +msgid "Area" +msgstr "Director" + +msgid "At" +msgstr "La" + +msgid "Average #minutes between posts (past week), boards without posts in past week not shown" +msgstr "Minute între postări în ultima săptămână (forumurile fără nicu un post nu sunt afişate)" + +msgid "back to board" +msgstr "înapoi la forum" + +msgid "Ban duration, reason, and appeal information" +msgstr "Durata, motivul şi cererea de debanare pentru ban" + +msgid "Ban file hash description" +msgstr "Descrierea banului pentru un hash" + +msgid "Ban file hash for" +msgstr "Banează hash-ul pentru" + +msgid "Ban file" +msgstr "Ban de fişiere" + +msgid "Ban from" +msgstr "Ban pe" + +msgid "Ban massage" +msgstr "Banat din cauza asta" + +msgid "Ban message" +msgstr "Mesajul pentru ban" + +msgid "Ban proxy list" +msgstr "Banare listă de proxy-uri" + +msgid "Ban successfully placed." +msgstr "Banat." + +msgid "Ban successfully removed." +msgstr "Ban scos." + +msgid "Ban time" +msgstr "Durata banului" + +msgid "Ban" +msgstr "Banează" + +msgid "Banned %d IP addresses using an IP address list." +msgstr "Am banat %d IP-uri din listă." + +msgid "Banned from" +msgstr "Banat pe" + +msgid "Banned md5 hash %s with a description of %s" +msgstr "Am banat MD5 hash-ul %s, cu descrierea %s" + +msgid "Banned" +msgstr "Banat" + +msgid "Blacklisted link ( %s ) detected." +msgstr "Link interzis ( %s )." + +msgid "Blotter entry added." +msgstr "Buletin adăugat." + +msgid "Blotter entry deleted." +msgstr "Buletin şters." + +msgid "Blotter entry updated." +msgstr "Buletin actualizat." + +msgid "Blotter is disabled." +msgstr "Bulteinul e dezactivat." + +msgid "Blotter updated" +msgstr "Buletin updatat" + +msgid "Blotter" +msgstr "Buletin" + +msgid "Board options" +msgstr "Administrare forumuri" + +msgid "Board successfully added." +msgstr "Forum adăugat." + +msgid "Board successfully deleted." +msgstr "Forum şters." + +msgid "Board type" +msgstr "Tip de forum" + +msgid "Board" +msgstr "Forum" + +msgid "Boards Administration" +msgstr "Administrare forumuri" + +msgid "Boards" +msgstr "Forumuri" + +msgid "Cache successfully flushed." +msgstr "Cache şters." + +msgid "Can be left blank." +msgstr "Poate fi lăsat gol." + +msgid "Can not be left blank" +msgstr "Nu poate fi lăsat gol" + +msgid "Can not be left blank, or longer than 3 characters" +msgstr "Nu poate fi nici gol, nici mai mare de 3 caractere" + +msgid "Can not be left blank. This is what comes before the embed ID. Example: 'http://www.youtube.com/watch?v='" +msgstr "Nu poate fi lăsat gol. E ceea ce vine înainte de IDul embedului, de exemplu http://www.youtube.com/watch?v=" + +msgid "Can not be left blank." +msgstr "Nu poate fi lăsat gol." + +msgid "Cancel" +msgstr "Anulare" + +msgid "Captcha" +msgstr "Captcha" + +msgid "Catalog Mode" +msgstr "Catalog" + +msgid "Change account password" +msgstr "Schimbare parolă" + +msgid "Check for new version" +msgstr "Versiune nouă?" + +msgid "Child Pornography" +msgstr "Porno ilegal" + +msgid "Choose one" +msgstr "Alege" + +msgid "Cleanup finished." +msgstr "Curăţenie completă." + +msgid "Cleanup" +msgstr "Curăţare" + +msgid "Clear All On Page As Reviewed" +msgstr "Toate sunt în regulă" + +msgid "Clear" +msgstr "Şterge" + +msgid "Cleared APC cache" +msgstr "Cache APC şters" + +msgid "Click %shere%s to return to Ad Management." +msgstr "Click %saici%s pentru a te întoarce la Administrarea Reclamelor." + +msgid "Click Reply to view, or %sexpand%s." +msgstr "Click pe Răspunde ca să vezi, sau %smăreşte%s." + +msgid "Click Reply to view." +msgstr "Click pe Răspunde ca să vezi." + +msgid "Click to edit board options" +msgstr "Click pentru a configura forumul" + +msgid "Click to show/hide" +msgstr "Arată / ascunde" + +msgid "Code" +msgstr "Cod" + +msgid "Compact list" +msgstr "Listare compactă" + +msgid "Continue" +msgstr "Continuă" + +msgid "Could not copy uploaded image." +msgstr "N-am putut copia imaginea uploadată." + +msgid "Could not create thumbnail." +msgstr "N-am putut crea thumbnailul." + +msgid "Current version:" +msgstr "Versiunea curentă:" + +msgid "Currently %1 unique user posts." +msgstr "%1 răspuns(uri) unic(e)." + +msgid "Date Added" +msgstr "Data adăugării" + +msgid "Date" +msgstr "Data" + +msgid "Days to keep modlog entries" +msgstr "Numărul de zile pentru păstrarea modlog-ului" + +msgid "days" +msgstr "zile" + +msgid "Default style" +msgstr "Stil implicit" + +msgid "Default" +msgstr "Implicit" + +msgid "Delete & Ban" +msgstr "Şterge şi Banează" + +msgid "Delete all posts by IP" +msgstr "Şterge toate mesajele după IP" + +msgid "Delete all posts by this IP" +msgstr "Şterge toate mesajele de la acest IP" + +msgid "Delete board" +msgstr "Şterge forumul" + +msgid "Delete post" +msgstr "Şterge mesajul" + +msgid "Delete posts" +msgstr "Şterge mesajele" + +msgid "Delete Results" +msgstr "Rezultatul ştergerii" + +msgid "Delete thread" +msgstr "Şterge discuţia" + +msgid "Delete thread/post" +msgstr "Şterge discuţia / mesajul" + +msgid "Delete" +msgstr "Şterge" + +msgid "Deleted a FAQ entry" +msgstr "FAQ şters" + +msgid "Deleted a news entry" +msgstr "Ştire ştearsă" + +msgid "Deleted a Rules entry" +msgstr "Regulă ştearsă" + +msgid "Deleted a VIP code" +msgstr "Cod VIP şters" + +msgid "Deleted an announcement" +msgstr "Anunţ şters" + +msgid "Deleted an Embed" +msgstr "Şters un embed" + +msgid "Deleted board" +msgstr "Forum şters" + +msgid "Deleted post" +msgstr "Răspuns şters" + +msgid "Deleted posts by ip" +msgstr "Mesaje şterse, după IP" + +msgid "Deleted staff member" +msgstr "Membru al staff-ului şters" + +msgid "Deleted thread" +msgstr "Discuţie ştearsă" + +msgid "DELETED" +msgstr "ŞTERS" + +msgid "Deleting non-deleted replies which belong to deleted threads." +msgstr "Ştergere mesaje orfane." + +msgid "Deleting unused images." +msgstr "Ştergere imagini neutilizate." + +msgid "Denied the ban appeal for" +msgstr "Cererea de debanare respinsă pentru" + +msgid "Description" +msgstr "Descriere" + +msgid "Directory" +msgstr "Director" + +msgid "Disk space used" +msgstr "Spaţiu utilizat" + +msgid "Display" +msgstr "Afişare" + +msgid "Displayed" +msgstr "Afişată" + +msgid "Does not expire" +msgstr "Nu expiră" + +msgid "Duplicate file entry detected." +msgstr "Fişier duplicat." + +msgid "Duplicate thread subject" +msgstr "Subiect duplicat" + +msgid "Duration:" +msgstr "Până pe:" + +msgid "Edit filetypes" +msgstr "Editare tipuri de fişiere" + +msgid "Edit sections" +msgstr "Editare secţiuni" + +msgid "Edit templates" +msgstr "Editare template-uri" + +msgid "Edit word" +msgstr "Editează filtrul" + +msgid "Edit" +msgstr "Editează" + +msgid "Edit/Delete announcement" +msgstr "Editează / şterge un anunţ" + +msgid "Edit/Delete Embeds" +msgstr "Editează / şterge embeduri" + +msgid "Edit/Delete FAQ Entries" +msgstr "Editează / şterge FAQ-urile" + +msgid "Edit/Delete News" +msgstr "Editează / şterge o ştire" + +msgid "Edit/Delete Rule Entries" +msgstr "Editează / şterge regulile" + +msgid "Edit/Delete" +msgstr "Editează / Şterge" + +msgid "Edited a FAQ entry" +msgstr "FAQ editat" + +msgid "Edited a news entry" +msgstr "Ştire editată" + +msgid "Edited a Rule entry" +msgstr "Regulă editată" + +msgid "Edited a VIP cod" +msgstr "Cod VIP editat" + +msgid "Edited an ad" +msgstr "Editat o reclamă" + +msgid "Edited an announcement" +msgstr "Anunţ editat" + +msgid "Edited an embed" +msgstr "Editat un embed" + +msgid "Email" +msgstr "Email" + +msgid "Embed deleted" +msgstr "Embed şters" + +msgid "Embed Edited" +msgstr "Embed editat" + +msgid "Embed Management" +msgstr "Administrare embeduri" + +msgid "Embed successfully added." +msgstr "Embed agăugat" + +msgid "Embed" +msgstr "Embed" + +msgid "Embedding only" +msgstr "Numai embed" + +msgid "Enable 'no file' posting" +msgstr "Postare fără fişier" + +msgid "Enable archiving" +msgstr "Arhivare" + +msgid "Enable captcha" +msgstr "Captcha" + +msgid "Enable catalog" +msgstr "Catalogare" + +msgid "Enable reporting" +msgstr "Raportare" + +msgid "Enable/disable captcha system for this board. If captcha is enabled, in order for a user to post, they must first correctly enter the text on an image." +msgstr "Activare / dezactivare captcha pe forum. Dacă e activat, utilizatorul va trebui sa scrie corect textul dintr-o imagine." + +msgid "Enable/disable thread archiving for this board (not available if load balancer is used). If enabled, when a thread is pruned or deleted through this panel with the archive checkbox checked, the thread and its images will be moved into the arch directory, found in the same directory as the board. To function properly, you must create and set proper permissions to /boardname/arch, /boardname/arch/res, /boardname/arch/src, and /boardname/arch/thumb" +msgstr "Activare / dezactivare arhivarea forumului (nu se poloseşte dacă ai un script adiţional). Dacă e activat, atunci când o discuţie este ştearsă cu opţiunea de arhivare, discuţia şi imaginile sale vor fi mutate în directorul arch din acelaşi director în care se află şi forumul. Ca să meargă cum trebuie, trebuie să creezi şi să acorzi permisii următoarelor directoare: /boardname/arch, /boardname/arch/res, /boardname/arch/src, şi /boardname/arch/thumb" + +msgid "Enclose text in {t}{/t} blocks to allow them to be translated for different languages." +msgstr "Încadrează textul care vrei sa fie localizabil între {t} şi {/t}" + +msgid "Entire Thread" +msgstr "Toată discuţia" + +msgid "Error" +msgstr "Eroare" + +msgid "Error, it appears your file did not transfer properly. Please go back and try again." +msgstr "Fişierul nu a fost uploadat cum trebuie. Incearcă din nou." + +msgid "Error: That thread doesn't have a file associated with it." +msgstr "Eroare: Discuţia nu are vreo imagine asociată." + +msgid "Error: The directory ./%s was not found and could not be created. Please notify the sites administrator with a copy of this error." +msgstr "Eroare: directorul ./%s nu există şi nu a putut fi creat. Anunţă un administrator de eroarea aceasta." + +msgid "Expand all images" +msgstr "Măreşte toate imaginile" + +msgid "Expires" +msgstr "Expiră pe:" + +msgid "Expires:" +msgstr "Expiră pe:" + +msgid "Extension icon displayed, click image to open file." +msgstr "Icoană; dă un click pentru a deschide fişierul." + +msgid "Failed to write file to disk." +msgstr "Nu am putut scrie pe disc." + +msgid "FAQ entry deleted" +msgstr "FAQ şters" + +msgid "FAQ entry edited" +msgstr "FAQ editat" + +msgid "FAQ entry successfully added." +msgstr "FAQ adăugat" + +msgid "FAQ Management" +msgstr "Administrare FAQ" + +msgid "FAQ" +msgstr "FAQ" + +msgid "File hash bans" +msgstr "Fişiere banate" + +msgid "File Only" +msgstr "Numai fişierul" + +msgid "File successfully deleted." +msgstr "Fişier şters." + +msgid "File transfer failure. Please go back and try again." +msgstr "N-am putut uploada fişierul. Încearcă din nou." + +msgid "File was not fully uploaded. Please go back and try again." +msgstr "Fişierul nu a fost uploadat complet. Încearcă din nou." + +msgid "File was not properly thumbnailed" +msgstr "Fişierul n-a fost redimensionat corect" + +msgid "File" +msgstr "Fişier" + +msgid "File
Removed" +msgstr "Fişier
Şters" + +msgid "Files" +msgstr "Fişiere" + +msgid "Filetype added." +msgstr "Tipul de fişier adăugat." + +msgid "Filetype deleted." +msgstr "Tipul de fişier şters." + +msgid "Filetype updated." +msgstr "Tipul de fişier actualizat." + +msgid "Filetype" +msgstr "Fişier" + +msgid "First 100 posts shown." +msgstr "Primele 100 de mesaje." + +msgid "First 100 posts" +msgstr "Primele 100 de mesaje" + +msgid "first phrase here" +msgstr "prima frază" + +msgid "First Post ID" +msgstr "ID-ul primului mesaj" + +msgid "for the following reason" +msgstr "pentru că" + +msgid "Forced anonymous" +msgstr "Anonimat forţat" + +msgid "forever" +msgstr "permanent" + +msgid "Frames removed" +msgstr "Frame-uri ascunse" + +msgid "From" +msgstr "De la" + +msgid "Front Page" +msgstr "Prima pagină" + +msgid "Front" +msgstr "Înainte" + +msgid "Get posting password" +msgstr "Parola mesajului" + +msgid "Global configuration succesfully updated." +msgstr "Configuraţia globală actualizată." + +msgid "Global options" +msgstr "Opţiuni globale" + +msgid "Go" +msgstr "Mai departe" + +msgid "Header image" +msgstr "Header" + +msgid "Heading" +msgstr "Subiect" + +msgid "Height" +msgstr "Înălţime" + +msgid "Hidden" +msgstr "Ascuns" + +msgid "hidden." +msgstr "ascunsă." + +msgid "Hide Directories" +msgstr "Ascunde directoarele" + +msgid "Hide the watched threads box" +msgstr "Ascunde discuţiile urmărite" + +msgid "Home" +msgstr "Acasă" + +msgid "ID" +msgstr "ID" + +msgid "If checked, the configured ban message will be added to the end of the post." +msgstr "Selectează pentru a adăuga mesajul de banare la sfârşitul mesajului userului." + +msgid "If checked, this section will be collapsed by default when a user visits the site." +msgstr "Selectează pentru a ascunde secţiunea la accesare." + +msgid "If enabled, each post will display the poster's ID, which is a representation of their IP address." +msgstr "Dacă alegi Da, fiecare răspuns va afişa ID-ul userului, adică o reprezentare a IP-ului său." + +msgid "If set to yes, a catalog.html file will be built with the other files, displaying the original picture of every thread in a box. This will only work on normal/oekaki imageboards." +msgstr "Dacă alegi Da, va fi creat fişierul catalog.html care va afişa imaginile originale din fiecare discuţie. Funcţionează doar pe forumurile normale şi cele de Oekaki." + +msgid "If set to yes, new threads will not require an image to be posted." +msgstr "Dacă alegi Da, discuţiile noi nu vor avea nevoie de o imagine." + +msgid "If set to yes, this board will appear in bold in the menu" +msgstr "Dacă alegi Da, forumul va apărea boldat în meniu." + +msgid "If set to yes, this board will appear in italics in the menu" +msgstr "Dacă alegi Da, forumul va apărea cu italice în meniu." + +msgid "If set to yes, users will be redirected to the thread they replied to/posted after posting. If set to no, users will be redirected to the first page of the board." +msgstr "Dacă alegi Da, userii vor fi redirecţionaţi către mesajul lor după ce-au postat. Daca alegi Nu, vor fi redirecţionaţi către prima pagină a forumului." + +msgid "If set to yes, users will not be allowed to enter a name, making everyone appear as Anonymous" +msgstr "Dacă alegi Da, userii nu vor putea alege un nume, apărând toţi ca Anonim." + +msgid "If this is set to Select a Board, it will not be shown in the menu." +msgstr "Dacă laşi valoarea implicită, nu va apărea în meniu." + +msgid "Image height" +msgstr "Înălţimea imaginii" + +msgid "Image successfully deleted from your post." +msgstr "Imaginea a fost ştearsă din mesaj." + +msgid "Image width" +msgstr "Lăţimea imaginii" + +msgid "Image" +msgstr "Imagine" + +msgid "Images and embedding" +msgstr "Imagini şi embed" + +msgid "Images greater than %1x%2 pixels will be thumbnailed." +msgstr "Imaginile mai mari de %1x%2 vor fi redimensionate." + +msgid "Images" +msgstr "Imagini" + +msgid "Important" +msgstr "Important" + +msgid "Improper filetype." +msgstr "Fişierul nu e permis." + +msgid "Include header" +msgstr "Header inclus" + +msgid "Incorrect captcha entered." +msgstr "Captcha incorect." + +msgid "Incorrect password." +msgstr "Parolă incorectă." + +msgid "Incorrect username/password." +msgstr "Nume / parolă incorectă" + +msgid "Index" +msgstr "Index" + +msgid "Inject" +msgstr "Execută" + +msgid "Inserted SQL" +msgstr "SQL inserat" + +msgid "Integer values must be entered correctly." +msgstr "Numerele întregi trebuiesc introduse corect." + +msgid "Invalid action" +msgstr "Acţiune invalidă." + +msgid "Invalid ban ID" +msgstr "ID de ban invalid." + +msgid "Invalid board directory." +msgstr "Director inavlid." + +msgid "Invalid board." +msgstr "Forum inavlid." + +msgid "Invalid ID" +msgstr "ID invalid" + +msgid "Invalid image data was sent. The error may be that the applet you are using is configured incorrectly (POO compatibility was be enabled). Save a screenshot of your work in case of continued failure." +msgstr "A fost trimisă o imagine invalidă. E posibil ca asta să se întâmple din cauză că appletul n-a fost configurat corect. Fă un screenshot la ce-ai făcut, în caz că pică appletul de tot." + +msgid "Invalid MIME type for this filetype." +msgstr "MIME invalid pentru acest tip de fişier." + +msgid "Invalid operation." +msgstr "Operaţie invalidă." + +msgid "Invalid reply image." +msgstr "Imagine invalidă." + +msgid "Invalid response code" +msgstr "Cod de răspuns invalid" + +msgid "Invalid session, please log in again." +msgstr "Sesiune invalidă, loghează-te din nou." + +msgid "Invalid session." +msgstr "Sesiune invalidă." + +msgid "Invalid staff ID." +msgstr "ID de staff invalid." + +msgid "Invalid thread ID %s. This may have been caused by the thread recently being deleted." +msgstr "ID de discuţie %s invalid. E posibil ca discuţia să fi fost ştearsă recent." + +msgid "Invalid thread ID. This may have been caused by the thread recently being deleted." +msgstr "ID de discuţie invalid. E posibil ca discuţia să fi fost ştearsă recent." + +msgid "Invalid thread ID." +msgstr "ID de discuţie invalid." + +msgid "Invalid video ID." +msgstr "ID de video invalid." + +msgid "Invalid video type." +msgstr "Tip de video invalid." + +msgid "IP address and ban type" +msgstr "IP şi tipul de ban" + +msgid "IP Address Search" +msgstr "Căutare după IP" + +msgid "IP Address" +msgstr "Adresa IP" + +msgid "IP Range Bans" +msgstr "Serie de IP-uri banată" + +msgid "IP Range" +msgstr "Serie de IP-uri" + +msgid "IP Search" +msgstr "Căutare după IP" + +msgid "IP" +msgstr "IP" + +msgid "Is replaced by" +msgstr "E înlocuit de" + +msgid "Janitor" +msgstr "Junior" + +msgid "Last 50 posts shown." +msgstr "Ultimele 50 de mesaje." + +msgid "Last 50 posts" +msgstr "Ultimele 50 de mesaje" + +msgid "Last active" +msgstr "Ultima activitate" + +msgid "Last Post" +msgstr "Ultimul mesaj" + +msgid "Load balance password" +msgstr "Parola scriptului adiţional" + +msgid "Load balance URL" +msgstr "Script adiţional" + +msgid "Locale to use on this board. Leave blank to use the locale defined in config.php" +msgstr "Limba forumului. Lasă gol ca să foloseşti limba definită în config.php" + +msgid "Locale" +msgstr "Limbă" + +msgid "Lock" +msgstr "Blocare" + +msgid "Locked thread" +msgstr "Blocat discuţie" + +msgid "Locked" +msgstr "Blocat" + +msgid "Log in again." +msgstr "Loghează-te din nou." + +msgid "Log in" +msgstr "Logare" + +msgid "Log out" +msgstr "Delogare" + +msgid "Logged in" +msgstr "S-a logat" + +msgid "Logo" +msgstr "Logo" + +msgid "Looking for orphans in" +msgstr "Caut orfani în" + +msgid "Looking for unused images in" +msgstr "Caut imagini nefolosite în" + +msgid "Manage Ads" +msgstr "Administrare reclame" + +msgid "Manage Boards" +msgstr "Administrare forumuri" + +msgid "Manage embeds" +msgstr "Administrare embeduri" + +msgid "Manage locked threads" +msgstr "Administrare discuţii blocate" + +msgid "Manage stickies" +msgstr "Administrare mesaje importante" + +msgid "Manage" +msgstr "Administrare" + +msgid "Mark page" +msgstr "Marcare pentru ştergere" + +msgid "Marked for deletion (old)." +msgstr "Marcat pentru ştergere (e vechi)" + +msgid "Maximum board pages" +msgstr "Număr maxim de pagini" + +msgid "Maximum file size allowed is" +msgstr "Dimensiune maximă pentru fişiere este" + +msgid "Maximum image size" +msgstr "Dimensiune maximă pentru imagini" + +msgid "Maximum message length" +msgstr "Dimensiune maximă pentru mesaj" + +msgid "Maximum thread age (Hours)" +msgstr "Vârsta maximă a discuţiei (ore)" + +msgid "Maximum thread replies" +msgstr "Număr maxim de răsunsuri" + +msgid "Maxmimum size of uploaded images, in bytes." +msgstr "Dimensiunea maximă a imaginilor uploadate, în bytes." + +msgid "Maxmimum thumbnail height" +msgstr "Înălţimea maximă a thumbnailului" + +msgid "Maxmimum thumbnail width" +msgstr "Lăţimea maximă a thumbnailului" + +msgid "Message too long. Click %shere%s to view the full text." +msgstr "Mesaj prea mare Click %saici%s pentru a vedea textul complet." + +msgid "Message" +msgstr "Mesaj" + +msgid "MIME type" +msgstr "Tipul de fişier (MIME type)" + +msgid "Misc" +msgstr "Altele" + +msgid "Missing a temporary folder." +msgstr "Lipseşte un folder temporar." + +msgid "Mod" +msgstr "Mod" + +msgid "Moderates" +msgstr "Moderează" + +msgid "Moderating Boards" +msgstr "Forumuri de moderare" + +msgid "Moderating boards" +msgstr "Moderare forumuri" + +msgid "Moderation" +msgstr "Moderare" + +msgid "Moderator" +msgstr "Moderator" + +msgid "Moderators" +msgstr "Moderatori" + +msgid "Modify staff member" +msgstr "Modifică membru al staff-ului" + +msgid "Modify" +msgstr "Modifică" + +msgid "ModLog" +msgstr "ModLog" + +msgid "Module settings" +msgstr "Configurare module" + +msgid "Modules" +msgstr "Module" + +msgid "More" +msgstr "Mai mult" + +msgid "Move complete." +msgstr "Mutare completă." + +msgid "Move Files" +msgstr "Mutare fişiere" + +msgid "Move thread" +msgstr "Mutare discuţie" + +msgid "Name to display when a name is not attached to a post." +msgstr "Numele care se va afişa in afara unui mesaj." + +msgid "Name" +msgstr "Nume" + +msgid "never" +msgstr "niciodată" + +msgid "New image" +msgstr "Imagine nouă" + +msgid "New password again" +msgstr "Din nou" + +msgid "New password" +msgstr "Parolă nouă" + +msgid "New Thread" +msgstr "Discuţie nouă" + +msgid "News entry successfully added." +msgstr "Ştire adugată." + +msgid "News Management" +msgstr "Administrare ştiri" + +msgid "News post deleted" +msgstr "Ştire ştearsă" + +msgid "News post edited" +msgstr "Ştire editată" + +msgid "News" +msgstr "Ştiri" + +msgid "Next" +msgstr "Înainte" + +msgid "No announcements yet." +msgstr "Încă nu sunt anunţuri" + +msgid "No Appeal" +msgstr "Fără drept de apel" + +msgid "No blotter entries" +msgstr "Nu sunt buletine." + +msgid "No blotter entries." +msgstr "Nu sunt buletine." + +msgid "No boards" +msgstr "Pe nici un forum" + +msgid "No embedding" +msgstr "Fără embed" + +msgid "No Embedding" +msgstr "Fără embed" + +msgid "No Embeds yet." +msgstr "Nu există embeduri." + +msgid "No FAQ entries yet." +msgstr "Nu este nimic în FAQ." + +msgid "No file was uploaded." +msgstr "Nu a fost uploadat nici un fişier." + +msgid "No File" +msgstr "Fără fişier" + +msgid "No locked threads." +msgstr "Nici o discuţie nu e blocată." + +msgid "No news posts yet." +msgstr "Încă nu sunt ştiri." + +msgid "No recent images currently need review." +msgstr "Nu este nici o imagine de revizuit." + +msgid "No reports to show." +msgstr "Nu este nici un raport." + +msgid "No results found for" +msgstr "Nu am găsit nimic pentru" + +msgid "No Rule entries yet." +msgstr "Nu este nici o regulă." + +msgid "No stickied threads." +msgstr "Nu sunt discuţii importante." + +msgid "No threads." +msgstr "Nu sunt discuţii." + +msgid "No valid posts specified." +msgstr "N-ai selectat nici un mesaj valid." + +msgid "No visible boards" +msgstr "Forumuri invizibile" + +msgid "No" +msgstr "Nu" + +msgid "No." +msgstr "Nr." + +msgid "None" +msgstr "Niciunul" + +msgid "Normal Imageboard" +msgstr "Imageboard normal" + +msgid "Not Displayed" +msgstr "Neafişată" + +msgid "NOTICE: You are using the default administrator account. Anyone can log in to this account, so a second administrator account needs to be created. Create another, log in to it, and delete this one." +msgstr "ATENŢIE: Foloseşti contul de administrator implicit. Oricine se poate loga pe acest cont, deci e necesară crearea unui nou cont de administrator. Crează-l, loghează-te pe el, şi şterge contul acesta." + +msgid "Number of images to show per page" +msgstr "Numărul de imagini pe pagină" + +msgid "Number of posts to show per page" +msgstr "Numărul de mesaje pe pagină" + +msgid "Oekaki imageboard" +msgstr "Oekaki" + +msgid "Old password" +msgstr "Parola veche" + +msgid "omitted" +msgstr "omis(e)" + +msgid "Online now" +msgstr "Online" + +msgid "Only moderators of the board and admins can make new posts/replies" +msgstr "Numai administratorii şi moderatorii pot posta" + +msgid "Only put in the letter(s) of the board directory, no slashes!" +msgstr "Pune doar litera / literele forumului, fără slashuri!" + +msgid "Open images in new window" +msgstr "Deschide imaginile în fereastră nouă" + +msgid "Optimizing all tables in database." +msgstr "Optimizare tabele." + +msgid "or" +msgstr "sau" + +msgid "Order to show board in menu list, in ascending order." +msgstr "Ordinea în care forumul să apară în listă (crescătoare)." + +msgid "Order to show this section with others, in ascending order" +msgstr "Ordinea în care secţiunea să apară în listă (crescătoare)" + +msgid "Order" +msgstr "Ordine" + +msgid "Overrides the header set in the config file. Leave blank to use configured global header image. Needs to be a full url including http://. Set to none to show no header image." +msgstr "Înlocuieşte headerul din config.php. Lasă-l gol pentru a folosi headerul global. Trebuie să fie un URL complet (cu http:// )" + +msgid "Pages" +msgstr "Pagini" + +msgid "Paint with" +msgstr "Desenează cu" + +msgid "Paint!" +msgstr "Dă-i drumul!" + +msgid "Password successfully changed." +msgstr "Parola schimbată" + +msgid "Password" +msgstr "Parola" + +msgid "Placed:" +msgstr "Pe:" + +msgid "Please enter a positive amount of seconds, or zero for a permanent ban." +msgstr "Introdu un număr pozitiv de secunde, sau 0 pentru ban permanent." + +msgid "Please enter a search query." +msgstr "Scrie query-ul." + +msgid "Please enter a width/height greater than zero." +msgstr "Lăţimea / înălţimea trebuie să fie mai mare ca 0." + +msgid "Please enter a width/height less than or equal to 750." +msgstr "Lăţimea / înălţimea trebuie să fie cel mult 750." + +msgid "Please fill in all required fields." +msgstr "Umple toate câmpurile." + +msgid "Please make sure your file is smaller than %dB" +msgstr "Fişierul trebuie să fie mai mic de %dB" + +msgid "Please select a board." +msgstr "Alege un forum." + +msgid "Please select only one image to upload." +msgstr "Alege o singură imagine." + +msgid "Please wait a moment before posting again." +msgstr "Aşteaptă puţin înainte să postezi din nou." + +msgid "Popular" +msgstr "Popular" + +msgid "Position" +msgstr "Poziţie" + +msgid "Post %s successfully deleted." +msgstr "Mesajul %s a fost şters." + +msgid "Post added." +msgstr "Mesaj adăugat." + +msgid "Post Number" +msgstr "Numărul mesajului" + +msgid "Post preview" +msgstr "Previzualizare" + +msgid "Post successfully deleted." +msgstr "Mesaj şters." + +msgid "Post" +msgstr "Mesaj" + +msgid "Postbox notice" +msgstr "Notificări" + +msgid "Posting a blacklisted link." +msgstr "Ai postat un link interzis." + +msgid "Posting mode: Reply" +msgstr "Răspuns" + +msgid "Posting rates (past hour)" +msgstr "Număr de postări în ultima oră" + +msgid "Posts per board in past 24hrs" +msgstr "Mesaje pe forumuri în ultimele 24 de ore" + +msgid "Posts per board in past week" +msgstr "Mesaje pe forumuri în ultima săptămână" + +msgid "Posts" +msgstr "Mesaje" + +msgid "Presets" +msgstr "Preseturi" + +msgid "Prev" +msgstr "Înapoi" + +msgid "Preview" +msgstr "Previzualizare" + +msgid "Previous bans on this IP" +msgstr "Banuri anterioare pentru IP" + +msgid "Previous" +msgstr "Înapoi" + +msgid "Proxy list" +msgstr "Lista de Proxy-uri" + +msgid "Put 0 for no display, 1 to display." +msgstr "Pune 0 pentru a o ascunde, 1 pentru a o afişa." + +msgid "Query executed successfully" +msgstr "Query executat" + +msgid "Query" +msgstr "Query" + +msgid "Quick Reply" +msgstr "Răspuns rapid" + +msgid "Ran cleanup" +msgstr "Curăţat" + +msgid "Raw HTML which will be inserted at the top of each page of the board." +msgstr "HTML ce va fi inserat deasupra fiecărei pagini." + +msgid "Read this thread from the beginning" +msgstr "Citeşte discuţia de la început" + +msgid "Reason" +msgstr "Motiv" + +msgid "Reason:" +msgstr "Motiv:" + +msgid "Rebuild all html files" +msgstr "Reconstruieşte fişierele HTML" + +msgid "Rebuild complete. Took %d seconds." +msgstr "Reconstrucţie completă, în %d secunde." + +msgid "Rebuild HTML after edit?" +msgstr "Să reconstruiesc HTML-urile după editare?" + +msgid "Rebuilt all boards and threads" +msgstr "Reconstruit toate forumurile şi discuţiile" + +msgid "Recent posts" +msgstr "Mesaje raportate" + +msgid "Recently uploaded images" +msgstr "Imagini raportate" + +msgid "Redirect to thread" +msgstr "Redirecţionare către discuţie" + +msgid "Redirecting" +msgstr "Redirecţionare" + +msgid "Refresh watched threads" +msgstr "Actualizează fişierele urmărite" + +msgid "Regenerated %s" +msgstr "Am reconstruit %s" + +msgid "Regenerated menu pages" +msgstr "Am reconstruit meniurile" + +msgid "Regular expression" +msgstr "Expresie regulară" + +msgid "Remove Frames" +msgstr "Ascunde frame-uri" + +msgid "Remove" +msgstr "Şterge" + +msgid "Removed Directory" +msgstr "Director şters" + +msgid "Removed File" +msgstr "Fişier şters" + +msgid "Removed word from wordfilter" +msgstr "Filtru şters" + +msgid "Removing posts deleted more than one week ago from the database." +msgstr "Ştergere mesaje şterse cu mai mult de o săptămână în urmă." + +msgid "Render Time" +msgstr "A durat" + +msgid "Rep." +msgstr "Răspunsuri" + +msgid "Replacement" +msgstr "E înlocuit de" + +msgid "Replies displayed per stickied thread (in thread list)" +msgstr "Răspunsuri în discuţiile importante (în lista de discuţii)" + +msgid "Replies displayed per thread (in thread list)" +msgstr "Răspunsuri în discuţii (în lista de discuţii)" + +msgid "Replies" +msgstr "Răspunsuri" + +msgid "Reply #%1$s's thread (#%2$s) does not exist! It has been deleted." +msgstr "Discuţia %2$s nu conţine mesajul %1$s; discuţia a fost ştearsă." + +msgid "Reply #%d's thread (#%d) does not exist! It has been deleted." +msgstr "Mesajul #%d nu apare în discuţia %d! A fost şters." + +msgid "reply to" +msgstr "răspuns la" + +msgid "Reply" +msgstr "Răspunde" + +msgid "Report" +msgstr "Raportează" + +msgid "Reporter IP" +msgstr "IP-ul care a raportat" + +msgid "Reporting allows users to report posts, adding the post to the report list." +msgstr "Raportarea permite userilor să raporteze mesajele, adăugând mesajul la lista de raporturi" + +msgid "Reports" +msgstr "Rapoarte" + +msgid "Restore watched threads" +msgstr "Restaurează fişierele urmărite" + +msgid "Results for" +msgstr "Rezultate pentru" + +msgid "Results from %s to %s of %s" +msgstr "Rezultate de la %s până la %s din %s" + +msgid "Results" +msgstr "Rezultate" + +msgid "Return" +msgstr "Înapoi" + +msgid "Rule entry deleted" +msgstr "Regulă ştearsă" + +msgid "Rule entry edited" +msgstr "Regulă editată" + +msgid "Rules entry successfully added." +msgstr "Regulă adugată." + +msgid "Rules Management" +msgstr "Administrarea regulilor" + +msgid "Rules" +msgstr "Reguli" + +msgid "Run Cleanup" +msgstr "Curăţă!" + +msgid "Search Help" +msgstr "Cum să cauţi" + +msgid "Search posts" +msgstr "Caută mesaje" + +msgid "Search" +msgstr "Caută" + +msgid "second phrase here" +msgstr "a doua frază" + +msgid "Seconds" +msgstr "Secunde" + +msgid "Section added." +msgstr "Secţiune adăugată." + +msgid "Section deleted." +msgstr "Secţiune ştearsă." + +msgid "Section updated." +msgstr "Secţiune actualizată." + +msgid "Section" +msgstr "Secţiune" + +msgid "Select a Board" +msgstr "Alege un forum" + +msgid "Select a Section" +msgstr "Alege o secţiune" + +msgid "Select Board" +msgstr "Alege forumul" + +msgid "Selecting No will prevent any reading of any page on the level of the boards on the server. It will also act as a global ban." +msgstr "Dacă selectezi Nu, nici o pagină nu va putea fi citită. Are acelaşi efect ca un ban global." + +msgid "Send Appeal" +msgstr "Trimite cererea de debanare" + +msgid "Separate search terms with the word" +msgstr "Cuvintele-cheie se separă cu" + +msgid "Show All" +msgstr "Arată tot" + +msgid "Show Directories" +msgstr "Arată directoarele" + +msgid "Show ID" +msgstr "Arată ID" + +msgid "Show Posting Password" +msgstr "Arată parola" + +msgid "Show/Hide" +msgstr "Arată / Ascunde" + +msgid "Shown below" +msgstr "Vezi mai jos" + +msgid "Single IP Bans" +msgstr "IP-uri unice banate" + +msgid "Single IP" +msgstr "IP unic" + +msgid "Site Administration" +msgstr "Administrare globală" + +msgid "Site Name" +msgstr "Site" + +msgid "Site Styles" +msgstr "Stilurile" + +msgid "Size" +msgstr "Dimensiune" + +msgid "some phrase here" +msgstr "fraza ta" + +msgid "Sorry, a generic error has occurred." +msgstr "S-a întâmplat ceva naşpa." + +msgid "Sorry, because of your numerous failed logins, you have been locked out from logging in for 20 minutes. Please wait and then try again." +msgstr "Pentru că ai încercat să te loghezi de prea multe ori, ţi s-a blocat accesul pentru 20 de minute. Aşteaptă, apoi încearcă din nou." + +msgid "Sorry, embed may only be enabled on normal imageboards." +msgstr "Embedarea se poate activa numai pe imageboarduri normale." + +msgid "Sorry, that filetype is not allowed on this board." +msgstr "Fişier interzis pe acest forum." + +msgid "Sorry, this board is locked and can not be posted in." +msgstr "Forumul e blocat, şi ca atare nu poţi posta în el." + +msgid "Sorry, this thread is locked and can not be replied to." +msgstr "Discuţia a fost blocată şi ca atare nu poţi răspunde." + +msgid "Sorry, your message is too long. Message length: %d, maxmimum allowed length: %d" +msgstr "Mesajul e prea mare. Dimensiunea mesajului: %d, dimensiunea maximă permisă: %d" + +msgid "Sorry, your search returned zero results." +msgstr "N-am găsit nimica." + +msgid "Source" +msgstr "Sursa" + +msgid "Space Used" +msgstr "Spaţiu ocupat" + +msgid "Spamfilter" +msgstr "Filtru de spam" + +msgid "SQL query" +msgstr "SQL query" + +msgid "Staff member successfully added." +msgstr "Membru adăugat" + +msgid "Staff Note" +msgstr "Nota staff-ului" + +msgid "Staff rights" +msgstr "Drepturi" + +msgid "Staff successfully deleted" +msgstr "Membru şters" + +msgid "Staff successfully updated" +msgstr "Staff actualizat" + +msgid "Staff" +msgstr "Staff" + +msgid "Statistics" +msgstr "Statistici" + +msgid "Stickied thread" +msgstr "Discuţie importantă" + +msgid "Stickied" +msgstr "Acuma e imporant" + +msgid "Sticky" +msgstr "E important?" + +msgid "Style" +msgstr "Stil" + +msgid "Styles" +msgstr "Stiluri" + +msgid "Subject" +msgstr "Subiect" + +msgid "Submit" +msgstr "Răspunde" + +msgid "Successfully marked previous posts as reviewed." +msgstr "Toate mesajele anterioare au fost revizuite." + +msgid "Supported file types are" +msgstr "Fişierele permise sunt" + +msgid "System lockout" +msgstr "Sistem blocat" + +msgid "Tag" +msgstr "Marchează" + +msgid "Template edited" +msgstr "Template editat" + +msgid "Template editor" +msgstr "Editor de template-uri" + +msgid "Template" +msgstr "Template" + +msgid "Text board" +msgstr "Textboard" + +msgid "Text boards may have only one thread with a unique subject. Please pick another." +msgstr "Pe forumurile de text, o singură discuţie poate avea un subiect. Alege şi tu altceva." + +msgid "Text boards only. If enabled, the list of threads displayed on the front page will be formatted differently to be compact." +msgstr "Numai pentru forumurile de text. Dacă alegi asta, lista de discuţii de pe prima pagină va fi mai compactă." + +msgid "That file already exists on the server." +msgstr "Fişierul există deja pe server." + +msgid "That file does not match up with the required mime type for that format." +msgstr "Tipul fişierului nu corespunde cu vreun tip permis pentru acest format." + +msgid "That file has already been deleted." +msgstr "Fişierul a fost şters deja." + +msgid "That ID does not exist." +msgstr "Nu există acest ID." + +msgid "That ID is a reply, not a thread." +msgstr "ID-ul e un răspuns, nu o discuţie." + +msgid "That IP has already been banned." +msgstr "IP-ul este deja banat." + +msgid "That is not a Oekaki compatible board!" +msgstr "Ăsta nu e un forum de Oekaki!" + +msgid "That name is for internal use. Please pick another." +msgstr "Numele acesta este rezervat. Alege şi tu altceva." + +msgid "That page is for admins only." +msgstr "Pagină rezervată pentru administratori." + +msgid "That page is for moderators and administrators only." +msgstr "Pagină rezervată pentru administratori şi moderatori." + +msgid "That post has been cleared as not requiring any deletion." +msgstr "Mesajul este în regula, nu trebuie şters." + +msgid "That post is already in the report list." +msgstr "Mesajul a fost deja raportat." + +msgid "That thread has yet to be deleted." +msgstr "Discuţia n-a fost încă ştearsă." + +msgid "That thread may have been recently deleted." +msgstr "Discuţia s-ar putea să fi fost deja ştearsă." + +msgid "That video ID has already been posted %shere%s." +msgstr "Acest video a fost postat %saici%s." + +msgid "That word already exists." +msgstr "Cuvântul există deja." + +msgid "That's either not a thread, or it's not deleted." +msgstr "Fie nu e discuţie, fie n-a fost ştearsă." + +msgid "The 5 newest replies are shown below." +msgstr "Cele mai noi 5 răspunsuri." + +msgid "The amount of time to ban the hash of the image which was posted under this ID. Leave blank to not ban the image, 0 for an infinite global ban, or any number of seconds for that duration of a global ban." +msgstr "Cât timp e valabil banul pentru imaginea postată cu acest ID. Lasă gol ca să nu banezi imaginea, 0 pentru un ban permanent global, sau un număr pozitiv de secunde pentru o banare globală." + +msgid "The change will not be apparent until the html files are rebuilt." +msgstr "Modificările nu se vor vedea până la regenerearea HTML-urilor." + +msgid "The data sent was not a JPG or PNG file. Please reattempt your save (and save a screenshot just in case of continued failure)." +msgstr "Imaginea trimisă nu e JPG sau PNG. Încearcă să salvezi din nou (şi fă un screenshot în caz că pică appletul de tot)." + +msgid "The data sent was not an image. Please reattempt your save (and save a screenshot just in case of continued failure)." +msgstr "Imaginea n-a fost updatată. Încearcă să salvezi din nou (şi fă un screenshot în caz că pică appletul de tot)." + +msgid "The description of the image being banned. Not applicable if the above box is blank." +msgstr "Descrierea imaginii banate. Nu e valabilă dacă ai lăsat gol câmpul anterior." + +msgid "The directory of the board." +msgstr "Directorul forumului." + +msgid "The extension this will be applied to. Must be lowercase" +msgstr "Extensia fişierului. Trebuie să fie doar litere mici." + +msgid "The first post of this board will recieve this ID." +msgstr "ID-ul primului mesaj de pe acest forum." + +msgid "The full http:// URL to the load balance script for this board. The script will handle file uploads, and creation of thumbnails. Only one script per board can be used, and there must be a src and thumb dir in the same folder as the script. Set to nothing to disable." +msgstr "URL-ul (cu http://) a scriptului adiţional pentru forum. Scriptul va face uploadul propriu-zis şi crearea de thumbnailuri. Se poate folosi un singur script pe fiecare forum, şi în directorul în care se află trebuie să aibă directoarele src şi thumb. Lasă gol pentru a-l dezactiva." + +msgid "The height of the image. Needs to be set to prevent the page from jumping around while images load." +msgstr "Înălţimea imaginii. Necesară ca layoutul să rămână la fel chiar dacă imagine nu s-a încărcat încă." + +msgid "The image which will be used, found in inc/filetypes." +msgstr "Imaginea folosită pentru tipul acesta de fişier; se află în inc/filetypes." + +msgid "The load balancer script stopped unexpectedly." +msgstr "Scriptul adiţional s-a oprit în mod neaşteptat." + +msgid "The load balancer script was unable to copy the file you uploaded." +msgstr "Scriptul adiţional nu a putut copia imaginea uploadată." + +msgid "The load balancer script was unable to create the thumbnail for that image." +msgstr "Scriptul adiţional nu a putut redimensiona imaginea." + +msgid "The MIME type which must be present with an image uploaded in this type. Leave blank to disable." +msgstr "MIME type-ul fişierului; trebuie să existe pentru a putea uploada fişierului. Poate fi lăsat gol." + +msgid "The name of the board." +msgstr "Numele forumului." + +msgid "The name of the section" +msgstr "Numele secţiunii" + +msgid "The number of replies a thread can have before autosaging to the back of the board." +msgstr "Numărul de răspunsuri după care discuţia nu va mai fi actualizată pe prima pagină." + +msgid "The old password you provided did not match the current one." +msgstr "Parola pe care-ai pus-o nu e cea curentă." + +msgid "The password which will be passed to the script above. The script must have this same password entered at the top, in the configuration area." +msgstr "Parola pentru scriptul de mai sus. Scriptul trebuie să conţină această parolă în zona de configurare." + +msgid "The passwords of the load balancer password in the board configuration and the load receiver script differ." +msgstr "Parolele pentru scriptul adiţional din config.php şi din scriptul în sine sunt diferite." + +msgid "The proxy list is assumed to be in plaintext *.*.*.*:port or *.*.*.* format, one IP per line." +msgstr "Lista de proxy-uri e text simplu, în format: *.*.*.*:port sau *.*.*.*, cu un singur IP pe linie." + +msgid "The second password did not match the first." +msgstr "Ambele parole trebuie să fie identice." + +msgid "The section the board is in. This is used for displaying the list of boards on the top and bottom of pages." +msgstr "Secţiunea în care se află forumul. În funcţie de asta, forumul se va afişa în lista de la începutul şi sfârşitul fiecărei pagini. Secţiunea trebuie să existe deja (Vezi Editare secţiuni)" + +msgid "The server has encountered an error saving your image. Save a screenshot of your work in case of continued failure." +msgstr "N-am putut salva imaginea. Fă un screenshot la ce-ai făcut, în caz că pică appletul de tot." + +msgid "The style which will be set when the user first visits the board." +msgstr "Stilul vizibil atunci când un user viziteaza pentru prima oară forumul." + +msgid "The type of ban. A single IP can be banned by providing the full address. A whitelist ban prevents that IP from being banned. An IP range can be banned by providing the IP range you would like to ban, in this format: 123.123.12" +msgstr "Tipul de banare. Un IP unic se poate bana folosind adresa lui completă. O listă albă previne banarea acelui IP. O serie de IP-uri banează toate IP-urile dependente; formatul este 123.123.12" + +msgid "The type of posts which will be accepted on this board. A normal imageboard will feature image and extended format posts, a text board will have no images, an Oekaki board will allow users to draw images and use them in their posts, and an Upload imageboard will be styled more towards file uploads." +msgstr "Tipul de postări permise. Un imageboard normal va afişa imagini şi texte extinse; un forum text nu va avea imagini; un forum de Oekaki permite desenarea şi postarea de imagini, iar un forum de upload permite uploadarea de fişiere." + +msgid "The type of posts which will be accepted on this board. A normal imageboard will feature image and extended format posts, a text board will have no images, and an Oekaki board will allow users to draw images and use them in their posts." +msgstr "Tipul de postări permise. Un imageboard normal va afişa imagini şi texte extinse; un forum text nu va avea imagini; un forum de Oekaki permite desenarea şi postarea de imagini." + +msgid "The uploaded file exceeds the upload_max_filesize directive (%s) in php.ini." +msgstr "Fişierul postat e mai mare decât e specificat de directiva upload_max_filesize (%s) în php.ini." + +msgid "The uploaded file was only partially uploaded." +msgstr "Fişierul a fost uloadat numai parţial." + +msgid "The width of the image. Needs to be set to prevent the page from jumping around while images load." +msgstr "Lăţimea imaginii. Necesară ca layoutul să rămână la fel chiar dacă imagine nu s-a încărcat încă." + +msgid "There are currently no bans" +msgstr "Nu există nici un ban" + +msgid "There are currently no bans." +msgstr "Nu există nici un ban." + +msgid "There are currently no filetypes." +msgstr "Nu sunt setate tipuri de fişiere." + +msgid "There are currently no sections." +msgstr "Nu există secţiuni." + +msgid "There are currently no threads to display." +msgstr "Nu există discuţii." + +msgid "There is already a file with that name." +msgstr "Mai există un fişier cu acest nume." + +msgid "There was an error during install, and the ads table didn't get populated." +msgstr "A apărut o eroare la instalare şi tabelul de reclame nu a fost populat." + +msgid "There was an error in trying to delete your post" +msgstr "Nu am putut şterge discuţia." + +msgid "There was no image data sent. Please reattempt your save (and save a screenshot just in case of continued failure)." +msgstr "Imaginea n-a fost trimisă. Încearcă să salvezi din nou (şi fă un screenshot în caz că pică appletul de tot)." + +msgid "This board does not allow post reporting." +msgstr "Pe forumul acesta nu se pot raporta răspunsurile." + +msgid "This can be left blank, however it will appear at the very top of the list" +msgstr "Poate fi lăsat gol; intrarea va fi prima în listă." + +msgid "This can be left blank. It will be reset with the default height set in config.php" +msgstr "Poate fi lăsat gol. Valoarea implicită va fi cea din config.php" + +msgid "This can be left blank. It will be reset with the default width set in config.php" +msgstr "Poate fi lăsat gol. Valoarea implicită va fi cea din config.php" + +msgid "This file is disabled because KU_STATICMENU is set to true." +msgstr "Cum KU_STATICMENU e adevărat, nu poţi vedea fişierul acesta." + +msgid "This message will be shown only on this page and only to staff, not to the user." +msgstr "Mesajul va fi vizibil doar pentru staff şi va apărea doar pe această pagină. Userii nu îl vor vedea." + +msgid "This post has been deleted." +msgstr "Acest răspuns a fost şters." + +msgid "Thread %s on /%s/" +msgstr "Discuţia %s de pe /%s/" + +msgid "Thread %s successfully deleted." +msgstr "Discuţia %s a fost ştearsă." + +msgid "Thread successfully deleted." +msgstr "Discuţie ştearsă." + +msgid "Thread successfully locked." +msgstr "Discuţie blocată." + +msgid "Thread successfully stickied." +msgstr "Discuţie marcată ca importantă" + +msgid "Thread successfully un-stickied" +msgstr "Discuţie marcată ca neimportantă" + +msgid "Thread successfully unlocked." +msgstr "Discuţie deblocată.Discuţie" + +msgid "Thread" +msgstr "Discuţia" + +msgid "Threads displayed per page (in thread list)" +msgstr "Discuţii pe pagină (în lista de discuţii)" + +msgid "Threads which reach this page or further will be marked to be deleted in two hours." +msgstr "Discuţiile de pe această pagină sau paginile ulterioare vor fi marcate pentru ştergere în două ore." + +msgid "Threads" +msgstr "Discuţii" + +msgid "Thumbnail displayed, click image for full size." +msgstr "Thumbnail, dă click pe imagine ca s-o vezi la dimensiunea reală." + +msgid "Time" +msgstr "Când?" + +msgid "To access Kusaba variables, use {%%KU_VARNAME}, for example {%%KU_BOARDSPATH} would be replaced with %s" +msgstr "Pentru a accesa variabilele folosite de Kusaba, foloseşte {%%KU_VARNAME}, de exemplu {%%KU_BOARDSPATH} va fi înlocuit de %s" + +msgid "to ban page" +msgstr "la pagina de banuri" + +msgid "To find a phrase at the beginning of a post's message:" +msgstr "Ca să găseşti o frază la începutul mesajului:" + +msgid "To find a phrase at the end of a post's message:" +msgstr "Ca să găseşti o frază la sfârşitul mesajului:" + +msgid "To find a single phrase anywhere in a post's message, use:" +msgstr "Ca să găseşti o singură frază într-un mesaj:" + +msgid "To find two phrases anywhere in a post's message, use:" +msgstr "Ca să găseşti două fraze în mesaj:" + +msgid "To" +msgstr "Pentru" + +msgid "Took" +msgstr "S-a încărcat în" + +msgid "Total posts per board" +msgstr "Total de mesaje pe forumuri" + +msgid "Total" +msgstr "Total" + +msgid "Translation" +msgstr "Traducere" + +msgid "Trial" +msgstr "Probă" + +msgid "Type" +msgstr "Tip" + +msgid "Un-Hide Thread" +msgstr "Arată discuția" + +msgid "Un-watch" +msgstr "Nu mai urmări" + +msgid "Unable to clear cache: you do not have caching enabled." +msgstr "Nu se poate şterge cache-ul: opţiunea nu este activată." + +msgid "Unable to connect to" +msgstr "Nu mă pot conecta la" + +msgid "Unable to create directories." +msgstr "Nu pot crea directoarele." + +msgid "Unable to delete board." +msgstr "Nu pot şterge forumul." + +msgid "Unable to find record of your IP being banned." +msgstr "Nu găsesc nici o dovadă că IP-ul tău a fost banat." + +msgid "Unable to find records of any posts matching that quote syntax." +msgstr "Nu găsesc nici o înregistrare care să conţină cuvintele acestea." + +msgid "Unable to locate a board named" +msgstr "Nu găsesc nici un forum numit" + +msgid "Unable to locate a filetype with that ID." +msgstr "Nu găsesc nici un fişier cu acest ID." + +msgid "Unable to locate a section with that ID." +msgstr "Nu găsesc nici o secţiune cu acest ID." + +msgid "Unable to locate that word." +msgstr "Nu găsesc cuvântul acesta." + +msgid "Unable to open the modules directory!" +msgstr "Nu am putut deschide directorul de module!" + +msgid "Unable to read uploaded file during thumbnailing." +msgstr "Nu pot citi fişierul uploadat în timp ce-l redimensionez." + +msgid "Unable to report post. Please go back and try again." +msgstr "Nu pot raporta postul. Încearcă din nou." + +msgid "Unbanned" +msgstr "Debanat" + +msgid "Unique user posts per board" +msgstr "Mesaje unice pe forumuri" + +msgid "Unknown File Error" +msgstr "S-a întâmplat ceva naşpa" + +msgid "Unlock" +msgstr "Deblocare" + +msgid "Unlocked thread" +msgstr "Discuţie deblocată" + +msgid "Unstickied thread" +msgstr "Discuţie neimportantă confirmată" + +msgid "Unsticky" +msgstr "Discuţie neimportantă" + +msgid "Upating pages." +msgstr "Actualizare pagini." + +msgid "Update and regenerate board" +msgstr "Actualizează şi reconstruieşte forumul" + +msgid "Update successful." +msgstr "Actualizare reuşită." + +msgid "Update without regenerating board" +msgstr "Actualizează fără a reconstrui forumul" + +msgid "Update" +msgstr "Actualizare" + +msgid "Updated board configuration" +msgstr "Configuraţie actualizată" + +msgid "Updated global configuration" +msgstr "Configuraţie globablă actualizată" + +msgid "Updated staff member" +msgstr "Membru actualizat" + +msgid "Updated word on wordfilter" +msgstr "Filtru actualizat" + +msgid "Upload type" +msgstr "Tip de upload" + +msgid "Use animation?" +msgstr "Fac şi o animaţie?" + +msgid "Use Default" +msgstr "Valoare implicită" + +msgid "Username" +msgstr "User" + +msgid "Video URL Start" +msgstr "URL-ul cu care începe video-ul" + +msgid "View all bans" +msgstr "Vezi toate banurile" + +msgid "View animation" +msgstr "Vezi animaţia" + +msgid "View Announcements" +msgstr "Vezi anunţurile" + +msgid "View Appeals" +msgstr "Vezi cererile de debanar" + +msgid "View catalog" +msgstr "Vezi catalogul" + +msgid "View deleted thread" +msgstr "Vezi discuţia ştearsă" + +msgid "View last %d bans" +msgstr "Vezi ultimele %d banuri" + +msgid "View Reports" +msgstr "Vezi rapoartele" + +msgid "View Thread (including deleted)" +msgstr "Vezi discuţii (inclusiv cele şterse)" + +msgid "View Threads (including deleted)" +msgstr "Vezi discuţiile (incusiv cele şterse)" + +msgid "View" +msgstr "Vezi" + +msgid "View/Add/Remove bans" +msgstr "Vezi / Adaugă / Şterge banuri" + +msgid "Viewed disk space used" +msgstr "Văzut spaţiul ocupat" + +msgid "Visit http://wiki.dwoo.org/ for syntax information." +msgstr "Intră pe http://wiki.dwoo.org/ pentru informaţii despre sintaxă." + +msgid "Warning" +msgstr "Atenţie" + +msgid "Watched Threads" +msgstr "Discuţii urmărite" + +msgid "Welcome" +msgstr "Salut" + +msgid "What embed sites are allowed on this board. Only useful on board with embedding enabled." +msgstr "Ce embeduri sunt permise pe forum. Numai pentru forumurile cu embed activat." + +msgid "What filetypes users are allowed to upload." +msgstr "Tipuri de fişiere permise." + +msgid "When adding an embed, please check %s and check if there is a tutorial image for the site you are adding. Put this image in the /inc/embedhelp/ folder, or create your own in this folder if one does not exist. The image must be the same as the site name in all lowercase." +msgstr "Dacă vrei să adaugi un embed, intră pe %s şi vezi dacă există vreun tutorial pentru site-ul pe care vrei să-l adaugi. Pune imaginea asta în directorul /inc/embedhelp/ (crează-l dacă nu există). Numele imaginii trebuie să fie tot cu litere mici, şi să aibă acelaşi nume ca şi site-ul." + +msgid "Whether or not the user(s) affected by this ban will be allowed to read the boards." +msgstr "Vor putea userii afectaţi de ban să citească mesajele de pe forumuri?" + +msgid "Whether or not to allow embedding of videos." +msgstr "Permite sau nu ca userul sa facă embed de videouri." + +msgid "Whitelist" +msgstr "Listă albă" + +msgid "Whitelisted IPs" +msgstr "IP-uri pe lista albă" + +msgid "Width" +msgstr "Lăţime" + +msgid "will expire on" +msgstr "expiră pe" + +msgid "will not expire" +msgstr "nu expiră" + +msgid "Word successfully added." +msgstr "Filtru adăugat." + +msgid "Word successfully removed." +msgstr "Filtru scos." + +msgid "Word successfully updated." +msgstr "Filtru actualizat." + +msgid "Word" +msgstr "Cuvântul" + +msgid "Wordfilter" +msgstr "Filtru" + +msgid "Yes" +msgstr "Da" + +msgid "You are banned from posting on:" +msgstr "Nu ai voie să postezi pe:" + +msgid "YOU ARE BANNED" +msgstr "ŢI-AI LUAT BAN, FRAIERE" + +msgid "You are currently posting faster than the configured minimum post delay allows." +msgstr "Postează şi tu mai rar." + +msgid "You are not a moderator of this board." +msgstr "Nu eşti moderator pe forumul acesta." + +msgid "YOU ARE NOT BANNED!" +msgstr "NU MAI EŞTI BANAT" + +msgid "You can only delete posts from boards you moderate." +msgstr "Nu poţi şterge mesaje decât pe forumurile pe care le moderezi." + +msgid "You can only make board specific bans to boards which you moderate." +msgstr "Nu poţi pune un ban pe alt forum decât cele pe care le moderezi." + +msgid "You do not moderate any boards." +msgstr "Nu eşti moredator pe nici un forum." + +msgid "You don't follow the rules." +msgstr "Eşti un dobitoc." + +msgid "You have been banned for posting Child Pornography. Your IP has been logged, and the proper authorities will be notified." +msgstr "Ai fost banat pentru postarea de pornografie ilegală. IP-ul tău a fost logat." + +msgid "You have been banned from posting on" +msgstr "Ai fost banat pe" + +msgid "You have been successfully logged out." +msgstr "Ai ieşit. Papa :) ." + +msgid "You may not appeal this ban." +msgstr "NU poţi cere să fii debanat." + +msgid "You may appeal this ban in" +msgstr "Poţi cere să fii debanat în" + +msgid "You may now appeal this ban." +msgstr "Acuma poţi cere să fii debanat." + +msgid "You must enter a heading as well as a post." +msgstr "Bagă şi un subiect, şi un mesaj." + +msgid "You must enter a subject as well as a post." +msgstr "Bagă şi un subiect, şi un mesaj." + +msgid "You must enter a subject." +msgstr "Bagă şi tu un titlu." + +msgid "You must enter code." +msgstr "Trebuie să bagi cod." + +msgid "You searched for" +msgstr "Ai căutat" + +msgid "Your appeal is currently pending review." +msgstr "Cererea ta urmează să fie verificată." + +msgid "Your appeal was reviewed and denied. You may not appeal this ban again." +msgstr "Cererea ta a fost respinsă. NU poţi cere din nou sa fii debanat." + +msgid "Your ban was placed on" +msgstr "Banul a fost pus pe" + +msgid "Your image" +msgstr "Imaginea ta" + +msgid "Your IP address is" +msgstr "IP-ul tău este" + +msgid "Your post already doesn't have an image!" +msgstr "Mesajul tău nu are vreo imagine!" + +msgid "Your post contains one or more illegal characters." +msgstr "Mesajul tăr conţine unul sau mai multe caractere ilegale." + +msgid "Your posting password" +msgstr "Parola de postare" + diff --git a/inc/lang/ru/LC_MESSAGES/kusaba.po b/inc/lang/ru/LC_MESSAGES/kusaba.po new file mode 100644 index 0000000..b11f302 --- /dev/null +++ b/inc/lang/ru/LC_MESSAGES/kusaba.po @@ -0,0 +1,542 @@ +msgid "" +msgstr "" +"Project-Id-Version: trevorchan\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2007-12-09 03:10+0000\n" +"PO-Revision-Date: 2007-12-05 18:15+0000\n" +"Last-Translator: Dmitry-Sh \n" +"Language-Team: Russian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2008-03-12 04:24+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +msgid "(for post and file deletion)" +msgstr "(для удаления постов и файлов)" + +msgid "

Add News Post

This message will be displayed as it is written, so make sure you add the proper HTML." +msgstr "

Добавить Новость

Это сообщение будет показано в точности с написанием, поэтому убедитесь, что используете допустимый HTML." + +msgid "A staff member with that ID already exists." +msgstr "Участник с таким ID уже существует." + +msgid "A staff member with that id does not appear to exist." +msgstr "Участник с таким ID отсутствует." + +msgid "Add" +msgstr "Добавить" + +msgid "Add staff member" +msgstr "Добавить участника" + +msgid "Added on" +msgstr "Добавлено" + +msgid "Administration" +msgstr "Администрация" + +msgid "Administrator" +msgstr "Администратор" + +msgid "Administrators" +msgstr "Администраторы" + +msgid "All Threads" +msgstr "Все Нити" + +msgid "All boards" +msgstr "Все разделы" + +msgid "All threads/posts by that IP in selected boards successfully deleted." +msgstr "Все темы/сообщения с этого IP успешно удалены в выбранных разделах." + +msgid "An image, or message, is required for a reply." +msgstr "Чтобы ответить, загрузите изображение или введите текст." + +msgid "Banned %d IP addresses using an IP address list." +msgstr "Забанено %d IP-адресов с использованием списка IP-адресов." + +msgid "Board" +msgstr "Доска" + +msgid "Board type:" +msgstr "Тип доски:" + +msgid "Boards" +msgstr "Разделы" + +msgid "Can be left blank." +msgstr "Можно оставить пустым." + +msgid "Can not be left blank." +msgstr "Нельзя оставить пустым." + +msgid "Cancel" +msgstr "Отменить" + +msgid "Captcha" +msgstr "Код" + +msgid "Continue" +msgstr "Дальше" + +msgid "Could not copy uploaded image." +msgstr "Загруженное изображение не удалось сохранить." + +msgid "Could not create thumbnail." +msgstr "Не удалось создать эскиз." + +msgid "Days to keep modlog entries" +msgstr "Дней до удаления логов действий модераторов" + +msgid "Default" +msgstr "По умолчанию" + +msgid "Default style:" +msgstr "Стиль по-умолчанию" + +msgid "Delete" +msgstr "Удалить" + +msgid "Description" +msgstr "Описание" + +msgid "Directory" +msgstr "Директория" + +msgid "Duplicate file entry detected." +msgstr "Этот файл уже загружен." + +msgid "Edit" +msgstr "Редактировать" + +msgid "Email" +msgstr "Адрес" + +msgid "Error, it appears your file did not transfer properly. Please go back and try again." +msgstr "Ошибка: файл не был загружен. Попробуйте еще раз." + +msgid "File" +msgstr "Файл" + +msgid "File was not fully uploaded. Please go back and try again." +msgstr "Файл не был загружен целиком. Пожалуйста, повторите попытку." + +msgid "First 100 posts" +msgstr "Первые 100 постов" + +msgid "First 100 posts shown." +msgstr "Показываются первые 100 постов." + +msgid "Forced anonymous" +msgstr "Форсированная анонимность" + +msgid "Global configuration succesfully updated." +msgstr "Общие настройки успешно обновлены." + +msgid "Go" +msgstr "ОК" + +msgid "Header image" +msgstr "Логотип" + +msgid "ID" +msgstr "ID" + +msgid "IP" +msgstr "IP" + +msgid "If set to yes, this board will appear in bold in the menu" +msgstr "Если включено, доска будет выделена полужирным шрифтом в меню." + +msgid "If set to yes, this board will appear in italics in the menu" +msgstr "Если включено, доска будет выделена наклонным шрифтом в меню." + +msgid "Image" +msgstr "Изображение" + +msgid "Image successfully deleted from your post." +msgstr "Изображение из сообщения удалено." + +msgid "Images" +msgstr "Изображения" + +msgid "Improper filetype." +msgstr "Недопустимый тип файла" + +msgid "Include header" +msgstr "Добавить логотип" + +msgid "Incorrect captcha entered." +msgstr "Введен неправильный код подтверждения" + +msgid "Incorrect password." +msgstr "Неправильный пароль." + +msgid "Incorrect username/password." +msgstr "Неправильный логин/пароль." + +msgid "Inject" +msgstr "Иньекция" + +msgid "Integer values must be entered correctly." +msgstr "Целые значения должны быть введены верно." + +msgid "Invalid session." +msgstr "Ошибка сессии." + +msgid "Invalid staff ID." +msgstr "Неверный ID участника." + +msgid "Invalid thread ID. This may have been caused by the thread recently being deleted." +msgstr "Неверный номер темы. Возможно, она только что была удалена." + +msgid "Last 50 posts" +msgstr "Последние 50 постов" + +msgid "Last 50 posts shown." +msgstr "Показываются последние 50 постов." + +msgid "Last Post" +msgstr "Последний Пост" + +msgid "Lock" +msgstr "Заблокировать" + +msgid "Locked" +msgstr "Блок" + +msgid "Log in again." +msgstr "Требуется повторная авторизация." + +msgid "Manage boards" +msgstr "Управление разделами." + +msgid "Maximum board pages" +msgstr "Максимальное количество страниц в разделе" + +msgid "Maximum image size" +msgstr "Максимальный объем изображения" + +msgid "Maximum message length" +msgstr "Максимальная длина сообщения" + +msgid "Maximum thread age (Hours)" +msgstr "Максимальный возраст темы (часы)" + +msgid "Maximum thread replies" +msgstr "Максимальное количество ответов в тему" + +msgid "Maxmimum thumbnail height" +msgstr "Максимальная высота эскиза" + +msgid "Maxmimum thumbnail width" +msgstr "Максимальная ширина эскиза" + +msgid "Message" +msgstr "Текст" + +msgid "Misc" +msgstr "Другое" + +msgid "Moderates" +msgstr "Модерирует" + +msgid "Moderating boards" +msgstr "Модерируемые разделы" + +msgid "Moderation" +msgstr "Модерирование" + +msgid "Moderator" +msgstr "Модератор" + +msgid "Moderators" +msgstr "Модераторы" + +msgid "Modify staff member" +msgstr "Изменить участника" + +msgid "Module settings" +msgstr "Настройки модулей" + +msgid "Modules" +msgstr "Модули" + +msgid "More" +msgstr "Далее" + +msgid "NOTICE: You are using the default administrator account. Anyone can log in to this account, so a second administrator account needs to be created. Create another, log in to it, and delete this one." +msgstr "ВНИМАНИЕ: Вы используете стандартную запись администратора! Любой может ею воспользоваться, поэтому настоятельно рекомендуем создать еще одну, удалив эту." + +msgid "Name" +msgstr "Ник" + +msgid "Never" +msgstr "Никогда" + +msgid "New Thread" +msgstr "Новая Нить" + +msgid "News entry successfully added." +msgstr "Новая запись успешно добавлена." + +msgid "Next" +msgstr "Дальше" + +msgid "No" +msgstr "Нет" + +msgid "No boards" +msgstr "Разделов нет" + +msgid "No threads." +msgstr "Нет нитей." + +msgid "None" +msgstr "Нету" + +msgid "Normal imageboard" +msgstr "Нормальная доска" + +msgid "Oekaki imageboard" +msgstr "Доска оекаки" + +msgid "Open images in new window" +msgstr "Открывать изображения в новом окне" + +msgid "Order" +msgstr "Последовательность" + +msgid "Password" +msgstr "Пaроль" + +msgid "Please enter a search query." +msgstr "Пожалуйста, введите поисковый запрос" + +msgid "Please make sure your file is smaller than %dB" +msgstr "Файл должен быть меньше %dБ." + +msgid "Please select only one image to upload." +msgstr "Пожалуйста, загружайте только одно изображение за раз." + +msgid "Popular" +msgstr "Популярная" + +msgid "Post" +msgstr "Сообщение" + +msgid "Post successfully deleted." +msgstr "Сообщение удалено." + +msgid "Postbox notice" +msgstr "Заметка" + +msgid "Posting rates (past hour)" +msgstr "Рейтинг сообщений (за последний час)" + +msgid "Posts" +msgstr "Сообщение" + +msgid "Preview" +msgstr "Предпросмотр" + +msgid "Previous" +msgstr "Назад" + +msgid "Proxy list" +msgstr "Список прокси" + +msgid "Query" +msgstr "Запрос" + +msgid "Query executed successfully" +msgstr "Запрос успешно выполнен." + +msgid "Quick Reply" +msgstr "Быстрый ответ" + +msgid "Read this thread from the beginning" +msgstr "Прочитать эту нить с начала." + +msgid "Rebuild complete. Took %d seconds." +msgstr "Пересчет завершен. Он занял %d секунд." + +msgid "Redirect to thread" +msgstr "Перенаправить в тему" + +msgid "Remove" +msgstr "Удалить" + +msgid "Replies" +msgstr "Ответы" + +msgid "Reply" +msgstr "Ответ" + +msgid "Report" +msgstr "Отчет" + +msgid "Reports" +msgstr "Отчеты" + +msgid "Results" +msgstr "Результаты" + +msgid "Search" +msgstr "Поиск" + +msgid "Section" +msgstr "Секция" + +msgid "Site Styles" +msgstr "Стили сайта" + +msgid "Sorry, a generic error has occurred." +msgstr "Извините, произошла ошибка." + +msgid "Sorry, because of your numerous failed logins, you have been locked out from logging in for 20 minutes. Please wait and then try again." +msgstr "Извините, но из-за ряда неудачных попыток входа, Вам будет закрыт доступ на 20 минут. Пожалуйста, подождите и попробуйте еще раз." + +msgid "Sorry, that filetype is not allowed on this board." +msgstr "Извините, этот тип файла не разрешен к загрузке в раздел." + +msgid "Sorry, this board is locked and can not be posted in." +msgstr "Извините, раздел закрыт для сообщений." + +msgid "Sorry, this thread is locked and can not be replied to." +msgstr "Извините, тема закрыта для ответов." + +msgid "Sorry, your message is too long. Message length: %d, maxmimum allowed length: %d" +msgstr "Извините, сообщение слишком длинное. %d символов при допустимом лимите в %d" + +msgid "Sorry, your search returned zero results." +msgstr "Поиск не дал результатов." + +msgid "Staff member successfully added." +msgstr "Участник добавлен" + +msgid "Staff rights" +msgstr "Права модераторов" + +msgid "Staff successfully deleted" +msgstr "Участник удален" + +msgid "Staff successfully updated" +msgstr "Участник обновлен" + +msgid "Statistics" +msgstr "Статистика" + +msgid "Stickied" +msgstr "Прикреплено" + +msgid "Sticky" +msgstr "Прикрепленный" + +msgid "Style" +msgstr "Стиль" + +msgid "Styles" +msgstr "Стили" + +msgid "Subject" +msgstr "Тема" + +msgid "Text board" +msgstr "Текстовая доска" + +msgid "Text boards only. If enabled, the list of threads displayed on the front page will be formatted differently to be compact." +msgstr "Только текстовые доски. Если включено, список нитей на главной странице будет форматироваться более компактно." + +msgid "That ID is a reply, not a thread." +msgstr "Это номер ответа, а не темы." + +msgid "That thread has yet to be deleted." +msgstr "Эта тема уже удалена." + +msgid "The 5 newest replies are shown below." +msgstr "Последние 5 ответов показаны ниже." + +msgid "The style which will be set when the user first visits the board." +msgstr "Стиль, который устанавливается при первом посещении доски." + +msgid "There are currently no threads to display." +msgstr "Нити для отображения отсутствуют." + +msgid "There was an error in trying to delete your post" +msgstr "Ошибка при попытке удалить сообщение." + +msgid "Thread" +msgstr "Thread" + +msgid "Threads" +msgstr "Отметить подшивки" + +msgid "Trial" +msgstr "Тестовая" + +msgid "Unable to locate a board named" +msgstr "Невозможно найти раздел под названием" + +msgid "Unlock" +msgstr "Разблокировать" + +msgid "Unsticky" +msgstr "Открепленный" + +msgid "Update" +msgstr "Обновить" + +msgid "Update successful." +msgstr "Успешно обновлено." + +msgid "Username" +msgstr "Логин" + +msgid "Welcome" +msgstr "Добро пожаловать!" + +msgid "Yes" +msgstr "Да" + +msgid "You have been successfully logged out." +msgstr "Вы успешно вышли." + +msgid "You must enter a subject." +msgstr "Вы должны ввести тему." + +msgid "You searched for" +msgstr "Вы искали" + +msgid "Your post already doesn't have an image!" +msgstr "В Вашем сообщении нет изображений." + +msgid "Your posting password" +msgstr "Пароль для сообщений" + +msgid "and" +msgstr "и" + +msgid "forever" +msgstr "всегда" + +msgid "log out" +msgstr "Выйти" + +msgid "or" +msgstr "или" + +msgid "translator-credits" +msgstr "" +"Launchpad Contributions:\n" +" 8ch_ru \n" +" Aleksej Korgenkov \n" +" tj9991 \n" +"\n" +"Launchpad Contributions:\n" +" Aleksej Korgenkov https://launchpad.net/~grimpanto\n" +" Dmitry-Sh https://launchpad.net/~tty01\n" +" Nikolay https://launchpad.net/~nicko4ever" + diff --git a/inc/lang/zh/LC_MESSAGES/kusaba.po b/inc/lang/zh/LC_MESSAGES/kusaba.po new file mode 100644 index 0000000..c2c73b7 --- /dev/null +++ b/inc/lang/zh/LC_MESSAGES/kusaba.po @@ -0,0 +1,204 @@ +msgid "" +msgstr "" +"Project-Id-Version: trevorchan\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2007-12-09 03:10+0000\n" +"PO-Revision-Date: 2008-03-10 04:45+0000\n" +"Last-Translator: 冴月麟\n" +"Language-Team: Chinese-zh\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2008-03-12 04:24+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +msgid "(for post and file deletion)" +msgstr "(用以删除贴或者文件)" + +msgid "Add" +msgstr "追加" + +msgid "Administration" +msgstr "管理" + +msgid "Administrator" +msgstr "管理员" + +msgid "Administrators" +msgstr "管理员组" + +msgid "All boards" +msgstr "所有板块" + +msgid "Board" +msgstr "板块" + +msgid "Boards" +msgstr "板块" + +msgid "Captcha" +msgstr "验证码" + +msgid "Catalog Mode" +msgstr "概览模式" + +msgid "Click Reply to view." +msgstr "点击回复来查看。" + +msgid "Date" +msgstr "日期" + +msgid "Delete" +msgstr "删除" + +msgid "Delete post" +msgstr "删除此贴" + +msgid "Email" +msgstr "E-Mail" + +msgid "Embed" +msgstr "嵌入" + +msgid "File" +msgstr "图片文件名" + +msgid "Home" +msgstr "主页" + +msgid "Image" +msgstr "图像" + +msgid "Images" +msgstr "图像" + +msgid "Incorrect password." +msgstr "密码错误。" + +msgid "Incorrect username/password." +msgstr "用户名或者密码错误。" + +msgid "Invalid session." +msgstr "无效的SESSION。" + +msgid "Lock" +msgstr "锁定" + +msgid "Log in again." +msgstr "请再次登录。" + +msgid "Manage" +msgstr "管理" + +msgid "Message" +msgstr "内容" + +msgid "Misc" +msgstr "其他" + +msgid "Moderates" +msgstr "管理" + +msgid "Moderating boards" +msgstr "管理板块" + +msgid "Moderation" +msgstr "管理" + +msgid "Moderator" +msgstr "猴子" + +msgid "Moderators" +msgstr "猴子" + +msgid "Name" +msgstr "名称" + +msgid "Next" +msgstr "下一个" + +msgid "No" +msgstr "否" + +msgid "No File" +msgstr "无文件" + +msgid "No boards" +msgstr "无板块" + +msgid "Password" +msgstr "密码" + +msgid "Post" +msgstr "投稿" + +msgid "Posting mode: Reply" +msgstr "回复模式" + +msgid "Posts" +msgstr "投稿" + +msgid "Preview" +msgstr "预览" + +msgid "Previous" +msgstr "上一个" + +msgid "Quick Reply" +msgstr "快速回复" + +msgid "Remove" +msgstr "删除" + +msgid "Replies" +msgstr "回复" + +msgid "Reply" +msgstr "回复" + +msgid "Return" +msgstr "返回" + +msgid "Size" +msgstr "大小" + +msgid "Sorry, a generic error has occurred." +msgstr "发生了一个奇怪的通常错误。" + +msgid "Subject" +msgstr "題名" + +msgid "Submit" +msgstr "送信" + +msgid "Tag" +msgstr "标签" + +msgid "Thread" +msgstr "帖子" + +msgid "Threads" +msgstr "帖子" + +msgid "Username" +msgstr "用户名" + +msgid "Yes" +msgstr "是" + +msgid "and" +msgstr "和" + +msgid "log in" +msgstr "登入" + +msgid "log out" +msgstr "登出" + +msgid "omitted" +msgstr "省略" + +msgid "translator-credits" +msgstr "" +"冴月麟 2013" + diff --git a/inc/pages/faq.php b/inc/pages/faq.php new file mode 100644 index 0000000..7685f1d --- /dev/null +++ b/inc/pages/faq.php @@ -0,0 +1,11 @@ +GetAll("SELECT * FROM `".KU_DBPREFIX."front` WHERE `page` = 1 ORDER BY `order` ASC"); +foreach($results AS $line) { + $content .= '
' . "\n" . + '

'.stripslashes($line['subject']).''; + $content .= '#

' . "\n" . + stripslashes($line['message']) . '

' . "\n"; +} +return $content; +?> \ No newline at end of file diff --git a/inc/pages/manage_login.html b/inc/pages/manage_login.html new file mode 100644 index 0000000..52f28c5 --- /dev/null +++ b/inc/pages/manage_login.html @@ -0,0 +1,72 @@ + + + Manage - Log In + + + + + + + + + + + + + + + + +
+   +
+ + +
+
+ + + + + + + + + + +
+ +
+ +
+ +
+
+
+
+ +
+   +
+ \ No newline at end of file diff --git a/inc/pages/modheader.html b/inc/pages/modheader.html new file mode 100644 index 0000000..e69de29 diff --git a/inc/pages/rules.php b/inc/pages/rules.php new file mode 100644 index 0000000..8a84452 --- /dev/null +++ b/inc/pages/rules.php @@ -0,0 +1,13 @@ +GetAll("SELECT * FROM `".KU_DBPREFIX."front` WHERE `page` = 2 ORDER BY `order` ASC"); +if (count($results) > 0) { + foreach($results AS $line) { + $content .= '
' . "\n" . + '

'.stripslashes($line['subject']).''; + $content .= '#

' . "\n" . + stripslashes($line['message']) . '

' . "\n"; + } +} +return $content; +?> \ No newline at end of file diff --git a/inc/player/player.swf b/inc/player/player.swf new file mode 100644 index 0000000..04be6a9 Binary files /dev/null and b/inc/player/player.swf differ diff --git a/index.php b/index.php new file mode 100644 index 0000000..6ec6e4d --- /dev/null +++ b/index.php @@ -0,0 +1,145 @@ + + * + * http://xchan.info + */ + +require_once 'config.php'; +require_once KU_ROOTDIR . 'lib/dwoo.php'; +require_once KU_ROOTDIR . 'inc/functions.php'; +require_once KU_ROOTDIR . 'inc/classes/bans.class.php'; + +$dwoo = new Dwoo(); + +$dwoo_data = new Dwoo_Data(); +$dwoo_data->assign('title', KU_NAME); + +$prefix = KU_DBPREFIX; + +$page = (isset($_GET['page']) ? $_GET['page'] : 'index'); + +$dwoo_data->assign('page', $page); + +switch ($page) { + case 'news': + $news = $tc_db->GetAll("SELECT * FROM {$prefix}front WHERE page = 0 ORDER BY timestamp DESC"); + + $dwoo_data->assign('news', $news); + + $dwoo->output(KU_TEMPLATEDIR . '/front_news.tpl', $dwoo_data); + + break; + + case 'faq': + $faq = $tc_db->GetAll("SELECT * FROM {$prefix}front WHERE page = 1 ORDER BY `order` ASC"); + + $dwoo_data->assign('faq', $faq); + + $dwoo->output(KU_TEMPLATEDIR . '/front_faq.tpl', $dwoo_data); + + break; + + case 'rules': + $rules = $tc_db->GetAll("SELECT * FROM {$prefix}front WHERE page = 2 ORDER BY `order` ASC"); + + $dwoo_data->assign('rules', $rules); + + $dwoo->output(KU_TEMPLATEDIR . '/front_rules.tpl', $dwoo_data); + + break; + + case 'banlist': + $bans = $tc_db->GetAll("SELECT ip, reason, boards, at, `by`, COALESCE(until, 'nuncAA') as until FROM {$prefix}banlist WHERE `by` != 'board.php' AND `by` != 'SERVER' ORDER BY `at` DESC LIMIT 25"); + + $dwoo_data->assign('bans', $bans); + $dwoo_data->assign('seed', KU_RANDOMSEED); + + $dwoo->output(KU_TEMPLATEDIR . '/front_bans.tpl', $dwoo_data); + + break; + + default: + $sections = $tc_db->GetAll("SELECT * FROM {$prefix}sections ORDER BY `order` ASC"); + + $boards = $tc_db->GetAll("SELECT * from {$prefix}boards ORDER by `order` ASC, name ASC"); + + $last_new = $tc_db->GetAll("SELECT * FROM {$prefix}front WHERE page = 0 ORDER BY timestamp DESC LIMIT 1"); + + $sql = "SELECT + p.id, + CASE p.parentid + WHEN 0 THEN p.id + ELSE p.parentid + END AS parentid, + b.name AS board, + p.file, + p.file_type + FROM {$prefix}posts AS p + JOIN {$prefix}boards AS b ON p.boardid = b.id + WHERE file_type IN ('jpg' , 'gif', 'png') AND IS_DELETED = 0 + ORDER BY TIMESTAMP DESC + LIMIT 10"; + + $last_images = $tc_db->GetAll($sql); + + $sql = "SELECT + c.name AS board, + a.id, + CASE a.parentid + WHEN 0 THEN a.id + ELSE a.parentid + END AS parentid, + a.message, + a.name, + a.timestamp + FROM {$prefix}posts a + JOIN (SELECT MAX(id) AS lastid, boardid FROM {$prefix}posts WHERE is_deleted = 0 GROUP BY boardid) b ON a.id = b.lastid AND a.boardid = b.boardid + JOIN {$prefix}boards c ON a.boardid = c.id"; + + $last_posts = $tc_db->GetAll($sql); + + // Sub-queries <3 + + $sql = "SELECT + c.name AS board, + a.id, + CASE a.parentid + WHEN 0 THEN a.id + ELSE a.parentid + END AS parentid, + a.message, + a.name, + b.replies, + a.timestamp + FROM {$prefix}posts a + JOIN (SELECT * FROM (SELECT COUNT(parentid) AS replies, parentid, boardid FROM {$prefix}posts WHERE parentid > 0 AND is_deleted = 0 GROUP BY parentid ORDER BY replies DESC) AS b GROUP BY b.boardid) b + ON a.id = b.parentid AND a.boardid = b.boardid + JOIN {$prefix}boards c ON a.boardid = c.id"; + + $popular_threads = $tc_db->GetAll($sql); + + $imagecount = $tc_db->GetAll("SELECT COUNT(*) AS imagecount, SUM(file_size) AS imagesize FROM {$prefix}posts WHERE file_type != '' AND is_deleted = 0"); + + $postcount = $tc_db->GetAll("SELECT COUNT(*) AS postcount FROM {$prefix}posts WHERE is_deleted = 0"); + + $dwoo_data->assign('sections', $sections); + $dwoo_data->assign('boards', $boards); + $dwoo_data->assign('last_new', $last_new); + $dwoo_data->assign('last_images', $last_images); + $dwoo_data->assign('last_posts', $last_posts); + $dwoo_data->assign('popular_threads', $popular_threads); + $dwoo_data->assign('imagecount', $imagecount); + $dwoo_data->assign('postcount', $postcount[0]['postcount']); + + $dwoo->output(KU_TEMPLATEDIR . '/front_index.tpl', $dwoo_data); + + break; +} + + + + diff --git a/kusaba.php b/kusaba.php new file mode 100644 index 0000000..4cb2f74 --- /dev/null +++ b/kusaba.php @@ -0,0 +1,82 @@ +here, or already have, and must delete it.'); +} +if (!isset($_GET['info'])) { + $preconfig_db_unnecessary = true; +} +require 'config.php'; +$menufile = (KU_STATICMENU) ? 'menu.html' : 'menu.php'; +$menusize = (KU_MENUTYPE == 'normal') ? '15%' : '10%'; +$mainsize = 100-$menusize . '%'; +header("Expires: Mon, 1 Jan 2030 05:00:00 GMT"); +?> + + + + <?php echo KU_NAME; ?> + + + +'; + echo '

General info:

    '; + echo '
  • Version: kusaba x ' . KU_VERSION . '
  • '; + $bans = $tc_db->GetOne("SELECT COUNT(*) FROM `".KU_DBPREFIX."banlist`"); + echo '
  • Active bans: ' . $bans . '
  • '; + $wordfilters = $tc_db->GetOne("SELECT COUNT(*) FROM `".KU_DBPREFIX."wordfilter`"); + echo '
  • Wordfilters: ' . $wordfilters . '
  • '; + echo '
  • Modules loaded: '; + $modules = modules_list(); + if (count($modules) > 0) { + $moduleslist = ''; + foreach ($modules as $module) { + $moduleslist .= $module . ', '; + } + echo substr($moduleslist, 0, -2); + } else { + echo 'none'; + } + echo '
  • '; + echo '
'; + echo ''; + die(); +} +?> + + + + + \ No newline at end of file diff --git a/kusabaoek/res/res.zip b/kusabaoek/res/res.zip new file mode 100644 index 0000000..92afa2b Binary files /dev/null and b/kusabaoek/res/res.zip differ diff --git a/kusabaoek/res/tt.zip b/kusabaoek/res/tt.zip new file mode 100644 index 0000000..6ce0df3 Binary files /dev/null and b/kusabaoek/res/tt.zip differ diff --git a/kusabaoek/uploadthisfolder.txt b/kusabaoek/uploadthisfolder.txt new file mode 100644 index 0000000..25ddb75 --- /dev/null +++ b/kusabaoek/uploadthisfolder.txt @@ -0,0 +1 @@ +Thise folder is purposely kept blank. Images which have been drawn from an Oekaki board, but have not yet been posted will stay in here until the user posts. diff --git a/lib/adodb/adodb-time.inc.php b/lib/adodb/adodb-time.inc.php new file mode 100644 index 0000000..d8ac322 --- /dev/null +++ b/lib/adodb/adodb-time.inc.php @@ -0,0 +1,1313 @@ + 4 digit year conversion. The maximum is billions of years in the +future, but this is a theoretical limit as the computation of that year +would take too long with the current implementation of adodb_mktime(). + +This library replaces native functions as follows: + +
+	getdate() with adodb_getdate()
+	date()	with adodb_date()
+	gmdate() with adodb_gmdate()
+	mktime() with adodb_mktime()
+	gmmktime() with adodb_gmmktime()
+	strftime() with adodb_strftime()
+	strftime() with adodb_gmstrftime()
+
+ +The parameters are identical, except that adodb_date() accepts a subset +of date()'s field formats. Mktime() will convert from local time to GMT, +and date() will convert from GMT to local time, but daylight savings is +not handled currently. + +This library is independant of the rest of ADOdb, and can be used +as standalone code. + +PERFORMANCE + +For high speed, this library uses the native date functions where +possible, and only switches to PHP code when the dates fall outside +the 32-bit signed integer range. + +GREGORIAN CORRECTION + +Pope Gregory shortened October of A.D. 1582 by ten days. Thursday, +October 4, 1582 (Julian) was followed immediately by Friday, October 15, +1582 (Gregorian). + +Since 0.06, we handle this correctly, so: + +adodb_mktime(0,0,0,10,15,1582) - adodb_mktime(0,0,0,10,4,1582) + == 24 * 3600 (1 day) + +============================================================================= + +COPYRIGHT + +(c) 2003-2005 John Lim and released under BSD-style license except for code by +jackbbs, which includes adodb_mktime, adodb_get_gmt_diff, adodb_is_leap_year +and originally found at http://www.php.net/manual/en/function.mktime.php + +============================================================================= + +BUG REPORTS + +These should be posted to the ADOdb forums at + + http://phplens.com/lens/lensforum/topics.php?id=4 + +============================================================================= + +FUNCTION DESCRIPTIONS + + +** FUNCTION adodb_getdate($date=false) + +Returns an array containing date information, as getdate(), but supports +dates greater than 1901 to 2038. The local date/time format is derived from a +heuristic the first time adodb_getdate is called. + + +** FUNCTION adodb_date($fmt, $timestamp = false) + +Convert a timestamp to a formatted local date. If $timestamp is not defined, the +current timestamp is used. Unlike the function date(), it supports dates +outside the 1901 to 2038 range. + +The format fields that adodb_date supports: + +
+	a - "am" or "pm"
+	A - "AM" or "PM"
+	d - day of the month, 2 digits with leading zeros; i.e. "01" to "31"
+	D - day of the week, textual, 3 letters; e.g. "Fri"
+	F - month, textual, long; e.g. "January"
+	g - hour, 12-hour format without leading zeros; i.e. "1" to "12"
+	G - hour, 24-hour format without leading zeros; i.e. "0" to "23"
+	h - hour, 12-hour format; i.e. "01" to "12"
+	H - hour, 24-hour format; i.e. "00" to "23"
+	i - minutes; i.e. "00" to "59"
+	j - day of the month without leading zeros; i.e. "1" to "31"
+	l (lowercase 'L') - day of the week, textual, long; e.g. "Friday"
+	L - boolean for whether it is a leap year; i.e. "0" or "1"
+	m - month; i.e. "01" to "12"
+	M - month, textual, 3 letters; e.g. "Jan"
+	n - month without leading zeros; i.e. "1" to "12"
+	O - Difference to Greenwich time in hours; e.g. "+0200"
+	Q - Quarter, as in 1, 2, 3, 4
+	r - RFC 822 formatted date; e.g. "Thu, 21 Dec 2000 16:01:07 +0200"
+	s - seconds; i.e. "00" to "59"
+	S - English ordinal suffix for the day of the month, 2 characters;
+				i.e. "st", "nd", "rd" or "th"
+	t - number of days in the given month; i.e. "28" to "31"
+	T - Timezone setting of this machine; e.g. "EST" or "MDT"
+	U - seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)
+	w - day of the week, numeric, i.e. "0" (Sunday) to "6" (Saturday)
+	Y - year, 4 digits; e.g. "1999"
+	y - year, 2 digits; e.g. "99"
+	z - day of the year; i.e. "0" to "365"
+	Z - timezone offset in seconds (i.e. "-43200" to "43200").
+				The offset for timezones west of UTC is always negative,
+				and for those east of UTC is always positive.
+
+ +Unsupported: +
+	B - Swatch Internet time
+	I (capital i) - "1" if Daylight Savings Time, "0" otherwise.
+	W - ISO-8601 week number of year, weeks starting on Monday
+
+
+ + +** FUNCTION adodb_date2($fmt, $isoDateString = false) +Same as adodb_date, but 2nd parameter accepts iso date, eg. + + adodb_date2('d-M-Y H:i','2003-12-25 13:01:34'); + + +** FUNCTION adodb_gmdate($fmt, $timestamp = false) + +Convert a timestamp to a formatted GMT date. If $timestamp is not defined, the +current timestamp is used. Unlike the function date(), it supports dates +outside the 1901 to 2038 range. + + +** FUNCTION adodb_mktime($hr, $min, $sec[, $month, $day, $year]) + +Converts a local date to a unix timestamp. Unlike the function mktime(), it supports +dates outside the 1901 to 2038 range. All parameters are optional. + + +** FUNCTION adodb_gmmktime($hr, $min, $sec [, $month, $day, $year]) + +Converts a gmt date to a unix timestamp. Unlike the function gmmktime(), it supports +dates outside the 1901 to 2038 range. Differs from gmmktime() in that all parameters +are currently compulsory. + +** FUNCTION adodb_gmstrftime($fmt, $timestamp = false) +Convert a timestamp to a formatted GMT date. + +** FUNCTION adodb_strftime($fmt, $timestamp = false) + +Convert a timestamp to a formatted local date. Internally converts $fmt into +adodb_date format, then echo result. + +For best results, you can define the local date format yourself. Define a global +variable $ADODB_DATE_LOCALE which is an array, 1st element is date format using +adodb_date syntax, and 2nd element is the time format, also in adodb_date syntax. + + eg. $ADODB_DATE_LOCALE = array('d/m/Y','H:i:s'); + + Supported format codes: + +
+	%a - abbreviated weekday name according to the current locale
+	%A - full weekday name according to the current locale
+	%b - abbreviated month name according to the current locale
+	%B - full month name according to the current locale
+	%c - preferred date and time representation for the current locale
+	%d - day of the month as a decimal number (range 01 to 31)
+	%D - same as %m/%d/%y
+	%e - day of the month as a decimal number, a single digit is preceded by a space (range ' 1' to '31')
+	%h - same as %b
+	%H - hour as a decimal number using a 24-hour clock (range 00 to 23)
+	%I - hour as a decimal number using a 12-hour clock (range 01 to 12)
+	%m - month as a decimal number (range 01 to 12)
+	%M - minute as a decimal number
+	%n - newline character
+	%p - either `am' or `pm' according to the given time value, or the corresponding strings for the current locale
+	%r - time in a.m. and p.m. notation
+	%R - time in 24 hour notation
+	%S - second as a decimal number
+	%t - tab character
+	%T - current time, equal to %H:%M:%S
+	%x - preferred date representation for the current locale without the time
+	%X - preferred time representation for the current locale without the date
+	%y - year as a decimal number without a century (range 00 to 99)
+	%Y - year as a decimal number including the century
+	%Z - time zone or name or abbreviation
+	%% - a literal `%' character
+
+ + Unsupported codes: +
+	%C - century number (the year divided by 100 and truncated to an integer, range 00 to 99)
+	%g - like %G, but without the century.
+	%G - The 4-digit year corresponding to the ISO week number (see %V).
+		This has the same format and value as %Y, except that if the ISO week number belongs
+		to the previous or next year, that year is used instead.
+	%j - day of the year as a decimal number (range 001 to 366)
+	%u - weekday as a decimal number [1,7], with 1 representing Monday
+	%U - week number of the current year as a decimal number, starting
+		with the first Sunday as the first day of the first week
+	%V - The ISO 8601:1988 week number of the current year as a decimal number,
+		range 01 to 53, where week 1 is the first week that has at least 4 days in the
+		current year, and with Monday as the first day of the week. (Use %G or %g for
+		the year component that corresponds to the week number for the specified timestamp.)
+	%w - day of the week as a decimal, Sunday being 0
+	%W - week number of the current year as a decimal number, starting with the
+		first Monday as the first day of the first week
+
+ +============================================================================= + +NOTES + +Useful url for generating test timestamps: + http://www.4webhelp.net/us/timestamp.php + +Possible future optimizations include + +a. Using an algorithm similar to Plauger's in "The Standard C Library" +(page 428, xttotm.c _Ttotm() function). Plauger's algorithm will not +work outside 32-bit signed range, so i decided not to implement it. + +b. Implement daylight savings, which looks awfully complicated, see + http://webexhibits.org/daylightsaving/ + + +CHANGELOG +- 08 Sept 2005 0.22 +In adodb_date2(), $is_gmt not supported properly. Fixed. + +- 18 July 2005 0.21 +In PHP 4.3.11, the 'r' format has changed. Leading 0 in day is added. Changed for compat. +Added support for negative months in adodb_mktime(). + +- 24 Feb 2005 0.20 +Added limited strftime/gmstrftime support. x10 improvement in performance of adodb_date(). + +- 21 Dec 2004 0.17 +In adodb_getdate(), the timestamp was accidentally converted to gmt when $is_gmt is false. +Also adodb_mktime(0,0,0) did not work properly. Both fixed thx Mauro. + +- 17 Nov 2004 0.16 +Removed intval typecast in adodb_mktime() for secs, allowing: + adodb_mktime(0,0,0 + 2236672153,1,1,1934); +Suggested by Ryan. + +- 18 July 2004 0.15 +All params in adodb_mktime were formerly compulsory. Now only the hour, min, secs is compulsory. +This brings it more in line with mktime (still not identical). + +- 23 June 2004 0.14 + +Allow you to define your own daylights savings function, adodb_daylight_sv. +If the function is defined (somewhere in an include), then you can correct for daylights savings. + +In this example, we apply daylights savings in June or July, adding one hour. This is extremely +unrealistic as it does not take into account time-zone, geographic location, current year. + +function adodb_daylight_sv(&$arr, $is_gmt) +{ + if ($is_gmt) return; + $m = $arr['mon']; + if ($m == 6 || $m == 7) $arr['hours'] += 1; +} + +This is only called by adodb_date() and not by adodb_mktime(). + +The format of $arr is +Array ( + [seconds] => 0 + [minutes] => 0 + [hours] => 0 + [mday] => 1 # day of month, eg 1st day of the month + [mon] => 2 # month (eg. Feb) + [year] => 2102 + [yday] => 31 # days in current year + [leap] => # true if leap year + [ndays] => 28 # no of days in current month + ) + + +- 28 Apr 2004 0.13 +Fixed adodb_date to properly support $is_gmt. Thx to Dimitar Angelov. + +- 20 Mar 2004 0.12 +Fixed month calculation error in adodb_date. 2102-June-01 appeared as 2102-May-32. + +- 26 Oct 2003 0.11 +Because of daylight savings problems (some systems apply daylight savings to +January!!!), changed adodb_get_gmt_diff() to ignore daylight savings. + +- 9 Aug 2003 0.10 +Fixed bug with dates after 2038. +See http://phplens.com/lens/lensforum/msgs.php?id=6980 + +- 1 July 2003 0.09 +Added support for Q (Quarter). +Added adodb_date2(), which accepts ISO date in 2nd param + +- 3 March 2003 0.08 +Added support for 'S' adodb_date() format char. Added constant ADODB_ALLOW_NEGATIVE_TS +if you want PHP to handle negative timestamps between 1901 to 1969. + +- 27 Feb 2003 0.07 +All negative numbers handled by adodb now because of RH 7.3+ problems. +See http://bugs.php.net/bug.php?id=20048&edit=2 + +- 4 Feb 2003 0.06 +Fixed a typo, 1852 changed to 1582! This means that pre-1852 dates +are now correctly handled. + +- 29 Jan 2003 0.05 + +Leap year checking differs under Julian calendar (pre 1582). Also +leap year code optimized by checking for most common case first. + +We also handle month overflow correctly in mktime (eg month set to 13). + +Day overflow for less than one month's days is supported. + +- 28 Jan 2003 0.04 + +Gregorian correction handled. In PHP5, we might throw an error if +mktime uses invalid dates around 5-14 Oct 1582. Released with ADOdb 3.10. +Added limbo 5-14 Oct 1582 check, when we set to 15 Oct 1582. + +- 27 Jan 2003 0.03 + +Fixed some more month problems due to gmt issues. Added constant ADODB_DATE_VERSION. +Fixed calculation of days since start of year for <1970. + +- 27 Jan 2003 0.02 + +Changed _adodb_getdate() to inline leap year checking for better performance. +Fixed problem with time-zones west of GMT +0000. + +- 24 Jan 2003 0.01 + +First implementation. +*/ + + +/* Initialization */ + +/* + Version Number +*/ +define('ADODB_DATE_VERSION',0.22); + +/* + This code was originally for windows. But apparently this problem happens + also with Linux, RH 7.3 and later! + + glibc-2.2.5-34 and greater has been changed to return -1 for dates < + 1970. This used to work. The problem exists with RedHat 7.3 and 8.0 + echo (mktime(0, 0, 0, 1, 1, 1960)); // prints -1 + + References: + http://bugs.php.net/bug.php?id=20048&edit=2 + http://lists.debian.org/debian-glibc/2002/debian-glibc-200205/msg00010.html +*/ + +if (!defined('ADODB_ALLOW_NEGATIVE_TS')) define('ADODB_NO_NEGATIVE_TS',1); + +function adodb_date_test_date($y1,$m,$d=13) +{ + $t = adodb_mktime(0,0,0,$m,$d,$y1); + $rez = adodb_date('Y-n-j H:i:s',$t); + if ("$y1-$m-$d 00:00:00" != $rez) { + print "$y1 error, expected=$y1-$m-$d 00:00:00, adodb=$rez
"; + return false; + } + return true; +} + +function adodb_date_test_strftime($fmt) +{ + $s1 = strftime($fmt); + $s2 = adodb_strftime($fmt); + + if ($s1 == $s2) return true; + + echo "error for $fmt, strftime=$s1, $adodb=$s2
"; + return false; +} + +/** + Test Suite +*/ +function adodb_date_test() +{ + + error_reporting(E_ALL); + print "

Testing adodb_date and adodb_mktime. version=".ADODB_DATE_VERSION.' PHP='.PHP_VERSION."

"; + @set_time_limit(0); + $fail = false; + + // This flag disables calling of PHP native functions, so we can properly test the code + if (!defined('ADODB_TEST_DATES')) define('ADODB_TEST_DATES',1); + + adodb_date_test_strftime('%Y %m %x %X'); + adodb_date_test_strftime("%A %d %B %Y"); + adodb_date_test_strftime("%H %M S"); + + $t = adodb_mktime(0,0,0); + if (!(adodb_date('Y-m-d') == date('Y-m-d'))) print 'Error in '.adodb_mktime(0,0,0).'
'; + + $t = adodb_mktime(0,0,0,6,1,2102); + if (!(adodb_date('Y-m-d',$t) == '2102-06-01')) print 'Error in '.adodb_date('Y-m-d',$t).'
'; + + $t = adodb_mktime(0,0,0,2,1,2102); + if (!(adodb_date('Y-m-d',$t) == '2102-02-01')) print 'Error in '.adodb_date('Y-m-d',$t).'
'; + + + print "

Testing gregorian <=> julian conversion

"; + $t = adodb_mktime(0,0,0,10,11,1492); + //http://www.holidayorigins.com/html/columbus_day.html - Friday check + if (!(adodb_date('D Y-m-d',$t) == 'Fri 1492-10-11')) print 'Error in Columbus landing
'; + + $t = adodb_mktime(0,0,0,2,29,1500); + if (!(adodb_date('Y-m-d',$t) == '1500-02-29')) print 'Error in julian leap years
'; + + $t = adodb_mktime(0,0,0,2,29,1700); + if (!(adodb_date('Y-m-d',$t) == '1700-03-01')) print 'Error in gregorian leap years
'; + + print adodb_mktime(0,0,0,10,4,1582).' '; + print adodb_mktime(0,0,0,10,15,1582); + $diff = (adodb_mktime(0,0,0,10,15,1582) - adodb_mktime(0,0,0,10,4,1582)); + if ($diff != 3600*24) print " Error in gregorian correction = ".($diff/3600/24)." days
"; + + print " 15 Oct 1582, Fri=".(adodb_dow(1582,10,15) == 5 ? 'Fri' : 'Error')."
"; + print " 4 Oct 1582, Thu=".(adodb_dow(1582,10,4) == 4 ? 'Thu' : 'Error')."
"; + + print "

Testing overflow

"; + + $t = adodb_mktime(0,0,0,3,33,1965); + if (!(adodb_date('Y-m-d',$t) == '1965-04-02')) print 'Error in day overflow 1
'; + $t = adodb_mktime(0,0,0,4,33,1971); + if (!(adodb_date('Y-m-d',$t) == '1971-05-03')) print 'Error in day overflow 2
'; + $t = adodb_mktime(0,0,0,1,60,1965); + if (!(adodb_date('Y-m-d',$t) == '1965-03-01')) print 'Error in day overflow 3 '.adodb_date('Y-m-d',$t).'
'; + $t = adodb_mktime(0,0,0,12,32,1965); + if (!(adodb_date('Y-m-d',$t) == '1966-01-01')) print 'Error in day overflow 4 '.adodb_date('Y-m-d',$t).'
'; + $t = adodb_mktime(0,0,0,12,63,1965); + if (!(adodb_date('Y-m-d',$t) == '1966-02-01')) print 'Error in day overflow 5 '.adodb_date('Y-m-d',$t).'
'; + $t = adodb_mktime(0,0,0,13,3,1965); + if (!(adodb_date('Y-m-d',$t) == '1966-01-03')) print 'Error in mth overflow 1
'; + + print "Testing 2-digit => 4-digit year conversion

"; + if (adodb_year_digit_check(00) != 2000) print "Err 2-digit 2000
"; + if (adodb_year_digit_check(10) != 2010) print "Err 2-digit 2010
"; + if (adodb_year_digit_check(20) != 2020) print "Err 2-digit 2020
"; + if (adodb_year_digit_check(30) != 2030) print "Err 2-digit 2030
"; + if (adodb_year_digit_check(40) != 1940) print "Err 2-digit 1940
"; + if (adodb_year_digit_check(50) != 1950) print "Err 2-digit 1950
"; + if (adodb_year_digit_check(90) != 1990) print "Err 2-digit 1990
"; + + // Test string formating + print "

Testing date formating

"; + $fmt = '\d\a\t\e T Y-m-d H:i:s a A d D F g G h H i j l L m M n O \R\F\C822 r s t U w y Y z Z 2003'; + $s1 = date($fmt,0); + $s2 = adodb_date($fmt,0); + if ($s1 != $s2) { + print " date() 0 failed
$s1
$s2
"; + } + flush(); + for ($i=100; --$i > 0; ) { + + $ts = 3600.0*((rand()%60000)+(rand()%60000))+(rand()%60000); + $s1 = date($fmt,$ts); + $s2 = adodb_date($fmt,$ts); + //print "$s1
$s2

"; + $pos = strcmp($s1,$s2); + + if (($s1) != ($s2)) { + for ($j=0,$k=strlen($s1); $j < $k; $j++) { + if ($s1[$j] != $s2[$j]) { + print substr($s1,$j).' '; + break; + } + } + print "Error date(): $ts

+  \"$s1\" (date len=".strlen($s1).")
+  \"$s2\" (adodb_date len=".strlen($s2).")

"; + $fail = true; + } + + $a1 = getdate($ts); + $a2 = adodb_getdate($ts); + $rez = array_diff($a1,$a2); + if (sizeof($rez)>0) { + print "Error getdate() $ts
"; + print_r($a1); + print "
"; + print_r($a2); + print "

"; + $fail = true; + } + } + + // Test generation of dates outside 1901-2038 + print "

Testing random dates between 100 and 4000

"; + adodb_date_test_date(100,1); + for ($i=100; --$i >= 0;) { + $y1 = 100+rand(0,1970-100); + $m = rand(1,12); + adodb_date_test_date($y1,$m); + + $y1 = 3000-rand(0,3000-1970); + adodb_date_test_date($y1,$m); + } + print '

'; + $start = 1960+rand(0,10); + $yrs = 12; + $i = 365.25*86400*($start-1970); + $offset = 36000+rand(10000,60000); + $max = 365*$yrs*86400; + $lastyear = 0; + + // we generate a timestamp, convert it to a date, and convert it back to a timestamp + // and check if the roundtrip broke the original timestamp value. + print "Testing $start to ".($start+$yrs).", or $max seconds, offset=$offset: "; + $cnt = 0; + for ($max += $i; $i < $max; $i += $offset) { + $ret = adodb_date('m,d,Y,H,i,s',$i); + $arr = explode(',',$ret); + if ($lastyear != $arr[2]) { + $lastyear = $arr[2]; + print " $lastyear "; + flush(); + } + $newi = adodb_mktime($arr[3],$arr[4],$arr[5],$arr[0],$arr[1],$arr[2]); + if ($i != $newi) { + print "Error at $i, adodb_mktime returned $newi ($ret)"; + $fail = true; + break; + } + $cnt += 1; + } + echo "Tested $cnt dates
"; + if (!$fail) print "

Passed !

"; + else print "

Failed :-(

"; +} + +/** + Returns day of week, 0 = Sunday,... 6=Saturday. + Algorithm from PEAR::Date_Calc +*/ +function adodb_dow($year, $month, $day) +{ +/* +Pope Gregory removed 10 days - October 5 to October 14 - from the year 1582 and +proclaimed that from that time onwards 3 days would be dropped from the calendar +every 400 years. + +Thursday, October 4, 1582 (Julian) was followed immediately by Friday, October 15, 1582 (Gregorian). +*/ + if ($year <= 1582) { + if ($year < 1582 || + ($year == 1582 && ($month < 10 || ($month == 10 && $day < 15)))) $greg_correction = 3; + else + $greg_correction = 0; + } else + $greg_correction = 0; + + if($month > 2) + $month -= 2; + else { + $month += 10; + $year--; + } + + $day = floor((13 * $month - 1) / 5) + + $day + ($year % 100) + + floor(($year % 100) / 4) + + floor(($year / 100) / 4) - 2 * + floor($year / 100) + 77 + $greg_correction; + + return $day - 7 * floor($day / 7); +} + + +/** + Checks for leap year, returns true if it is. No 2-digit year check. Also + handles julian calendar correctly. +*/ +function _adodb_is_leap_year($year) +{ + if ($year % 4 != 0) return false; + + if ($year % 400 == 0) { + return true; + // if gregorian calendar (>1582), century not-divisible by 400 is not leap + } else if ($year > 1582 && $year % 100 == 0 ) { + return false; + } + + return true; +} + + +/** + checks for leap year, returns true if it is. Has 2-digit year check +*/ +function adodb_is_leap_year($year) +{ + return _adodb_is_leap_year(adodb_year_digit_check($year)); +} + +/** + Fix 2-digit years. Works for any century. + Assumes that if 2-digit is more than 30 years in future, then previous century. +*/ +function adodb_year_digit_check($y) +{ + if ($y < 100) { + + $yr = (integer) date("Y"); + $century = (integer) ($yr /100); + + if ($yr%100 > 50) { + $c1 = $century + 1; + $c0 = $century; + } else { + $c1 = $century; + $c0 = $century - 1; + } + $c1 *= 100; + // if 2-digit year is less than 30 years in future, set it to this century + // otherwise if more than 30 years in future, then we set 2-digit year to the prev century. + if (($y + $c1) < $yr+30) $y = $y + $c1; + else $y = $y + $c0*100; + } + return $y; +} + +/** + get local time zone offset from GMT +*/ +function adodb_get_gmt_diff() +{ +static $TZ; + if (isset($TZ)) return $TZ; + + $TZ = mktime(0,0,0,1,2,1970,0) - gmmktime(0,0,0,1,2,1970,0); + return $TZ; +} + +/** + Returns an array with date info. +*/ +function adodb_getdate($d=false,$fast=false) +{ + if ($d === false) return getdate(); + if (!defined('ADODB_TEST_DATES')) { + if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range + if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer + return @getdate($d); + } + } + return _adodb_getdate($d); +} + +/* +// generate $YRS table for _adodb_getdate() +function adodb_date_gentable($out=true) +{ + + for ($i=1970; $i >= 1600; $i-=10) { + $s = adodb_gmmktime(0,0,0,1,1,$i); + echo "$i => $s,
"; + } +} +adodb_date_gentable(); + +for ($i=1970; $i > 1500; $i--) { + +echo "
$i "; + adodb_date_test_date($i,1,1); +} + +*/ + + +$_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31); +$_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31); + +function adodb_validdate($y,$m,$d) +{ +global $_month_table_normal,$_month_table_leaf; + + if (_adodb_is_leap_year($y)) $marr =& $_month_table_leaf; + else $marr =& $_month_table_normal; + + if ($m > 12 || $m < 1) return false; + + if ($d > 31 || $d < 1) return false; + + if ($marr[$m] < $d) return false; + + if ($y < 1000 && $y > 3000) return false; + + return true; +} + +/** + Low-level function that returns the getdate() array. We have a special + $fast flag, which if set to true, will return fewer array values, + and is much faster as it does not calculate dow, etc. +*/ +function _adodb_getdate($origd=false,$fast=false,$is_gmt=false) +{ +static $YRS; +global $_month_table_normal,$_month_table_leaf; + + $d = $origd - ($is_gmt ? 0 : adodb_get_gmt_diff()); + + $_day_power = 86400; + $_hour_power = 3600; + $_min_power = 60; + + if ($d < -12219321600) $d -= 86400*10; // if 15 Oct 1582 or earlier, gregorian correction + + $_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31); + $_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31); + + $d366 = $_day_power * 366; + $d365 = $_day_power * 365; + + if ($d < 0) { + + if (empty($YRS)) $YRS = array( + 1970 => 0, + 1960 => -315619200, + 1950 => -631152000, + 1940 => -946771200, + 1930 => -1262304000, + 1920 => -1577923200, + 1910 => -1893456000, + 1900 => -2208988800, + 1890 => -2524521600, + 1880 => -2840140800, + 1870 => -3155673600, + 1860 => -3471292800, + 1850 => -3786825600, + 1840 => -4102444800, + 1830 => -4417977600, + 1820 => -4733596800, + 1810 => -5049129600, + 1800 => -5364662400, + 1790 => -5680195200, + 1780 => -5995814400, + 1770 => -6311347200, + 1760 => -6626966400, + 1750 => -6942499200, + 1740 => -7258118400, + 1730 => -7573651200, + 1720 => -7889270400, + 1710 => -8204803200, + 1700 => -8520336000, + 1690 => -8835868800, + 1680 => -9151488000, + 1670 => -9467020800, + 1660 => -9782640000, + 1650 => -10098172800, + 1640 => -10413792000, + 1630 => -10729324800, + 1620 => -11044944000, + 1610 => -11360476800, + 1600 => -11676096000); + + if ($is_gmt) $origd = $d; + // The valid range of a 32bit signed timestamp is typically from + // Fri, 13 Dec 1901 20:45:54 GMT to Tue, 19 Jan 2038 03:14:07 GMT + // + + # old algorithm iterates through all years. new algorithm does it in + # 10 year blocks + + /* + # old algo + for ($a = 1970 ; --$a >= 0;) { + $lastd = $d; + + if ($leaf = _adodb_is_leap_year($a)) $d += $d366; + else $d += $d365; + + if ($d >= 0) { + $year = $a; + break; + } + } + */ + + $lastsecs = 0; + $lastyear = 1970; + foreach($YRS as $year => $secs) { + if ($d >= $secs) { + $a = $lastyear; + break; + } + $lastsecs = $secs; + $lastyear = $year; + } + + $d -= $lastsecs; + if (!isset($a)) $a = $lastyear; + + //echo ' yr=',$a,' ', $d,'.'; + + for (; --$a >= 0;) { + $lastd = $d; + + if ($leaf = _adodb_is_leap_year($a)) $d += $d366; + else $d += $d365; + + if ($d >= 0) { + $year = $a; + break; + } + } + /**/ + + $secsInYear = 86400 * ($leaf ? 366 : 365) + $lastd; + + $d = $lastd; + $mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal; + for ($a = 13 ; --$a > 0;) { + $lastd = $d; + $d += $mtab[$a] * $_day_power; + if ($d >= 0) { + $month = $a; + $ndays = $mtab[$a]; + break; + } + } + + $d = $lastd; + $day = $ndays + ceil(($d+1) / ($_day_power)); + + $d += ($ndays - $day+1)* $_day_power; + $hour = floor($d/$_hour_power); + + } else { + for ($a = 1970 ;; $a++) { + $lastd = $d; + + if ($leaf = _adodb_is_leap_year($a)) $d -= $d366; + else $d -= $d365; + if ($d < 0) { + $year = $a; + break; + } + } + $secsInYear = $lastd; + $d = $lastd; + $mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal; + for ($a = 1 ; $a <= 12; $a++) { + $lastd = $d; + $d -= $mtab[$a] * $_day_power; + if ($d < 0) { + $month = $a; + $ndays = $mtab[$a]; + break; + } + } + $d = $lastd; + $day = ceil(($d+1) / $_day_power); + $d = $d - ($day-1) * $_day_power; + $hour = floor($d /$_hour_power); + } + + $d -= $hour * $_hour_power; + $min = floor($d/$_min_power); + $secs = $d - $min * $_min_power; + if ($fast) { + return array( + 'seconds' => $secs, + 'minutes' => $min, + 'hours' => $hour, + 'mday' => $day, + 'mon' => $month, + 'year' => $year, + 'yday' => floor($secsInYear/$_day_power), + 'leap' => $leaf, + 'ndays' => $ndays + ); + } + + + $dow = adodb_dow($year,$month,$day); + + return array( + 'seconds' => $secs, + 'minutes' => $min, + 'hours' => $hour, + 'mday' => $day, + 'wday' => $dow, + 'mon' => $month, + 'year' => $year, + 'yday' => floor($secsInYear/$_day_power), + 'weekday' => gmdate('l',$_day_power*(3+$dow)), + 'month' => gmdate('F',mktime(0,0,0,$month,2,1971)), + 0 => $origd + ); +} + +function adodb_gmdate($fmt,$d=false) +{ + return adodb_date($fmt,$d,true); +} + +// accepts unix timestamp and iso date format in $d +function adodb_date2($fmt, $d=false, $is_gmt=false) +{ + if ($d !== false) { + if (!preg_match( + "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ -]?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", + ($d), $rr)) return adodb_date($fmt,false,$is_gmt); + + if ($rr[1] <= 100 && $rr[2]<= 1) return adodb_date($fmt,false,$is_gmt); + + // h-m-s-MM-DD-YY + if (!isset($rr[5])) $d = adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1],false,$is_gmt); + else $d = @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1],false,$is_gmt); + } + + return adodb_date($fmt,$d,$is_gmt); +} + + +/** + Return formatted date based on timestamp $d +*/ +function adodb_date($fmt,$d=false,$is_gmt=false) +{ +static $daylight; + + if ($d === false) return ($is_gmt)? @gmdate($fmt): @date($fmt); + if (!defined('ADODB_TEST_DATES')) { + if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range + if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer + return ($is_gmt)? @gmdate($fmt,$d): @date($fmt,$d); + + } + } + $_day_power = 86400; + + $arr = _adodb_getdate($d,true,$is_gmt); + + if (!isset($daylight)) $daylight = function_exists('adodb_daylight_sv'); + if ($daylight) adodb_daylight_sv($arr, $is_gmt); + + $year = $arr['year']; + $month = $arr['mon']; + $day = $arr['mday']; + $hour = $arr['hours']; + $min = $arr['minutes']; + $secs = $arr['seconds']; + + $max = strlen($fmt); + $dates = ''; + + /* + at this point, we have the following integer vars to manipulate: + $year, $month, $day, $hour, $min, $secs + */ + for ($i=0; $i < $max; $i++) { + switch($fmt[$i]) { + case 'T': $dates .= date('T');break; + // YEAR + case 'L': $dates .= $arr['leap'] ? '1' : '0'; break; + case 'r': // Thu, 21 Dec 2000 16:01:07 +0200 + + // 4.3.11 uses '04 Jun 2004' + // 4.3.8 uses ' 4 Jun 2004' + $dates .= gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))).', ' + . ($day<10?'0'.$day:$day) . ' '.date('M',mktime(0,0,0,$month,2,1971)).' '.$year.' '; + + if ($hour < 10) $dates .= '0'.$hour; else $dates .= $hour; + + if ($min < 10) $dates .= ':0'.$min; else $dates .= ':'.$min; + + if ($secs < 10) $dates .= ':0'.$secs; else $dates .= ':'.$secs; + + $gmt = adodb_get_gmt_diff(); + $dates .= sprintf(' %s%04d',($gmt<0)?'+':'-',abs($gmt)/36); break; + + case 'Y': $dates .= $year; break; + case 'y': $dates .= substr($year,strlen($year)-2,2); break; + // MONTH + case 'm': if ($month<10) $dates .= '0'.$month; else $dates .= $month; break; + case 'Q': $dates .= ($month+3)>>2; break; + case 'n': $dates .= $month; break; + case 'M': $dates .= date('M',mktime(0,0,0,$month,2,1971)); break; + case 'F': $dates .= date('F',mktime(0,0,0,$month,2,1971)); break; + // DAY + case 't': $dates .= $arr['ndays']; break; + case 'z': $dates .= $arr['yday']; break; + case 'w': $dates .= adodb_dow($year,$month,$day); break; + case 'l': $dates .= gmdate('l',$_day_power*(3+adodb_dow($year,$month,$day))); break; + case 'D': $dates .= gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))); break; + case 'j': $dates .= $day; break; + case 'd': if ($day<10) $dates .= '0'.$day; else $dates .= $day; break; + case 'S': + $d10 = $day % 10; + if ($d10 == 1) $dates .= 'st'; + else if ($d10 == 2 && $day != 12) $dates .= 'nd'; + else if ($d10 == 3) $dates .= 'rd'; + else $dates .= 'th'; + break; + + // HOUR + case 'Z': + $dates .= ($is_gmt) ? 0 : -adodb_get_gmt_diff(); break; + case 'O': + $gmt = ($is_gmt) ? 0 : adodb_get_gmt_diff(); + $dates .= sprintf('%s%04d',($gmt<0)?'+':'-',abs($gmt)/36); break; + + case 'H': + if ($hour < 10) $dates .= '0'.$hour; + else $dates .= $hour; + break; + case 'h': + if ($hour > 12) $hh = $hour - 12; + else { + if ($hour == 0) $hh = '12'; + else $hh = $hour; + } + + if ($hh < 10) $dates .= '0'.$hh; + else $dates .= $hh; + break; + + case 'G': + $dates .= $hour; + break; + + case 'g': + if ($hour > 12) $hh = $hour - 12; + else { + if ($hour == 0) $hh = '12'; + else $hh = $hour; + } + $dates .= $hh; + break; + // MINUTES + case 'i': if ($min < 10) $dates .= '0'.$min; else $dates .= $min; break; + // SECONDS + case 'U': $dates .= $d; break; + case 's': if ($secs < 10) $dates .= '0'.$secs; else $dates .= $secs; break; + // AM/PM + // Note 00:00 to 11:59 is AM, while 12:00 to 23:59 is PM + case 'a': + if ($hour>=12) $dates .= 'pm'; + else $dates .= 'am'; + break; + case 'A': + if ($hour>=12) $dates .= 'PM'; + else $dates .= 'AM'; + break; + default: + $dates .= $fmt[$i]; break; + // ESCAPE + case "\\": + $i++; + if ($i < $max) $dates .= $fmt[$i]; + break; + } + } + return $dates; +} + +/** + Returns a timestamp given a GMT/UTC time. + Note that $is_dst is not implemented and is ignored. +*/ +function adodb_gmmktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false) +{ + return adodb_mktime($hr,$min,$sec,$mon,$day,$year,$is_dst,true); +} + +/** + Return a timestamp given a local time. Originally by jackbbs. + Note that $is_dst is not implemented and is ignored. + + Not a very fast algorithm - O(n) operation. Could be optimized to O(1). +*/ +function adodb_mktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false,$is_gmt=false) +{ + if (!defined('ADODB_TEST_DATES')) { + + if ($mon === false) { + return $is_gmt? @gmmktime($hr,$min,$sec): @mktime($hr,$min,$sec); + } + + // for windows, we don't check 1970 because with timezone differences, + // 1 Jan 1970 could generate negative timestamp, which is illegal + if (1971 < $year && $year < 2038 + || !defined('ADODB_NO_NEGATIVE_TS') && (1901 < $year && $year < 2038) + ) { + return $is_gmt ? + @gmmktime($hr,$min,$sec,$mon,$day,$year): + @mktime($hr,$min,$sec,$mon,$day,$year); + } + } + + $gmt_different = ($is_gmt) ? 0 : adodb_get_gmt_diff(); + + /* + # disabled because some people place large values in $sec. + # however we need it for $mon because we use an array... + $hr = intval($hr); + $min = intval($min); + $sec = intval($sec); + */ + $mon = intval($mon); + $day = intval($day); + $year = intval($year); + + + $year = adodb_year_digit_check($year); + + if ($mon > 12) { + $y = floor($mon / 12); + $year += $y; + $mon -= $y*12; + } + if ($mon < 1) { + $y = ceil((1-$mon) / 12); + $year -= $y; + $mon += $y*12; + } + + $_day_power = 86400; + $_hour_power = 3600; + $_min_power = 60; + + $_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31); + $_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31); + + $_total_date = 0; + if ($year >= 1970) { + for ($a = 1970 ; $a <= $year; $a++) { + $leaf = _adodb_is_leap_year($a); + if ($leaf == true) { + $loop_table = $_month_table_leaf; + $_add_date = 366; + } else { + $loop_table = $_month_table_normal; + $_add_date = 365; + } + if ($a < $year) { + $_total_date += $_add_date; + } else { + for($b=1;$b<$mon;$b++) { + $_total_date += $loop_table[$b]; + } + } + } + $_total_date +=$day-1; + $ret = $_total_date * $_day_power + $hr * $_hour_power + $min * $_min_power + $sec + $gmt_different; + + } else { + for ($a = 1969 ; $a >= $year; $a--) { + $leaf = _adodb_is_leap_year($a); + if ($leaf == true) { + $loop_table = $_month_table_leaf; + $_add_date = 366; + } else { + $loop_table = $_month_table_normal; + $_add_date = 365; + } + if ($a > $year) { $_total_date += $_add_date; + } else { + for($b=12;$b>$mon;$b--) { + $_total_date += $loop_table[$b]; + } + } + } + $_total_date += $loop_table[$mon] - $day; + + $_day_time = $hr * $_hour_power + $min * $_min_power + $sec; + $_day_time = $_day_power - $_day_time; + $ret = -( $_total_date * $_day_power + $_day_time - $gmt_different); + if ($ret < -12220185600) $ret += 10*86400; // if earlier than 5 Oct 1582 - gregorian correction + else if ($ret < -12219321600) $ret = -12219321600; // if in limbo, reset to 15 Oct 1582. + } + //print " dmy=$day/$mon/$year $hr:$min:$sec => " .$ret; + return $ret; +} + +function adodb_gmstrftime($fmt, $ts=false) +{ + return adodb_strftime($fmt,$ts,true); +} + +// hack - convert to adodb_date +function adodb_strftime($fmt, $ts=false,$is_gmt=false) +{ +global $ADODB_DATE_LOCALE; + + if (!defined('ADODB_TEST_DATES')) { + if ((abs($ts) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range + if (!defined('ADODB_NO_NEGATIVE_TS') || $ts >= 0) // if windows, must be +ve integer + return ($is_gmt)? @gmstrftime($fmt,$ts): @strftime($fmt,$ts); + + } + } + + if (empty($ADODB_DATE_LOCALE)) { + $tstr = strtoupper(gmstrftime('%c',31366800)); // 30 Dec 1970, 1 am + $sep = substr($tstr,2,1); + $hasAM = strrpos($tstr,'M') !== false; + + $ADODB_DATE_LOCALE = array(); + $ADODB_DATE_LOCALE[] = strncmp($tstr,'30',2) == 0 ? 'd'.$sep.'m'.$sep.'y' : 'm'.$sep.'d'.$sep.'y'; + $ADODB_DATE_LOCALE[] = ($hasAM) ? 'h:i:s a' : 'H:i:s'; + + } + $inpct = false; + $fmtdate = ''; + for ($i=0,$max = strlen($fmt); $i < $max; $i++) { + $ch = $fmt[$i]; + if ($ch == '%') { + if ($inpct) { + $fmtdate .= '%'; + $inpct = false; + } else + $inpct = true; + } else if ($inpct) { + + $inpct = false; + switch($ch) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 'E': + case 'O': + /* ignore format modifiers */ + $inpct = true; + break; + + case 'a': $fmtdate .= 'D'; break; + case 'A': $fmtdate .= 'l'; break; + case 'h': + case 'b': $fmtdate .= 'M'; break; + case 'B': $fmtdate .= 'F'; break; + case 'c': $fmtdate .= $ADODB_DATE_LOCALE[0].$ADODB_DATE_LOCALE[1]; break; + case 'C': $fmtdate .= '\C?'; break; // century + case 'd': $fmtdate .= 'd'; break; + case 'D': $fmtdate .= 'm/d/y'; break; + case 'e': $fmtdate .= 'j'; break; + case 'g': $fmtdate .= '\g?'; break; //? + case 'G': $fmtdate .= '\G?'; break; //? + case 'H': $fmtdate .= 'H'; break; + case 'I': $fmtdate .= 'h'; break; + case 'j': $fmtdate .= '?z'; $parsej = true; break; // wrong as j=1-based, z=0-basd + case 'm': $fmtdate .= 'm'; break; + case 'M': $fmtdate .= 'i'; break; + case 'n': $fmtdate .= "\n"; break; + case 'p': $fmtdate .= 'a'; break; + case 'r': $fmtdate .= 'h:i:s a'; break; + case 'R': $fmtdate .= 'H:i:s'; break; + case 'S': $fmtdate .= 's'; break; + case 't': $fmtdate .= "\t"; break; + case 'T': $fmtdate .= 'H:i:s'; break; + case 'u': $fmtdate .= '?u'; $parseu = true; break; // wrong strftime=1-based, date=0-based + case 'U': $fmtdate .= '?U'; $parseU = true; break;// wrong strftime=1-based, date=0-based + case 'x': $fmtdate .= $ADODB_DATE_LOCALE[0]; break; + case 'X': $fmtdate .= $ADODB_DATE_LOCALE[1]; break; + case 'w': $fmtdate .= '?w'; $parseu = true; break; // wrong strftime=1-based, date=0-based + case 'W': $fmtdate .= '?W'; $parseU = true; break;// wrong strftime=1-based, date=0-based + case 'y': $fmtdate .= 'y'; break; + case 'Y': $fmtdate .= 'Y'; break; + case 'Z': $fmtdate .= 'T'; break; + } + } else if (('A' <= ($ch) && ($ch) <= 'Z' ) || ('a' <= ($ch) && ($ch) <= 'z' )) + $fmtdate .= "\\".$ch; + else + $fmtdate .= $ch; + } + //echo "fmt=",$fmtdate,"
"; + if ($ts === false) $ts = time(); + $ret = adodb_date($fmtdate, $ts, $is_gmt); + return $ret; +} + + +?> \ No newline at end of file diff --git a/lib/adodb/adodb.config.php b/lib/adodb/adodb.config.php new file mode 100644 index 0000000..feb8ff6 --- /dev/null +++ b/lib/adodb/adodb.config.php @@ -0,0 +1,52 @@ + \ No newline at end of file diff --git a/lib/adodb/adodb.inc.php b/lib/adodb/adodb.inc.php new file mode 100644 index 0000000..a5dbaae --- /dev/null +++ b/lib/adodb/adodb.inc.php @@ -0,0 +1,392 @@ +''); + + $dbtype = strtolower($dbtype); + include_once ADODB_DIR . '/adodbSQL_drivers/' . $dbtype . '/' . $dbtype . '_driver.inc'; + $last_module = $dbtype . '_' . 'driver'; + if(!empty($modules)) + { + $module_list = explode(":", strtolower($modules)); + $generic_modules = array(); + foreach($module_list as $mod) { + $mod = trim($mod); + if(is_file(ADODB_DIR . '/generic_modules/' . $mod . '_module.inc')) + { + $generic_modules[] = $mod; + } + else + { + include_once ADODB_DIR . '/adodbSQL_drivers/' . $dbtype . '/' . $dbtype . '_' . $mod . '_module.inc'; + $last_module = $dbtype . '_' . $mod; + } + } + + if(count($generic_modules)) + { + foreach($generic_modules as $mod) { + include_once ADODB_DIR . '/generic_modules/' . $mod . '_module.inc'; + $last_module = $mod; + } + } + } + + $extention = $last_module . '_ADOConnection'; + + $object = new $extention(); + $object->last_module_name = $last_module; + $object->raiseErrorFn = (defined('ADODB_ERROR_HANDLER')) ? ADODB_ERROR_HANDLER : false; + $object->query_count = 0; + $object->query_time_total = 0; + + if(!empty($dsn_array['scheme'])) + { + if (isset($dsn_array['port'])) $object->port = $dsn_array['port']; + $persistent = false; + $forcenew = false; + if (isset($dsn_array['query'])) { + $option_array = explode('&', $dsn_array['query']); + foreach($option_array as $element => $value) { + $array = explode('=', $value); + $data = isset($array[1]) ? $array[1] : 1; + switch(strtolower($array[0])) { + case 'persist': + case 'persistent': + $persistent = $data; + break; + case 'debug': + $object->debug = (integer) $data; + break; + case 'fetchmode': + $ADODB_FETCH_MODE = constant($data); + break; + case 'clientflags': + $object->clientFlags = $data; + break; + case 'port': + $object->port = $data; + break; + case 'socket': + $object->socket = $data; + break; + case 'forcenew': + $forcenew = $data; + break; + } + } + } + + $dsn_array['host'] = isset($dsn_array['host']) ? $dsn_array['host'] : ''; + $dsn_array['user'] = isset($dsn_array['user']) ? $dsn_array['user'] : ''; + $dsn_array['pass'] = isset($dsn_array['pass']) ? $dsn_array['pass'] : ''; + $dsn_array['path'] = isset($dsn_array['path']) ? substr($dsn_array['path'], 1) : ''; + + $result = $object->_connect($dsn_array['host'], $dsn_array['user'], $dsn_array['pass'], $dsn_array['path'], $persistent, $forcenew); + + if (!$result) return $false; + } + + return $object; +} + +/** + * Alternative Database connection + * Usage: $db = new NewADOConnection('dbtype'); + * + * @access public + * @param string $dbtype + */ + +function &NewADOConnection($dbtype='', $module = '' ) +{ + $tmp =& ADONewConnection($dbtype, $module); + return $tmp; +} + +function &NewDataDictionary(&$connection, $dbtype=false) +{ + if(!$dbtype) + $dbtype = $connection->dbtype; + include_once ADODB_DIR . '/adodb-datadict.inc.php'; + include_once ADODB_DIR . '/adodbSQL_drivers/' . $dbtype . '/' . $dbtype . '_datadict.inc'; + + $class = "ADODB2_$dbtype"; + $dict = new $class(); + $dict->connection = &$connection; + $dict->upperName = strtoupper($dbtype); + $dict->quote = $connection->nameQuote; + $dict->debug_echo = $connection->debug_echo; + + return $dict; +} + +/** + * Backwards compatible with ADOdb usage of NewPerfMonitor + * Change to module basis for PerfMon mean we need only return a reference to $connection object. + * Usage: $perf =& NewPerfMonitor($conn); - $perf is a reference to $conn + * + * @access public + * @param ADOConnection $connection + * @param string $dbtype This is an optional parameter with no actual use in ADOdb-Lite; for BC only. + */ +function &NewPerfMonitor(&$connection, $dbtype=false) +{ + return $connection; +} + +class ADOConnection +{ + var $connectionId = false; + var $record_set = false; + var $database; + var $dbtype; + var $dataProvider; + var $host; + var $open; + var $password; + var $username; + var $persistent; + var $debug = false; + var $debug_console = false; + var $debug_echo = true; + var $debug_output; + var $forcenewconnection = false; + var $createdatabase = false; + var $last_module_name; + var $socket = false; + var $port = false; + var $clientFlags = 0; + var $nameQuote = '"'; + var $sysDate = false; /// name of function that returns the current date + var $sysTimeStamp = false; /// name of function that returns the current timestamp + var $sql; + var $raiseErrorFn = false; + var $query_count = 0; + var $query_time_total = 0; + var $query_list = array(); + var $query_list_time = array(); + var $query_list_errors = array(); + var $_logsql = false; + + function ADOConnection() + { + } + + /** + * Returns floating point version number of ADOdb Lite + * Usage: $db->Version(); + * + * @access public + */ + + function Version() + { + global $ADODB_vers; + return (float) substr($ADODB_vers,1); + } + + /** + * Returns true if connected to database + * Usage: $db->IsConnected(); + * + * @access public + */ + + function IsConnected() + { + if($this->connectionId === false || $this->connectionId == false) + return false; + else return true; + } + + /** + * Normal Database connection + * Usage: $result = $db->Connect('host', 'username', 'password', 'database'); + * + * @access public + * @param string $database + * @param string $host + * @param string $password + * @param string $username + * @param string $forcenew // private + */ + + function Connect( $host = "", $username = "", $password = "", $database = "", $forcenew = false) + { + return $this->_connect($host, $username, $password, $database, false, $forcenew); + } + + /** + * Persistent Database connection + * Usage: $result = $db->PConnect('host', 'username', 'password', 'database'); + * + * @access public + * @param string $database + * @param string $host + * @param string $password + * @param string $username + */ + + function PConnect( $host = "", $username = "", $password = "", $database = "") + { + return $this->_connect($host, $username, $password, $database, true, false); + } + + /** + * Force New Database connection + * Usage: $result = $db->NConnect('host', 'username', 'password', 'database'); + * + * @access public + * @param string $database + * @param string $host + * @param string $password + * @param string $username + */ + + function NConnect( $host = "", $username = "", $password = "", $database = "") + { + return $this->_connect($host, $username, $password, $database, false, true); + } + + /** + * Returns SQL query and instantiates sql statement & resultset driver + * Usage: $linkId =& $db->execute( 'SELECT * FROM foo ORDER BY id' ); + * + * @access public + * @param string $sql + * @return mixed Resource ID, Array + */ + + function &Execute( $sql, $inputarr = false ) + { + // adodb_log_sql will time the query execution and log the sql query + // note: the later $this->do_query() should not run since adodb_log_sql() independently executes the query itself. + if($this->_logsql === true) + { + $ret =& adodb_log_sql($this, $sql, $inputarr); + if (isset($ret)) return $ret; + } + $rs =& $this->do_query($sql, -1, -1, $inputarr); + return $rs; + } + + /** + * Returns SQL query and instantiates sql statement & resultset driver + * Usage: $linkId =& $db->SelectLimit( 'SELECT * FROM foo ORDER BY id', $nrows, $offset ); + * $nrows and $offset are optional + * + * @access public + * @param string $sql + * @param string $nrows + * @param string $offset + * @return mixed Resource ID, Array + */ + + function &SelectLimit( $sql, $nrows=-1, $offset=-1, $inputarr=false, $secs2cache=0 ) + { + $rs =& $this->do_query( $sql, $offset, $nrows, $inputarr); + return $rs; + } + + /** + * Display debug output and database error. + * + * @access private + */ + + function outp($text, $newline = true) + { + global $ADODB_OUTP; + $this->debug_output = "
\n(" . $this->dbtype . "): ".htmlspecialchars($text)."
\n Error (" . $this->ErrorNo() .'): '. $this->ErrorMsg() . "
\n"; + + if(defined('ADODB_OUTP')) + { + $fn = ADODB_OUTP; + } else if(isset($ADODB_OUTP)) + { + $fn = $ADODB_OUTP; + } + + if(defined('ADODB_OUTP') || isset($ADODB_OUTP)) + { + $fn($this->debug_output, $newline); + return; + } + + if($this->debug_echo) + echo $this->debug_output; + } + +} + +/** + * Empty result record set for updates, inserts, ect + * + * @access private + */ + +class ADORecordSet_empty +{ + var $fields = false; + var $EOF = true; + function MoveNext() {return;} + function RecordCount() {return 0;} + function FieldCount() {return 0;} + function EOF(){return TRUE;} + function Close(){return true;} +} + +class ADOFieldObject { + var $name = ''; + var $max_length=0; + var $type=""; +} + +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/mysql/mysql_datadict.inc b/lib/adodb/adodbSQL_drivers/mysql/mysql_datadict.inc new file mode 100644 index 0000000..20ee6e2 --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/mysql/mysql_datadict.inc @@ -0,0 +1,112 @@ +alterTableAddIndex) $sql[] = "ALTER TABLE $tabname DROP INDEX $idxname"; + else $sql[] = sprintf($this->dropIndex, $idxname, $tabname); + + if ( isset($idxoptions['DROP']) ) + return $sql; + } + + if ( empty ($flds) ) { + return $sql; + } + + if (isset($idxoptions['FULLTEXT'])) { + $unique = ' FULLTEXT'; + } elseif (isset($idxoptions['UNIQUE'])) { + $unique = ' UNIQUE'; + } else { + $unique = ''; + } + + if ( is_array($flds) ) $flds = implode(', ',$flds); + + if ($this->alterTableAddIndex) $s = "ALTER TABLE $tabname ADD $unique INDEX $idxname "; + else $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname; + + $s .= ' (' . $flds . ')'; + + if ( isset($idxoptions[$this->upperName]) ) + $s .= $idxoptions[$this->upperName]; + + $sql[] = $s; + + return $sql; + } + +} + +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/mysql/mysql_date_module.inc b/lib/adodb/adodbSQL_drivers/mysql/mysql_date_module.inc new file mode 100644 index 0000000..7bc6e22 --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/mysql/mysql_date_module.inc @@ -0,0 +1,321 @@ +_Execute("select $this->sysTimeStamp"); + if ($rs && !$rs->EOF) + return $this->UnixTimeStamp(reset($rs->fields)); + else return false; + } + + function OffsetDate($dayFraction, $date=false) + { + if (!$date) + $date = $this->sysDate; + + $fraction = $dayFraction * 24 * 3600; + return "from_unixtime(unix_timestamp($date)+$fraction)"; + } + + function SetDateLocale($locale = 'En') + { + $this->locale = $locale; + switch (strtoupper($locale)) + { + case 'EN': + $this->fmtDate="'Y-m-d'"; + $this->fmtTimeStamp = "'Y-m-d H:i:s'"; + break; + + case 'US': + $this->fmtDate = "'m-d-Y'"; + $this->fmtTimeStamp = "'m-d-Y H:i:s'"; + break; + + case 'NL': + case 'FR': + case 'RO': + case 'IT': + $this->fmtDate="'d-m-Y'"; + $this->fmtTimeStamp = "'d-m-Y H:i:s'"; + break; + + case 'GE': + $this->fmtDate="'d.m.Y'"; + $this->fmtTimeStamp = "'d.m.Y H:i:s'"; + break; + + default: + $this->fmtDate="'Y-m-d'"; + $this->fmtTimeStamp = "'Y-m-d H:i:s'"; + break; + } + } + + function DBDate($date) + { + if (empty($date) && $date !== 0) + return 'null'; + + if (is_string($date) && !is_numeric($date)) { + if ($date === 'null' || strncmp($date, "'", 1) === 0) + return $date; + + if ($this->isoDates) + return "'$date'"; + + $date = $this->UnixDate($date); + } + return adodb_date($this->fmtDate, $date); + } + + function DBTimeStamp($timestamp) + { + if (empty($timestamp) && $timestamp !== 0) + return 'null'; + + # strlen(14) allows YYYYMMDDHHMMSS format + if (!is_string($timestamp) || (is_numeric($timestamp) && strlen($timestamp)<14)) + return adodb_date($this->fmtTimeStamp, $timestamp); + + if ($timestamp === 'null') + return $timestamp; + + if ($this->isoDates && strlen($timestamp) !== 14) + return "'$timestamp'"; + + return adodb_date($this->fmtTimeStamp, $this->UnixTimeStamp($timestamp)); + } + + function UnixDate($v) + { + if (is_object($v)) { + // odbtp support + //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 ) + return adodb_mktime($v->hour, $v->minute, $v->second, $v->month, $v->day, $v->year); + } + if (is_numeric($v) && strlen($v) !== 8) + return $v; + + if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", ($v), $rr)) + return false; + + if ($rr[1] <= TIMESTAMP_FIRST_YEAR) + return 0; + + // h-m-s-MM-DD-YY + return adodb_mktime(0, 0, 0, $rr[2], $rr[3], $rr[1]); + } + + + function UnixTimeStamp($v) + { + if (is_object($v)) { + // odbtp support + //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 ) + return adodb_mktime($v->hour, $v->minute, $v->second, $v->month, $v->day, $v->year); + } + + if (!preg_match("|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ ,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", ($v), $rr)) + return false; + + if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) + return 0; + + // h-m-s-MM-DD-YY + if (!isset($rr[5])) + return adodb_mktime(0, 0, 0, $rr[2], $rr[3], $rr[1]); + + return adodb_mktime($rr[5], $rr[6], $rr[7], $rr[2], $rr[3], $rr[1]); + } + + function UserDate($v, $fmt='Y-m-d', $gmt=false) + { + $tt = $this->UnixDate($v); + + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + else if ($tt == 0) + return $this->emptyDate; + else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR + } + + return ($gmt) ? adodb_gmdate($fmt, $tt) : adodb_date($fmt, $tt); + } + + function UserTimeStamp($v, $fmt='Y-m-d H:i:s', $gmt=false) + { + if (!isset($v)) + return $this->emptyTimeStamp; + + # strlen(14) allows YYYYMMDDHHMMSS format + if (is_numeric($v) && strlen($v)<14) + return ($gmt) ? adodb_gmdate($fmt, $v) : adodb_date($fmt,$v); + + $tt = $this->UnixTimeStamp($v); + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + + if ($tt == 0) + return $this->emptyTimeStamp; + + return ($gmt) ? adodb_gmdate($fmt, $tt) : adodb_date($fmt, $tt); + } + + function SQLDate($fmt, $col=false) + { + if (!$col) + $col = $this->sysTimeStamp; + + $s = 'DATE_FORMAT('.$col.",'"; + $concat = false; + $len = strlen($fmt); + for ($i=0; $i < $len; $i++) { + $ch = $fmt[$i]; + switch($ch) { + default: + if ($ch == '\\') { + $i++; + $ch = substr($fmt, $i, 1); + } + + /** FALL THROUGH */ + case '-': + case '/': + $s .= $ch; + break; + + case 'Y': + case 'y': + $s .= '%Y'; + break; + + case 'M': + $s .= '%b'; + break; + + case 'm': + $s .= '%m'; + break; + + case 'D': + case 'd': + $s .= '%d'; + break; + + case 'Q': + case 'q': + $s .= "'),Quarter($col)"; + if ($len > $i+1) + $s .= ",DATE_FORMAT($col,'"; + else $s .= ",('"; + $concat = true; + break; + + case 'H': + $s .= '%H'; + break; + + case 'h': + $s .= '%I'; + break; + + case 'i': + $s .= '%i'; + break; + + case 's': + $s .= '%s'; + break; + + case 'a': + case 'A': + $s .= '%p'; + break; + + case 'w': + $s .= '%w'; + break; + + case 'l': + $s .= '%W'; + break; + } + } + $s.="')"; + if ($concat) + $s = "CONCAT($s)"; + + return $s; + } +} + +eval('class mysql_date_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class mysql_date_ResultSet extends mysql_date_resultset_EXTENDER +{ + var $emptyTimeStamp = ' '; /// what to display when $time==0 + var $emptyDate = ' '; /// what to display when $time==0 + var $datetime = false; + + function UserTimeStamp($v, $fmt='Y-m-d H:i:s') + { + if (is_numeric($v) && strlen($v)<14) + return adodb_date($fmt, $v); + + $tt = $this->UnixTimeStamp($v); + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + + if ($tt === 0) + return $this->emptyTimeStamp; + else return adodb_date($fmt, $tt); + } + + function UserDate($v,$fmt='Y-m-d') + { + $tt = $this->UnixDate($v); + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + else if ($tt == 0) + return $this->emptyDate; + else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR + } + return adodb_date($fmt, $tt); + } + + function UnixDate($v) + { + return mysql_date_ADOConnection::UnixDate($v); + } + + function UnixTimeStamp($v) + { + return mysql_date_ADOConnection::UnixTimeStamp($v); + } +} +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/mysql/mysql_driver.inc b/lib/adodb/adodbSQL_drivers/mysql/mysql_driver.inc new file mode 100644 index 0000000..b2ec9d8 --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/mysql/mysql_driver.inc @@ -0,0 +1,660 @@ +dbtype = 'mysql'; + $this->dataProvider = 'mysql'; + } + + /** + * Connection to database server and selected database + * + * @access private + */ + + function _connect($host = "", $username = "", $password = "", $database = "", $persistent, $forcenew) + { + if (!function_exists('mysql_connect')) { + echo "ERROR: Function 'mysql_connect' not found! Check if MySQL is properly set up. And that PHP has the MySQL extension installed."; + return false; + } + + $this->host = $host; + if (!empty($this->port)) $this->host .= ":" . $this->port; + $this->username = $username; + $this->password = $password; + $this->database = $database; + $this->persistent = $persistent; + $this->forcenewconnection = $forcenew; + + if($this->persistent == 1) + { + if (strnatcmp(PHP_VERSION, '4.3.0') >= 0) + $this->connectionId = @mysql_pconnect( $this->host, $this->username, $this->password, $this->clientFlags ); + else + $this->connectionId = @mysql_pconnect( $this->host, $this->username, $this->password ); + } + else + { + if (strnatcmp(PHP_VERSION, '4.3.0') >= 0) + $this->connectionId = @mysql_connect( $this->host, $this->username, $this->password, $this->forcenewconnection, $this->clientFlags ); + else if (strnatcmp(PHP_VERSION, '4.2.0') >= 0) + $this->connectionId = @mysql_connect( $this->host, $this->username, $this->password, $this->forcenewconnection ); + else + $this->connectionId = @mysql_connect( $this->host, $this->username, $this->password ); + } + + if ($this->connectionId === false) + { + if ($fn = $this->raiseErrorFn) + $fn($this->dbtype, 'CONNECT', $this->ErrorNo(), $this->ErrorMsg(), $this->host, $this->database, $this); + return false; + } + + if (!empty($this->database)) + { + if($this->SelectDB( $this->database ) == false) + { + $this->connectionId = false; + return false; + } + } + + return true; + } + + /** + * Choose a database to connect. + * + * @param dbname is the name of the database to select + * @return true or false + * @access public + */ + + function SelectDB($dbname) + { + $this->database = $dbname; + + if ($this->connectionId === false) + { + $this->connectionId = false; + return false; + } + else + { + $result = @mysql_select_db( $this->database, $this->connectionId ); + + if($result === false) + { + if($this->createdatabase == true) + { + $result = @mysql_query( "CREATE DATABASE IF NOT EXISTS " . $this->database, $this->connectionId ); + if ($result === false) { // error handling if query fails + return false; + } + $result = @mysql_select_db( $this->database, $this->connectionId ); + if($result === false) + { + return false; + } + } + else + { + return false; + } + } + return true; + } + } + + /** + * Return database error message + * Usage: $errormessage =& $db->ErrorMsg(); + * + * @access public + */ + + function ErrorMsg() + { + if ($this->connectionId === false) + { + return @mysql_error(); + } + else + { + return @mysql_error($this->connectionId); + } + } + + /** + * Return database error number + * Usage: $errorbo =& $db->ErrorNo(); + * + * @access public + */ + + function ErrorNo() + { + if ($this->connectionId === false) + { + return @mysql_errno(); + } + else + { + return @mysql_errno($this->connectionId); + } + } + + /** + * Returns # of affected rows from insert/delete/update query + * + * @access public + * @return integer Affected rows + */ + + function Affected_Rows() + { + return @mysql_affected_rows($this->connectionId); + } + + /** + * Returns the last record id of an inserted item + * Usage: $db->Insert_ID(); + * + * @access public + */ + + function Insert_ID() + { + return @mysql_insert_id($this->connectionId); + } + + /** + * Correctly quotes a string so that all strings are escape coded. + * An example is $db->qstr("Haven't a clue."); + * + * @param string the string to quote + * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc(). + * + * @return single-quoted string IE: 'Haven\'t a clue.' + */ + + function qstr($string, $magic_quotes=false) + { + if (!$magic_quotes) { + if (strnatcmp(PHP_VERSION, '4.3.0') >= 0) { + return "'" . mysql_real_escape_string($string, $this->connectionId) . "'"; + } + $string = str_replace("'", "\\'" , str_replace('\\', '\\\\', str_replace("\0", "\\\0", $string))); + return "'" . $string . "'"; + } + return "'" . str_replace('\\"', '"', $string) . "'"; + } + + function QMagic($string) + { + return $this->qstr($string, get_magic_quotes_gpc()); + } + + /** + * Returns concatenated string + * Usage: $db->Concat($str1,$str2); + * + * @return concatenated string + */ + function Concat() + { + $arr = func_get_args(); + $list = implode(', ', $arr); + + if (strlen($list) > 0) return "CONCAT($list)"; + else return ''; + } + + function IfNull( $field, $ifNull ) + { + return " IFNULL($field, $ifNull) "; + } + + /** + * Closes database connection + * Usage: $db->close(); + * + * @access public + */ + + function Close() + { + @mysql_close( $this->connectionId ); + $this->connectionId = false; + } + + /** + * Returns All Records in an array + * + * Usage: $db->GetAll($sql); + * @access public + */ + + function &GetAll($sql, $inputarr = false) + { + $data =& $this->GetArray($sql, $inputarr); + return $data; + } + + /** + * Returns All Records in an array + * + * Usage: $db->GetArray($sql); + * @access public + */ + + function &GetArray($sql, $inputarr = false) + { + $data = false; + $result =& $this->Execute($sql, $inputarr); + if ($result) + { + $data =& $result->GetArray(); + $result->Close(); + } + return $data; + } + + /** + * Executes SQL query and instantiates resultset methods + * + * @access private + * @return mixed Resultset methods + */ + + function &do_query( $sql, $offset, $nrows, $inputarr=false ) + { + global $ADODB_FETCH_MODE; + + $false = false; + + $limit = ''; + if ($offset >= 0 || $nrows >= 0) + { + $offset = ($offset >= 0) ? $offset . "," : ''; + $nrows = ($nrows >= 0) ? $nrows : '18446744073709551615'; + $limit = ' LIMIT ' . $offset . ' ' . $nrows; + } + + if ($inputarr && is_array($inputarr)) { + $sqlarr = explode('?', $sql); + if (!is_array(reset($inputarr))) $inputarr = array($inputarr); + foreach($inputarr as $arr) { + $sql = ''; $i = 0; + foreach($arr as $v) { + $sql .= $sqlarr[$i]; + switch(gettype($v)){ + case 'string': + $sql .= $this->qstr($v); + break; + case 'double': + $sql .= str_replace(',', '.', $v); + break; + case 'boolean': + $sql .= $v ? 1 : 0; + break; + default: + if ($v === null) + $sql .= 'NULL'; + else $sql .= $v; + } + $i += 1; + } + $sql .= $sqlarr[$i]; + if ($i+1 != sizeof($sqlarr)) + return $false; + $this->sql = $sql . $limit; + $time_start = array_sum(explode(' ', microtime())); + $this->query_count++; + $resultId = @mysql_query( $this->sql, $this->connectionId ); + $time_total = (array_sum(explode(' ', microtime())) - $time_start); + $this->query_time_total += $time_total; + if($this->debug_console) + { + $this->query_list[] = $this->sql; + $this->query_list_time[] = $time_total; + $this->query_list_errors[] = $this->ErrorMsg(); + } + if($this->debug) + { + $this->outp($sql . $limit); + } + if ($resultId === false) { // error handling if query fails + if ($fn = $this->raiseErrorFn) + $fn($this->dbtype, 'EXECUTE', $this->ErrorNo(), $this->ErrorMsg(), $this->sql, $inputarr, $this); + return $false; + } + } + } + else + { + $this->sql = $sql . $limit; + $this->sql = $sql . $limit; + $time_start = array_sum(explode(' ', microtime())); + $this->query_count++; + $resultId = @mysql_query( $this->sql, $this->connectionId ); + $time_total = (array_sum(explode(' ', microtime())) - $time_start); + $this->query_time_total += $time_total; + if($this->debug_console) + { + $this->query_list[] = $this->sql; + $this->query_list_time[] = $time_total; + $this->query_list_errors[] = $this->ErrorMsg(); + } + if($this->debug) + { + $this->outp($sql . $limit); + } + } + + if ($resultId === false) { // error handling if query fails + if ($fn = $this->raiseErrorFn) + $fn($this->dbtype, 'EXECUTE', $this->ErrorNo(), $this->ErrorMsg(), $this->sql, $inputarr, $this); + return $false; + } + + if ($resultId === true) { // return simplified recordset for inserts/updates/deletes with lower overhead + $recordset = new ADORecordSet_empty(); + return $recordset; + } + + $resultset_name = $this->last_module_name . "_ResultSet"; + $recordset = new $resultset_name( $resultId, $this->connectionId ); + + $recordset->_currentRow = 0; + + switch ($ADODB_FETCH_MODE) + { + case ADODB_FETCH_NUM: $recordset->fetchMode = MYSQL_NUM; break; + case ADODB_FETCH_ASSOC: $recordset->fetchMode = MYSQL_ASSOC; break; + default: + case ADODB_FETCH_DEFAULT: + case ADODB_FETCH_BOTH: $recordset->fetchMode = MYSQL_BOTH; break; + } + + $recordset->_numOfRows = @mysql_num_rows( $resultId ); + if( $recordset->_numOfRows == 0) + { + $recordset->EOF = true; + } + $recordset->_numOfFields = @mysql_num_fields( $resultId ); + $recordset->_fetch(); + + return $recordset; + } +} + +class mysql_driver_ResultSet +{ + var $connectionId; + var $fields; + var $resultId; + var $_currentRow = 0; + var $_numOfRows = -1; + var $_numOfFields = -1; + var $fetchMode; + var $EOF; + + /** + * mysqlResultSet Constructor + * + * @access private + * @param string $record + * @param string $resultId + */ + + function mysql_driver_ResultSet( $resultId, $connectionId ) + { + $this->fields = array(); + $this->connectionId = $connectionId; + $this->record = array(); + $this->resultId = $resultId; + $this->EOF = false; + } + + /** + * Frees resultset + * + * @access public + */ + + function Close() + { + @mysql_free_result( $this->resultId ); + $this->fields = array(); + $this->resultId = false; + } + + /** + * Returns field name from select query + * + * @access public + * @param string $field + * @return string Field name + */ + + function fields( $field ) + { + if(empty($field)) + { + return $this->fields; + } + else + { + return $this->fields[$field]; + } + } + + /** + * Returns numrows from select query + * + * @access public + * @return integer Numrows + */ + + function RecordCount() + { + return $this->_numOfRows; + } + + /** + * Returns num of fields from select query + * + * @access public + * @return integer numfields + */ + + function FieldCount() + { + return $this->_numOfFields; + } + + /** + * Returns next record + * + * @access public + */ + + function MoveNext() + { + if (@$this->fields = mysql_fetch_array($this->resultId,$this->fetchMode)) { + $this->_currentRow += 1; + return true; + } + if (!$this->EOF) { + $this->_currentRow += 1; + $this->EOF = true; + } + return false; + } + + /** + * Move to the first row in the recordset. Many databases do NOT support this. + * + * @return true or false + */ + + function MoveFirst() + { + if ($this->_currentRow == 0) return true; + return $this->Move(0); + } + + /** + * Returns the Last Record + * + * @access public + */ + + function MoveLast() + { + if ($this->EOF) return false; + return $this->Move($this->_numOfRows - 1); + } + + /** + * Random access to a specific row in the recordset. Some databases do not support + * access to previous rows in the databases (no scrolling backwards). + * + * @param rowNumber is the row to move to (0-based) + * + * @return true if there still rows available, or false if there are no more rows (EOF). + */ + + function Move($rowNumber = 0) + { + if ($rowNumber == $this->_currentRow) return true; + $this->EOF = false; + if ($this->_numOfRows > 0){ + if ($rowNumber >= $this->_numOfRows - 1){ + $rowNumber = $this->_numOfRows - 1; + } + } + + if ($this->_seek($rowNumber)) { + $this->_currentRow = $rowNumber; + if ($this->_fetch()) { + return true; + } + $this->fields = false; + } + $this->EOF = true; + return false; + } + + /** + * Perform Seek to specific row + * + * @access private + */ + + function _seek($row) + { + if ($this->_numOfRows == 0) return false; + return @mysql_data_seek($this->resultId,$row); + } + + /** + * Fills field array with first database element when query initially executed + * + * @access private + */ + + function _fetch() + { + $this->fields = @mysql_fetch_array($this->resultId,$this->fetchMode); + return is_array($this->fields); + } + + /** + * Check to see if last record reached + * + * @access public + */ + + function EOF() + { + if( $this->_currentRow < $this->_numOfRows) + { + return false; + } + else + { + $this->EOF = true; + return true; + } + } + + /** + * Returns All Records in an array + * + * @access public + * @param [nRows] is the number of rows to return. -1 means every row. + */ + + function &GetArray($nRows = -1) + { + $results = array(); + $cnt = 0; + while (!$this->EOF && $nRows != $cnt) { + $results[] = $this->fields; + $this->MoveNext(); + $cnt++; + } + return $results; + } + + function &GetRows($nRows = -1) + { + $arr =& $this->GetArray($nRows); + return $arr; + } + + function &GetAll($nRows = -1) + { + $arr =& $this->GetArray($nRows); + return $arr; + } + + /** + * Fetch field information for a table. + * + * @return object containing the name, type and max_length + */ + function FetchField($fieldOffset = -1) + { + if ($fieldOffset != -1) { + $fieldObject = @mysql_fetch_field($this->resultId, $fieldOffset); + $fieldObject->max_length = @mysql_field_len($this->resultId,$fieldOffset); + } + else + { + $fieldObject = @mysql_fetch_field($this->resultId); + $fieldObject->max_length = @mysql_field_len($this->resultId); + } + return $fieldObject; + } + +} + +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/mysql/mysql_extend_module.inc b/lib/adodb/adodbSQL_drivers/mysql/mysql_extend_module.inc new file mode 100644 index 0000000..a7d0b8f --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/mysql/mysql_extend_module.inc @@ -0,0 +1,150 @@ +Execute($sql, $inputarr); + if ($result) { + $data =& $result->GetAssoc($force_array, $first2cols); + $result->Close(); + } + return $data; + } + + /** + * Generates a sequence id and stores it in $this->genID; + * GenID is only available if $this->hasGenID = true; + * + * @param seqname name of sequence to use + * @param startID if sequence does not exist, start at this ID + * @return 0 if not supported, otherwise a sequence id + */ + + var $genID = 0; + var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);"; + var $_genSeqSQL = "create table %s (id int not null)"; + var $_genSeq2SQL = "insert into %s values (%s)"; + var $_dropSeqSQL = "drop table %s"; + + function GenID($seqname='adodbseq', $startID=1) + { + $getnext = sprintf($this->_genIDSQL, $seqname); + $holdtransOK = $this->transaction_status; + $result = @$this->Execute($getnext); + if (!$result) { + if ($holdtransOK) + $this->transaction_status = true; +// $u = strtoupper($seqname); + $this->Execute(sprintf($this->_genSeqSQL, $seqname)); + $this->Execute(sprintf($this->_genSeq2SQL, $seqname, $startID-1)); + $result = $this->Execute($getnext); + } + $this->genID = mysql_insert_id($this->connectionId); + + if ($result) + $result->Close(); + + return $this->genID; + } + + function CreateSequence($seqname='adodbseq',$startID=1) + { + $u = strtoupper($seqname); + + $ok = $this->Execute(sprintf($this->_genSeqSQL, $seqname)); + if (!$ok) + return false; + return $this->Execute(sprintf($this->_genSeq2SQL, $seqname, $startID-1)); + } + + function DropSequence($seqname='adodbseq') + { + return $this->Execute(sprintf($this->_dropSeqSQL, $seqname)); + } + +} + +eval('class mysql_extend_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class mysql_extend_ResultSet extends mysql_extend_resultset_EXTENDER +{ + function &GetAssoc($force_array = false, $first2cols = false) + { + $results = false; + + if ($this->_numOfFields > 1) { + $numIndex = isset($this->fields[0]); + $results = array(); + if (!$first2cols && ($this->_numOfFields > 2 || $force_array)) { + if ($numIndex) { + while (!$this->EOF) { + $results[trim($this->fields[0])] = array_slice($this->fields, 1); + $this->MoveNext(); + } + } else { + while (!$this->EOF) { + $results[trim(reset($this->fields))] = array_slice($this->fields, 1); + $this->MoveNext(); + } + } + } else { + if ($numIndex) { + while (!$this->EOF) { + $results[trim(($this->fields[0]))] = $this->fields[1]; + $this->MoveNext(); + } + } else { + while (!$this->EOF) { + $v1 = trim(reset($this->fields)); + $v2 = ''.next($this->fields); + $results[$v1] = $v2; + $this->MoveNext(); + } + } + } + } + return $results; + } + + function PO_RecordCount($table="", $condition="") + { + $lnumrows = $this->_numOfRows; + if($lnumrows == -1 && $this->connectionId) + { + if($table) + { + if ($condition) + $condition = " WHERE " . $condition; + $resultrows = &$this->connectionId->Execute("SELECT COUNT(*) FROM $table $condition"); + if ($resultrows) + $lnumrows = reset($resultrows->fields); + } + } + return $lnumrows; + } + + function CurrentRow() + { + return $this->_currentRow; + } + + function AbsolutePosition() + { + return $this->_currentRow; + } + + function NextRecordSet() + { + return false; + } + +} +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/mysql/mysql_meta_module.inc b/lib/adodb/adodbSQL_drivers/mysql/mysql_meta_module.inc new file mode 100644 index 0000000..9a6ea88 --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/mysql/mysql_meta_module.inc @@ -0,0 +1,623 @@ +ErrorNo(); + + return adodb_error($this->dataProvider,$this->databaseType,$err); + } + + function MetaErrorMsg($errno) + { + include_once(ADODB_DIR."/adodb-error.inc.php"); + return adodb_errormsg($errno); + } + + /** + * @returns an array with the primary key columns in it. + */ + function MetaPrimaryKeys($table, $owner=false) + { + // owner not used in base class - see oci8 + $p = array(); + $objs =& $this->MetaColumns($table); + if ($objs) { + foreach($objs as $v) { + if (!empty($v->primary_key)) + $p[] = $v->name; + } + } + if (sizeof($p)) + return $p; + if (function_exists('ADODB_VIEW_PRIMARYKEYS')) + return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner); + return false; + } + + /** + * @returns assoc array where keys are tables, and values are foreign keys + */ + function MetaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $associative = FALSE ) + { + if ( !empty($owner) ) { + $table = "$owner.$table"; + } + $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE %s', $table)); + if ($associative) $create_sql = $a_create_table["Create Table"]; + else $create_sql = $a_create_table[1]; + + $matches = array(); + + if (!preg_match_all("/FOREIGN KEY \(`(.*?)`\) REFERENCES `(.*?)` \(`(.*?)`\)/", $create_sql, $matches)) return false; + $foreign_keys = array(); + $num_keys = count($matches[0]); + for ( $i = 0; $i < $num_keys; $i ++ ) { + $my_field = explode('`, `', $matches[1][$i]); + $ref_table = $matches[2][$i]; + $ref_field = explode('`, `', $matches[3][$i]); + + if ( $upper ) { + $ref_table = strtoupper($ref_table); + } + + $foreign_keys[$ref_table] = array(); + $num_fields = count($my_field); + for ( $j = 0; $j < $num_fields; $j ++ ) { + if ( $associative ) { + $foreign_keys[$ref_table][$ref_field[$j]] = $my_field[$j]; + } else { + $foreign_keys[$ref_table][] = "{$my_field[$j]}={$ref_field[$j]}"; + } + } + } + + return $foreign_keys; + } + + // not the fastest implementation - quick and dirty - jlim + // for best performance, use the actual $rs->MetaType(). + function MetaType($t,$len=-1,$fieldobj=false) + { + if (empty($this->_metars)) { + $rsclass = $this->last_module_name . "_ResultSet"; + $this->_metars =& new $rsclass(false,$this->fetchMode); + } + + return $this->_metars->MetaType($t,$len,$fieldobj); + } + + /** + * return the databases that the driver can connect to. + * Some databases will return an empty array. + * + * @return an array of database names. + */ + function &MetaDatabases() + { + $qid = mysql_list_dbs($this->connectionId); + $arr = array(); + $i = 0; + $max = mysql_num_rows($qid); + while ($i < $max) { + $db = mysql_tablename($qid,$i); + if ($db != 'mysql') $arr[] = $db; + $i += 1; + } + return $arr; + } + + /** + * @param ttype can either be 'VIEW' or 'TABLE' or false. + * If false, both views and tables are returned. + * "VIEW" returns only views + * "TABLE" returns only tables + * @param showSchema returns the schema/user with the table name, eg. USER.TABLE + * @param mask is the input mask - only supported by oci8 and postgresql + * + * @return array of tables for current database. + */ + function &MetaTables($ttype=false,$showSchema=false,$mask=false) + { + $save = $this->metaTablesSQL; + if ($showSchema && is_string($showSchema)) { + $this->metaTablesSQL .= " from $showSchema"; + } + + if ($mask) { + $mask = $this->qstr($mask); + $this->metaTablesSQL .= " like $mask"; + } + $ret =& $this->_MetaTables($ttype,$showSchema); + + $this->metaTablesSQL = $save; + return $ret; + } + + function &_MetaTables($ttype=false,$showSchema=false,$mask=false) + { + global $ADODB_FETCH_MODE; + + $false = false; + if ($mask) { + return $false; + } + if ($this->metaTablesSQL) { + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + + $rs = $this->Execute($this->metaTablesSQL); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if ($rs === false) return $false; + $arr =& $rs->GetArray(); + $arr2 = array(); + + if ($hast = ($ttype && isset($arr[0][1]))) { + $showt = strncmp($ttype,'T',1); + } + + for ($i=0; $i < sizeof($arr); $i++) { + if ($hast) { + if ($showt == 0) { + if (strncmp($arr[$i][1],'T',1) == 0) $arr2[] = trim($arr[$i][0]); + } else { + if (strncmp($arr[$i][1],'V',1) == 0) $arr2[] = trim($arr[$i][0]); + } + } else + $arr2[] = trim($arr[$i][0]); + } + $rs->Close(); + return $arr2; + } + return $false; + } + + function _findschema(&$table,&$schema) + { + if (!$schema && ($at = strpos($table,'.')) !== false) { + $schema = substr($table,0,$at); + $table = substr($table,$at+1); + } + } + + /** + * List columns in a database as an array of ADOFieldObjects. + * See top of file for definition of object. + * + * @param $table table name to query + * @param $normalize makes table name case-insensitive (required by some databases) + * @schema is optional database schema to use - not supported by all databases. + * + * @return array of ADOFieldObjects for current table. + */ + function MetaColumns($table) + { + $this->_findschema($table,$schema); + if ($schema) { + $dbName = $this->database; + $this->connection->SelectDB($schema); + } + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table)); + + if ($schema) { + $this->SelectDB($dbName); + } + + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + if (!is_object($rs)) { + $false = false; + return $false; + } + + $retarr = array(); + while (!$rs->EOF){ + $fld = new ADOFieldObject(); + $fld->name = $rs->fields[0]; + $type = $rs->fields[1]; + + // split type into type(length): + $fld->scale = null; + if (preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) { + $fld->type = $query_array[1]; + $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; + $fld->scale = is_numeric($query_array[3]) ? $query_array[3] : -1; + } elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) { + $fld->type = $query_array[1]; + $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; + } elseif (preg_match("/^(enum)\((.*)\)$/i", $type, $query_array)) { + $fld->type = $query_array[1]; + $arr = explode(",",$query_array[2]); + $fld->enums = $arr; + $zlen = max(array_map("strlen",$arr)) - 2; // PHP >= 4.0.6 + $fld->max_length = ($zlen > 0) ? $zlen : 1; + } else { + $fld->type = $type; + $fld->max_length = -1; + } + $fld->not_null = ($rs->fields[2] != 'YES'); + $fld->primary_key = ($rs->fields[3] == 'PRI'); + $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false); + $fld->binary = (strpos($type,'blob') !== false); + $fld->unsigned = (strpos($type,'unsigned') !== false); + + if (!$fld->binary) { + $d = $rs->fields[4]; + if ($d != '' && $d != 'NULL') { + $fld->has_default = true; + $fld->default_value = $d; + } else { + $fld->has_default = false; + } + } + + if ($save == ADODB_FETCH_NUM) { + $retarr[] = $fld; + } else { + $retarr[strtoupper($fld->name)] = $fld; + } + $rs->MoveNext(); + } + + $rs->Close(); + return $retarr; + } + + /** + * List indexes on a table as an array. + * @param table table name to query + * @param primary true to only show primary keys. Not actually used for most databases + * + * @return array of indexes on current table. Each element represents an index, and is itself an associative array. + + Array ( + [name_of_index] => Array + ( + [unique] => true or false + [columns] => Array + ( + [0] => firstname + [1] => lastname + ) + ) + */ + function MetaIndexes ($table, $primary = FALSE, $owner=false) + { + // save old fetch mode + global $ADODB_FETCH_MODE; + + $false = false; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== FALSE) { + $savem = $this->SetFetchMode(FALSE); + } + + // get index details + $rs =& $this->Execute(sprintf('SHOW INDEX FROM %s',$table)); + + // restore fetchmode + if (isset($savem)) { + $this->SetFetchMode($savem); + } + $ADODB_FETCH_MODE = $save; + + if (!is_object($rs)) { + return $false; + } + + $indexes = array (); + + // parse index data into array + while (!$rs->EOF) + { + if ($primary == FALSE AND $rs->fields[2] == 'PRIMARY') { + $rs->MoveNext(); + continue; + } + + if (!isset($indexes[$rs->fields[2]])) { + $indexes[$rs->fields[2]] = array( + 'unique' => ($rs->fields[1] == 0), + 'columns' => array() + ); + } + + $indexes[$rs->fields[2]]['columns'][$rs->fields[3] - 1] = $rs->fields[4]; + + $rs->MoveNext(); + } + + // sort columns by order in the index + foreach ( array_keys ($indexes) as $index ) + { + ksort ($indexes[$index]['columns']); + } + + return $indexes; + } + + /** + * List columns names in a table as an array. + * @param table table name to query + * + * @return array of column names for current table. + */ + function &MetaColumnNames($table, $numIndexes=false) + { + $objarr =& $this->MetaColumns($table); + if (!is_array($objarr)) { + $false = false; + return $false; + } + $arr = array(); + if ($numIndexes) { + $i = 0; + foreach($objarr as $v) $arr[$i++] = $v->name; + } else + foreach($objarr as $v) $arr[strtoupper($v->name)] = $v->name; + + return $arr; + } + + function MetaTransaction($mode,$db) + { + $mode = strtoupper($mode); + $mode = str_replace('ISOLATION LEVEL ','',$mode); + + switch($mode) { + + case 'READ UNCOMMITTED': + switch($db) { + case 'oci8': + case 'oracle': + return 'ISOLATION LEVEL READ COMMITTED'; + default: + return 'ISOLATION LEVEL READ UNCOMMITTED'; + } + break; + + case 'READ COMMITTED': + return 'ISOLATION LEVEL READ COMMITTED'; + break; + + case 'REPEATABLE READ': + switch($db) { + case 'oci8': + case 'oracle': + return 'ISOLATION LEVEL SERIALIZABLE'; + default: + return 'ISOLATION LEVEL REPEATABLE READ'; + } + break; + + case 'SERIALIZABLE': + return 'ISOLATION LEVEL SERIALIZABLE'; + break; + + default: + return $mode; + } + } + +} + +eval('class mysql_meta_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class mysql_meta_ResultSet extends mysql_meta_resultset_EXTENDER +{ + /** + * Get the metatype of the column. This is used for formatting. This is because + * many databases use different names for the same type, so we transform the original + * type to our standardised version which uses 1 character codes: + * + * @param t is the type passed in. Normally is ADOFieldObject->type. + * @param len is the maximum length of that field. This is because we treat character + * fields bigger than a certain size as a 'B' (blob). + * @param fieldobj is the field object returned by the database driver. Can hold + * additional info (eg. primary_key for mysql). + * + * @return the general type of the data: + * C for character < 250 chars + * X for teXt (>= 250 chars) + * B for Binary + * N for numeric or floating point + * D for date + * T for timestamp + * L for logical/Boolean + * I for integer + * R for autoincrement counter/integer + * + * + */ + function MetaType($t,$len=-1,$fieldobj=false) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + + $len = -1; // mysql max_length is not accurate + switch (strtoupper($t)) { + case 'STRING': + case 'CHAR': + case 'VARCHAR': + case 'TINYBLOB': + case 'TINYTEXT': + case 'ENUM': + case 'SET': + if ($len <= $this->blobSize) return 'C'; + + case 'TEXT': + case 'LONGTEXT': + case 'MEDIUMTEXT': + return 'X'; + + // php_mysql extension always returns 'blob' even if 'text' + // so we have to check whether binary... + case 'IMAGE': + case 'LONGBLOB': + case 'BLOB': + case 'MEDIUMBLOB': + return !empty($fieldobj->binary) ? 'B' : 'X'; + + case 'YEAR': + case 'DATE': return 'D'; + + case 'TIME': + case 'DATETIME': + case 'TIMESTAMP': return 'T'; + + case 'INT': + case 'INTEGER': + case 'BIGINT': + case 'TINYINT': + case 'MEDIUMINT': + case 'SMALLINT': + + if (!empty($fieldobj->primary_key)) return 'R'; + else return 'I'; + + default: + static $typeMap = array( + 'VARCHAR' => 'C', + 'VARCHAR2' => 'C', + 'CHAR' => 'C', + 'C' => 'C', + 'STRING' => 'C', + 'NCHAR' => 'C', + 'NVARCHAR' => 'C', + 'VARYING' => 'C', + 'BPCHAR' => 'C', + 'CHARACTER' => 'C', + 'INTERVAL' => 'C', # Postgres + 'MACADDR' => 'C', # postgres + ## + 'LONGCHAR' => 'X', + 'TEXT' => 'X', + 'NTEXT' => 'X', + 'M' => 'X', + 'X' => 'X', + 'CLOB' => 'X', + 'NCLOB' => 'X', + 'LVARCHAR' => 'X', + ## + 'BLOB' => 'B', + 'IMAGE' => 'B', + 'BINARY' => 'B', + 'VARBINARY' => 'B', + 'LONGBINARY' => 'B', + 'B' => 'B', + ## + 'YEAR' => 'D', // mysql + 'DATE' => 'D', + 'D' => 'D', + ## + 'UNIQUEIDENTIFIER' => 'C', # MS SQL Server + ## + 'TIME' => 'T', + 'TIMESTAMP' => 'T', + 'DATETIME' => 'T', + 'TIMESTAMPTZ' => 'T', + 'T' => 'T', + 'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql + ## + 'BOOL' => 'L', + 'BOOLEAN' => 'L', + 'BIT' => 'L', + 'L' => 'L', + ## + 'COUNTER' => 'R', + 'R' => 'R', + 'SERIAL' => 'R', // ifx + 'INT IDENTITY' => 'R', + ## + 'INT' => 'I', + 'INT2' => 'I', + 'INT4' => 'I', + 'INT8' => 'I', + 'INTEGER' => 'I', + 'INTEGER UNSIGNED' => 'I', + 'SHORT' => 'I', + 'TINYINT' => 'I', + 'SMALLINT' => 'I', + 'I' => 'I', + ## + 'LONG' => 'N', // interbase is numeric, oci8 is blob + 'BIGINT' => 'N', // this is bigger than PHP 32-bit integers + 'DECIMAL' => 'N', + 'DEC' => 'N', + 'REAL' => 'N', + 'DOUBLE' => 'N', + 'DOUBLE PRECISION' => 'N', + 'SMALLFLOAT' => 'N', + 'FLOAT' => 'N', + 'NUMBER' => 'N', + 'NUM' => 'N', + 'NUMERIC' => 'N', + 'MONEY' => 'N', + + ## informix 9.2 + 'SQLINT' => 'I', + 'SQLSERIAL' => 'I', + 'SQLSMINT' => 'I', + 'SQLSMFLOAT' => 'N', + 'SQLFLOAT' => 'N', + 'SQLMONEY' => 'N', + 'SQLDECIMAL' => 'N', + 'SQLDATE' => 'D', + 'SQLVCHAR' => 'C', + 'SQLCHAR' => 'C', + 'SQLDTIME' => 'T', + 'SQLINTERVAL' => 'N', + 'SQLBYTES' => 'B', + 'SQLTEXT' => 'X', + ## informix 10 + "SQLINT8" => 'I8', + "SQLSERIAL8" => 'I8', + "SQLNCHAR" => 'C', + "SQLNVCHAR" => 'C', + "SQLLVARCHAR" => 'X', + "SQLBOOL" => 'L' + ); + + $tmap = false; + $t = strtoupper($t); + $tmap = (isset($typeMap[$t])) ? $typeMap[$t] : 'N'; + return $tmap; + } + } + +} + +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/mysql/mysql_perfmon_module.inc b/lib/adodb/adodbSQL_drivers/mysql/mysql_perfmon_module.inc new file mode 100644 index 0000000..827a6b2 --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/mysql/mysql_perfmon_module.inc @@ -0,0 +1,426 @@ + array('RATIO', + '=GetKeyHitRatio', + '=WarnCacheRatio'), + 'InnoDB cache hit ratio' => array('RATIO', + '=GetInnoDBHitRatio', + '=WarnCacheRatio'), + 'data cache hit ratio' => array('HIDE', # only if called + '=FindDBHitRatio', + '=WarnCacheRatio'), + 'sql cache hit ratio' => array('RATIO', + '=GetQHitRatio', + ''), + 'IO', + 'data reads' => array('IO', + '=GetReads', + 'Number of selects (Key_reads is not accurate)'), + 'data writes' => array('IO', + '=GetWrites', + 'Number of inserts/updates/deletes * coef (Key_writes is not accurate)'), + + 'Data Cache', + 'MyISAM data cache size' => array('DATAC', + array("show variables", 'key_buffer_size'), + '' ), + 'BDB data cache size' => array('DATAC', + array("show variables", 'bdb_cache_size'), + '' ), + 'InnoDB data cache size' => array('DATAC', + array("show variables", 'innodb_buffer_pool_size'), + '' ), + 'Memory Usage', + 'read buffer size' => array('CACHE', + array("show variables", 'read_buffer_size'), + '(per session)'), + 'sort buffer size' => array('CACHE', + array("show variables", 'sort_buffer_size'), + 'Size of sort buffer (per session)' ), + 'table cache' => array('CACHE', + array("show variables", 'table_cache'), + 'Number of tables to keep open'), + 'Connections', + 'current connections' => array('SESS', + array('show status','Threads_connected'), + ''), + 'max connections' => array( 'SESS', + array("show variables",'max_connections'), + ''), + + false + ); + + /** + Get server version info... + + @returns An array with 2 elements: $arr['description'] is the description string, + and $arr['version'] is the version (also a string). + */ + function ServerInfo() + { + $arr = array(); + $result = $this->do_query('select version()', -1, -1, false); + if (!$result->EOF) $data = $result->fields; + else $data = array(); + $arr['version'] = $arr['description'] = $data[0]; + //****// Where does $arr come from in ADOdb - doesn't appear global, maybe null? A possible bug? + return $arr; + } + + /* + Explain Plan for $sql. + If only a snippet of the $sql is passed in, then $partial will hold the crc32 of the + actual sql. + */ + function Explain($sql,$partial=false) + { + $perf_table = perfmon_parent_ADOConnection::table(); // this was missing in the original ADOdb perf class - bug? + + if (strtoupper(substr(trim($sql),0,6)) !== 'SELECT') return '

Unable to EXPLAIN a non-select statement

'; + $save = $this->LogSQL(false); + if ($partial) { + $sqlq = $this->qstr($sql.'%'); + $arr = $this->GetArray("select distinct sql1 from $perf_table where sql1 like $sqlq"); + if ($arr) + { + foreach($arr as $row) + { + $sql = reset($row); + if (crc32($sql) == $partial) break; + } + } + } + $sql = str_replace('?',"''",$sql); + + if ($partial) + { + $sqlq = $this->qstr($sql.'%'); + $sql = $this->GetOne("select sql1 from $perf_table where sql1 like $sqlq"); + } + + $s = '

Explain: '.htmlentities($sql, ENT_QUOTES, 'UTF-8').'

'; + $rs = $this->Execute('EXPLAIN '.$sql); + $s .= rs2html($rs,false,false,false,false); + $this->LogSQL($save); + $s .= $this->Tracer($sql); + return $s; + } + + function Tables() + { + if (!$this->tablesSQL) return false; + + $rs = $this->Execute($this->tablesSQL); + if (!$rs) return false; + + $html = rs2html($rs,false,false,false,false); + return $html; + } + + + function CreateLogTable() + { + if (!$this->createTableSQL) return false; + + $savelog = $this->LogSQL(false); + $ok = $this->Execute($this->createTableSQL); + $this->LogSQL($savelog); + return ($ok) ? true : false; + } + + + function GetReads() + { + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + $rs = $this->Execute('show status'); + + $ADODB_FETCH_MODE = $save; + + if (!$rs) return 0; + $val = 0; + while (!$rs->EOF) + { + switch($rs->fields[0]) + { + case 'Com_select': + $val = $rs->fields[1]; + $rs->Close(); + return $val; + } + $rs->MoveNext(); + } + + $rs->Close(); + return $val; + } + + function GetWrites() + { + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + $rs = $this->Execute('show status'); + + $ADODB_FETCH_MODE = $save; + + if (!$rs) return 0; + $val = 0.0; + while (!$rs->EOF) + { + switch($rs->fields[0]) + { + case 'Com_insert': + $val += $rs->fields[1]; + break; + case 'Com_delete': + $val += $rs->fields[1]; + break; + case 'Com_update': + $val += $rs->fields[1]/2; + $rs->Close(); + return $val; + } + $rs->MoveNext(); + } + + $rs->Close(); + return $val; + } + + function FindDBHitRatio() + { + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + $rs = $this->Execute('show table status'); + + $ADODB_FETCH_MODE = $save; + + if (!$rs) return ''; + $type = strtoupper($rs->fields[1]); + $rs->Close(); + switch($type) + { + case 'MYISAM': + case 'ISAM': + return $this->DBParameter('MyISAM cache hit ratio').' (MyISAM)'; + case 'INNODB': + return $this->DBParameter('InnoDB cache hit ratio').' (InnoDB)'; + default: + return $type.' not supported'; + } + } + + function GetQHitRatio() + { + //Total number of queries = Qcache_inserts + Qcache_hits + Qcache_not_cached + $hits = $this->_DBParameter(array("show status","Qcache_hits")); + $total = $this->_DBParameter(array("show status","Qcache_inserts")); + $total += $this->_DBParameter(array("show status","Qcache_not_cached")); + + $total += $hits; + if ($total) return round(($hits*100)/$total,2); + return 0; + } + + /* + Use session variable to store Hit percentage, because MySQL + does not remember last value of SHOW INNODB STATUS hit ratio + + # 1st query to SHOW INNODB STATUS + 0.00 reads/s, 0.00 creates/s, 0.00 writes/s + Buffer pool hit rate 1000 / 1000 + + # 2nd query to SHOW INNODB STATUS + 0.00 reads/s, 0.00 creates/s, 0.00 writes/s + No buffer pool activity since the last printout + */ + function GetInnoDBHitRatio() + { + global $ADODB_FETCH_MODE; + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + $rs = $this->Execute('show innodb status'); +; + $ADODB_FETCH_MODE = $save; + + if (!$rs || $rs->EOF) return 0; + $stat = $rs->fields[0]; + $rs->Close(); + $at = strpos($stat,'Buffer pool hit rate'); + $stat = substr($stat,$at,200); + if (preg_match('!Buffer pool hit rate\s*([0-9]*) / ([0-9]*)!',$stat,$arr)) + { + $val = 100*$arr[1]/$arr[2]; + $_SESSION['INNODB_HIT_PCT'] = $val; + return round($val,2); + } + else + { + if (isset($_SESSION['INNODB_HIT_PCT'])) return $_SESSION['INNODB_HIT_PCT']; + return 0; + } + return 0; + } + + function GetKeyHitRatio() + { + $hits = $this->_DBParameter(array("show status","Key_read_requests")); + $reqs = $this->_DBParameter(array("show status","Key_reads")); + if ($reqs == 0) return 0; + + return round(($hits/($reqs+$hits))*100,2); + } + + // start hack + var $optimizeTableLow = 'CHECK TABLE %s FAST QUICK'; + var $optimizeTableHigh = 'OPTIMIZE TABLE %s'; + + /** + * @see adodb_perf#optimizeTable + */ + function optimizeTable( $table, $mode = ADODB_OPT_LOW) + { + if ( !is_string( $table)) return false; + + $sql = ''; + switch( $mode) + { + case ADODB_OPT_LOW: + $sql = $this->optimizeTableLow; + break; + case ADODB_OPT_HIGH: + $sql = $this->optimizeTableHigh; + break; + default: + { + // May dont use __FUNCTION__ constant for BC (__FUNCTION__ Added in PHP 4.3.0) + trigger_error(sprintf( "

%s: '%s' using of undefined mode '%s'

", __CLASS__, __FUNCTION__, $mode), E_USER_ERROR); + return false; + } + } + $sql = sprintf( $sql, $table); + + return $this->Execute( $sql) !== false; + } + +} + + + +eval('class mysql_perfmon_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class mysql_perfmon_ResultSet extends mysql_perfmon_resultset_EXTENDER +{ + + function MetaType($t,$len=-1,$fieldobj=false) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + + $len = -1; // mysql max_length is not accurate + switch (strtoupper($t)) { + case 'STRING': + case 'CHAR': + case 'VARCHAR': + case 'TINYBLOB': + case 'TINYTEXT': + case 'ENUM': + case 'SET': + if ($len <= $this->blobSize) return 'C'; + + case 'TEXT': + case 'LONGTEXT': + case 'MEDIUMTEXT': + return 'X'; + + // php_mysql extension always returns 'blob' even if 'text' + // so we have to check whether binary... + case 'IMAGE': + case 'LONGBLOB': + case 'BLOB': + case 'MEDIUMBLOB': + return !empty($fieldobj->binary) ? 'B' : 'X'; + + case 'YEAR': + case 'DATE': return 'D'; + + case 'TIME': + case 'DATETIME': + case 'TIMESTAMP': return 'T'; + + case 'INT': + case 'INTEGER': + case 'BIGINT': + case 'TINYINT': + case 'MEDIUMINT': + case 'SMALLINT': + + if (!empty($fieldobj->primary_key)) return 'R'; + else return 'I'; + + default: return 'N'; + } + } + +} + +?> diff --git a/lib/adodb/adodbSQL_drivers/mysql/mysql_transaction_module.inc b/lib/adodb/adodbSQL_drivers/mysql/mysql_transaction_module.inc new file mode 100644 index 0000000..3bb5a2a --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/mysql/mysql_transaction_module.inc @@ -0,0 +1,113 @@ +transOff > 0) { + $this->transOff += 1; + return; + } + + $this->transaction_status = true; + + if ($this->debug && $this->transCnt > 0) + ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans"); + + $this->BeginTrans(); + $this->transOff = 1; + } + + function BeginTrans() + { + return false; + } + + function CompleteTrans($autoComplete = true) + { + if ($this->transOff > 1) { + $this->transOff -= 1; + return true; + } + + $this->transOff = 0; + if ($this->transaction_status && $autoComplete) { + if (!$this->CommitTrans()) { + $this->transaction_status = false; + if ($this->debug) + ADOConnection::outp("Smart Commit failed"); + } else + if ($this->debug) + ADOConnection::outp("Smart Commit occurred"); + } else { + $this->transaction_status = false; + $this->RollbackTrans(); + if ($this->debug) + ADOCOnnection::outp("Smart Rollback occurred"); + } + + return $this->transaction_status; + } + + function CommitTrans($ok=true) + { + return true; + } + + function RollbackTrans() + { + return false; + } + + function FailTrans() + { + if ($this->debug) + if ($this->transOff == 0) { + ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans"); + } else { + ADOConnection::outp("FailTrans was called"); + } + $this->transaction_status = false; + } + + function HasFailedTrans() + { + if ($this->transOff > 0) + return $this->transaction_status == false; + + return false; + } + + function RowLock($table,$where) + { + return false; + } + + function CommitLock($table) + { + return $this->CommitTrans(); + } + + function RollbackLock($table) + { + return $this->RollbackTrans(); + } +} + +eval('class mysql_transaction_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class mysql_transaction_ResultSet extends mysql_transaction_resultset_EXTENDER +{ +} +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/mysqli/mysqli_datadict.inc b/lib/adodb/adodbSQL_drivers/mysqli/mysqli_datadict.inc new file mode 100644 index 0000000..5db473f --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/mysqli/mysqli_datadict.inc @@ -0,0 +1,112 @@ +alterTableAddIndex) $sql[] = "ALTER TABLE $tabname DROP INDEX $idxname"; + else $sql[] = sprintf($this->dropIndex, $idxname, $tabname); + + if ( isset($idxoptions['DROP']) ) + return $sql; + } + + if ( empty ($flds) ) { + return $sql; + } + + if (isset($idxoptions['FULLTEXT'])) { + $unique = ' FULLTEXT'; + } elseif (isset($idxoptions['UNIQUE'])) { + $unique = ' UNIQUE'; + } else { + $unique = ''; + } + + if ( is_array($flds) ) $flds = implode(', ',$flds); + + if ($this->alterTableAddIndex) $s = "ALTER TABLE $tabname ADD $unique INDEX $idxname "; + else $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname; + + $s .= ' (' . $flds . ')'; + + if ( isset($idxoptions[$this->upperName]) ) + $s .= $idxoptions[$this->upperName]; + + $sql[] = $s; + + return $sql; + } + +} + +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/mysqli/mysqli_date_module.inc b/lib/adodb/adodbSQL_drivers/mysqli/mysqli_date_module.inc new file mode 100644 index 0000000..17a4668 --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/mysqli/mysqli_date_module.inc @@ -0,0 +1,321 @@ +_Execute("select $this->sysTimeStamp"); + if ($rs && !$rs->EOF) + return $this->UnixTimeStamp(reset($rs->fields)); + else return false; + } + + function OffsetDate($dayFraction, $date=false) + { + if (!$date) + $date = $this->sysDate; + + $fraction = $dayFraction * 24 * 3600; + return "from_unixtime(unix_timestamp($date)+$fraction)"; + } + + function SetDateLocale($locale = 'En') + { + $this->locale = $locale; + switch (strtoupper($locale)) + { + case 'EN': + $this->fmtDate="'Y-m-d'"; + $this->fmtTimeStamp = "'Y-m-d H:i:s'"; + break; + + case 'US': + $this->fmtDate = "'m-d-Y'"; + $this->fmtTimeStamp = "'m-d-Y H:i:s'"; + break; + + case 'NL': + case 'FR': + case 'RO': + case 'IT': + $this->fmtDate="'d-m-Y'"; + $this->fmtTimeStamp = "'d-m-Y H:i:s'"; + break; + + case 'GE': + $this->fmtDate="'d.m.Y'"; + $this->fmtTimeStamp = "'d.m.Y H:i:s'"; + break; + + default: + $this->fmtDate="'Y-m-d'"; + $this->fmtTimeStamp = "'Y-m-d H:i:s'"; + break; + } + } + + function DBDate($date) + { + if (empty($date) && $date !== 0) + return 'null'; + + if (is_string($date) && !is_numeric($date)) { + if ($date === 'null' || strncmp($date, "'", 1) === 0) + return $date; + + if ($this->isoDates) + return "'$date'"; + + $date = $this->UnixDate($date); + } + return adodb_date($this->fmtDate, $date); + } + + function DBTimeStamp($timestamp) + { + if (empty($timestamp) && $timestamp !== 0) + return 'null'; + + # strlen(14) allows YYYYMMDDHHMMSS format + if (!is_string($timestamp) || (is_numeric($timestamp) && strlen($timestamp)<14)) + return adodb_date($this->fmtTimeStamp, $timestamp); + + if ($timestamp === 'null') + return $timestamp; + + if ($this->isoDates && strlen($timestamp) !== 14) + return "'$timestamp'"; + + return adodb_date($this->fmtTimeStamp, $this->UnixTimeStamp($timestamp)); + } + + function UnixDate($v) + { + if (is_object($v)) { + // odbtp support + //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 ) + return adodb_mktime($v->hour, $v->minute, $v->second, $v->month, $v->day, $v->year); + } + if (is_numeric($v) && strlen($v) !== 8) + return $v; + + if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", ($v), $rr)) + return false; + + if ($rr[1] <= TIMESTAMP_FIRST_YEAR) + return 0; + + // h-m-s-MM-DD-YY + return adodb_mktime(0, 0, 0, $rr[2], $rr[3], $rr[1]); + } + + + function UnixTimeStamp($v) + { + if (is_object($v)) { + // odbtp support + //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 ) + return adodb_mktime($v->hour, $v->minute, $v->second, $v->month, $v->day, $v->year); + } + + if (!preg_match("|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ ,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", ($v), $rr)) + return false; + + if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) + return 0; + + // h-m-s-MM-DD-YY + if (!isset($rr[5])) + return adodb_mktime(0, 0, 0, $rr[2], $rr[3], $rr[1]); + + return adodb_mktime($rr[5], $rr[6], $rr[7], $rr[2], $rr[3], $rr[1]); + } + + function UserDate($v, $fmt='Y-m-d', $gmt=false) + { + $tt = $this->UnixDate($v); + + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + else if ($tt == 0) + return $this->emptyDate; + else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR + } + + return ($gmt) ? adodb_gmdate($fmt, $tt) : adodb_date($fmt, $tt); + } + + function UserTimeStamp($v, $fmt='Y-m-d H:i:s', $gmt=false) + { + if (!isset($v)) + return $this->emptyTimeStamp; + + # strlen(14) allows YYYYMMDDHHMMSS format + if (is_numeric($v) && strlen($v)<14) + return ($gmt) ? adodb_gmdate($fmt, $v) : adodb_date($fmt,$v); + + $tt = $this->UnixTimeStamp($v); + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + + if ($tt == 0) + return $this->emptyTimeStamp; + + return ($gmt) ? adodb_gmdate($fmt, $tt) : adodb_date($fmt, $tt); + } + + function SQLDate($fmt, $col=false) + { + if (!$col) + $col = $this->sysTimeStamp; + + $s = 'DATE_FORMAT('.$col.",'"; + $concat = false; + $len = strlen($fmt); + for ($i=0; $i < $len; $i++) { + $ch = $fmt[$i]; + switch($ch) { + default: + if ($ch == '\\') { + $i++; + $ch = substr($fmt, $i, 1); + } + + /** FALL THROUGH */ + case '-': + case '/': + $s .= $ch; + break; + + case 'Y': + case 'y': + $s .= '%Y'; + break; + + case 'M': + $s .= '%b'; + break; + + case 'm': + $s .= '%m'; + break; + + case 'D': + case 'd': + $s .= '%d'; + break; + + case 'Q': + case 'q': + $s .= "'),Quarter($col)"; + if ($len > $i+1) + $s .= ",DATE_FORMAT($col,'"; + else $s .= ",('"; + $concat = true; + break; + + case 'H': + $s .= '%H'; + break; + + case 'h': + $s .= '%I'; + break; + + case 'i': + $s .= '%i'; + break; + + case 's': + $s .= '%s'; + break; + + case 'a': + case 'A': + $s .= '%p'; + break; + + case 'w': + $s .= '%w'; + break; + + case 'l': + $s .= '%W'; + break; + } + } + $s.="')"; + if ($concat) + $s = "CONCAT($s)"; + + return $s; + } +} + +eval('class mysqli_date_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class mysqli_date_ResultSet extends mysqli_date_resultset_EXTENDER +{ + var $emptyTimeStamp = ' '; /// what to display when $time==0 + var $emptyDate = ' '; /// what to display when $time==0 + var $datetime = false; + + function UserTimeStamp($v, $fmt='Y-m-d H:i:s') + { + if (is_numeric($v) && strlen($v)<14) + return adodb_date($fmt, $v); + + $tt = $this->UnixTimeStamp($v); + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + + if ($tt === 0) + return $this->emptyTimeStamp; + else return adodb_date($fmt, $tt); + } + + function UserDate($v,$fmt='Y-m-d') + { + $tt = $this->UnixDate($v); + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + else if ($tt == 0) + return $this->emptyDate; + else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR + } + return adodb_date($fmt, $tt); + } + + function UnixDate($v) + { + return mysqli_date_ADOConnection::UnixDate($v); + } + + function UnixTimeStamp($v) + { + return mysqli_date_ADOConnection::UnixTimeStamp($v); + } +} +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/mysqli/mysqli_driver.inc b/lib/adodb/adodbSQL_drivers/mysqli/mysqli_driver.inc new file mode 100644 index 0000000..9f04690 --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/mysqli/mysqli_driver.inc @@ -0,0 +1,641 @@ +dbtype = 'mysqli'; + $this->dataProvider = 'mysql'; + } + + /** + * Connection to database server and selected database + * + * @access private + */ + + function _connect($host = "", $username = "", $password = "", $database = "", $persistent, $forcenew) + { + if (!function_exists('mysqli_real_connect')) { + echo "ERROR: Function 'mysqli_real_connect' not found! Check if MySQL is properly set up. And that PHP has the MySQLi extension installed. If MySQLi is not installed, try setting KU_DBTYPE to 'mysql' and try again."; + return false; + } + + $this->host = $host; + $this->username = $username; + $this->password = $password; + $this->database = $database; + $this->persistent = $persistent; + $this->forcenewconnection = $forcenew; + + $this->connectionId = @mysqli_init(); + @mysqli_real_connect( $this->connectionId, $this->host, $this->username, $this->password, $this->database, $this->port, $this->socket, $this->clientFlags ); + + if (mysqli_connect_errno() != 0) + { + $this->connectionId = false; + } + + if ($this->connectionId === false) + { + if ($fn = $this->raiseErrorFn) + $fn($this->dbtype, 'CONNECT', $this->ErrorNo(), $this->ErrorMsg(), $this->host, $this->database, $this); + return false; + } + + if (!empty($this->database)) + { + if($this->SelectDB( $this->database ) == false) + { + $this->connectionId = false; + return false; + } + } + + return true; + } + + /** + * Choose a database to connect. + * + * @param dbname is the name of the database to select + * @return true or false + * @access public + */ + + function SelectDB($dbname) + { + $this->database = $dbname; + + if ($this->connectionId === false) + { + $this->connectionId = false; + return false; + } + else + { + $result = @mysqli_select_db( $this->connectionId, $this->database ); + + if($result === false) + { + if($this->createdatabase == true) + { + $result = @mysqli_query( $this->connectionId, "CREATE DATABASE IF NOT EXISTS " . $this->database ); + if ($result === false) { // error handling if query fails + return false; + } + $result = @mysqli_select_db( $this->connectionId, $this->database ); + if($result === false) + { + return false; + } + } + else + { + return false; + } + } + return true; + } + } + + /** + * Return database error message + * Usage: $errormessage =& $db->ErrorMsg(); + * + * @access public + */ + + function ErrorMsg() + { + if ($this->connectionId === false) + { + return @mysqli_connect_error(); + } + else + { + return @mysqli_error($this->connectionId); + } + } + + /** + * Return database error number + * Usage: $errorbo =& $db->ErrorNo(); + * + * @access public + */ + + function ErrorNo() + { + if ($this->connectionId === false) + { + return @mysqli_connect_errno(); + } + else + { + return @mysqli_errno($this->connectionId); + } + } + + /** + * Returns # of affected rows from insert/delete/update query + * + * @access public + * @return integer Affected rows + */ + + function Affected_Rows() + { + return @mysqli_affected_rows($this->connectionId); + } + + /** + * Returns the last record id of an inserted item + * Usage: $db->Insert_ID(); + * + * @access public + */ + + function Insert_ID() + { + return @mysqli_insert_id($this->connectionId); + } + + /** + * Correctly quotes a string so that all strings are escape coded. + * An example is $db->qstr("Haven't a clue."); + * + * @param string the string to quote + * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc(). + * + * @return single-quoted string IE: 'Haven\'t a clue.' + */ + + function qstr($string, $magic_quotes=false) + { + if (!$magic_quotes) { + if (strnatcmp(PHP_VERSION, '4.3.0') >= 0 && function_exists('mysqli_real_escape_string')) { + return "'" . mysqli_real_escape_string($this->connectionId, $string) . "'"; + } + $string = str_replace("'", "\\'" , str_replace('\\', '\\\\', str_replace("\0", "\\\0", $string))); + return "'" . $string . "'"; + } + return "'" . str_replace('\\"', '"', $string) . "'"; + } + + function QMagic($string) + { + return $this->qstr($string, get_magic_quotes_gpc()); + } + + /** + * Returns concatenated string + * Usage: $db->Concat($str1,$str2); + * + * @return concatenated string + */ + function Concat() + { + $arr = func_get_args(); + $list = implode(', ', $arr); + + if (strlen($list) > 0) return "CONCAT($list)"; + else return ''; + } + + function IfNull( $field, $ifNull ) + { + return " IFNULL($field, $ifNull) "; + } + + /** + * Closes database connection + * Usage: $db->close(); + * + * @access public + */ + + function Close() + { + @mysqli_close( $this->connectionId ); + $this->connectionId = false; + } + + /** + * Returns All Records in an array + * + * Usage: $db->GetAll($sql); + * @access public + */ + + function &GetAll($sql, $inputarr = false) + { + $data =& $this->GetArray($sql, $inputarr); + return $data; + } + + /** + * Returns All Records in an array + * + * Usage: $db->GetArray($sql); + * @access public + */ + + function &GetArray($sql, $inputarr = false) + { + $data = false; + $result =& $this->Execute($sql, $inputarr); + if ($result) + { + $data =& $result->GetArray(); + $result->Close(); + } + return $data; + } + + /** + * Executes SQL query and instantiates resultset methods + * + * @access private + * @return mixed Resultset methods + */ + + function &do_query( $sql, $offset, $nrows, $inputarr=false ) + { + global $ADODB_FETCH_MODE; + + $false = false; + + $limit = ''; + if ($offset >= 0 || $nrows >= 0) + { + $offset = ($offset >= 0) ? $offset . "," : ''; + $nrows = ($nrows >= 0) ? $nrows : '18446744073709551615'; + $limit = ' LIMIT ' . $offset . ' ' . $nrows; + } + + + if ($inputarr && is_array($inputarr)) { + $sqlarr = explode('?', $sql); + if (!is_array(reset($inputarr))) $inputarr = array($inputarr); + foreach($inputarr as $arr) { + $sql = ''; $i = 0; + foreach($arr as $v) { + $sql .= $sqlarr[$i]; + switch(gettype($v)){ + case 'string': + $sql .= $this->qstr($v); + break; + case 'double': + $sql .= str_replace(',', '.', $v); + break; + case 'boolean': + $sql .= $v ? 1 : 0; + break; + default: + if ($v === null) + $sql .= 'NULL'; + else $sql .= $v; + } + $i += 1; + } + $sql .= $sqlarr[$i]; + if ($i+1 != sizeof($sqlarr)) + return $false; + $this->sql = $sql . $limit; + $time_start = array_sum(explode(' ', microtime())); + $this->query_count++; + $resultId = @mysqli_query($this->connectionId, $this->sql ); + $time_total = (array_sum(explode(' ', microtime())) - $time_start); + $this->query_time_total += $time_total; + if($this->debug_console) + { + $this->query_list[] = $this->sql; + $this->query_list_time[] = $time_total; + $this->query_list_errors[] = $this->ErrorMsg(); + } + if($this->debug) + { + $this->outp($sql . $limit); + } + if ($resultId === false) { // error handling if query fails + if ($fn = $this->raiseErrorFn) + $fn($this->dbtype, 'EXECUTE', $this->ErrorNo(), $this->ErrorMsg(), $this->sql, $inputarr, $this); + return $false; + } + } + } + else + { + $this->sql = $sql . $limit; + $time_start = array_sum(explode(' ', microtime())); + $this->query_count++; + $resultId = @mysqli_query($this->connectionId, $this->sql ); + $time_total = (array_sum(explode(' ', microtime())) - $time_start); + $this->query_time_total += $time_total; + if($this->debug_console) + { + $this->query_list[] = $this->sql; + $this->query_list_time[] = $time_total; + $this->query_list_errors[] = $this->ErrorMsg(); + } + if($this->debug) + { + $this->outp($sql . $limit); + } + } + + if ($resultId === false) { // error handling if query fails + if ($fn = $this->raiseErrorFn) + $fn($this->dbtype, 'EXECUTE', $this->ErrorNo(), $this->ErrorMsg(), $this->sql, $inputarr, $this); + return $false; + } + + if ($resultId === true) { // return simplified recordset for inserts/updates/deletes with lower overhead + $recordset = new ADORecordSet_empty(); + return $recordset; + } + + $resultset_name = $this->last_module_name . "_ResultSet"; + $recordset = new $resultset_name( $resultId, $this->connectionId ); + + $recordset->_currentRow = 0; + + switch ($ADODB_FETCH_MODE) + { + case ADODB_FETCH_NUM: $recordset->fetchMode = MYSQLI_NUM; break; + case ADODB_FETCH_ASSOC:$recordset->fetchMode = MYSQLI_ASSOC; break; + default: + case ADODB_FETCH_DEFAULT: + case ADODB_FETCH_BOTH:$recordset->fetchMode = MYSQLI_BOTH; break; + } + + $recordset->_numOfRows = @mysqli_num_rows( $resultId ); + if( $recordset->_numOfRows == 0) + { + $recordset->EOF = true; + } + $recordset->_numOfFields = @mysqli_num_fields( $resultId ); + $recordset->_fetch(); + + return $recordset; + } +} + +class mysqli_driver_ResultSet +{ + var $connectionId; + var $fields; + var $resultId; + var $_currentRow = 0; + var $_numOfRows = -1; + var $_numOfFields = -1; + var $fetchMode; + var $EOF; + + /** + * mysqlResultSet Constructor + * + * @access private + * @param string $record + * @param string $resultId + */ + + function mysqli_driver_ResultSet( $resultId, $connectionId ) + { + $this->fields = array(); + $this->connectionId = $connectionId; + $this->record = array(); + $this->resultId = $resultId; + $this->EOF = false; + } + + /** + * Frees resultset + * + * @access public + */ + + function Close() + { + @mysqli_free_result( $this->resultId ); + $this->fields = array(); + $this->resultId = false; + } + + /** + * Returns field name from select query + * + * @access public + * @param string $field + * @return string Field name + */ + + function fields( $field ) + { + if(empty($field)) + { + return $this->fields; + } + else + { + return $this->fields[$field]; + } + } + + /** + * Returns numrows from select query + * + * @access public + * @return integer Numrows + */ + + function RecordCount() + { + return $this->_numOfRows; + } + + /** + * Returns num of fields from select query + * + * @access public + * @return integer numfields + */ + + function FieldCount() + { + return $this->_numOfFields; + } + + /** + * Returns next record + * + * @access public + */ + + function MoveNext() + { + if (@$this->fields = mysqli_fetch_array($this->resultId,$this->fetchMode)) { + $this->_currentRow += 1; + return true; + } + if (!$this->EOF) { + $this->_currentRow += 1; + $this->EOF = true; + } + return false; + } + + /** + * Move to the first row in the recordset. Many databases do NOT support this. + * + * @return true or false + */ + + function MoveFirst() + { + if ($this->_currentRow == 0) return true; + return $this->Move(0); + } + + /** + * Returns the Last Record + * + * @access public + */ + + function MoveLast() + { + if ($this->EOF) return false; + return $this->Move($this->_numOfRows - 1); + } + + /** + * Random access to a specific row in the recordset. Some databases do not support + * access to previous rows in the databases (no scrolling backwards). + * + * @param rowNumber is the row to move to (0-based) + * + * @return true if there still rows available, or false if there are no more rows (EOF). + */ + + function Move($rowNumber = 0) + { + if ($rowNumber == $this->_currentRow) return true; + $this->EOF = false; + if ($this->_numOfRows > 0){ + if ($rowNumber >= $this->_numOfRows - 1){ + $rowNumber = $this->_numOfRows - 1; + } + } + + if ($this->_seek($rowNumber)) { + $this->_currentRow = $rowNumber; + if ($this->_fetch()) { + return true; + } + $this->fields = false; + } + $this->EOF = true; + return false; + } + + /** + * Perform Seek to specific row + * + * @access private + */ + + function _seek($row) + { + if ($this->_numOfRows == 0) return false; + return @mysqli_data_seek($this->resultId,$row); + } + + /** + * Fills field array with first database element when query initially executed + * + * @access private + */ + + function _fetch() + { + $this->fields = @mysqli_fetch_array($this->resultId,$this->fetchMode); + return is_array($this->fields); + } + + /** + * Check to see if last record reached + * + * @access public + */ + + function EOF() + { + if( $this->_currentRow < $this->_numOfRows) + { + return false; + } + else + { + $this->EOF = true; + return true; + } + } + + /** + * Returns All Records in an array + * + * @access public + * @param [nRows] is the number of rows to return. -1 means every row. + */ + + function &GetArray($nRows = -1) + { + $results = array(); + $cnt = 0; + while (!$this->EOF && $nRows != $cnt) { + $results[] = $this->fields; + $this->MoveNext(); + $cnt++; + } + return $results; + } + + function &GetRows($nRows = -1) + { + $arr =& $this->GetArray($nRows); + return $arr; + } + + function &GetAll($nRows = -1) + { + $arr =& $this->GetArray($nRows); + return $arr; + } + + /** + * Fetch field information for a table. + * + * @return object containing the name, type and max_length + */ + function FetchField($fieldOffset = -1) + { + // $fieldOffset not supported by mysqli + $fieldObject = @mysqli_fetch_field($this->resultId); + return $fieldObject; + } +} +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/mysqli/mysqli_extend_module.inc b/lib/adodb/adodbSQL_drivers/mysqli/mysqli_extend_module.inc new file mode 100644 index 0000000..ada6ea9 --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/mysqli/mysqli_extend_module.inc @@ -0,0 +1,150 @@ +Execute($sql, $inputarr); + if ($result) { + $data =& $result->GetAssoc($force_array, $first2cols); + $result->Close(); + } + return $data; + } + + /** + * Generates a sequence id and stores it in $this->genID; + * GenID is only available if $this->hasGenID = true; + * + * @param seqname name of sequence to use + * @param startID if sequence does not exist, start at this ID + * @return 0 if not supported, otherwise a sequence id + */ + + var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);"; + var $_genSeqSQL = "create table %s (id int not null)"; + var $_genSeq2SQL = "insert into %s values (%s)"; + var $_dropSeqSQL = "drop table %s"; + var $genID = 0; + + function GenID($seqname='adodbseq', $startID=1) + { + $getnext = sprintf($this->_genIDSQL, $seqname); + $holdtransOK = $this->transaction_status; + $result = @$this->Execute($getnext); + if (!$result) { + if ($holdtransOK) + $this->transaction_status = true; +// $u = strtoupper($seqname); + $this->Execute(sprintf($this->_genSeqSQL, $seqname)); + $this->Execute(sprintf($this->_genSeq2SQL, $seqname, $startID-1)); + $result = $this->Execute($getnext); + } + $this->genID = mysqli_insert_id($this->connectionId); + + if ($result) + $result->Close(); + + return $this->genID; + } + + function CreateSequence($seqname='adodbseq',$startID=1) + { + $u = strtoupper($seqname); + + $ok = $this->Execute(sprintf($this->_genSeqSQL, $seqname)); + if (!$ok) + return false; + return $this->Execute(sprintf($this->_genSeq2SQL, $seqname, $startID-1)); + } + + function DropSequence($seqname='adodbseq') + { + return $this->Execute(sprintf($this->_dropSeqSQL, $seqname)); + } + +} + +eval('class mysqli_extend_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class mysqli_extend_ResultSet extends mysqli_extend_resultset_EXTENDER +{ + function &GetAssoc($force_array = false, $first2cols = false) + { + $results = false; + + if ($this->_numOfFields > 1) { + $numIndex = isset($this->fields[0]); + $results = array(); + if (!$first2cols && ($this->_numOfFields > 2 || $force_array)) { + if ($numIndex) { + while (!$this->EOF) { + $results[trim($this->fields[0])] = array_slice($this->fields, 1); + $this->MoveNext(); + } + } else { + while (!$this->EOF) { + $results[trim(reset($this->fields))] = array_slice($this->fields, 1); + $this->MoveNext(); + } + } + } else { + if ($numIndex) { + while (!$this->EOF) { + $results[trim(($this->fields[0]))] = $this->fields[1]; + $this->MoveNext(); + } + } else { + while (!$this->EOF) { + $v1 = trim(reset($this->fields)); + $v2 = ''.next($this->fields); + $results[$v1] = $v2; + $this->MoveNext(); + } + } + } + } + return $results; + } + + function PO_RecordCount($table="", $condition="") + { + $lnumrows = $this->_numOfRows; + if($lnumrows == -1 && $this->connectionId) + { + if($table) + { + if ($condition) + $condition = " WHERE " . $condition; + $resultrows = &$this->connectionId->Execute("SELECT COUNT(*) FROM $table $condition"); + if ($resultrows) + $lnumrows = reset($resultrows->fields); + } + } + return $lnumrows; + } + + function CurrentRow() + { + return $this->_currentRow; + } + + function AbsolutePosition() + { + return $this->_currentRow; + } + + function NextRecordSet() + { + return false; + } + +} +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/mysqli/mysqli_meta_module.inc b/lib/adodb/adodbSQL_drivers/mysqli/mysqli_meta_module.inc new file mode 100644 index 0000000..ab17637 --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/mysqli/mysqli_meta_module.inc @@ -0,0 +1,624 @@ +ErrorNo(); + + return adodb_error($this->dataProvider,$this->databaseType,$err); + } + + function MetaErrorMsg($errno) + { + include_once(ADODB_DIR . "/adodb-error.inc.php"); + return adodb_errormsg($errno); + } + + /** + * @returns an array with the primary key columns in it. + */ + function MetaPrimaryKeys($table, $owner=false) + { + // owner not used in base class - see oci8 + $p = array(); + $objs =& $this->MetaColumns($table); + if ($objs) { + foreach($objs as $v) { + if (!empty($v->primary_key)) + $p[] = $v->name; + } + } + if (sizeof($p)) + return $p; + if (function_exists('ADODB_VIEW_PRIMARYKEYS')) + return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner); + return false; + } + + /** + * @returns assoc array where keys are tables, and values are foreign keys + */ + function MetaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $associative = FALSE ) + { + if ( !empty($owner) ) { + $table = "$owner.$table"; + } + $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE %s', $table)); + if ($associative) $create_sql = $a_create_table["Create Table"]; + else $create_sql = $a_create_table[1]; + + $matches = array(); + + if (!preg_match_all("/FOREIGN KEY \(`(.*?)`\) REFERENCES `(.*?)` \(`(.*?)`\)/", $create_sql, $matches)) return false; + $foreign_keys = array(); + $num_keys = count($matches[0]); + for ( $i = 0; $i < $num_keys; $i ++ ) { + $my_field = explode('`, `', $matches[1][$i]); + $ref_table = $matches[2][$i]; + $ref_field = explode('`, `', $matches[3][$i]); + + if ( $upper ) { + $ref_table = strtoupper($ref_table); + } + + $foreign_keys[$ref_table] = array(); + $num_fields = count($my_field); + for ( $j = 0; $j < $num_fields; $j ++ ) { + if ( $associative ) { + $foreign_keys[$ref_table][$ref_field[$j]] = $my_field[$j]; + } else { + $foreign_keys[$ref_table][] = "{$my_field[$j]}={$ref_field[$j]}"; + } + } + } + + return $foreign_keys; + } + + // not the fastest implementation - quick and dirty - jlim + // for best performance, use the actual $rs->MetaType(). + function MetaType($t,$len=-1,$fieldobj=false) + { + if (empty($this->_metars)) { + $rsclass = $this->last_module_name . "_ResultSet"; + $this->_metars =& new $rsclass(false, $this->fetchMode); + } + + return $this->_metars->MetaType($t,$len,$fieldobj); + } + + /** + * return the databases that the driver can connect to. + * Some databases will return an empty array. + * + * @return an array of database names. + */ + function &MetaDatabases() + { + $qid = mysql_list_dbs($this->connectionId); + $arr = array(); + $i = 0; + $max = mysql_num_rows($qid); + while ($i < $max) { + $db = mysql_tablename($qid,$i); + if ($db != 'mysql') $arr[] = $db; + $i += 1; + } + return $arr; + } + + /** + * @param ttype can either be 'VIEW' or 'TABLE' or false. + * If false, both views and tables are returned. + * "VIEW" returns only views + * "TABLE" returns only tables + * @param showSchema returns the schema/user with the table name, eg. USER.TABLE + * @param mask is the input mask - only supported by oci8 and postgresql + * + * @return array of tables for current database. + */ + function &MetaTables($ttype=false,$showSchema=false,$mask=false) + { + $save = $this->metaTablesSQL; + if ($showSchema && is_string($showSchema)) { + $this->metaTablesSQL .= " from $showSchema"; + } + + if ($mask) { + $mask = $this->qstr($mask); + $this->metaTablesSQL .= " like $mask"; + } + $ret =& $this->_MetaTables($ttype,$showSchema); + + $this->metaTablesSQL = $save; + return $ret; + } + + function &_MetaTables($ttype=false,$showSchema=false,$mask=false) + { + global $ADODB_FETCH_MODE; + + $false = false; + if ($mask) { + return $false; + } + if ($this->metaTablesSQL) { + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + + $rs = $this->Execute($this->metaTablesSQL); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if ($rs === false) return $false; + $arr =& $rs->GetArray(); + $arr2 = array(); + + if ($hast = ($ttype && isset($arr[0][1]))) { + $showt = strncmp($ttype,'T',1); + } + + for ($i=0; $i < sizeof($arr); $i++) { + if ($hast) { + if ($showt == 0) { + if (strncmp($arr[$i][1],'T',1) == 0) $arr2[] = trim($arr[$i][0]); + } else { + if (strncmp($arr[$i][1],'V',1) == 0) $arr2[] = trim($arr[$i][0]); + } + } else + $arr2[] = trim($arr[$i][0]); + } + $rs->Close(); + return $arr2; + } + return $false; + } + + function _findschema(&$table,&$schema) + { + if (!$schema && ($at = strpos($table,'.')) !== false) { + $schema = substr($table,0,$at); + $table = substr($table,$at+1); + } + } + + /** + * List columns in a database as an array of ADOFieldObjects. + * See top of file for definition of object. + * + * @param $table table name to query + * @param $normalize makes table name case-insensitive (required by some databases) + * @schema is optional database schema to use - not supported by all databases. + * + * @return array of ADOFieldObjects for current table. + */ + function MetaColumns($table) + { + $this->_findschema($table,$schema); + if ($schema) { + $dbName = $this->database; + $this->connection->SelectDB($schema); + } + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table)); + + if ($schema) { + $this->SelectDB($dbName); + } + + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + if (!is_object($rs)) { + $false = false; + return $false; + } + + $retarr = array(); + while (!$rs->EOF){ + $fld = new ADOFieldObject(); + $fld->name = $rs->fields[0]; + $type = $rs->fields[1]; + + // split type into type(length): + $fld->scale = null; + if (preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) { + $fld->type = $query_array[1]; + $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; + $fld->scale = is_numeric($query_array[3]) ? $query_array[3] : -1; + } elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) { + $fld->type = $query_array[1]; + $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; + } elseif (preg_match("/^(enum)\((.*)\)$/i", $type, $query_array)) { + $fld->type = $query_array[1]; + $arr = explode(",",$query_array[2]); + $fld->enums = $arr; + $zlen = max(array_map("strlen",$arr)) - 2; // PHP >= 4.0.6 + $fld->max_length = ($zlen > 0) ? $zlen : 1; + } else { + $fld->type = $type; + $fld->max_length = -1; + } + $fld->not_null = ($rs->fields[2] != 'YES'); + $fld->primary_key = ($rs->fields[3] == 'PRI'); + $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false); + $fld->binary = (strpos($type,'blob') !== false); + $fld->unsigned = (strpos($type,'unsigned') !== false); + + if (!$fld->binary) { + $d = $rs->fields[4]; + if ($d != '' && $d != 'NULL') { + $fld->has_default = true; + $fld->default_value = $d; + } else { + $fld->has_default = false; + } + } + + if ($save == ADODB_FETCH_NUM) { + $retarr[] = $fld; + } else { + $retarr[strtoupper($fld->name)] = $fld; + } + $rs->MoveNext(); + } + + $rs->Close(); + return $retarr; + } + + /** + * List indexes on a table as an array. + * @param table table name to query + * @param primary true to only show primary keys. Not actually used for most databases + * + * @return array of indexes on current table. Each element represents an index, and is itself an associative array. + + Array ( + [name_of_index] => Array + ( + [unique] => true or false + [columns] => Array + ( + [0] => firstname + [1] => lastname + ) + ) + */ + function MetaIndexes ($table, $primary = FALSE, $owner=false) + { + // save old fetch mode + global $ADODB_FETCH_MODE; + + $false = false; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== FALSE) { + $savem = $this->SetFetchMode(FALSE); + } + + // get index details + $rs =& $this->Execute(sprintf('SHOW INDEX FROM %s',$table)); + + // restore fetchmode + if (isset($savem)) { + $this->SetFetchMode($savem); + } + $ADODB_FETCH_MODE = $save; + + if (!is_object($rs)) { + return $false; + } + + $indexes = array (); + + // parse index data into array + while (!$rs->EOF) + { + if ($primary == FALSE AND $rs->fields[2] == 'PRIMARY') { + $rs->MoveNext(); + continue; + } + + if (!isset($indexes[$rs->fields[2]])) { + $indexes[$rs->fields[2]] = array( + 'unique' => ($rs->fields[1] == 0), + 'columns' => array() + ); + } + + $indexes[$rs->fields[2]]['columns'][$rs->fields[3] - 1] = $rs->fields[4]; + + $rs->MoveNext(); + } + + // sort columns by order in the index + foreach ( array_keys ($indexes) as $index ) + { + ksort ($indexes[$index]['columns']); + } + + return $indexes; + } + + /** + * List columns names in a table as an array. + * @param table table name to query + * + * @return array of column names for current table. + */ + function &MetaColumnNames($table, $numIndexes=false) + { + $objarr =& $this->MetaColumns($table); + if (!is_array($objarr)) { + $false = false; + return $false; + } + $arr = array(); + if ($numIndexes) { + $i = 0; + foreach($objarr as $v) $arr[$i++] = $v->name; + } else + foreach($objarr as $v) $arr[strtoupper($v->name)] = $v->name; + + return $arr; + } + + function MetaTransaction($mode,$db) + { + $mode = strtoupper($mode); + $mode = str_replace('ISOLATION LEVEL ','',$mode); + + switch($mode) { + + case 'READ UNCOMMITTED': + switch($db) { + case 'oci8': + case 'oracle': + return 'ISOLATION LEVEL READ COMMITTED'; + default: + return 'ISOLATION LEVEL READ UNCOMMITTED'; + } + break; + + case 'READ COMMITTED': + return 'ISOLATION LEVEL READ COMMITTED'; + break; + + case 'REPEATABLE READ': + switch($db) { + case 'oci8': + case 'oracle': + return 'ISOLATION LEVEL SERIALIZABLE'; + default: + return 'ISOLATION LEVEL REPEATABLE READ'; + } + break; + + case 'SERIALIZABLE': + return 'ISOLATION LEVEL SERIALIZABLE'; + break; + + default: + return $mode; + } + } + +} + +eval('class mysqli_meta_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class mysqli_meta_ResultSet extends mysqli_meta_resultset_EXTENDER +{ + /** + * Get the metatype of the column. This is used for formatting. This is because + * many databases use different names for the same type, so we transform the original + * type to our standardised version which uses 1 character codes: + * + * @param t is the type passed in. Normally is ADOFieldObject->type. + * @param len is the maximum length of that field. This is because we treat character + * fields bigger than a certain size as a 'B' (blob). + * @param fieldobj is the field object returned by the database driver. Can hold + * additional info (eg. primary_key for mysql). + * + * @return the general type of the data: + * C for character < 250 chars + * X for teXt (>= 250 chars) + * B for Binary + * N for numeric or floating point + * D for date + * T for timestamp + * L for logical/Boolean + * I for integer + * R for autoincrement counter/integer + * + * + */ + function MetaType($t,$len=-1,$fieldobj=false) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + + $len = -1; // mysql max_length is not accurate + switch (strtoupper($t)) { + case 'STRING': + case 'CHAR': + case 'VARCHAR': + case 'TINYBLOB': + case 'TINYTEXT': + case 'ENUM': + case 'SET': + if ($len <= $this->blobSize) return 'C'; + + case 'TEXT': + case 'LONGTEXT': + case 'MEDIUMTEXT': + return 'X'; + + // php_mysql extension always returns 'blob' even if 'text' + // so we have to check whether binary... + case 'IMAGE': + case 'LONGBLOB': + case 'BLOB': + case 'MEDIUMBLOB': + return !empty($fieldobj->binary) ? 'B' : 'X'; + + case 'YEAR': + case 'DATE': return 'D'; + + case 'TIME': + case 'DATETIME': + case 'TIMESTAMP': return 'T'; + + case 'INT': + case 'INTEGER': + case 'BIGINT': + case 'TINYINT': + case 'MEDIUMINT': + case 'SMALLINT': + + if (!empty($fieldobj->primary_key)) return 'R'; + else return 'I'; + + default: + static $typeMap = array( + 'VARCHAR' => 'C', + 'VARCHAR2' => 'C', + 'CHAR' => 'C', + 'C' => 'C', + 'STRING' => 'C', + 'NCHAR' => 'C', + 'NVARCHAR' => 'C', + 'VARYING' => 'C', + 'BPCHAR' => 'C', + 'CHARACTER' => 'C', + 'INTERVAL' => 'C', # Postgres + 'MACADDR' => 'C', # postgres + ## + 'LONGCHAR' => 'X', + 'TEXT' => 'X', + 'NTEXT' => 'X', + 'M' => 'X', + 'X' => 'X', + 'CLOB' => 'X', + 'NCLOB' => 'X', + 'LVARCHAR' => 'X', + ## + 'BLOB' => 'B', + 'IMAGE' => 'B', + 'BINARY' => 'B', + 'VARBINARY' => 'B', + 'LONGBINARY' => 'B', + 'B' => 'B', + ## + 'YEAR' => 'D', // mysql + 'DATE' => 'D', + 'D' => 'D', + ## + 'UNIQUEIDENTIFIER' => 'C', # MS SQL Server + ## + 'TIME' => 'T', + 'TIMESTAMP' => 'T', + 'DATETIME' => 'T', + 'TIMESTAMPTZ' => 'T', + 'T' => 'T', + 'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql + ## + 'BOOL' => 'L', + 'BOOLEAN' => 'L', + 'BIT' => 'L', + 'L' => 'L', + ## + 'COUNTER' => 'R', + 'R' => 'R', + 'SERIAL' => 'R', // ifx + 'INT IDENTITY' => 'R', + ## + 'INT' => 'I', + 'INT2' => 'I', + 'INT4' => 'I', + 'INT8' => 'I', + 'INTEGER' => 'I', + 'INTEGER UNSIGNED' => 'I', + 'SHORT' => 'I', + 'TINYINT' => 'I', + 'SMALLINT' => 'I', + 'I' => 'I', + ## + 'LONG' => 'N', // interbase is numeric, oci8 is blob + 'BIGINT' => 'N', // this is bigger than PHP 32-bit integers + 'DECIMAL' => 'N', + 'DEC' => 'N', + 'REAL' => 'N', + 'DOUBLE' => 'N', + 'DOUBLE PRECISION' => 'N', + 'SMALLFLOAT' => 'N', + 'FLOAT' => 'N', + 'NUMBER' => 'N', + 'NUM' => 'N', + 'NUMERIC' => 'N', + 'MONEY' => 'N', + + ## informix 9.2 + 'SQLINT' => 'I', + 'SQLSERIAL' => 'I', + 'SQLSMINT' => 'I', + 'SQLSMFLOAT' => 'N', + 'SQLFLOAT' => 'N', + 'SQLMONEY' => 'N', + 'SQLDECIMAL' => 'N', + 'SQLDATE' => 'D', + 'SQLVCHAR' => 'C', + 'SQLCHAR' => 'C', + 'SQLDTIME' => 'T', + 'SQLINTERVAL' => 'N', + 'SQLBYTES' => 'B', + 'SQLTEXT' => 'X', + ## informix 10 + "SQLINT8" => 'I8', + "SQLSERIAL8" => 'I8', + "SQLNCHAR" => 'C', + "SQLNVCHAR" => 'C', + "SQLLVARCHAR" => 'X', + "SQLBOOL" => 'L' + ); + + $tmap = false; + $t = strtoupper($t); + $tmap = (isset($typeMap[$t])) ? $typeMap[$t] : 'N'; + if ($t == 'LONG' && $this->dataProvider == 'oci8') return 'B'; + return $tmap; + } + } + +} + +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/mysqli/mysqli_perfmon_module.inc b/lib/adodb/adodbSQL_drivers/mysqli/mysqli_perfmon_module.inc new file mode 100644 index 0000000..a9394ba --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/mysqli/mysqli_perfmon_module.inc @@ -0,0 +1,468 @@ + array('RATIO', + '=GetKeyHitRatio', + '=WarnCacheRatio'), + 'InnoDB cache hit ratio' => array('RATIO', + '=GetInnoDBHitRatio', + '=WarnCacheRatio'), + 'data cache hit ratio' => array('HIDE', # only if called + '=FindDBHitRatio', + '=WarnCacheRatio'), + 'sql cache hit ratio' => array('RATIO', + '=GetQHitRatio', + ''), + 'IO', + 'data reads' => array('IO', + '=GetReads', + 'Number of selects (Key_reads is not accurate)'), + 'data writes' => array('IO', + '=GetWrites', + 'Number of inserts/updates/deletes * coef (Key_writes is not accurate)'), + + 'Data Cache', + 'MyISAM data cache size' => array('DATAC', + array("show variables", 'key_buffer_size'), + '' ), + 'BDB data cache size' => array('DATAC', + array("show variables", 'bdb_cache_size'), + '' ), + 'InnoDB data cache size' => array('DATAC', + array("show variables", 'innodb_buffer_pool_size'), + '' ), + 'Memory Usage', + 'read buffer size' => array('CACHE', + array("show variables", 'read_buffer_size'), + '(per session)'), + 'sort buffer size' => array('CACHE', + array("show variables", 'sort_buffer_size'), + 'Size of sort buffer (per session)' ), + 'table cache' => array('CACHE', + array("show variables", 'table_cache'), + 'Number of tables to keep open'), + 'Connections', + 'current connections' => array('SESS', + array('show status','Threads_connected'), + ''), + 'max connections' => array( 'SESS', + array("show variables",'max_connections'), + ''), + + false + ); + + /** + Get server version info... + + @returns An array with 2 elements: $arr['description'] is the description string, + and $arr['version'] is the version (also a string). + */ + function ServerInfo() + { + $arr = array(); + $result = $this->do_query('select version()', -1, -1, false); + if (!$result->EOF) $data = $result->fields; + else $data = array(); + $arr['version'] = $arr['description'] = $data[0]; + //****// Where does $arr come from in ADOdb - doesn't appear global, maybe null? A possible bug? + return $arr; + } + + /* + Explain Plan for $sql. + If only a snippet of the $sql is passed in, then $partial will hold the crc32 of the + actual sql. + */ + function Explain($sql,$partial=false) + { + $perf_table = perfmon_parent_ADOConnection::table(); // this was missing in the original ADOdb perf class - bug? + + if (strtoupper(substr(trim($sql),0,6)) !== 'SELECT') return '

Unable to EXPLAIN a non-select statement

'; + $save = $this->LogSQL(false); + if ($partial) { + $sqlq = $this->qstr($sql.'%'); + $arr = $this->GetArray("select distinct sql1 from $perf_table where sql1 like $sqlq"); + if ($arr) + { + foreach($arr as $row) + { + $sql = reset($row); + if (crc32($sql) == $partial) break; + } + } + } + $sql = str_replace('?',"''",$sql); + + if ($partial) + { + $sqlq = $this->qstr($sql.'%'); + $sql = $this->GetOne("select sql1 from $perf_table where sql1 like $sqlq"); + } + + $s = '

Explain: '.htmlentities($sql, ENT_QUOTES, 'UTF-8').'

'; + $rs = $this->Execute('EXPLAIN '.$sql); + $s .= rs2html($rs,false,false,false,false); + $this->LogSQL($save); + $s .= $this->Tracer($sql); + return $s; + } + + function Tables() + { + if (!$this->tablesSQL) return false; + + $rs = $this->Execute($this->tablesSQL); + if (!$rs) return false; + + $html = rs2html($rs,false,false,false,false); + return $html; + } + + + function CreateLogTable() + { + if (!$this->createTableSQL) return false; + + $savelog = $this->LogSQL(false); + $ok = $this->Execute($this->createTableSQL); + $this->LogSQL($savelog); + return ($ok) ? true : false; + } + + + function GetReads() + { + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + $rs = $this->Execute('show status'); + + $ADODB_FETCH_MODE = $save; + + if (!$rs) return 0; + $val = 0; + while (!$rs->EOF) + { + switch($rs->fields[0]) + { + case 'Com_select': + $val = $rs->fields[1]; + $rs->Close(); + return $val; + } + $rs->MoveNext(); + } + + $rs->Close(); + return $val; + } + + function GetWrites() + { + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + $rs = $this->Execute('show status'); + + $ADODB_FETCH_MODE = $save; + + if (!$rs) return 0; + $val = 0.0; + while (!$rs->EOF) + { + switch($rs->fields[0]) + { + case 'Com_insert': + $val += $rs->fields[1]; + break; + case 'Com_delete': + $val += $rs->fields[1]; + break; + case 'Com_update': + $val += $rs->fields[1]/2; + $rs->Close(); + return $val; + } + $rs->MoveNext(); + } + + $rs->Close(); + return $val; + } + + function FindDBHitRatio() + { + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + $rs = $this->Execute('show table status'); + + $ADODB_FETCH_MODE = $save; + + if (!$rs) return ''; + $type = strtoupper($rs->fields[1]); + $rs->Close(); + switch($type) + { + case 'MYISAM': + case 'ISAM': + return $this->DBParameter('MyISAM cache hit ratio').' (MyISAM)'; + case 'INNODB': + return $this->DBParameter('InnoDB cache hit ratio').' (InnoDB)'; + default: + return $type.' not supported'; + } + } + + function GetQHitRatio() + { + //Total number of queries = Qcache_inserts + Qcache_hits + Qcache_not_cached + $hits = $this->_DBParameter(array("show status","Qcache_hits")); + $total = $this->_DBParameter(array("show status","Qcache_inserts")); + $total += $this->_DBParameter(array("show status","Qcache_not_cached")); + + $total += $hits; + if ($total) return round(($hits*100)/$total,2); + return 0; + } + + /* + Use session variable to store Hit percentage, because MySQL + does not remember last value of SHOW INNODB STATUS hit ratio + + # 1st query to SHOW INNODB STATUS + 0.00 reads/s, 0.00 creates/s, 0.00 writes/s + Buffer pool hit rate 1000 / 1000 + + # 2nd query to SHOW INNODB STATUS + 0.00 reads/s, 0.00 creates/s, 0.00 writes/s + No buffer pool activity since the last printout + */ + function GetInnoDBHitRatio() + { + global $ADODB_FETCH_MODE; + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + $rs = $this->Execute('show innodb status'); +; + $ADODB_FETCH_MODE = $save; + + if (!$rs || $rs->EOF) return 0; + $stat = $rs->fields[0]; + $rs->Close(); + $at = strpos($stat,'Buffer pool hit rate'); + $stat = substr($stat,$at,200); + if (preg_match('!Buffer pool hit rate\s*([0-9]*) / ([0-9]*)!',$stat,$arr)) + { + $val = 100*$arr[1]/$arr[2]; + $_SESSION['INNODB_HIT_PCT'] = $val; + return round($val,2); + } + else + { + if (isset($_SESSION['INNODB_HIT_PCT'])) return $_SESSION['INNODB_HIT_PCT']; + return 0; + } + return 0; + } + + function GetKeyHitRatio() + { + $hits = $this->_DBParameter(array("show status","Key_read_requests")); + $reqs = $this->_DBParameter(array("show status","Key_reads")); + if ($reqs == 0) return 0; + + return round(($hits/($reqs+$hits))*100,2); + } + + // start hack + var $optimizeTableLow = 'CHECK TABLE %s FAST QUICK'; + var $optimizeTableHigh = 'OPTIMIZE TABLE %s'; + + /** + * @see adodb_perf#optimizeTable + */ + function optimizeTable( $table, $mode = ADODB_OPT_LOW) + { + if ( !is_string( $table)) return false; + + $sql = ''; + switch( $mode) + { + case ADODB_OPT_LOW: + $sql = $this->optimizeTableLow; + break; + case ADODB_OPT_HIGH: + $sql = $this->optimizeTableHigh; + break; + default: + { + // May dont use __FUNCTION__ constant for BC (__FUNCTION__ Added in PHP 4.3.0) + trigger_error(sprintf( "

%s: '%s' using of undefined mode '%s'

", __CLASS__, __FUNCTION__, $mode), E_USER_ERROR); + return false; + } + } + $sql = sprintf( $sql, $table); + + return $this->Execute( $sql) !== false; + } + +} + + + +eval('class mysqli_perfmon_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class mysqli_perfmon_ResultSet extends mysqli_perfmon_resultset_EXTENDER +{ + + function MetaType($t, $len = -1, $fieldobj = false) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + + + $len = -1; // mysql max_length is not accurate + switch (strtoupper($t)) { + case 'STRING': + case 'CHAR': + case 'VARCHAR': + case 'TINYBLOB': + case 'TINYTEXT': + case 'ENUM': + case 'SET': + + case MYSQLI_TYPE_TINY_BLOB : + case MYSQLI_TYPE_CHAR : + case MYSQLI_TYPE_STRING : + case MYSQLI_TYPE_ENUM : + case MYSQLI_TYPE_SET : + case 253 : + if ($len <= $this->blobSize) return 'C'; + + case 'TEXT': + case 'LONGTEXT': + case 'MEDIUMTEXT': + return 'X'; + + + // php_mysql extension always returns 'blob' even if 'text' + // so we have to check whether binary... + case 'IMAGE': + case 'LONGBLOB': + case 'BLOB': + case 'MEDIUMBLOB': + + case MYSQLI_TYPE_BLOB : + case MYSQLI_TYPE_LONG_BLOB : + case MYSQLI_TYPE_MEDIUM_BLOB : + + return !empty($fieldobj->binary) ? 'B' : 'X'; + case 'YEAR': + case 'DATE': + case MYSQLI_TYPE_DATE : + case MYSQLI_TYPE_YEAR : + + return 'D'; + + case 'TIME': + case 'DATETIME': + case 'TIMESTAMP': + + case MYSQLI_TYPE_DATETIME : + case MYSQLI_TYPE_NEWDATE : + case MYSQLI_TYPE_TIME : + case MYSQLI_TYPE_TIMESTAMP : + + return 'T'; + + case 'INT': + case 'INTEGER': + case 'BIGINT': + case 'TINYINT': + case 'MEDIUMINT': + case 'SMALLINT': + + case MYSQLI_TYPE_INT24 : + case MYSQLI_TYPE_LONG : + case MYSQLI_TYPE_LONGLONG : + case MYSQLI_TYPE_SHORT : + case MYSQLI_TYPE_TINY : + + if (!empty($fieldobj->primary_key)) return 'R'; + + return 'I'; + + + // Added floating-point types + // Maybe not necessery. + case 'FLOAT': + case 'DOUBLE': + // case 'DOUBLE PRECISION': + case 'DECIMAL': + case 'DEC': + case 'FIXED': + default: + //if (!is_numeric($t)) echo "

--- Error in type matching $t -----

"; + return 'N'; + } + } // function + +} + +?> diff --git a/lib/adodb/adodbSQL_drivers/mysqli/mysqli_transaction_module.inc b/lib/adodb/adodbSQL_drivers/mysqli/mysqli_transaction_module.inc new file mode 100644 index 0000000..ce57348 --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/mysqli/mysqli_transaction_module.inc @@ -0,0 +1,138 @@ +transOff > 0) { + $this->transOff += 1; + return; + } + $this->transaction_status = true; + + if ($this->debug && $this->transCnt > 0) + ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans"); + + $this->BeginTrans(); + $this->transOff = 1; + } + + function BeginTrans() + { + if ($this->transOff) + return true; + + $this->transCnt += 1; + $this->Execute('SET AUTOCOMMIT=0'); + $this->Execute('BEGIN'); + return true; + } + + function CompleteTrans($autoComplete = true) + { + if ($this->transOff > 1) { + $this->transOff -= 1; + return true; + } + $this->transOff = 0; + if ($this->transaction_status && $autoComplete) { + if (!$this->CommitTrans()) { + $this->transaction_status = false; + if ($this->debug) + ADOConnection::outp("Smart Commit failed"); + } else + if ($this->debug) + ADOConnection::outp("Smart Commit occurred"); + } else { + $this->RollbackTrans(); + if ($this->debug) + ADOCOnnection::outp("Smart Rollback occurred"); + } + return $this->transaction_status; + } + + function CommitTrans($ok=true) + { + if ($this->transOff) + return true; + + if (!$ok) return + $this->RollbackTrans(); + + if ($this->transCnt) + $this->transCnt -= 1; + + $this->Execute('COMMIT'); + $this->Execute('SET AUTOCOMMIT=1'); + return true; + } + + function RollbackTrans() + { + if ($this->transOff) + return true; + + if ($this->transCnt) + $this->transCnt -= 1; + + $this->Execute('ROLLBACK'); + $this->Execute('SET AUTOCOMMIT=1'); + return true; + } + + function FailTrans() + { + if ($this->debug) + if ($this->transOff == 0) { + ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans"); + } else { + ADOConnection::outp("FailTrans was called"); + } + $this->transaction_status = false; + } + + function HasFailedTrans() + { + if ($this->transOff > 0) + return $this->transaction_status == false; + + return false; + } + + function RowLock($tables,$where,$flds='1 as ignore') + { + if ($this->transCnt==0) + $this->BeginTrans(); + + return $this->GetOne("select $flds from $tables where $where for update"); + } + + function CommitLock($table) + { + return $this->CommitTrans(); + } + + function RollbackLock($table) + { + return $this->RollbackTrans(); + } + +} + +eval('class mysqli_transaction_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class mysqli_transaction_ResultSet extends mysqli_transaction_resultset_EXTENDER +{ +} +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/postgres64/postgres64_datadict.inc b/lib/adodb/adodbSQL_drivers/postgres64/postgres64_datadict.inc new file mode 100644 index 0000000..ea6e17c --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/postgres64/postgres64_datadict.inc @@ -0,0 +1,211 @@ +TableName ($tabname); + $sql = array(); + list($lines,$pkey) = $this->_GenFields($flds); + $alter = 'ALTER TABLE ' . $tabname . $this->addCol . ' '; + foreach($lines as $v) { + if (($not_null = preg_match('/NOT NULL/i',$v))) { + $v = preg_replace('/NOT NULL/i','',$v); + } + if (preg_match('/^([^ ]+) .*(DEFAULT [^ ]+)/',$v,$matches)) { + list(,$colname,$default) = $matches; + $sql[] = $alter . str_replace($default,'',$v); + $sql[] = 'ALTER TABLE '.$tabname.' ALTER COLUMN '.$colname.' SET ' . $default; + } else { + $sql[] = $alter . $v; + } + if ($not_null) { + list($colname) = explode(' ',$v); + $sql[] = 'ALTER TABLE '.$tabname.' ALTER COLUMN '.$colname.' SET NOT NULL'; + } + } + return $sql; + } + + function AlterColumnSQL($tabname, $flds, $tableflds='',$tableoptions='') + { + if (!$tableflds) { + if ($this->debug) $this->outp("AlterColumnSQL needs a complete table-definiton for PostgreSQL"); + return array(); + } + return $this->_recreate_copy_table($tabname,False,$tableflds,$tableoptions); + } + + function DropColumnSQL($tabname, $flds, $tableflds='',$tableoptions='') + { + $has_drop_column = 7.3 <= (float) @$this->serverInfo['version']; + if (!$has_drop_column && !$tableflds) { + if ($this->debug) $this->outp("DropColumnSQL needs complete table-definiton for PostgreSQL < 7.3"); + return array(); + } + if ($has_drop_column) { + return ADODB_DataDict::DropColumnSQL($tabname, $flds); + } + return $this->_recreate_copy_table($tabname,$flds,$tableflds,$tableoptions); + } + + function DropTableSQL($tabname) + { + $sql = ADODB_DataDict::DropTableSQL($tabname); + $drop_seq = $this->_DropAutoIncrement($tabname); + if ($drop_seq) $sql[] = $drop_seq; + return $sql; + } + + function _CreateSuffix($fname, &$ftype, $fnotnull,$fdefault,$fautoinc,$fconstraint) + { + if ($fautoinc) { + $ftype = 'SERIAL'; + return ''; + } + $suffix = ''; + if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault"; + if ($fnotnull) $suffix .= ' NOT NULL'; + if ($fconstraint) $suffix .= ' '.$fconstraint; + return $suffix; + } + + function _DropAutoIncrement($tabname) + { + $tabname = $this->connection->qstr('%'.$tabname.'%'); + + $seq = $this->connection->GetOne("SELECT relname FROM pg_class WHERE NOT relname ~ 'pg_.*' AND relname LIKE $tabname AND relkind='S'"); + + // check if a tables depends on the sequenz and it therefor cant and dont need to be droped separatly + if (!$seq || $this->connection->GetOne("SELECT relname FROM pg_class JOIN pg_depend ON pg_class.relfilenode=pg_depend.objid WHERE relname='$seq' AND relkind='S' AND deptype='i'")) { + return False; + } + return "DROP SEQUENCE ".$seq; + } + + function _IndexSQL($idxname, $tabname, $flds, $idxoptions) + { + $sql = array(); + if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) { + $sql[] = sprintf ($this->dropIndex, $idxname, $tabname); + if ( isset($idxoptions['DROP']) ) + return $sql; + } + if ( empty ($flds) ) { + return $sql; + } + + $unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : ''; + $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' '; + if (isset($idxoptions['HASH'])) + $s .= 'USING HASH '; + + if ( isset($idxoptions[$this->upperName]) ) + $s .= $idxoptions[$this->upperName]; + + if ( is_array($flds) ) + $flds = implode(', ',$flds); + $s .= '(' . $flds . ')'; + $sql[] = $s; + return $sql; + } + + + function _recreate_copy_table($tabname,$dropflds,$tableflds,$tableoptions='') + { + if ($dropflds && !is_array($dropflds)) $dropflds = explode(',',$dropflds); + $copyflds = array(); + foreach($this->MetaColumns($tabname) as $fld) { + if (!$dropflds || !in_array($fld->name,$dropflds)) { + // we need to explicit convert varchar to a number to be able to do an AlterColumn of a char column to a nummeric one + if (preg_match('/'.$fld->name.' (I|I2|I4|I8|N|F)/i',$tableflds,$matches) && + in_array($fld->type,array('varchar','char','text','bytea'))) { + $copyflds[] = "to_number($fld->name,'S99D99')"; + } else { + $copyflds[] = $fld->name; + } + // identify the sequence name and the fld its on + if ($fld->primary_key && $fld->has_default && + preg_match("/nextval\('([^']+)'::text\)/",$fld->default_value,$matches)) { + $seq_name = $matches[1]; + $seq_fld = $fld->name; + } + } + } + $copyflds = implode(', ',$copyflds); + + $tempname = $tabname.'_tmp'; + $aSql[] = 'BEGIN'; // we use a transaction, to make sure not to loose the content of the table + $aSql[] = "SELECT * INTO TEMPORARY TABLE $tempname FROM $tabname"; + $aSql = array_merge($aSql,$this->DropTableSQL($tabname)); + $aSql = array_merge($aSql,$this->CreateTableSQL($tabname,$tableflds,$tableoptions)); + $aSql[] = "INSERT INTO $tabname SELECT $copyflds FROM $tempname"; + if ($seq_name && $seq_fld) { // if we have a sequence we need to set it again + $seq_name = $tabname.'_'.$seq_fld.'_seq'; // has to be the name of the new implicit sequence + $aSql[] = "SELECT setval('$seq_name',MAX($seq_fld)) FROM $tabname"; + } + $aSql[] = "DROP TABLE $tempname"; + // recreate the indexes, if they not contain one of the droped columns + foreach($this->MetaIndexes($tabname) as $idx_name => $idx_data) + { + if (substr($idx_name,-5) != '_pkey' && (!$dropflds || !count(array_intersect($dropflds,$idx_data['columns'])))) { + $aSql = array_merge($aSql,$this->CreateIndexSQL($idx_name,$tabname,$idx_data['columns'], + $idx_data['unique'] ? array('UNIQUE') : False)); + } + } + $aSql[] = 'COMMIT'; + return $aSql; + } +} + +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/postgres64/postgres64_date_module.inc b/lib/adodb/adodbSQL_drivers/postgres64/postgres64_date_module.inc new file mode 100644 index 0000000..cd6a4a0 --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/postgres64/postgres64_date_module.inc @@ -0,0 +1,316 @@ +_Execute("select $this->sysTimeStamp"); + if ($rs && !$rs->EOF) + return $this->UnixTimeStamp(reset($rs->fields)); + + return false; + } + + function OffsetDate($dayFraction, $date=false) + { + if (!$date) + $date = $this->sysDate; + else if (strncmp($date,"'",1) == 0) { + $len = strlen($date); + if (10 <= $len && $len <= 12) + $date = 'date ' . $date; + else $date = 'timestamp ' . $date; + } + return "($date+interval'$dayFraction days')"; + } + + function SetDateLocale($locale = 'En') + { + $this->locale = $locale; + switch (strtoupper($locale)) + { + case 'EN': + $this->fmtDate="'Y-m-d'"; + $this->fmtTimeStamp = "'Y-m-d H:i:s'"; + break; + + case 'US': + $this->fmtDate = "'m-d-Y'"; + $this->fmtTimeStamp = "'m-d-Y H:i:s'"; + break; + + case 'NL': + case 'FR': + case 'RO': + case 'IT': + $this->fmtDate="'d-m-Y'"; + $this->fmtTimeStamp = "'d-m-Y H:i:s'"; + break; + + case 'GE': + $this->fmtDate="'d.m.Y'"; + $this->fmtTimeStamp = "'d.m.Y H:i:s'"; + break; + + default: + $this->fmtDate="'Y-m-d'"; + $this->fmtTimeStamp = "'Y-m-d H:i:s'"; + break; + } + } + + function DBDate($date) + { + if (empty($date) && $date !== 0) + return 'null'; + + if (is_string($date) && !is_numeric($date)) { + if ($date === 'null' || strncmp($date, "'", 1) === 0) + return $date; + + if ($this->isoDates) + return "'$date'"; + + $date = $this->UnixDate($date); + } + + return adodb_date($this->fmtDate,$date); + } + + function DBTimeStamp($timestamp) + { + if (empty($timestamp) && $timestamp !== 0) + return 'null'; + + # strlen(14) allows YYYYMMDDHHMMSS format + if (!is_string($timestamp) || (is_numeric($timestamp) && strlen($timestamp)<14)) + return adodb_date($this->fmtTimeStamp, $timestamp); + + if ($timestamp === 'null') + return $timestamp; + + if ($this->isoDates && strlen($timestamp) !== 14) + return "'$timestamp'"; + + $timestamp = $this->UnixTimeStamp($timestamp); + return adodb_date($this->fmtTimeStamp, $timestamp); + } + + function UnixDate($v) + { + if (is_object($v)) { + // odbtp support + //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 ) + return adodb_mktime($v->hour, $v->minute, $v->second, $v->month, $v->day, $v->year); + } + + if (is_numeric($v) && strlen($v) !== 8) + return $v; + + if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", ($v), $rr)) + return false; + + if ($rr[1] <= TIMESTAMP_FIRST_YEAR) + return 0; + + // h-m-s-MM-DD-YY + return adodb_mktime(0, 0, 0, $rr[2], $rr[3], $rr[1]); + } + + function UnixTimeStamp($v) + { + if (is_object($v)) { + // odbtp support + //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 ) + return adodb_mktime($v->hour, $v->minute, $v->second, $v->month, $v->day, $v->year); + } + + if (!preg_match("|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ ,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", ($v), $rr)) + return false; + + if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) + return 0; + + // h-m-s-MM-DD-YY + if (!isset($rr[5])) + return adodb_mktime(0, 0, 0, $rr[2], $rr[3], $rr[1]); + else return adodb_mktime($rr[5], $rr[6], $rr[7], $rr[2], $rr[3], $rr[1]); + } + + function UserDate($v, $fmt='Y-m-d', $gmt=false) + { + $tt = $this->UnixDate($v); + + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + else if ($tt == 0) + return $this->emptyDate; + else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR + } + + return ($gmt) ? adodb_gmdate($fmt, $tt) : adodb_date($fmt, $tt); + } + + function UserTimeStamp($v, $fmt='Y-m-d H:i:s', $gmt=false) + { + if (!isset($v)) + return $this->emptyTimeStamp; + + # strlen(14) allows YYYYMMDDHHMMSS format + if (is_numeric($v) && strlen($v)<14) + return ($gmt) ? adodb_gmdate($fmt,$v) : adodb_date($fmt,$v); + + $tt = $this->UnixTimeStamp($v); + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + + if ($tt == 0) + return $this->emptyTimeStamp; + else return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt); + } + + function SQLDate($fmt, $col=false) + { + if (!$col) + $col = $this->sysTimeStamp; + + $s = 'TO_CHAR('.$col.",'"; + $len = strlen($fmt); + for ($i=0; $i < $len; $i++) { + $ch = $fmt[$i]; + switch($ch) { + case 'Y': + case 'y': + $s .= 'YYYY'; + break; + + case 'Q': + case 'q': + $s .= 'Q'; + break; + + case 'M': + $s .= 'Mon'; + break; + + case 'm': + $s .= 'MM'; + break; + + case 'D': + case 'd': + $s .= 'DD'; + break; + + case 'H': + $s.= 'HH24'; + break; + + case 'h': + $s .= 'HH'; + break; + + case 'i': + $s .= 'MI'; + break; + + case 's': + $s .= 'SS'; + break; + + case 'a': + case 'A': + $s .= 'AM'; + break; + + case 'w': + $s .= 'D'; + break; + + case 'l': + $s .= 'DAY'; + break; + + default: + // handle escape characters... + if ($ch == '\\') { + $i++; + $ch = substr($fmt,$i,1); + } + if (strpos('-/.:;, ',$ch) !== false) + $s .= $ch; + else $s .= '"'.$ch.'"'; + } + } + return $s. "')"; + } +} + +eval('class postgres64_date_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class postgres64_date_ResultSet extends postgres64_date_resultset_EXTENDER +{ + var $emptyTimeStamp = ' '; /// what to display when $time==0 + var $emptyDate = ' '; /// what to display when $time==0 + var $datetime = false; + + function UserTimeStamp($v, $fmt='Y-m-d H:i:s') + { + if (is_numeric($v) && strlen($v)<14) + return adodb_date($fmt,$v); + + $tt = $this->UnixTimeStamp($v); + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + + if ($tt === 0) + return $this->emptyTimeStamp; + else return adodb_date($fmt,$tt); + } + + function UserDate($v,$fmt='Y-m-d') + { + $tt = $this->UnixDate($v); + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + else if ($tt == 0) + return $this->emptyDate; + else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR + } + return adodb_date($fmt,$tt); + } + + function UnixDate($v) + { + return postgres64_date_ADOConnection::UnixDate($v); + } + + function UnixTimeStamp($v) + { + return postgres64_date_ADOConnection::UnixTimeStamp($v); + } + +} +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/postgres64/postgres64_driver.inc b/lib/adodb/adodbSQL_drivers/postgres64/postgres64_driver.inc new file mode 100644 index 0000000..fa90c93 --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/postgres64/postgres64_driver.inc @@ -0,0 +1,659 @@ +dbtype = 'postgres64'; + $this->dataProvider = 'postgres'; + } + + /** + * Connection to database server and selected database + * + * @access private + */ + + function _connect($host = "", $username = "", $password = "", $database = "", $persistent, $forcenew) + { + if (!function_exists('pg_connect')) return false; + + $this->host = $host; + $this->username = $this->query_addslashes($username); + $this->password = $this->query_addslashes($password); + if (strlen($database) == 0) $database = 'template1'; + $this->database = $this->query_addslashes($database); + + if ($this->username || $this->password || $this->database) { + $this->connect_string = $this->host; + if ($this->connect_string) { + $host = split(":", $this->connect_string); + if ($host[0]) $this->connect_string = "host=" . $this->query_addslashes($host[0]); + else $this->connect_string = 'host=localhost'; + if (isset($host[1])) $this->connect_string .= " port=$host[1]"; + else if (!empty($this->port)) $this->connect_string .= " port=" . $this->port; + } + if ($this->username) $this->connect_string .= " user=" . $this->username; + if ($this->password) $this->connect_string .= " password=" . $this->password; + if ($this->database) $this->connect_string .= " dbname=" . $this->database; + } + else + { + $this->connect_string = $this->host; + } + + $this->persistent = $persistent; + $this->forcenewconnection = $forcenew; + + $this->_makeconnection(); + + if ($this->connectionId === false) + { + if ($fn = $this->raiseErrorFn) + $fn($this->dbtype, 'CONNECT', $this->ErrorNo(), $this->ErrorMsg(), $this->host, $this->database, $this); + return $this->SelectDB( $this->database ); + } + + return true; + } + + function _makeconnection() + { + if($this->persistent == 1) + { + $this->connectionId = @pg_pconnect( $this->connect_string ); + } + else + { + if(!$this->forcenewconnection) + { + $this->connectionId = @pg_connect( $this->connect_string ); + } + else + { + $this->connectionId = @pg_connect( $this->connect_string, PGSQL_CONNECT_FORCE_NEW ); + } + } + } + + function query_addslashes($query) + { + $len = strlen($query); + if ($len == 0) + return "''"; + if (strncmp($query,"'",1) === 0 && substr($query,$len-1) == "'") + return $s; + return "'".addslashes($query)."'"; + } + + /** + * Choose a database to connect. + * + * @param dbname is the name of the database to select + * @return true or false + * @access public + */ + + function SelectDB($dbname) + { + $this->database = $dbname; + + if ($this->connectionId === false) + { + if($this->createdatabase == true) + { + $this->connectionId = @pg_pconnect( "host=$this->host user=$this->username password=$this->password" ); + $result = @pg_query($this->connectionId, "CREATE DATABASE " . $this->database ); + if ($result === false) { // error handling if query fails + $this->connectionId = false; + return false; + } + + $this->_makeconnection(); + if($this->connectionId === false) + { + $this->connectionId = false; + return false; + } + else + { + return true; + } + } + $this->connectionId = false; + return false; + } + else + { + return true; + } + } + + /** + * Return database error message + * Usage: $errormessage =& $db->ErrorMsg(); + * + * @access public + */ + + function ErrorMsg() + { + return @pg_last_error($this->connectionId); + } + + /** + * Return database error number + * Usage: $errorbo =& $db->ErrorNo(); + * + * @access public + */ + + function ErrorNo() + { + $error = @pg_last_error( $this->connectionId ); + return strlen($error) ? $error : 0; + } + + /** + * Returns # of affected rows from insert/delete/update query + * + * @access public + * @return integer Affected rows + */ + + function Affected_Rows() + { + return @pg_affected_rows($this->record_set); + } + + /** + * Returns the last record id of an inserted item + * Usage: $db->Insert_ID(); + * + * @access public + */ + + function Insert_ID() + { + return @pg_getlastoid($this->record_set); + } + + /** + * Correctly quotes a string so that all strings are escape coded. + * An example is $db->qstr("Haven't a clue."); + * + * @param string the string to quote + * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc(). + * + * @return single-quoted string IE: 'Haven\'t a clue.' + */ + + function qstr($string, $magic_quotes=false) + { + // Ugly hack alert! Repalce backticks with some arbitrary character + $string = str_replace('`', "\x1C", $string); + if (!$magic_quotes) { + $string = str_replace("'", "\\'", str_replace('\\', '\\\\', str_replace("\0", "\\\0", $string))); + return "'" . $string . "'"; + } + return "'" . str_replace('\\"', '"', $string) . "'"; + } + + function QMagic($string) + { + return $this->qstr($string, get_magic_quotes_gpc()); + } + + /** + * Returns concatenated string + * Usage: $db->Concat($str1,$str2); + * + * @return concatenated string + */ + function Concat() + { + $arr = func_get_args(); + return implode("||", $arr); + } + + function IfNull( $field, $ifNull ) + { + return " coalesce($field, $ifNull) "; + } + + /** + * Closes database connection + * Usage: $db->close(); + * + * @access public + */ + + function Close() + { + @pg_close( $this->connectionId ); + $this->connectionId = false; + } + + /** + * Returns All Records in an array + * + * Usage: $db->GetAll($sql); + * @access public + */ + + function &GetAll($sql, $inputarr = false) + { + $data =& $this->GetArray($sql, $inputarr); + return $data; + } + + /** + * Returns All Records in an array + * + * Usage: $db->GetArray($sql); + * @access public + */ + + function &GetArray($sql, $inputarr = false) + { + $data = false; + $result =& $this->Execute($sql, $inputarr); + if ($result) + { + $data =& $result->GetArray(); + $result->Close(); + } + return $data; + } + + /** + * Executes SQL query and instantiates resultset methods + * + * @access private + * @return mixed Resultset methods + */ + + function &do_query( $sql, $offset, $nrows, $inputarr=false ) + { + global $ADODB_FETCH_MODE; + $sql = str_replace('`', '"', $sql); + $sql = str_replace("\x1C", "`", $sql); + $sql = str_replace('IS_DELETED', 'is_deleted', $sql); + $sql = str_replace("HIGH_PRIORITY", "", $sql); + $false = false; + +// $limit = ''; +// if ($offset != -1 || $nrows != -1) +// { +// $offset = ($offset>=0) ? $offset . "," : ''; +// $limit = ' LIMIT ' . $offset . ' ' . $nrows; +// } + + if ($inputarr && is_array($inputarr)) { + $sqlarr = explode('?', $sql); + if (!is_array(reset($inputarr))) $inputarr = array($inputarr); + foreach($inputarr as $arr) { + $sql = ''; $i = 0; + foreach($arr as $v) { + $sql .= $sqlarr[$i]; + switch(gettype($v)){ + case 'string': + $sql .= $this->qstr($v); + break; + case 'double': + $sql .= str_replace(',', '.', $v); + break; + case 'boolean': + $sql .= $v ? "'t'" : "'f'"; + break; + default: + if ($v === null) + $sql .= 'NULL'; + else $sql .= $v; + } + $i += 1; + } + $sql .= $sqlarr[$i]; + if ($i+1 != sizeof($sqlarr)) + return $false; + $this->sql = $sql; + $time_start = array_sum(explode(' ', microtime())); + $this->query_count++; + $resultId = @pg_query( $this->sql ); + $time_total = (array_sum(explode(' ', microtime())) - $time_start); + $this->query_time_total += $time_total; + if($this->debug_console) + { + $this->query_list[] = $this->sql; + $this->query_list_time[] = $time_total; + $this->query_list_errors[] = $this->ErrorMsg(); + } + if($this->debug) + { + $this->outp($sql); + } + if ($resultId === false) { // error handling if query fails + if ($fn = $this->raiseErrorFn) + $fn($this->dbtype, 'EXECUTE', $this->ErrorNo(), $this->ErrorMsg(), $this->sql, $inputarr, $this); + return $false; + } + } + } + else + { + $this->sql = $sql; + $time_start = array_sum(explode(' ', microtime())); + $this->query_count++; + $resultId = @pg_query( $this->sql); + $time_total = (array_sum(explode(' ', microtime())) - $time_start); + $this->query_time_total += $time_total; + if($this->debug_console) + { + $this->query_list[] = $this->sql; + $this->query_list_time[] = $time_total; + $this->query_list_errors[] = $this->ErrorMsg(); + } + if($this->debug) + { + $this->outp($sql); + } + } + + if ($resultId === false) { // error handling if query fails + if ($fn = $this->raiseErrorFn) + $fn($this->dbtype, 'EXECUTE', $this->ErrorNo(), $this->ErrorMsg(), $this->sql, $inputarr, $this); + return $false; + } + + if (@pg_numfields( $resultId ) <= 0) { // return simplified recordset for inserts/updates/deletes with lower overhead + $recordset = new ADORecordSet_empty(); + $this->record_set = $recordset; + return $recordset; + } + + $resultset_name = $this->last_module_name . "_ResultSet"; + $recordset = new $resultset_name( $resultId, $this->connectionId ); + $this->record_set = $recordset; + + $recordset->_currentRow = 0; + + switch ($ADODB_FETCH_MODE) + { + case ADODB_FETCH_NUM: $recordset->fetchMode = PGSQL_NUM; break; + case ADODB_FETCH_ASSOC:$recordset->fetchMode = PGSQL_ASSOC; break; + default: + case ADODB_FETCH_DEFAULT: + case ADODB_FETCH_BOTH:$recordset->fetchMode = PGSQL_BOTH; break; + } + + $recordset->_numOfRows = @pg_numrows( $resultId ); + if( $recordset->_numOfRows == 0) + { + $recordset->EOF = true; + } + $recordset->_numOfFields = @pg_numfields( $resultId ); + $recordset->_fetch(); + + return $recordset; + } +} + +class postgres64_driver_ResultSet +{ + var $connectionId; + var $fields; + var $resultId; + var $_currentRow = 0; + var $_numOfRows = -1; + var $_numOfFields = -1; + var $fetchMode; + var $EOF; + + /** + * pgsqlResultSet Constructor + * + * @access private + * @param string $record + * @param string $resultId + */ + + function postgres64_driver_ResultSet( $resultId, $connectionId ) + { + $this->fields = array(); + $this->connectionId = $connectionId; + $this->record = array(); + $this->resultId = $resultId; + $this->EOF = false; + } + + /** + * Frees resultset + * + * @access public + */ + + function Close() + { + pg_free_result( $this->resultId ); + $this->fields = array(); + $this->resultId = false; + } + + /** + * Returns field name from select query + * + * @access public + * @param string $field + * @return string Field name + */ + + function fields( $field ) + { + if(empty($field)) + { + return $this->fields; + } + else + { + return $this->fields[$field]; + } + } + + /** + * Returns numrows from select query + * + * @access public + * @return integer Numrows + */ + + function RecordCount() + { + return $this->_numOfRows; + } + + /** + * Returns num of fields from select query + * + * @access public + * @return integer numfields + */ + + function FieldCount() + { + return $this->_numOfFields; + } + + /** + * Returns next record + * + * @access public + */ + + function MoveNext() + { + if (@$this->fields = pg_fetch_array($this->resultId, NULL, $this->fetchMode)) { + $this->_currentRow += 1; + return true; + } + if (!$this->EOF) { + $this->_currentRow += 1; + $this->EOF = true; + } + return false; + } + + /** + * Move to the first row in the recordset. Many databases do NOT support this. + * + * @return true or false + */ + + function MoveFirst() + { + if ($this->_currentRow == 0) return true; + return $this->Move(0); + } + + /** + * Returns the Last Record + * + * @access public + */ + + function MoveLast() + { + if ($this->EOF) return false; + return $this->Move($this->_numOfRows - 1); + } + + /** + * Random access to a specific row in the recordset. Some databases do not support + * access to previous rows in the databases (no scrolling backwards). + * + * @param rowNumber is the row to move to (0-based) + * + * @return true if there still rows available, or false if there are no more rows (EOF). + */ + + function Move($rowNumber = 0) + { + if ($rowNumber == $this->_currentRow) return true; + $this->EOF = false; + if ($this->_numOfRows > 0){ + if ($rowNumber >= $this->_numOfRows - 1){ + $rowNumber = $this->_numOfRows - 1; + } + } + + if ($this->_seek($rowNumber)) { + $this->_currentRow = $rowNumber; + if ($this->_fetch()) { + return true; + } + $this->fields = false; + } + $this->EOF = true; + return false; + } + + /** + * Perform Seek to specific row + * + * @access private + */ + + function _seek($row) + { + if ($this->_numOfRows == 0) return false; + return @pg_result_seek($this->resultId,$row); + } + + /** + * Fills field array with first database element when query initially executed + * + * @access private + */ + + function _fetch() + { + $this->fields = @pg_fetch_array($this->resultId, NULL, $this->fetchMode); + return is_array($this->fields); + } + + /** + * Check to see if last record reached + * + * @access public + */ + + function EOF() + { + if( $this->_currentRow < $this->_numOfRows) + { + return false; + } + else + { + $this->EOF = true; + return true; + } + } + + /** + * Returns All Records in an array + * + * @access public + * @param [nRows] is the number of rows to return. -1 means every row. + */ + + function &GetArray($nRows = -1) + { + $results = array(); + $cnt = 0; + while (!$this->EOF && $nRows != $cnt) { + $results[] = $this->fields; + $this->MoveNext(); + $cnt++; + } + return $results; + } + + function &GetRows($nRows = -1) + { + $arr =& $this->GetArray($nRows); + return $arr; + } + + function &GetAll($nRows = -1) + { + $arr =& $this->GetArray($nRows); + return $arr; + } + + /** + * Fetch field information for a table. + * + * @return object containing the name, type and max_length + */ + function FetchField($fieldOffset = -1) + { + $fieldObject= new ADOFieldObject(); + $fieldObject->name = @pg_fieldname($this->resultId, $fieldOffset); + $fieldObject->type = @pg_fieldtype($this->resultId, $fieldOffset); + $fieldObject->max_length = @pg_fieldsize($this->resultId, $fieldOffset); + return $fieldObject; + } +} +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/postgres64/postgres64_extend_module.inc b/lib/adodb/adodbSQL_drivers/postgres64/postgres64_extend_module.inc new file mode 100644 index 0000000..4130663 --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/postgres64/postgres64_extend_module.inc @@ -0,0 +1,147 @@ +Execute($sql, $inputarr); + if ($result) { + $data =& $result->GetAssoc($force_array, $first2cols); + $result->Close(); + } + return $data; + } + + /** + * Generates a sequence id and stores it in $this->genID; + * GenID is only available if $this->hasGenID = true; + * + * @param seqname name of sequence to use + * @param startID if sequence does not exist, start at this ID + * @return 0 if not supported, otherwise a sequence id + */ + + var $_genIDSQL = "SELECT NEXTVAL('%s')"; + var $_genSeqSQL = "CREATE SEQUENCE %s START %s"; + var $_dropSeqSQL = "DROP SEQUENCE %s"; + var $genID = 0; + + function GenID($seqname='adodbseq', $startID=1) + { + $getnext = sprintf($this->_genIDSQL, $seqname); + $holdtransOK = $this->transaction_status; + $save_handler = $this->raiseErrorFn; + $this->raiseErrorFn = ''; + @($result = $this->Execute($getnext)); + $this->raiseErrorFn = $save_handler; + + if (!$result) { + $this->transaction_status = $holdtransOK; + $createseq = $this->Execute(sprintf($this->_genSeqSQL, $seqname, $startID)); + $result = $this->Execute($getnext); + } + if ($result && !$result->EOF) + $this->genID = reset($result->fields); + else $this->genID = 0; + + if ($result) + $result->Close(); + + return $this->genID; + } + + function CreateSequence($seqname='adodbseq', $startID=1) + { + return $this->Execute(sprintf($this->_genSeqSQL, $seqname, $startID)); + } + + function DropSequence($seqname='adodbseq') + { + return $this->Execute(sprintf($this->_dropSeqSQL, $seqname)); + } + +} + +eval('class postgres64_extend_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class postgres64_extend_ResultSet extends postgres64_extend_resultset_EXTENDER +{ + function &GetAssoc($force_array = false, $first2cols = false) + { + $results = false; + + if ($this->_numOfFields > 1) { + $numIndex = isset($this->fields[0]); + $results = array(); + if (!$first2cols && ($this->_numOfFields > 2 || $force_array)) { + if ($numIndex) { + while (!$this->EOF) { + $results[trim($this->fields[0])] = array_slice($this->fields, 1); + $this->MoveNext(); + } + } else { + while (!$this->EOF) { + $results[trim(reset($this->fields))] = array_slice($this->fields, 1); + $this->MoveNext(); + } + } + } else { + if ($numIndex) { + while (!$this->EOF) { + $results[trim(($this->fields[0]))] = $this->fields[1]; + $this->MoveNext(); + } + } else { + while (!$this->EOF) { + $v1 = trim(reset($this->fields)); + $v2 = ''.next($this->fields); + $results[$v1] = $v2; + $this->MoveNext(); + } + } + } + } + return $results; + } + + function PO_RecordCount($table="", $condition="") + { + $lnumrows = $this->_numOfRows; + if($lnumrows == -1 && $this->connectionId) + { + if($table) + { + if ($condition) + $condition = " WHERE " . $condition; + $resultrows = &$this->connectionId->Execute("SELECT COUNT(*) FROM $table $condition"); + if ($resultrows) + $lnumrows = reset($resultrows->fields); + } + } + return $lnumrows; + } + + function CurrentRow() + { + return $this->_currentRow; + } + + function AbsolutePosition() + { + return $this->_currentRow; + } + + function NextRecordSet() + { + return false; + } + +} +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/postgres64/postgres64_meta_module.inc b/lib/adodb/adodbSQL_drivers/postgres64/postgres64_meta_module.inc new file mode 100644 index 0000000..02ac70f --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/postgres64/postgres64_meta_module.inc @@ -0,0 +1,684 @@ + 0 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum"; + + // used when schema defined + var $metaColumnsSQL1 = "SELECT a.attname, t.typname, a.attlen, a.atttypmod, a.attnotnull, a.atthasdef, a.attnum +FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n +WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s')) + and c.relnamespace=n.oid and n.nspname='%s' + and a.attname not like '....%%' AND a.attnum > 0 + AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum"; + + // get primary key etc -- from Freek Dijkstra + var $metaKeySQL = "SELECT ic.relname AS index_name, a.attname AS column_name,i.indisunique AS unique_key, i.indisprimary AS primary_key + FROM pg_class bc, pg_class ic, pg_index i, pg_attribute a WHERE bc.oid = i.indrelid AND ic.oid = i.indexrelid AND (i.indkey[0] = a.attnum OR i.indkey[1] = a.attnum OR i.indkey[2] = a.attnum OR i.indkey[3] = a.attnum OR i.indkey[4] = a.attnum OR i.indkey[5] = a.attnum OR i.indkey[6] = a.attnum OR i.indkey[7] = a.attnum) AND a.attrelid = bc.oid AND bc.relname = '%s'"; + var $metaDefaultsSQL = "SELECT d.adnum as num, d.adsrc as def from pg_attrdef d, pg_class c where d.adrelid=c.oid and c.relname='%s' order by d.adnum"; + + function MetaError($err=false) + { + include_once(ADODB_DIR."/adodb-error.inc.php"); + if ($err === false) + $err = $this->ErrorNo(); + + return adodb_error($this->dataProvider,$this->databaseType,$err); + } + + function MetaErrorMsg($errno) + { + include_once(ADODB_DIR."/adodb-error.inc.php"); + return adodb_errormsg($errno); + } + + /** + * @returns an array with the primary key columns in it. + */ + function MetaPrimaryKeys($table, $owner=false) + { + // owner not used in base class - see oci8 + $p = array(); + $objs =& $this->MetaColumns($table); + if ($objs) { + foreach($objs as $v) { + if (!empty($v->primary_key)) + $p[] = $v->name; + } + } + if (sizeof($p)) return $p; + if (function_exists('ADODB_VIEW_PRIMARYKEYS')) + return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner); + return false; + } + + /** + * @returns assoc array where keys are tables, and values are foreign keys + */ + function MetaForeignKeys($table, $owner=false, $upper=false) + { + return false; + } + + // not the fastest implementation - quick and dirty - jlim + // for best performance, use the actual $rs->MetaType(). + function MetaType($t,$len=-1,$fieldobj=false) + { + if (empty($this->_metars)) { + $rsclass = $this->last_module_name . "_ResultSet"; + $this->_metars =& new $rsclass(false,$this->fetchMode); + } + + return $this->_metars->MetaType($t,$len,$fieldobj); + } + + /** + * return the databases that the driver can connect to. + * Some databases will return an empty array. + * + * @return an array of database names. + */ + function MetaDatabases() + { + global $ADODB_FETCH_MODE; + + if ($this->metaDatabasesSQL) { + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + + $arr = $this->GetCol($this->metaDatabasesSQL); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + return $arr; + } + + return false; + } + + /** + * @param ttype can either be 'VIEW' or 'TABLE' or false. + * If false, both views and tables are returned. + * "VIEW" returns only views + * "TABLE" returns only tables + * @param showSchema returns the schema/user with the table name, eg. USER.TABLE + * @param mask is the input mask - only supported by oci8 and postgresql + * + * @return array of tables for current database. + */ + function &MetaTables($ttype=false,$showSchema=false,$mask=false) + { + $info = $this->ServerInfo(); + if ($info['version'] >= 7.3) { + $this->metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%' + and schemaname not in ( 'pg_catalog','information_schema') + union + select viewname,'V' from pg_views where viewname not like 'pg\_%' and schemaname not in ( 'pg_catalog','information_schema') "; + } + if ($mask) { + $save = $this->metaTablesSQL; + $mask = $this->qstr(strtolower($mask)); + if ($info['version']>=7.3) + $this->metaTablesSQL = " +select tablename,'T' from pg_tables where tablename like $mask and schemaname not in ( 'pg_catalog','information_schema') + union +select viewname,'V' from pg_views where viewname like $mask and schemaname not in ( 'pg_catalog','information_schema') "; + else + $this->metaTablesSQL = " +select tablename,'T' from pg_tables where tablename like $mask + union +select viewname,'V' from pg_views where viewname like $mask"; + } + $ret =& $this->_MetaTables($ttype,$showSchema); + + if ($mask) { + $this->metaTablesSQL = $save; + } + return $ret; + } + + function &_MetaTables($ttype=false,$showSchema=false,$mask=false) + { + global $ADODB_FETCH_MODE; + + $false = false; + if ($mask) { + return $false; + } + if ($this->metaTablesSQL) { + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + + $rs = $this->Execute($this->metaTablesSQL); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if ($rs === false) return $false; + $arr =& $rs->GetArray(); + $arr2 = array(); + + if ($hast = ($ttype && isset($arr[0][1]))) { + $showt = strncmp($ttype,'T',1); + } + + for ($i=0; $i < sizeof($arr); $i++) { + if ($hast) { + if ($showt == 0) { + if (strncmp($arr[$i][1],'T',1) == 0) $arr2[] = trim($arr[$i][0]); + } else { + if (strncmp($arr[$i][1],'V',1) == 0) $arr2[] = trim($arr[$i][0]); + } + } else + $arr2[] = trim($arr[$i][0]); + } + $rs->Close(); + return $arr2; + } + return $false; + } + + function _findschema(&$table,&$schema) + { + if (!$schema && ($at = strpos($table,'.')) !== false) { + $schema = substr($table,0,$at); + $table = substr($table,$at+1); + } + } + + /** + * List columns in a database as an array of ADOFieldObjects. + * See top of file for definition of object. + * + * @param $table table name to query + * @param $normalize makes table name case-insensitive (required by some databases) + * @schema is optional database schema to use - not supported by all databases. + * + * @return array of ADOFieldObjects for current table. + */ + function &MetaColumns($table,$normalize=true) + { + global $ADODB_FETCH_MODE; + + $schema = false; + $false = false; + $this->_findschema($table,$schema); + + if ($normalize) $table = strtolower($table); + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + + if ($schema) $rs =& $this->Execute(sprintf($this->metaColumnsSQL1,$table,$table,$schema)); + else $rs =& $this->Execute(sprintf($this->metaColumnsSQL,$table,$table)); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if ($rs === false) { + return $false; + } + if (!empty($this->metaKeySQL)) { + // If we want the primary keys, we have to issue a separate query + // Of course, a modified version of the metaColumnsSQL query using a + // LEFT JOIN would have been much more elegant, but postgres does + // not support OUTER JOINS. So here is the clumsy way. + + $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; + + $rskey = $this->Execute(sprintf($this->metaKeySQL,($table))); + // fetch all result in once for performance. + $keys =& $rskey->GetArray(); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + $rskey->Close(); + unset($rskey); + } + + $rsdefa = array(); + if (!empty($this->metaDefaultsSQL)) { + $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; + $sql = sprintf($this->metaDefaultsSQL, ($table)); + $rsdef = $this->Execute($sql); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if ($rsdef) { + while (!$rsdef->EOF) { + $num = $rsdef->fields['num']; + $s = $rsdef->fields['def']; + if (strpos($s,'::')===false && substr($s, 0, 1) == "'") { /* quoted strings hack... for now... fixme */ + $s = substr($s, 1); + $s = substr($s, 0, strlen($s) - 1); + } + + $rsdefa[$num] = $s; + $rsdef->MoveNext(); + } + } else { + ADOConnection::outp( "==> SQL => " . $sql); + } + unset($rsdef); + } + + $retarr = array(); + while (!$rs->EOF) { + $fld = new ADOFieldObject(); + $fld->name = $rs->fields[0]; + $fld->type = $rs->fields[1]; + $fld->max_length = $rs->fields[2]; + $fld->attnum = $rs->fields[6]; + + if ($fld->max_length <= 0) $fld->max_length = $rs->fields[3]-4; + if ($fld->max_length <= 0) $fld->max_length = -1; + if ($fld->type == 'numeric') { + $fld->scale = $fld->max_length & 0xFFFF; + $fld->max_length >>= 16; + } + // dannym + // 5 hasdefault; 6 num-of-column + $fld->has_default = ($rs->fields[5] == 't'); + if ($fld->has_default) { + $fld->default_value = $rsdefa[$rs->fields[6]]; + } + + //Freek + $fld->not_null = $rs->fields[4] == 't'; + + + // Freek + if (is_array($keys)) { + foreach($keys as $key) { + if ($fld->name == $key['column_name'] AND $key['primary_key'] == 't') + $fld->primary_key = true; + if ($fld->name == $key['column_name'] AND $key['unique_key'] == 't') + $fld->unique = true; // What name is more compatible? + } + } + + if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld; + else $retarr[($normalize) ? strtoupper($fld->name) : $fld->name] = $fld; + + $rs->MoveNext(); + } + $rs->Close(); + if (empty($retarr)) + return $false; + else + return $retarr; + + } + + /** + * List indexes on a table as an array. + * @param table table name to query + * @param primary true to only show primary keys. Not actually used for most databases + * + * @return array of indexes on current table. Each element represents an index, and is itself an associative array. + + Array ( + [name_of_index] => Array + ( + [unique] => true or false + [columns] => Array + ( + [0] => firstname + [1] => lastname + ) + ) + */ + function &MetaIndexes ($table, $primary = FALSE) + { + global $ADODB_FETCH_MODE; + + $schema = false; + $this->_findschema($table,$schema); + + if ($schema) { // requires pgsql 7.3+ - pg_namespace used. + $sql = ' +SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns" +FROM pg_catalog.pg_class c +JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid +JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid + ,pg_namespace n +WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\')) and c.relnamespace=c2.relnamespace and c.relnamespace=n.oid and n.nspname=\'%s\''; + } else { + $sql = ' +SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns" +FROM pg_catalog.pg_class c +JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid +JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid +WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\'))'; + } + + if ($primary == FALSE) { + $sql .= ' AND i.indisprimary=false;'; + } + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== FALSE) { + $savem = $this->SetFetchMode(FALSE); + } + + $rs = $this->Execute(sprintf($sql,$table,$table,$schema)); + if (isset($savem)) { + $this->SetFetchMode($savem); + } + $ADODB_FETCH_MODE = $save; + + if (!is_object($rs)) { + $false = false; + return $false; + } + + $col_names = $this->MetaColumnNames($table,true,true); + //3rd param is use attnum, + // see http://sourceforge.net/tracker/index.php?func=detail&aid=1451245&group_id=42718&atid=433976 + $indexes = array(); + while ($row = $rs->FetchRow()) { + $columns = array(); + foreach (explode(' ', $row[2]) as $col) { + $columns[] = $col_names[$col]; + } + + $indexes[$row[0]] = array( + 'unique' => ($row[1] == 't'), + 'columns' => $columns + ); + } + return $indexes; + } + + /** + * List columns names in a table as an array. + * @param table table name to query + * + * @return array of column names for current table. + */ + function &MetaColumnNames($table, $numIndexes=false,$useattnum=false /* only for postgres */) + { + $objarr =& $this->MetaColumns($table); + if (!is_array($objarr)) { + $false = false; + return $false; + } + $arr = array(); + if ($numIndexes) { + $i = 0; + if ($useattnum) { + foreach($objarr as $v) + $arr[$v->attnum] = $v->name; + + } else + foreach($objarr as $v) $arr[$i++] = $v->name; + } else + foreach($objarr as $v) $arr[strtoupper($v->name)] = $v->name; + + return $arr; + } + + function MetaTransaction($mode,$db) + { + $mode = strtoupper($mode); + $mode = str_replace('ISOLATION LEVEL ','',$mode); + + switch($mode) { + + case 'READ UNCOMMITTED': + switch($db) { + case 'oci8': + case 'oracle': + return 'ISOLATION LEVEL READ COMMITTED'; + default: + return 'ISOLATION LEVEL READ UNCOMMITTED'; + } + break; + + case 'READ COMMITTED': + return 'ISOLATION LEVEL READ COMMITTED'; + break; + + case 'REPEATABLE READ': + switch($db) { + case 'oci8': + case 'oracle': + return 'ISOLATION LEVEL SERIALIZABLE'; + default: + return 'ISOLATION LEVEL REPEATABLE READ'; + } + break; + + case 'SERIALIZABLE': + return 'ISOLATION LEVEL SERIALIZABLE'; + break; + + default: + return $mode; + } + } + +} + +eval('class postgres64_meta_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class postgres64_meta_ResultSet extends postgres64_meta_resultset_EXTENDER +{ + /** + * Get the metatype of the column. This is used for formatting. This is because + * many databases use different names for the same type, so we transform the original + * type to our standardised version which uses 1 character codes: + * + * @param t is the type passed in. Normally is ADOFieldObject->type. + * @param len is the maximum length of that field. This is because we treat character + * fields bigger than a certain size as a 'B' (blob). + * @param fieldobj is the field object returned by the database driver. Can hold + * additional info (eg. primary_key for mysql). + * + * @return the general type of the data: + * C for character < 250 chars + * X for teXt (>= 250 chars) + * B for Binary + * N for numeric or floating point + * D for date + * T for timestamp + * L for logical/Boolean + * I for integer + * R for autoincrement counter/integer + * + * + */ + function MetaType($t,$len=-1,$fieldobj=false) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + $is_serial = is_object($fieldobj) && $fieldobj->primary_key && $fieldobj->unique && $fieldobj->has_default && substr($fieldobj->default_value,0,8) == 'nextval('; + switch (strtoupper($t)) { + case 'MONEY': // stupid, postgres expects money to be a string + case 'INTERVAL': + case 'CHAR': + case 'CHARACTER': + case 'VARCHAR': + case 'NAME': + case 'BPCHAR': + case '_VARCHAR': + case 'INET': + case 'MACADDR': + if ($len <= $this->blobSize) return 'C'; + case 'TEXT': + return 'X'; + case 'IMAGE': // user defined type + case 'BLOB': // user defined type + case 'BIT': // This is a bit string, not a single bit, so don't return 'L' + case 'VARBIT': + case 'BYTEA': + return 'B'; + case 'BOOL': + case 'BOOLEAN': + return 'L'; + case 'DATE': + return 'D'; + case 'TIMESTAMP WITHOUT TIME ZONE': + case 'TIME': + case 'DATETIME': + case 'TIMESTAMP': + case 'TIMESTAMPTZ': + return 'T'; + case 'INTEGER': return !$is_serial ? 'I' : 'R'; + case 'SMALLINT': + case 'INT2': return !$is_serial ? 'I2' : 'R'; + case 'INT4': return !$is_serial ? 'I4' : 'R'; + case 'BIGINT': + case 'INT8': return !$is_serial ? 'I8' : 'R'; + case 'OID': + case 'SERIAL': + return 'R'; + case 'FLOAT4': + case 'FLOAT8': + case 'DOUBLE PRECISION': + case 'REAL': + return 'F'; + default: + static $typeMap = array( + 'VARCHAR' => 'C', + 'VARCHAR2' => 'C', + 'CHAR' => 'C', + 'C' => 'C', + 'STRING' => 'C', + 'NCHAR' => 'C', + 'NVARCHAR' => 'C', + 'VARYING' => 'C', + 'BPCHAR' => 'C', + 'CHARACTER' => 'C', + 'INTERVAL' => 'C', # Postgres + 'MACADDR' => 'C', # postgres + ## + 'LONGCHAR' => 'X', + 'TEXT' => 'X', + 'NTEXT' => 'X', + 'M' => 'X', + 'X' => 'X', + 'CLOB' => 'X', + 'NCLOB' => 'X', + 'LVARCHAR' => 'X', + ## + 'BLOB' => 'B', + 'IMAGE' => 'B', + 'BINARY' => 'B', + 'VARBINARY' => 'B', + 'LONGBINARY' => 'B', + 'B' => 'B', + ## + 'YEAR' => 'D', // mysql + 'DATE' => 'D', + 'D' => 'D', + ## + 'UNIQUEIDENTIFIER' => 'C', # MS SQL Server + ## + 'TIME' => 'T', + 'TIMESTAMP' => 'T', + 'DATETIME' => 'T', + 'TIMESTAMPTZ' => 'T', + 'T' => 'T', + 'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql + ## + 'BOOL' => 'L', + 'BOOLEAN' => 'L', + 'BIT' => 'L', + 'L' => 'L', + ## + 'COUNTER' => 'R', + 'R' => 'R', + 'SERIAL' => 'R', // ifx + 'INT IDENTITY' => 'R', + ## + 'INT' => 'I', + 'INT2' => 'I', + 'INT4' => 'I', + 'INT8' => 'I', + 'INTEGER' => 'I', + 'INTEGER UNSIGNED' => 'I', + 'SHORT' => 'I', + 'TINYINT' => 'I', + 'SMALLINT' => 'I', + 'I' => 'I', + ## + 'LONG' => 'N', // interbase is numeric, oci8 is blob + 'BIGINT' => 'N', // this is bigger than PHP 32-bit integers + 'DECIMAL' => 'N', + 'DEC' => 'N', + 'REAL' => 'N', + 'DOUBLE' => 'N', + 'DOUBLE PRECISION' => 'N', + 'SMALLFLOAT' => 'N', + 'FLOAT' => 'N', + 'NUMBER' => 'N', + 'NUM' => 'N', + 'NUMERIC' => 'N', + 'MONEY' => 'N', + + ## informix 9.2 + 'SQLINT' => 'I', + 'SQLSERIAL' => 'I', + 'SQLSMINT' => 'I', + 'SQLSMFLOAT' => 'N', + 'SQLFLOAT' => 'N', + 'SQLMONEY' => 'N', + 'SQLDECIMAL' => 'N', + 'SQLDATE' => 'D', + 'SQLVCHAR' => 'C', + 'SQLCHAR' => 'C', + 'SQLDTIME' => 'T', + 'SQLINTERVAL' => 'N', + 'SQLBYTES' => 'B', + 'SQLTEXT' => 'X', + ## informix 10 + "SQLINT8" => 'I8', + "SQLSERIAL8" => 'I8', + "SQLNCHAR" => 'C', + "SQLNVCHAR" => 'C', + "SQLLVARCHAR" => 'X', + "SQLBOOL" => 'L' + ); + + $tmap = false; + $t = strtoupper($t); + $tmap = (isset($typeMap[$t])) ? $typeMap[$t] : 'N'; + if ($t == 'LONG' && $this->dataProvider == 'oci8') return 'B'; + return $tmap; + } + } + +} + +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/postgres64/postgres64_transaction_module.inc b/lib/adodb/adodbSQL_drivers/postgres64/postgres64_transaction_module.inc new file mode 100644 index 0000000..e398fa5 --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/postgres64/postgres64_transaction_module.inc @@ -0,0 +1,128 @@ +transOff > 0) { + $this->transOff += 1; + return; + } + $this->transaction_status = true; + + if ($this->debug && $this->transCnt > 0) + ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans"); + + $this->BeginTrans(); + $this->transOff = 1; + } + + function BeginTrans() + { + if ($this->transOff) + return true; + + $this->transCnt += 1; + return @pg_Exec($this->connectionId, "begin"); + } + + function CompleteTrans($autoComplete = true) + { + if ($this->transOff > 1) { + $this->transOff -= 1; + return true; + } + $this->transOff = 0; + if ($this->transaction_status && $autoComplete) { + if (!$this->CommitTrans()) { + $this->transaction_status = false; + if ($this->debug) + ADOConnection::outp("Smart Commit failed"); + } else + if ($this->debug) + ADOConnection::outp("Smart Commit occurred"); + } else { + $this->RollbackTrans(); + if ($this->debug) + ADOCOnnection::outp("Smart Rollback occurred"); + } + return $this->transaction_status; + } + + function CommitTrans($ok=true) + { + if ($this->transOff) + return true; + + if (!$ok) + return $this->RollbackTrans(); + + $this->transCnt -= 1; + return @pg_Exec($this->connectionId, "commit"); + } + + function RollbackTrans() + { + if ($this->transOff) + return true; + + $this->transCnt -= 1; + return @pg_Exec($this->connectionId, "rollback"); + } + + function FailTrans() + { + if ($this->debug) + if ($this->transOff == 0) { + ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans"); + } else { + ADOConnection::outp("FailTrans was called"); + } + $this->transaction_status = false; + } + + function HasFailedTrans() + { + if ($this->transOff > 0) + return $this->transaction_status == false; + + return false; + } + + function RowLock($tables,$where,$flds='1 as ignore') + { + if (!$this->transCnt) + $this->BeginTrans(); + + return $this->GetOne("select $flds from $tables where $where for update"); + } + + function CommitLock($table) + { + return $this->CommitTrans(); + } + + function RollbackLock($table) + { + return $this->RollbackTrans(); + } + +} + +eval('class postgres64_transaction_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class postgres64_transaction_ResultSet extends postgres64_transaction_resultset_EXTENDER +{ +} +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/postgres7/postgres7_datadict.inc b/lib/adodb/adodbSQL_drivers/postgres7/postgres7_datadict.inc new file mode 100644 index 0000000..1f8888d --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/postgres7/postgres7_datadict.inc @@ -0,0 +1,211 @@ +TableName ($tabname); + $sql = array(); + list($lines,$pkey) = $this->_GenFields($flds); + $alter = 'ALTER TABLE ' . $tabname . $this->addCol . ' '; + foreach($lines as $v) { + if (($not_null = preg_match('/NOT NULL/i',$v))) { + $v = preg_replace('/NOT NULL/i','',$v); + } + if (preg_match('/^([^ ]+) .*(DEFAULT [^ ]+)/',$v,$matches)) { + list(,$colname,$default) = $matches; + $sql[] = $alter . str_replace($default,'',$v); + $sql[] = 'ALTER TABLE '.$tabname.' ALTER COLUMN '.$colname.' SET ' . $default; + } else { + $sql[] = $alter . $v; + } + if ($not_null) { + list($colname) = explode(' ',$v); + $sql[] = 'ALTER TABLE '.$tabname.' ALTER COLUMN '.$colname.' SET NOT NULL'; + } + } + return $sql; + } + + function AlterColumnSQL($tabname, $flds, $tableflds='',$tableoptions='') + { + if (!$tableflds) { + if ($this->debug) $this->outp("AlterColumnSQL needs a complete table-definiton for PostgreSQL"); + return array(); + } + return $this->_recreate_copy_table($tabname,False,$tableflds,$tableoptions); + } + + function DropColumnSQL($tabname, $flds, $tableflds='',$tableoptions='') + { + $has_drop_column = 7.3 <= (float) @$this->serverInfo['version']; + if (!$has_drop_column && !$tableflds) { + if ($this->debug) $this->outp("DropColumnSQL needs complete table-definiton for PostgreSQL < 7.3"); + return array(); + } + if ($has_drop_column) { + return ADODB_DataDict::DropColumnSQL($tabname, $flds); + } + return $this->_recreate_copy_table($tabname,$flds,$tableflds,$tableoptions); + } + + function DropTableSQL($tabname) + { + $sql = ADODB_DataDict::DropTableSQL($tabname); + $drop_seq = $this->_DropAutoIncrement($tabname); + if ($drop_seq) $sql[] = $drop_seq; + return $sql; + } + + function _CreateSuffix($fname, &$ftype, $fnotnull,$fdefault,$fautoinc,$fconstraint) + { + if ($fautoinc) { + $ftype = 'SERIAL'; + return ''; + } + $suffix = ''; + if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault"; + if ($fnotnull) $suffix .= ' NOT NULL'; + if ($fconstraint) $suffix .= ' '.$fconstraint; + return $suffix; + } + + function _DropAutoIncrement($tabname) + { + $tabname = $this->connection->qstr('%'.$tabname.'%'); + + $seq = $this->connection->GetOne("SELECT relname FROM pg_class WHERE NOT relname ~ 'pg_.*' AND relname LIKE $tabname AND relkind='S'"); + + // check if a tables depends on the sequenz and it therefor cant and dont need to be droped separatly + if (!$seq || $this->connection->GetOne("SELECT relname FROM pg_class JOIN pg_depend ON pg_class.relfilenode=pg_depend.objid WHERE relname='$seq' AND relkind='S' AND deptype='i'")) { + return False; + } + return "DROP SEQUENCE ".$seq; + } + + function _IndexSQL($idxname, $tabname, $flds, $idxoptions) + { + $sql = array(); + if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) { + $sql[] = sprintf ($this->dropIndex, $idxname, $tabname); + if ( isset($idxoptions['DROP']) ) + return $sql; + } + if ( empty ($flds) ) { + return $sql; + } + + $unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : ''; + $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' '; + if (isset($idxoptions['HASH'])) + $s .= 'USING HASH '; + + if ( isset($idxoptions[$this->upperName]) ) + $s .= $idxoptions[$this->upperName]; + + if ( is_array($flds) ) + $flds = implode(', ',$flds); + $s .= '(' . $flds . ')'; + $sql[] = $s; + return $sql; + } + + + function _recreate_copy_table($tabname,$dropflds,$tableflds,$tableoptions='') + { + if ($dropflds && !is_array($dropflds)) $dropflds = explode(',',$dropflds); + $copyflds = array(); + foreach($this->MetaColumns($tabname) as $fld) { + if (!$dropflds || !in_array($fld->name,$dropflds)) { + // we need to explicit convert varchar to a number to be able to do an AlterColumn of a char column to a nummeric one + if (preg_match('/'.$fld->name.' (I|I2|I4|I8|N|F)/i',$tableflds,$matches) && + in_array($fld->type,array('varchar','char','text','bytea'))) { + $copyflds[] = "to_number($fld->name,'S99D99')"; + } else { + $copyflds[] = $fld->name; + } + // identify the sequence name and the fld its on + if ($fld->primary_key && $fld->has_default && + preg_match("/nextval\('([^']+)'::text\)/",$fld->default_value,$matches)) { + $seq_name = $matches[1]; + $seq_fld = $fld->name; + } + } + } + $copyflds = implode(', ',$copyflds); + + $tempname = $tabname.'_tmp'; + $aSql[] = 'BEGIN'; // we use a transaction, to make sure not to loose the content of the table + $aSql[] = "SELECT * INTO TEMPORARY TABLE $tempname FROM $tabname"; + $aSql = array_merge($aSql,$this->DropTableSQL($tabname)); + $aSql = array_merge($aSql,$this->CreateTableSQL($tabname,$tableflds,$tableoptions)); + $aSql[] = "INSERT INTO $tabname SELECT $copyflds FROM $tempname"; + if ($seq_name && $seq_fld) { // if we have a sequence we need to set it again + $seq_name = $tabname.'_'.$seq_fld.'_seq'; // has to be the name of the new implicit sequence + $aSql[] = "SELECT setval('$seq_name',MAX($seq_fld)) FROM $tabname"; + } + $aSql[] = "DROP TABLE $tempname"; + // recreate the indexes, if they not contain one of the droped columns + foreach($this->MetaIndexes($tabname) as $idx_name => $idx_data) + { + if (substr($idx_name,-5) != '_pkey' && (!$dropflds || !count(array_intersect($dropflds,$idx_data['columns'])))) { + $aSql = array_merge($aSql,$this->CreateIndexSQL($idx_name,$tabname,$idx_data['columns'], + $idx_data['unique'] ? array('UNIQUE') : False)); + } + } + $aSql[] = 'COMMIT'; + return $aSql; + } +} + +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/postgres7/postgres7_date_module.inc b/lib/adodb/adodbSQL_drivers/postgres7/postgres7_date_module.inc new file mode 100644 index 0000000..06eea17 --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/postgres7/postgres7_date_module.inc @@ -0,0 +1,316 @@ +_Execute("select $this->sysTimeStamp"); + if ($rs && !$rs->EOF) + return $this->UnixTimeStamp(reset($rs->fields)); + + return false; + } + + function OffsetDate($dayFraction, $date=false) + { + if (!$date) + $date = $this->sysDate; + else if (strncmp($date,"'",1) == 0) { + $len = strlen($date); + if (10 <= $len && $len <= 12) + $date = 'date ' . $date; + else $date = 'timestamp ' . $date; + } + return "($date+interval'$dayFraction days')"; + } + + function SetDateLocale($locale = 'En') + { + $this->locale = $locale; + switch (strtoupper($locale)) + { + case 'EN': + $this->fmtDate="'Y-m-d'"; + $this->fmtTimeStamp = "'Y-m-d H:i:s'"; + break; + + case 'US': + $this->fmtDate = "'m-d-Y'"; + $this->fmtTimeStamp = "'m-d-Y H:i:s'"; + break; + + case 'NL': + case 'FR': + case 'RO': + case 'IT': + $this->fmtDate="'d-m-Y'"; + $this->fmtTimeStamp = "'d-m-Y H:i:s'"; + break; + + case 'GE': + $this->fmtDate="'d.m.Y'"; + $this->fmtTimeStamp = "'d.m.Y H:i:s'"; + break; + + default: + $this->fmtDate="'Y-m-d'"; + $this->fmtTimeStamp = "'Y-m-d H:i:s'"; + break; + } + } + + function DBDate($date) + { + if (empty($date) && $date !== 0) + return 'null'; + + if (is_string($date) && !is_numeric($date)) { + if ($date === 'null' || strncmp($date, "'", 1) === 0) + return $date; + + if ($this->isoDates) + return "'$date'"; + + $date = $this->UnixDate($date); + } + + return adodb_date($this->fmtDate,$date); + } + + function DBTimeStamp($timestamp) + { + if (empty($timestamp) && $timestamp !== 0) + return 'null'; + + # strlen(14) allows YYYYMMDDHHMMSS format + if (!is_string($timestamp) || (is_numeric($timestamp) && strlen($timestamp)<14)) + return adodb_date($this->fmtTimeStamp, $timestamp); + + if ($timestamp === 'null') + return $timestamp; + + if ($this->isoDates && strlen($timestamp) !== 14) + return "'$timestamp'"; + + $timestamp = $this->UnixTimeStamp($timestamp); + return adodb_date($this->fmtTimeStamp, $timestamp); + } + + function UnixDate($v) + { + if (is_object($v)) { + // odbtp support + //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 ) + return adodb_mktime($v->hour, $v->minute, $v->second, $v->month, $v->day, $v->year); + } + + if (is_numeric($v) && strlen($v) !== 8) + return $v; + + if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", ($v), $rr)) + return false; + + if ($rr[1] <= TIMESTAMP_FIRST_YEAR) + return 0; + + // h-m-s-MM-DD-YY + return adodb_mktime(0, 0, 0, $rr[2], $rr[3], $rr[1]); + } + + function UnixTimeStamp($v) + { + if (is_object($v)) { + // odbtp support + //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 ) + return adodb_mktime($v->hour, $v->minute, $v->second, $v->month, $v->day, $v->year); + } + + if (!preg_match("|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ ,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", ($v), $rr)) + return false; + + if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) + return 0; + + // h-m-s-MM-DD-YY + if (!isset($rr[5])) + return adodb_mktime(0, 0, 0, $rr[2], $rr[3], $rr[1]); + else return adodb_mktime($rr[5], $rr[6], $rr[7], $rr[2], $rr[3], $rr[1]); + } + + function UserDate($v, $fmt='Y-m-d', $gmt=false) + { + $tt = $this->UnixDate($v); + + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + else if ($tt == 0) + return $this->emptyDate; + else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR + } + + return ($gmt) ? adodb_gmdate($fmt, $tt) : adodb_date($fmt, $tt); + } + + function UserTimeStamp($v, $fmt='Y-m-d H:i:s', $gmt=false) + { + if (!isset($v)) + return $this->emptyTimeStamp; + + # strlen(14) allows YYYYMMDDHHMMSS format + if (is_numeric($v) && strlen($v)<14) + return ($gmt) ? adodb_gmdate($fmt,$v) : adodb_date($fmt,$v); + + $tt = $this->UnixTimeStamp($v); + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + + if ($tt == 0) + return $this->emptyTimeStamp; + else return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt); + } + + function SQLDate($fmt, $col=false) + { + if (!$col) + $col = $this->sysTimeStamp; + + $s = 'TO_CHAR('.$col.",'"; + $len = strlen($fmt); + for ($i=0; $i < $len; $i++) { + $ch = $fmt[$i]; + switch($ch) { + case 'Y': + case 'y': + $s .= 'YYYY'; + break; + + case 'Q': + case 'q': + $s .= 'Q'; + break; + + case 'M': + $s .= 'Mon'; + break; + + case 'm': + $s .= 'MM'; + break; + + case 'D': + case 'd': + $s .= 'DD'; + break; + + case 'H': + $s.= 'HH24'; + break; + + case 'h': + $s .= 'HH'; + break; + + case 'i': + $s .= 'MI'; + break; + + case 's': + $s .= 'SS'; + break; + + case 'a': + case 'A': + $s .= 'AM'; + break; + + case 'w': + $s .= 'D'; + break; + + case 'l': + $s .= 'DAY'; + break; + + default: + // handle escape characters... + if ($ch == '\\') { + $i++; + $ch = substr($fmt,$i,1); + } + if (strpos('-/.:;, ',$ch) !== false) + $s .= $ch; + else $s .= '"'.$ch.'"'; + } + } + return $s. "')"; + } +} + +eval('class postgres7_date_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class postgres7_date_ResultSet extends postgres7_date_resultset_EXTENDER +{ + var $emptyTimeStamp = ' '; /// what to display when $time==0 + var $emptyDate = ' '; /// what to display when $time==0 + var $datetime = false; + + function UserTimeStamp($v, $fmt='Y-m-d H:i:s') + { + if (is_numeric($v) && strlen($v)<14) + return adodb_date($fmt,$v); + + $tt = $this->UnixTimeStamp($v); + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + + if ($tt === 0) + return $this->emptyTimeStamp; + else return adodb_date($fmt,$tt); + } + + function UserDate($v,$fmt='Y-m-d') + { + $tt = $this->UnixDate($v); + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + else if ($tt == 0) + return $this->emptyDate; + else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR + } + return adodb_date($fmt,$tt); + } + + function UnixDate($v) + { + return postgres7_date_ADOConnection::UnixDate($v); + } + + function UnixTimeStamp($v) + { + return postgres7_date_ADOConnection::UnixTimeStamp($v); + } + +} +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/postgres7/postgres7_driver.inc b/lib/adodb/adodbSQL_drivers/postgres7/postgres7_driver.inc new file mode 100644 index 0000000..50de7fa --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/postgres7/postgres7_driver.inc @@ -0,0 +1,680 @@ +dbtype = 'postgres7'; + $this->dataProvider = 'postgres'; + } + + /** + * Connection to database server and selected database + * + * @access private + */ + + function _connect($host = "", $username = "", $password = "", $database = "", $persistent, $forcenew) + { + if (!function_exists('pg_connect')) return false; + + $this->host = $host; + $this->username = $this->query_addslashes($username); + $this->password = $this->query_addslashes($password); + if (strlen($database) == 0) $database = 'template1'; + $this->database = $this->query_addslashes($database); + + if ($this->username || $this->password || $this->database) { + $this->connect_string = $this->host; + if ($this->connect_string) { + $host = split(":", $this->connect_string); + if ($host[0]) $this->connect_string = "host=" . $this->query_addslashes($host[0]); + else $this->connect_string = 'host=localhost'; + if (isset($host[1])) $this->connect_string .= " port=$host[1]"; + else if (!empty($this->port)) $this->connect_string .= " port=" . $this->port; + } + if ($this->username) $this->connect_string .= " user=" . $this->username; + if ($this->password) $this->connect_string .= " password=" . $this->password; + if ($this->database) $this->connect_string .= " dbname=" . $this->database; + } + else + { + $this->connect_string = $this->host; + } + + $this->persistent = $persistent; + $this->forcenewconnection = $forcenew; + + $this->_makeconnection(); + + if ($this->connectionId === false) + { + if ($fn = $this->raiseErrorFn) + $fn($this->dbtype, 'CONNECT', $this->ErrorNo(), $this->ErrorMsg(), $this->host, $this->database, $this); + return $this->SelectDB( $this->database ); + } + + return true; + } + + function _makeconnection() + { + if($this->persistent == 1) + { + $this->connectionId = @pg_pconnect( $this->connect_string ); + } + else + { + if(!$this->forcenewconnection) + { + $this->connectionId = @pg_connect( $this->connect_string ); + } + else + { + $this->connectionId = @pg_connect( $this->connect_string, PGSQL_CONNECT_FORCE_NEW ); + } + } + } + + function query_addslashes($query) + { + $len = strlen($query); + if ($len == 0) + return "''"; + if (strncmp($query,"'",1) === 0 && substr($query,$len-1) == "'") + return $s; + return "'".addslashes($query)."'"; + } + + /** + * Choose a database to connect. + * + * @param dbname is the name of the database to select + * @return true or false + * @access public + */ + + function SelectDB($dbname) + { + $this->database = $dbname; + + if ($this->connectionId === false) + { + if($this->createdatabase == true) + { + $this->connectionId = @pg_pconnect( "host=$this->host user=$this->username password=$this->password" ); + $result = @pg_query($this->connectionId, "CREATE DATABASE " . $this->database ); + if ($result === false) { // error handling if query fails + $this->connectionId = false; + return false; + } + + $this->_makeconnection(); + if($this->connectionId === false) + { + $this->connectionId = false; + return false; + } + else + { + return true; + } + } + $this->connectionId = false; + return false; + } + else + { + return true; + } + } + + /** + * Return database error message + * Usage: $errormessage =& $db->ErrorMsg(); + * + * @access public + */ + + function ErrorMsg() + { + return @pg_last_error($this->connectionId); + } + + /** + * Return database error number + * Usage: $errorbo =& $db->ErrorNo(); + * + * @access public + */ + + function ErrorNo() + { + $error = @pg_last_error( $this->connectionId ); + return strlen($error) ? $error : 0; + } + + /** + * Returns # of affected rows from insert/delete/update query + * + * @access public + * @return integer Affected rows + */ + + function Affected_Rows() + { + return @pg_affected_rows( $this->record_set ); + } + + /** + * Returns the last record id of an inserted item + * Usage: $db->Insert_ID(); + * + * @access public + */ + + function Insert_ID() + { + return @pg_getlastoid($this->record_set); + } + + /** + * Correctly quotes a string so that all strings are escape coded. + * An example is $db->qstr("Haven't a clue."); + * + * @param string the string to quote + * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc(). + * + * @return single-quoted string IE: 'Haven\'t a clue.' + */ + + function qstr($string, $magic_quotes=false) + { + // Ugly hack alert! Repalce backticks with some arbitrary character + $string = str_replace('`', "\x1C", $string); + if (!$magic_quotes) { + if (strnatcmp(PHP_VERSION, '4.2.0') >= 0 && $this->pg_escape_enable) { + return "'" . pg_escape_string($string) . "'"; + } + $string = str_replace("'", "\\'", str_replace('\\', '\\\\', str_replace("\0", "\\\0", $string))); + return "'" . $string . "'"; + } + return "'" . str_replace('\\"', '"', $string) . "'"; + } + + function QMagic($string) + { + return $this->qstr($string, get_magic_quotes_gpc()); + } + + /** + * Returns concatenated string + * Usage: $db->Concat($str1,$str2); + * + * @return concatenated string + */ + function Concat() + { + $arr = func_get_args(); + return implode("||", $arr); + } + + function IfNull( $field, $ifNull ) + { + return " coalesce($field, $ifNull) "; + } + + /** + * Closes database connection + * Usage: $db->close(); + * + * @access public + */ + + function Close() + { + @pg_close( $this->connectionId ); + $this->connectionId = false; + } + + /** + * Returns All Records in an array + * + * Usage: $db->GetAll($sql); + * @access public + */ + + function &GetAll($sql, $inputarr = false) + { + $data =& $this->GetArray($sql, $inputarr); + return $data; + } + + /** + * Returns All Records in an array + * + * Usage: $db->GetArray($sql); + * @access public + */ + + function &GetArray($sql, $inputarr = false) + { + $data = false; + $result =& $this->Execute($sql, $inputarr); + if ($result) + { + $data =& $result->GetArray(); + $result->Close(); + } + return $data; + } + + /** + * Executes SQL query and instantiates resultset methods + * + * @access private + * @return mixed Resultset methods + */ + + function &do_query( $sql, $offset, $nrows, $inputarr=false ) + { + global $ADODB_FETCH_MODE; + $sql = str_replace('`', '"', $sql); + $sql = str_replace("\x1C", "`", $sql); + $sql = str_replace('IS_DELETED', 'is_deleted', $sql); + $sql = str_replace("HIGH_PRIORITY", "", $sql); + $false = false; + + $offsetStr = ''; + $limitStr = ''; + if ($offset != -1 || $nrows != -1) + { + $offsetStr = ($offset >= 0) ? " OFFSET " . ((integer)$offset) : ''; + $limitStr = ($nrows >= 0) ? " LIMIT " . ((integer)$nrows) : ''; + } + + if ($inputarr && is_array($inputarr)) { + $sqlarr = explode('?', $sql); + if (!is_array(reset($inputarr))) $inputarr = array($inputarr); + foreach($inputarr as $arr) { + $sql = ''; $i = 0; + foreach($arr as $v) { + $sql .= $sqlarr[$i]; + switch(gettype($v)){ + case 'string': + $sql .= $this->qstr($v); + break; + case 'double': + $sql .= str_replace(',', '.', $v); + break; + case 'boolean': + $sql .= $v ? "'t'" : "'f'"; + break; + default: + if ($v === null) + $sql .= 'NULL'; + else $sql .= $v; + } + $i += 1; + } + $sql .= $sqlarr[$i]; + if ($i+1 != sizeof($sqlarr)) + return $false; + $this->sql = $sql . "$limitStr$offsetStr"; + $time_start = array_sum(explode(' ', microtime())); + $this->query_count++; + $resultId = @pg_query( $this->sql); + $time_total = (array_sum(explode(' ', microtime())) - $time_start); + $this->query_time_total += $time_total; + if($this->debug_console) + { + $this->query_list[] = $this->sql; + $this->query_list_time[] = $time_total; + $this->query_list_errors[] = $this->ErrorMsg(); + } + if($this->debug) + { + $this->outp($sql . "$limitStr$offsetStr"); + } + if ($resultId === false) { // error handling if query fails + if ($fn = $this->raiseErrorFn) + $fn($this->dbtype, 'EXECUTE', $this->ErrorNo(), $this->ErrorMsg(), $this->sql, $inputarr, $this); + return $false; + } + } + } + else + { + $this->sql = $sql . "$limitStr$offsetStr"; + $time_start = array_sum(explode(' ', microtime())); + $this->query_count++; + $resultId = @pg_query( $this->sql); + $time_total = (array_sum(explode(' ', microtime())) - $time_start); + $this->query_time_total += $time_total; + if($this->debug_console) + { + $this->query_list[] = $this->sql; + $this->query_list_time[] = $time_total; + $this->query_list_errors[] = $this->ErrorMsg(); + } + if($this->debug) + { + $this->outp($sql . "$limitStr$offsetStr"); + } + } + + if ($resultId === false) { // error handling if query fails + if ($fn = $this->raiseErrorFn) + $fn($this->dbtype, 'EXECUTE', $this->ErrorNo(), $this->ErrorMsg(), $this->sql, $inputarr, $this); + return $false; + } + + if (@pg_numfields( $resultId ) <= 0) { // return simplified recordset for inserts/updates/deletes with lower overhead + $recordset = new ADORecordSet_empty(); + $this->record_set = $recordset; + return $recordset; + } + + $resultset_name = $this->last_module_name . "_ResultSet"; + $recordset = new $resultset_name( $resultId, $this->connectionId ); + $this->record_set = $recordset; + + $recordset->_currentRow = 0; + + switch ($ADODB_FETCH_MODE) + { + case ADODB_FETCH_NUM: $recordset->fetchMode = PGSQL_NUM; break; + case ADODB_FETCH_ASSOC:$recordset->fetchMode = PGSQL_ASSOC; break; + default: + case ADODB_FETCH_DEFAULT: + case ADODB_FETCH_BOTH:$recordset->fetchMode = PGSQL_BOTH; break; + } + + $recordset->_numOfRows = @pg_numrows( $resultId ); + if( $recordset->_numOfRows == 0) + { + $recordset->EOF = true; + } + $recordset->_numOfFields = @pg_numfields( $resultId ); + $recordset->_fetch(); + + return $recordset; + } +} + +class postgres7_driver_ResultSet +{ + var $connectionId; + var $fields; + var $resultId; + var $_currentRow = 0; + var $_numOfRows = -1; + var $_numOfFields = -1; + var $fetchMode; + var $EOF; + + /** + * pgsqlResultSet Constructor + * + * @access private + * @param string $record + * @param string $resultId + */ + + function postgres7_driver_ResultSet( $resultId, $connectionId ) + { + $this->fields = array(); + $this->connectionId = $connectionId; + $this->record = array(); + $this->resultId = $resultId; + $this->EOF = false; + } + + /** + * Frees resultset + * + * @access public + */ + + function Close() + { + pg_free_result( $this->resultId ); + $this->fields = array(); + $this->resultId = false; + } + + /** + * Returns field name from select query + * + * @access public + * @param string $field + * @return string Field name + */ + + function fields( $field ) + { + if(empty($field)) + { + return $this->fields; + } + else + { + return $this->fields[$field]; + } + } + + /** + * Returns numrows from select query + * + * @access public + * @return integer Numrows + */ + + function RecordCount() + { + return $this->_numOfRows; + } + + /** + * PEAR DB Compatable Command + */ + function NumRows() + { + return $this->_numOfRows; + } + + /** + * Returns num of fields from select query + * + * @access public + * @return integer numfields + */ + + function FieldCount() + { + return $this->_numOfFields; + } + + /** + * PEAR DB Compatable Command + */ + function NumCols() + { + return $this->_numOfFields; + } + + /** + * Returns next record + * + * @access public + */ + + function MoveNext() + { + if (@$this->fields = pg_fetch_array($this->resultId, NULL, $this->fetchMode)) { + $this->_currentRow += 1; + return true; + } + if (!$this->EOF) { + $this->_currentRow += 1; + $this->EOF = true; + } + return false; + } + + /** + * Move to the first row in the recordset. Many databases do NOT support this. + * + * @return true or false + */ + + function MoveFirst() + { + if ($this->_currentRow == 0) return true; + return $this->Move(0); + } + + /** + * Returns the Last Record + * + * @access public + */ + + function MoveLast() + { + if ($this->EOF) return false; + return $this->Move($this->_numOfRows - 1); + } + + /** + * Random access to a specific row in the recordset. Some databases do not support + * access to previous rows in the databases (no scrolling backwards). + * + * @param rowNumber is the row to move to (0-based) + * + * @return true if there still rows available, or false if there are no more rows (EOF). + */ + + function Move($rowNumber = 0) + { + if ($rowNumber == $this->_currentRow) return true; + $this->EOF = false; + if ($this->_numOfRows > 0){ + if ($rowNumber >= $this->_numOfRows - 1){ + $rowNumber = $this->_numOfRows - 1; + } + } + + if ($this->_seek($rowNumber)) { + $this->_currentRow = $rowNumber; + if ($this->_fetch()) { + return true; + } + $this->fields = false; + } + $this->EOF = true; + return false; + } + + /** + * Perform Seek to specific row + * + * @access private + */ + + function _seek($row) + { + if ($this->_numOfRows == 0) return false; + return @pg_result_seek($this->resultId,$row); + } + + /** + * Fills field array with first database element when query initially executed + * + * @access private + */ + + function _fetch() + { + $this->fields = @pg_fetch_array($this->resultId, NULL, $this->fetchMode); + return is_array($this->fields); + } + + /** + * Check to see if last record reached + * + * @access public + */ + + function EOF() + { + if( $this->_currentRow < $this->_numOfRows) + { + return false; + } + else + { + $this->EOF = true; + return true; + } + } + + /** + * Returns All Records in an array + * + * @access public + * @param [nRows] is the number of rows to return. -1 means every row. + */ + + function &GetArray($nRows = -1) + { + $results = array(); + $cnt = 0; + while (!$this->EOF && $nRows != $cnt) { + $results[] = $this->fields; + $this->MoveNext(); + $cnt++; + } + return $results; + } + + function &GetRows($nRows = -1) + { + $arr =& $this->GetArray($nRows); + return $arr; + } + + function &GetAll($nRows = -1) + { + $arr =& $this->GetArray($nRows); + return $arr; + } + + /** + * Fetch field information for a table. + * + * @return object containing the name, type and max_length + */ + function FetchField($fieldOffset = -1) + { + $fieldObject= new ADOFieldObject(); + $fieldObject->name = @pg_fieldname($this->resultId, $fieldOffset); + $fieldObject->type = @pg_fieldtype($this->resultId, $fieldOffset); + $fieldObject->max_length = @pg_fieldsize($this->resultId, $fieldOffset); + return $fieldObject; + } +} +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/postgres7/postgres7_extend_module.inc b/lib/adodb/adodbSQL_drivers/postgres7/postgres7_extend_module.inc new file mode 100644 index 0000000..68b16ec --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/postgres7/postgres7_extend_module.inc @@ -0,0 +1,147 @@ +Execute($sql, $inputarr); + if ($result) { + $data =& $result->GetAssoc($force_array, $first2cols); + $result->Close(); + } + return $data; + } + + /** + * Generates a sequence id and stores it in $this->genID; + * GenID is only available if $this->hasGenID = true; + * + * @param seqname name of sequence to use + * @param startID if sequence does not exist, start at this ID + * @return 0 if not supported, otherwise a sequence id + */ + + var $_genIDSQL = "SELECT NEXTVAL('%s')"; + var $_genSeqSQL = "CREATE SEQUENCE %s START %s"; + var $_dropSeqSQL = "DROP SEQUENCE %s"; + var $genID = 0; + + function GenID($seqname='adodbseq', $startID=1) + { + $getnext = sprintf($this->_genIDSQL, $seqname); + $holdtransOK = $this->transaction_status; + $save_handler = $this->raiseErrorFn; + $this->raiseErrorFn = ''; + @($result = $this->Execute($getnext)); + $this->raiseErrorFn = $save_handler; + + if (!$result) { + $this->transaction_status = $holdtransOK; + $createseq = $this->Execute(sprintf($this->_genSeqSQL, $seqname, $startID)); + $result = $this->Execute($getnext); + } + if ($result && !$result->EOF) + $this->genID = reset($result->fields); + else $this->genID = 0; + + if ($result) + $result->Close(); + + return $this->genID; + } + + function CreateSequence($seqname='adodbseq', $startID=1) + { + return $this->Execute(sprintf($this->_genSeqSQL, $seqname, $startID)); + } + + function DropSequence($seqname='adodbseq') + { + return $this->Execute(sprintf($this->_dropSeqSQL, $seqname)); + } + +} + +eval('class postgres7_extend_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class postgres7_extend_ResultSet extends postgres7_extend_resultset_EXTENDER +{ + function &GetAssoc($force_array = false, $first2cols = false) + { + $results = false; + + if ($this->_numOfFields > 1) { + $numIndex = isset($this->fields[0]); + $results = array(); + if (!$first2cols && ($this->_numOfFields > 2 || $force_array)) { + if ($numIndex) { + while (!$this->EOF) { + $results[trim($this->fields[0])] = array_slice($this->fields, 1); + $this->MoveNext(); + } + } else { + while (!$this->EOF) { + $results[trim(reset($this->fields))] = array_slice($this->fields, 1); + $this->MoveNext(); + } + } + } else { + if ($numIndex) { + while (!$this->EOF) { + $results[trim(($this->fields[0]))] = $this->fields[1]; + $this->MoveNext(); + } + } else { + while (!$this->EOF) { + $v1 = trim(reset($this->fields)); + $v2 = ''.next($this->fields); + $results[$v1] = $v2; + $this->MoveNext(); + } + } + } + } + return $results; + } + + function PO_RecordCount($table="", $condition="") + { + $lnumrows = $this->_numOfRows; + if($lnumrows == -1 && $this->connectionId) + { + if($table) + { + if ($condition) + $condition = " WHERE " . $condition; + $resultrows = &$this->connectionId->Execute("SELECT COUNT(*) FROM $table $condition"); + if ($resultrows) + $lnumrows = reset($resultrows->fields); + } + } + return $lnumrows; + } + + function CurrentRow() + { + return $this->_currentRow; + } + + function AbsolutePosition() + { + return $this->_currentRow; + } + + function NextRecordSet() + { + return false; + } + +} +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/postgres7/postgres7_meta_module.inc b/lib/adodb/adodbSQL_drivers/postgres7/postgres7_meta_module.inc new file mode 100644 index 0000000..65db8a8 --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/postgres7/postgres7_meta_module.inc @@ -0,0 +1,712 @@ + 0 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum"; + + // used when schema defined + var $metaColumnsSQL1 = "SELECT a.attname, t.typname, a.attlen, a.atttypmod, a.attnotnull, a.atthasdef, a.attnum +FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n +WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s')) + and c.relnamespace=n.oid and n.nspname='%s' + and a.attname not like '....%%' AND a.attnum > 0 + AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum"; + + // get primary key etc -- from Freek Dijkstra + var $metaKeySQL = "SELECT ic.relname AS index_name, a.attname AS column_name,i.indisunique AS unique_key, i.indisprimary AS primary_key + FROM pg_class bc, pg_class ic, pg_index i, pg_attribute a WHERE bc.oid = i.indrelid AND ic.oid = i.indexrelid AND (i.indkey[0] = a.attnum OR i.indkey[1] = a.attnum OR i.indkey[2] = a.attnum OR i.indkey[3] = a.attnum OR i.indkey[4] = a.attnum OR i.indkey[5] = a.attnum OR i.indkey[6] = a.attnum OR i.indkey[7] = a.attnum) AND a.attrelid = bc.oid AND bc.relname = '%s'"; + var $metaDefaultsSQL = "SELECT d.adnum as num, d.adsrc as def from pg_attrdef d, pg_class c where d.adrelid=c.oid and c.relname='%s' order by d.adnum"; + + function MetaError($err=false) + { + include_once(ADODB_DIR."/adodb-error.inc.php"); + if ($err === false) + $err = $this->ErrorNo(); + + return adodb_error($this->dataProvider,$this->databaseType,$err); + } + + function MetaErrorMsg($errno) + { + include_once(ADODB_DIR."/adodb-error.inc.php"); + return adodb_errormsg($errno); + } + + /** + * @returns an array with the primary key columns in it. + */ + function MetaPrimaryKeys($table, $owner=false) + { + // owner not used in base class - see oci8 + $p = array(); + $objs =& $this->MetaColumns($table); + if ($objs) { + foreach($objs as $v) { + if (!empty($v->primary_key)) + $p[] = $v->name; + } + } + if (sizeof($p)) return $p; + if (function_exists('ADODB_VIEW_PRIMARYKEYS')) + return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner); + return false; + } + + /** + * @returns assoc array where keys are tables, and values are foreign keys + */ + function MetaForeignKeys($table, $owner=false, $upper=false) + { + $sql = 'SELECT t.tgargs as args + FROM + pg_trigger t,pg_class c,pg_proc p + WHERE + t.tgenabled AND + t.tgrelid = c.oid AND + t.tgfoid = p.oid AND + p.proname = \'RI_FKey_check_ins\' AND + c.relname = \''.strtolower($table).'\' + ORDER BY + t.tgrelid'; + + $rs =& $this->Execute($sql); + + if (!$rs || $rs->EOF) return false; + + $arr =& $rs->GetArray(); + $a = array(); + foreach($arr as $v) { + $data = explode(chr(0), $v['args']); + $size = count($data)-1; //-1 because the last node is empty + for($i = 4; $i < $size; $i++) { + if ($upper) + $a[strtoupper($data[2])][] = strtoupper($data[$i].'='.$data[++$i]); + else + $a[$data[2]][] = $data[$i].'='.$data[++$i]; + } + } + return $a; + } + + // not the fastest implementation - quick and dirty - jlim + // for best performance, use the actual $rs->MetaType(). + function MetaType($t,$len=-1,$fieldobj=false) + { + if (empty($this->_metars)) { + $rsclass = $this->last_module_name . "_ResultSet"; + $this->_metars =& new $rsclass(false,$this->fetchMode); + } + + return $this->_metars->MetaType($t,$len,$fieldobj); + } + + /** + * return the databases that the driver can connect to. + * Some databases will return an empty array. + * + * @return an array of database names. + */ + function MetaDatabases() + { + global $ADODB_FETCH_MODE; + + if ($this->metaDatabasesSQL) { + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + + $arr = $this->GetCol($this->metaDatabasesSQL); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + return $arr; + } + + return false; + } + + /** + * @param ttype can either be 'VIEW' or 'TABLE' or false. + * If false, both views and tables are returned. + * "VIEW" returns only views + * "TABLE" returns only tables + * @param showSchema returns the schema/user with the table name, eg. USER.TABLE + * @param mask is the input mask - only supported by oci8 and postgresql + * + * @return array of tables for current database. + */ + function &MetaTables($ttype=false,$showSchema=false,$mask=false) + { + $info = $this->ServerInfo(); + if ($info['version'] >= 7.3) { + $this->metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%' + and schemaname not in ( 'pg_catalog','information_schema') + union + select viewname,'V' from pg_views where viewname not like 'pg\_%' and schemaname not in ( 'pg_catalog','information_schema') "; + } + if ($mask) { + $save = $this->metaTablesSQL; + $mask = $this->qstr(strtolower($mask)); + if ($info['version']>=7.3) + $this->metaTablesSQL = " +select tablename,'T' from pg_tables where tablename like $mask and schemaname not in ( 'pg_catalog','information_schema') + union +select viewname,'V' from pg_views where viewname like $mask and schemaname not in ( 'pg_catalog','information_schema') "; + else + $this->metaTablesSQL = " +select tablename,'T' from pg_tables where tablename like $mask + union +select viewname,'V' from pg_views where viewname like $mask"; + } + $ret =& $this->_MetaTables($ttype,$showSchema); + + if ($mask) { + $this->metaTablesSQL = $save; + } + return $ret; + } + + function &_MetaTables($ttype=false,$showSchema=false,$mask=false) + { + global $ADODB_FETCH_MODE; + + $false = false; + if ($mask) { + return $false; + } + if ($this->metaTablesSQL) { + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + + $rs = $this->Execute($this->metaTablesSQL); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if ($rs === false) return $false; + $arr =& $rs->GetArray(); + $arr2 = array(); + + if ($hast = ($ttype && isset($arr[0][1]))) { + $showt = strncmp($ttype,'T',1); + } + + for ($i=0; $i < sizeof($arr); $i++) { + if ($hast) { + if ($showt == 0) { + if (strncmp($arr[$i][1],'T',1) == 0) $arr2[] = trim($arr[$i][0]); + } else { + if (strncmp($arr[$i][1],'V',1) == 0) $arr2[] = trim($arr[$i][0]); + } + } else + $arr2[] = trim($arr[$i][0]); + } + $rs->Close(); + return $arr2; + } + return $false; + } + + function _findschema(&$table,&$schema) + { + if (!$schema && ($at = strpos($table,'.')) !== false) { + $schema = substr($table,0,$at); + $table = substr($table,$at+1); + } + } + + /** + * List columns in a database as an array of ADOFieldObjects. + * See top of file for definition of object. + * + * @param $table table name to query + * @param $normalize makes table name case-insensitive (required by some databases) + * @schema is optional database schema to use - not supported by all databases. + * + * @return array of ADOFieldObjects for current table. + */ + function &MetaColumns($table,$normalize=true) + { + global $ADODB_FETCH_MODE; + + $schema = false; + $false = false; + $this->_findschema($table,$schema); + + if ($normalize) $table = strtolower($table); + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + + if ($schema) $rs =& $this->Execute(sprintf($this->metaColumnsSQL1,$table,$table,$schema)); + else $rs =& $this->Execute(sprintf($this->metaColumnsSQL,$table,$table)); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if ($rs === false) { + return $false; + } + if (!empty($this->metaKeySQL)) { + // If we want the primary keys, we have to issue a separate query + // Of course, a modified version of the metaColumnsSQL query using a + // LEFT JOIN would have been much more elegant, but postgres does + // not support OUTER JOINS. So here is the clumsy way. + + $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; + + $rskey = $this->Execute(sprintf($this->metaKeySQL,($table))); + // fetch all result in once for performance. + $keys =& $rskey->GetArray(); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + $rskey->Close(); + unset($rskey); + } + + $rsdefa = array(); + if (!empty($this->metaDefaultsSQL)) { + $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; + $sql = sprintf($this->metaDefaultsSQL, ($table)); + $rsdef = $this->Execute($sql); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if ($rsdef) { + while (!$rsdef->EOF) { + $num = $rsdef->fields['num']; + $s = $rsdef->fields['def']; + if (strpos($s,'::')===false && substr($s, 0, 1) == "'") { /* quoted strings hack... for now... fixme */ + $s = substr($s, 1); + $s = substr($s, 0, strlen($s) - 1); + } + + $rsdefa[$num] = $s; + $rsdef->MoveNext(); + } + } else { + ADOConnection::outp( "==> SQL => " . $sql); + } + unset($rsdef); + } + + $retarr = array(); + while (!$rs->EOF) { + $fld = new ADOFieldObject(); + $fld->name = $rs->fields[0]; + $fld->type = $rs->fields[1]; + $fld->max_length = $rs->fields[2]; + $fld->attnum = $rs->fields[6]; + + if ($fld->max_length <= 0) $fld->max_length = $rs->fields[3]-4; + if ($fld->max_length <= 0) $fld->max_length = -1; + if ($fld->type == 'numeric') { + $fld->scale = $fld->max_length & 0xFFFF; + $fld->max_length >>= 16; + } + // dannym + // 5 hasdefault; 6 num-of-column + $fld->has_default = ($rs->fields[5] == 't'); + if ($fld->has_default) { + $fld->default_value = $rsdefa[$rs->fields[6]]; + } + + //Freek + $fld->not_null = $rs->fields[4] == 't'; + + + // Freek + if (is_array($keys)) { + foreach($keys as $key) { + if ($fld->name == $key['column_name'] AND $key['primary_key'] == 't') + $fld->primary_key = true; + if ($fld->name == $key['column_name'] AND $key['unique_key'] == 't') + $fld->unique = true; // What name is more compatible? + } + } + + if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld; + else $retarr[($normalize) ? strtoupper($fld->name) : $fld->name] = $fld; + + $rs->MoveNext(); + } + $rs->Close(); + if (empty($retarr)) + return $false; + else + return $retarr; + + } + + /** + * List indexes on a table as an array. + * @param table table name to query + * @param primary true to only show primary keys. Not actually used for most databases + * + * @return array of indexes on current table. Each element represents an index, and is itself an associative array. + + Array ( + [name_of_index] => Array + ( + [unique] => true or false + [columns] => Array + ( + [0] => firstname + [1] => lastname + ) + ) + */ + function &MetaIndexes ($table, $primary = FALSE) + { + global $ADODB_FETCH_MODE; + + $schema = false; + $this->_findschema($table,$schema); + + if ($schema) { // requires pgsql 7.3+ - pg_namespace used. + $sql = ' +SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns" +FROM pg_catalog.pg_class c +JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid +JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid + ,pg_namespace n +WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\')) and c.relnamespace=c2.relnamespace and c.relnamespace=n.oid and n.nspname=\'%s\''; + } else { + $sql = ' +SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns" +FROM pg_catalog.pg_class c +JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid +JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid +WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\'))'; + } + + if ($primary == FALSE) { + $sql .= ' AND i.indisprimary=false;'; + } + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== FALSE) { + $savem = $this->SetFetchMode(FALSE); + } + + $rs = $this->Execute(sprintf($sql,$table,$table,$schema)); + if (isset($savem)) { + $this->SetFetchMode($savem); + } + $ADODB_FETCH_MODE = $save; + + if (!is_object($rs)) { + $false = false; + return $false; + } + + $col_names = $this->MetaColumnNames($table,true,true); + //3rd param is use attnum, + // see http://sourceforge.net/tracker/index.php?func=detail&aid=1451245&group_id=42718&atid=433976 + $indexes = array(); + while ($row = $rs->FetchRow()) { + $columns = array(); + foreach (explode(' ', $row[2]) as $col) { + $columns[] = $col_names[$col]; + } + + $indexes[$row[0]] = array( + 'unique' => ($row[1] == 't'), + 'columns' => $columns + ); + } + return $indexes; + } + + /** + * List columns names in a table as an array. + * @param table table name to query + * + * @return array of column names for current table. + */ + function &MetaColumnNames($table, $numIndexes=false,$useattnum=false /* only for postgres */) + { + $objarr =& $this->MetaColumns($table); + if (!is_array($objarr)) { + $false = false; + return $false; + } + $arr = array(); + if ($numIndexes) { + $i = 0; + if ($useattnum) { + foreach($objarr as $v) + $arr[$v->attnum] = $v->name; + + } else + foreach($objarr as $v) $arr[$i++] = $v->name; + } else + foreach($objarr as $v) $arr[strtoupper($v->name)] = $v->name; + + return $arr; + } + + function MetaTransaction($mode,$db) + { + $mode = strtoupper($mode); + $mode = str_replace('ISOLATION LEVEL ','',$mode); + + switch($mode) { + + case 'READ UNCOMMITTED': + switch($db) { + case 'oci8': + case 'oracle': + return 'ISOLATION LEVEL READ COMMITTED'; + default: + return 'ISOLATION LEVEL READ UNCOMMITTED'; + } + break; + + case 'READ COMMITTED': + return 'ISOLATION LEVEL READ COMMITTED'; + break; + + case 'REPEATABLE READ': + switch($db) { + case 'oci8': + case 'oracle': + return 'ISOLATION LEVEL SERIALIZABLE'; + default: + return 'ISOLATION LEVEL REPEATABLE READ'; + } + break; + + case 'SERIALIZABLE': + return 'ISOLATION LEVEL SERIALIZABLE'; + break; + + default: + return $mode; + } + } + +} + +eval('class postgres7_meta_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class postgres7_meta_ResultSet extends postgres7_meta_resultset_EXTENDER +{ + /** + * Get the metatype of the column. This is used for formatting. This is because + * many databases use different names for the same type, so we transform the original + * type to our standardised version which uses 1 character codes: + * + * @param t is the type passed in. Normally is ADOFieldObject->type. + * @param len is the maximum length of that field. This is because we treat character + * fields bigger than a certain size as a 'B' (blob). + * @param fieldobj is the field object returned by the database driver. Can hold + * additional info (eg. primary_key for mysql). + * + * @return the general type of the data: + * C for character < 250 chars + * X for teXt (>= 250 chars) + * B for Binary + * N for numeric or floating point + * D for date + * T for timestamp + * L for logical/Boolean + * I for integer + * R for autoincrement counter/integer + * + * + */ + function MetaType($t,$len=-1,$fieldobj=false) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + $is_serial = is_object($fieldobj) && $fieldobj->primary_key && $fieldobj->unique && $fieldobj->has_default && substr($fieldobj->default_value,0,8) == 'nextval('; + switch (strtoupper($t)) { + case 'MONEY': // stupid, postgres expects money to be a string + case 'INTERVAL': + case 'CHAR': + case 'CHARACTER': + case 'VARCHAR': + case 'NAME': + case 'BPCHAR': + case '_VARCHAR': + case 'INET': + case 'MACADDR': + if ($len <= $this->blobSize) return 'C'; + case 'TEXT': + return 'X'; + case 'IMAGE': // user defined type + case 'BLOB': // user defined type + case 'BIT': // This is a bit string, not a single bit, so don't return 'L' + case 'VARBIT': + case 'BYTEA': + return 'B'; + case 'BOOL': + case 'BOOLEAN': + return 'L'; + case 'DATE': + return 'D'; + case 'TIMESTAMP WITHOUT TIME ZONE': + case 'TIME': + case 'DATETIME': + case 'TIMESTAMP': + case 'TIMESTAMPTZ': + return 'T'; + case 'INTEGER': return !$is_serial ? 'I' : 'R'; + case 'SMALLINT': + case 'INT2': return !$is_serial ? 'I2' : 'R'; + case 'INT4': return !$is_serial ? 'I4' : 'R'; + case 'BIGINT': + case 'INT8': return !$is_serial ? 'I8' : 'R'; + case 'OID': + case 'SERIAL': + return 'R'; + case 'FLOAT4': + case 'FLOAT8': + case 'DOUBLE PRECISION': + case 'REAL': + return 'F'; + default: + static $typeMap = array( + 'VARCHAR' => 'C', + 'VARCHAR2' => 'C', + 'CHAR' => 'C', + 'C' => 'C', + 'STRING' => 'C', + 'NCHAR' => 'C', + 'NVARCHAR' => 'C', + 'VARYING' => 'C', + 'BPCHAR' => 'C', + 'CHARACTER' => 'C', + 'INTERVAL' => 'C', # Postgres + 'MACADDR' => 'C', # postgres + ## + 'LONGCHAR' => 'X', + 'TEXT' => 'X', + 'NTEXT' => 'X', + 'M' => 'X', + 'X' => 'X', + 'CLOB' => 'X', + 'NCLOB' => 'X', + 'LVARCHAR' => 'X', + ## + 'BLOB' => 'B', + 'IMAGE' => 'B', + 'BINARY' => 'B', + 'VARBINARY' => 'B', + 'LONGBINARY' => 'B', + 'B' => 'B', + ## + 'YEAR' => 'D', // mysql + 'DATE' => 'D', + 'D' => 'D', + ## + 'UNIQUEIDENTIFIER' => 'C', # MS SQL Server + ## + 'TIME' => 'T', + 'TIMESTAMP' => 'T', + 'DATETIME' => 'T', + 'TIMESTAMPTZ' => 'T', + 'T' => 'T', + 'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql + ## + 'BOOL' => 'L', + 'BOOLEAN' => 'L', + 'BIT' => 'L', + 'L' => 'L', + ## + 'COUNTER' => 'R', + 'R' => 'R', + 'SERIAL' => 'R', // ifx + 'INT IDENTITY' => 'R', + ## + 'INT' => 'I', + 'INT2' => 'I', + 'INT4' => 'I', + 'INT8' => 'I', + 'INTEGER' => 'I', + 'INTEGER UNSIGNED' => 'I', + 'SHORT' => 'I', + 'TINYINT' => 'I', + 'SMALLINT' => 'I', + 'I' => 'I', + ## + 'LONG' => 'N', // interbase is numeric, oci8 is blob + 'BIGINT' => 'N', // this is bigger than PHP 32-bit integers + 'DECIMAL' => 'N', + 'DEC' => 'N', + 'REAL' => 'N', + 'DOUBLE' => 'N', + 'DOUBLE PRECISION' => 'N', + 'SMALLFLOAT' => 'N', + 'FLOAT' => 'N', + 'NUMBER' => 'N', + 'NUM' => 'N', + 'NUMERIC' => 'N', + 'MONEY' => 'N', + + ## informix 9.2 + 'SQLINT' => 'I', + 'SQLSERIAL' => 'I', + 'SQLSMINT' => 'I', + 'SQLSMFLOAT' => 'N', + 'SQLFLOAT' => 'N', + 'SQLMONEY' => 'N', + 'SQLDECIMAL' => 'N', + 'SQLDATE' => 'D', + 'SQLVCHAR' => 'C', + 'SQLCHAR' => 'C', + 'SQLDTIME' => 'T', + 'SQLINTERVAL' => 'N', + 'SQLBYTES' => 'B', + 'SQLTEXT' => 'X', + ## informix 10 + "SQLINT8" => 'I8', + "SQLSERIAL8" => 'I8', + "SQLNCHAR" => 'C', + "SQLNVCHAR" => 'C', + "SQLLVARCHAR" => 'X', + "SQLBOOL" => 'L' + ); + + $tmap = false; + $t = strtoupper($t); + $tmap = (isset($typeMap[$t])) ? $typeMap[$t] : 'N'; + if ($t == 'LONG' && $this->dataProvider == 'oci8') return 'B'; + return $tmap; + } + } + +} + +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/postgres7/postgres7_transaction_module.inc b/lib/adodb/adodbSQL_drivers/postgres7/postgres7_transaction_module.inc new file mode 100644 index 0000000..6cdc61e --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/postgres7/postgres7_transaction_module.inc @@ -0,0 +1,128 @@ +transOff > 0) { + $this->transOff += 1; + return; + } + $this->transaction_status = true; + + if ($this->debug && $this->transCnt > 0) + ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans"); + + $this->BeginTrans(); + $this->transOff = 1; + } + + function BeginTrans() + { + if ($this->transOff) + return true; + + $this->transCnt += 1; + return @pg_Exec($this->connectionId, "begin"); + } + + function CompleteTrans($autoComplete = true) + { + if ($this->transOff > 1) { + $this->transOff -= 1; + return true; + } + $this->transOff = 0; + if ($this->transaction_status && $autoComplete) { + if (!$this->CommitTrans()) { + $this->transaction_status = false; + if ($this->debug) + ADOConnection::outp("Smart Commit failed"); + } else + if ($this->debug) + ADOConnection::outp("Smart Commit occurred"); + } else { + $this->RollbackTrans(); + if ($this->debug) + ADOCOnnection::outp("Smart Rollback occurred"); + } + return $this->transaction_status; + } + + function CommitTrans($ok=true) + { + if ($this->transOff) + return true; + + if (!$ok) + return $this->RollbackTrans(); + + $this->transCnt -= 1; + return @pg_Exec($this->connectionId, "commit"); + } + + function RollbackTrans() + { + if ($this->transOff) + return true; + + $this->transCnt -= 1; + return @pg_Exec($this->connectionId, "rollback"); + } + + function FailTrans() + { + if ($this->debug) + if ($this->transOff == 0) { + ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans"); + } else { + ADOConnection::outp("FailTrans was called"); + } + $this->transaction_status = false; + } + + function HasFailedTrans() + { + if ($this->transOff > 0) + return $this->transaction_status == false; + + return false; + } + + function RowLock($tables,$where,$flds='1 as ignore') + { + if (!$this->transCnt) + $this->BeginTrans(); + + return $this->GetOne("select $flds from $tables where $where for update"); + } + + function CommitLock($table) + { + return $this->CommitTrans(); + } + + function RollbackLock($table) + { + return $this->RollbackTrans(); + } + +} + +eval('class postgres7_transaction_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class postgres7_transaction_ResultSet extends postgres7_transaction_resultset_EXTENDER +{ +} +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/postgres8/postgres8_datadict.inc b/lib/adodb/adodbSQL_drivers/postgres8/postgres8_datadict.inc new file mode 100644 index 0000000..c8c7f9f --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/postgres8/postgres8_datadict.inc @@ -0,0 +1,211 @@ +TableName ($tabname); + $sql = array(); + list($lines,$pkey) = $this->_GenFields($flds); + $alter = 'ALTER TABLE ' . $tabname . $this->addCol . ' '; + foreach($lines as $v) { + if (($not_null = preg_match('/NOT NULL/i',$v))) { + $v = preg_replace('/NOT NULL/i','',$v); + } + if (preg_match('/^([^ ]+) .*(DEFAULT [^ ]+)/',$v,$matches)) { + list(,$colname,$default) = $matches; + $sql[] = $alter . str_replace($default,'',$v); + $sql[] = 'ALTER TABLE '.$tabname.' ALTER COLUMN '.$colname.' SET ' . $default; + } else { + $sql[] = $alter . $v; + } + if ($not_null) { + list($colname) = explode(' ',$v); + $sql[] = 'ALTER TABLE '.$tabname.' ALTER COLUMN '.$colname.' SET NOT NULL'; + } + } + return $sql; + } + + function AlterColumnSQL($tabname, $flds, $tableflds='',$tableoptions='') + { + if (!$tableflds) { + if ($this->debug) $this->outp("AlterColumnSQL needs a complete table-definiton for PostgreSQL"); + return array(); + } + return $this->_recreate_copy_table($tabname,False,$tableflds,$tableoptions); + } + + function DropColumnSQL($tabname, $flds, $tableflds='',$tableoptions='') + { + $has_drop_column = 7.3 <= (float) @$this->serverInfo['version']; + if (!$has_drop_column && !$tableflds) { + if ($this->debug) $this->outp("DropColumnSQL needs complete table-definiton for PostgreSQL < 7.3"); + return array(); + } + if ($has_drop_column) { + return ADODB_DataDict::DropColumnSQL($tabname, $flds); + } + return $this->_recreate_copy_table($tabname,$flds,$tableflds,$tableoptions); + } + + function DropTableSQL($tabname) + { + $sql = ADODB_DataDict::DropTableSQL($tabname); + $drop_seq = $this->_DropAutoIncrement($tabname); + if ($drop_seq) $sql[] = $drop_seq; + return $sql; + } + + function _CreateSuffix($fname, &$ftype, $fnotnull,$fdefault,$fautoinc,$fconstraint) + { + if ($fautoinc) { + $ftype = 'SERIAL'; + return ''; + } + $suffix = ''; + if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault"; + if ($fnotnull) $suffix .= ' NOT NULL'; + if ($fconstraint) $suffix .= ' '.$fconstraint; + return $suffix; + } + + function _DropAutoIncrement($tabname) + { + $tabname = $this->connection->qstr('%'.$tabname.'%'); + + $seq = $this->connection->GetOne("SELECT relname FROM pg_class WHERE NOT relname ~ 'pg_.*' AND relname LIKE $tabname AND relkind='S'"); + + // check if a tables depends on the sequenz and it therefor cant and dont need to be droped separatly + if (!$seq || $this->connection->GetOne("SELECT relname FROM pg_class JOIN pg_depend ON pg_class.relfilenode=pg_depend.objid WHERE relname='$seq' AND relkind='S' AND deptype='i'")) { + return False; + } + return "DROP SEQUENCE ".$seq; + } + + function _IndexSQL($idxname, $tabname, $flds, $idxoptions) + { + $sql = array(); + if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) { + $sql[] = sprintf ($this->dropIndex, $idxname, $tabname); + if ( isset($idxoptions['DROP']) ) + return $sql; + } + if ( empty ($flds) ) { + return $sql; + } + + $unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : ''; + $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' '; + if (isset($idxoptions['HASH'])) + $s .= 'USING HASH '; + + if ( isset($idxoptions[$this->upperName]) ) + $s .= $idxoptions[$this->upperName]; + + if ( is_array($flds) ) + $flds = implode(', ',$flds); + $s .= '(' . $flds . ')'; + $sql[] = $s; + return $sql; + } + + + function _recreate_copy_table($tabname,$dropflds,$tableflds,$tableoptions='') + { + if ($dropflds && !is_array($dropflds)) $dropflds = explode(',',$dropflds); + $copyflds = array(); + foreach($this->MetaColumns($tabname) as $fld) { + if (!$dropflds || !in_array($fld->name,$dropflds)) { + // we need to explicit convert varchar to a number to be able to do an AlterColumn of a char column to a nummeric one + if (preg_match('/'.$fld->name.' (I|I2|I4|I8|N|F)/i',$tableflds,$matches) && + in_array($fld->type,array('varchar','char','text','bytea'))) { + $copyflds[] = "to_number($fld->name,'S99D99')"; + } else { + $copyflds[] = $fld->name; + } + // identify the sequence name and the fld its on + if ($fld->primary_key && $fld->has_default && + preg_match("/nextval\('([^']+)'::text\)/",$fld->default_value,$matches)) { + $seq_name = $matches[1]; + $seq_fld = $fld->name; + } + } + } + $copyflds = implode(', ',$copyflds); + + $tempname = $tabname.'_tmp'; + $aSql[] = 'BEGIN'; // we use a transaction, to make sure not to loose the content of the table + $aSql[] = "SELECT * INTO TEMPORARY TABLE $tempname FROM $tabname"; + $aSql = array_merge($aSql,$this->DropTableSQL($tabname)); + $aSql = array_merge($aSql,$this->CreateTableSQL($tabname,$tableflds,$tableoptions)); + $aSql[] = "INSERT INTO $tabname SELECT $copyflds FROM $tempname"; + if ($seq_name && $seq_fld) { // if we have a sequence we need to set it again + $seq_name = $tabname.'_'.$seq_fld.'_seq'; // has to be the name of the new implicit sequence + $aSql[] = "SELECT setval('$seq_name',MAX($seq_fld)) FROM $tabname"; + } + $aSql[] = "DROP TABLE $tempname"; + // recreate the indexes, if they not contain one of the droped columns + foreach($this->MetaIndexes($tabname) as $idx_name => $idx_data) + { + if (substr($idx_name,-5) != '_pkey' && (!$dropflds || !count(array_intersect($dropflds,$idx_data['columns'])))) { + $aSql = array_merge($aSql,$this->CreateIndexSQL($idx_name,$tabname,$idx_data['columns'], + $idx_data['unique'] ? array('UNIQUE') : False)); + } + } + $aSql[] = 'COMMIT'; + return $aSql; + } +} + +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/postgres8/postgres8_date_module.inc b/lib/adodb/adodbSQL_drivers/postgres8/postgres8_date_module.inc new file mode 100644 index 0000000..99a4ad7 --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/postgres8/postgres8_date_module.inc @@ -0,0 +1,316 @@ +_Execute("select $this->sysTimeStamp"); + if ($rs && !$rs->EOF) + return $this->UnixTimeStamp(reset($rs->fields)); + + return false; + } + + function OffsetDate($dayFraction, $date=false) + { + if (!$date) + $date = $this->sysDate; + else if (strncmp($date,"'",1) == 0) { + $len = strlen($date); + if (10 <= $len && $len <= 12) + $date = 'date ' . $date; + else $date = 'timestamp ' . $date; + } + return "($date+interval'$dayFraction days')"; + } + + function SetDateLocale($locale = 'En') + { + $this->locale = $locale; + switch (strtoupper($locale)) + { + case 'EN': + $this->fmtDate="'Y-m-d'"; + $this->fmtTimeStamp = "'Y-m-d H:i:s'"; + break; + + case 'US': + $this->fmtDate = "'m-d-Y'"; + $this->fmtTimeStamp = "'m-d-Y H:i:s'"; + break; + + case 'NL': + case 'FR': + case 'RO': + case 'IT': + $this->fmtDate="'d-m-Y'"; + $this->fmtTimeStamp = "'d-m-Y H:i:s'"; + break; + + case 'GE': + $this->fmtDate="'d.m.Y'"; + $this->fmtTimeStamp = "'d.m.Y H:i:s'"; + break; + + default: + $this->fmtDate="'Y-m-d'"; + $this->fmtTimeStamp = "'Y-m-d H:i:s'"; + break; + } + } + + function DBDate($date) + { + if (empty($date) && $date !== 0) + return 'null'; + + if (is_string($date) && !is_numeric($date)) { + if ($date === 'null' || strncmp($date, "'", 1) === 0) + return $date; + + if ($this->isoDates) + return "'$date'"; + + $date = $this->UnixDate($date); + } + + return adodb_date($this->fmtDate,$date); + } + + function DBTimeStamp($timestamp) + { + if (empty($timestamp) && $timestamp !== 0) + return 'null'; + + # strlen(14) allows YYYYMMDDHHMMSS format + if (!is_string($timestamp) || (is_numeric($timestamp) && strlen($timestamp)<14)) + return adodb_date($this->fmtTimeStamp, $timestamp); + + if ($timestamp === 'null') + return $timestamp; + + if ($this->isoDates && strlen($timestamp) !== 14) + return "'$timestamp'"; + + $timestamp = $this->UnixTimeStamp($timestamp); + return adodb_date($this->fmtTimeStamp, $timestamp); + } + + function UnixDate($v) + { + if (is_object($v)) { + // odbtp support + //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 ) + return adodb_mktime($v->hour, $v->minute, $v->second, $v->month, $v->day, $v->year); + } + + if (is_numeric($v) && strlen($v) !== 8) + return $v; + + if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", ($v), $rr)) + return false; + + if ($rr[1] <= TIMESTAMP_FIRST_YEAR) + return 0; + + // h-m-s-MM-DD-YY + return adodb_mktime(0, 0, 0, $rr[2], $rr[3], $rr[1]); + } + + function UnixTimeStamp($v) + { + if (is_object($v)) { + // odbtp support + //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 ) + return adodb_mktime($v->hour, $v->minute, $v->second, $v->month, $v->day, $v->year); + } + + if (!preg_match("|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ ,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", ($v), $rr)) + return false; + + if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) + return 0; + + // h-m-s-MM-DD-YY + if (!isset($rr[5])) + return adodb_mktime(0, 0, 0, $rr[2], $rr[3], $rr[1]); + else return adodb_mktime($rr[5], $rr[6], $rr[7], $rr[2], $rr[3], $rr[1]); + } + + function UserDate($v, $fmt='Y-m-d', $gmt=false) + { + $tt = $this->UnixDate($v); + + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + else if ($tt == 0) + return $this->emptyDate; + else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR + } + + return ($gmt) ? adodb_gmdate($fmt, $tt) : adodb_date($fmt, $tt); + } + + function UserTimeStamp($v, $fmt='Y-m-d H:i:s', $gmt=false) + { + if (!isset($v)) + return $this->emptyTimeStamp; + + # strlen(14) allows YYYYMMDDHHMMSS format + if (is_numeric($v) && strlen($v)<14) + return ($gmt) ? adodb_gmdate($fmt,$v) : adodb_date($fmt,$v); + + $tt = $this->UnixTimeStamp($v); + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + + if ($tt == 0) + return $this->emptyTimeStamp; + else return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt); + } + + function SQLDate($fmt, $col=false) + { + if (!$col) + $col = $this->sysTimeStamp; + + $s = 'TO_CHAR('.$col.",'"; + $len = strlen($fmt); + for ($i=0; $i < $len; $i++) { + $ch = $fmt[$i]; + switch($ch) { + case 'Y': + case 'y': + $s .= 'YYYY'; + break; + + case 'Q': + case 'q': + $s .= 'Q'; + break; + + case 'M': + $s .= 'Mon'; + break; + + case 'm': + $s .= 'MM'; + break; + + case 'D': + case 'd': + $s .= 'DD'; + break; + + case 'H': + $s.= 'HH24'; + break; + + case 'h': + $s .= 'HH'; + break; + + case 'i': + $s .= 'MI'; + break; + + case 's': + $s .= 'SS'; + break; + + case 'a': + case 'A': + $s .= 'AM'; + break; + + case 'w': + $s .= 'D'; + break; + + case 'l': + $s .= 'DAY'; + break; + + default: + // handle escape characters... + if ($ch == '\\') { + $i++; + $ch = substr($fmt,$i,1); + } + if (strpos('-/.:;, ',$ch) !== false) + $s .= $ch; + else $s .= '"'.$ch.'"'; + } + } + return $s. "')"; + } +} + +eval('class postgres8_date_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class postgres8_date_ResultSet extends postgres8_date_resultset_EXTENDER +{ + var $emptyTimeStamp = ' '; /// what to display when $time==0 + var $emptyDate = ' '; /// what to display when $time==0 + var $datetime = false; + + function UserTimeStamp($v, $fmt='Y-m-d H:i:s') + { + if (is_numeric($v) && strlen($v)<14) + return adodb_date($fmt,$v); + + $tt = $this->UnixTimeStamp($v); + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + + if ($tt === 0) + return $this->emptyTimeStamp; + else return adodb_date($fmt,$tt); + } + + function UserDate($v,$fmt='Y-m-d') + { + $tt = $this->UnixDate($v); + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + else if ($tt == 0) + return $this->emptyDate; + else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR + } + return adodb_date($fmt,$tt); + } + + function UnixDate($v) + { + return postgres8_date_ADOConnection::UnixDate($v); + } + + function UnixTimeStamp($v) + { + return postgres8_date_ADOConnection::UnixTimeStamp($v); + } + +} +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/postgres8/postgres8_driver.inc b/lib/adodb/adodbSQL_drivers/postgres8/postgres8_driver.inc new file mode 100644 index 0000000..ea60d32 --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/postgres8/postgres8_driver.inc @@ -0,0 +1,663 @@ +dbtype = 'postgres8'; + $this->dataProvider = 'postgres'; + } + + /** + * Connection to database server and selected database + * + * @access private + */ + + function _connect($host = "", $username = "", $password = "", $database = "", $persistent, $forcenew) + { + if (!function_exists('pg_connect')) return false; + + $this->host = $host; + $this->username = $this->query_addslashes($username); + $this->password = $this->query_addslashes($password); + if (strlen($database) == 0) $database = 'template1'; + $this->database = $this->query_addslashes($database); + + if ($this->username || $this->password || $this->database) { + $this->connect_string = $this->host; + if ($this->connect_string) { + $host = split(":", $this->connect_string); + if ($host[0]) $this->connect_string = "host=" . $this->query_addslashes($host[0]); + else $this->connect_string = 'host=localhost'; + if (isset($host[1])) $this->connect_string .= " port=$host[1]"; + else if (!empty($this->port)) $this->connect_string .= " port=" . $this->port; + } + if ($this->username) $this->connect_string .= " user=" . $this->username; + if ($this->password) $this->connect_string .= " password=" . $this->password; + if ($this->database) $this->connect_string .= " dbname=" . $this->database; + } + else + { + $this->connect_string = $this->host; + } + + $this->persistent = $persistent; + $this->forcenewconnection = $forcenew; + + $this->_makeconnection(); + + if ($this->connectionId === false) + { + if ($fn = $this->raiseErrorFn) + $fn($this->dbtype, 'CONNECT', $this->ErrorNo(), $this->ErrorMsg(), $this->host, $this->database, $this); + return $this->SelectDB( $this->database ); + } + + return true; + } + + function _makeconnection() + { + if($this->persistent == 1) + { + $this->connectionId = @pg_pconnect( $this->connect_string ); + } + else + { + if(!$this->forcenewconnection) + { + $this->connectionId = @pg_connect( $this->connect_string ); + } + else + { + $this->connectionId = @pg_connect( $this->connect_string, PGSQL_CONNECT_FORCE_NEW ); + } + } + } + + function query_addslashes($query) + { + $len = strlen($query); + if ($len == 0) + return "''"; + if (strncmp($query,"'",1) === 0 && substr($query,$len-1) == "'") + return $s; + return "'".addslashes($query)."'"; + } + + /** + * Choose a database to connect. + * + * @param dbname is the name of the database to select + * @return true or false + * @access public + */ + + function SelectDB($dbname) + { + $this->database = $dbname; + + if ($this->connectionId === false) + { + if($this->createdatabase == true) + { + $this->connectionId = @pg_pconnect( "host=$this->host user=$this->username password=$this->password" ); + $result = @pg_query($this->connectionId, "CREATE DATABASE " . $this->database ); + if ($result === false) { // error handling if query fails + $this->connectionId = false; + return false; + } + + $this->_makeconnection(); + if($this->connectionId === false) + { + $this->connectionId = false; + return false; + } + else + { + return true; + } + } + $this->connectionId = false; + return false; + } + else + { + return true; + } + } + + /** + * Return database error message + * Usage: $errormessage =& $db->ErrorMsg(); + * + * @access public + */ + + function ErrorMsg() + { + return @pg_last_error($this->connectionId); + } + + /** + * Return database error number + * Usage: $errorbo =& $db->ErrorNo(); + * + * @access public + */ + + function ErrorNo() + { + $error = @pg_last_error( $this->connectionId ); + return strlen($error) ? $error : 0; + } + + /** + * Returns # of affected rows from insert/delete/update query + * + * @access public + * @return integer Affected rows + */ + + function Affected_Rows() + { + return @pg_affected_rows( $this->record_set ); + } + + /** + * Returns the last record id of an inserted item + * Usage: $db->Insert_ID(); + * + * @access public + */ + + function Insert_ID() + { + return @pg_getlastoid($this->record_set); + } + + /** + * Correctly quotes a string so that all strings are escape coded. + * An example is $db->qstr("Haven't a clue."); + * + * @param string the string to quote + * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc(). + * + * @return single-quoted string IE: 'Haven\'t a clue.' + */ + + function qstr($string, $magic_quotes=false) + { + // Ugly hack alert! Repalce backticks with some arbitrary character + $string = str_replace('`', "\x1C", $string); + if (!$magic_quotes) { + if (strnatcmp(PHP_VERSION, '4.2.0') >= 0) { + return "'" . pg_escape_string($string) . "'"; + } + $string = str_replace("'", "\\'", str_replace('\\', '\\\\', str_replace("\0", "\\\0", $string))); + return "'" . $string . "'"; + } + return "'" . str_replace('\\"', '"', $string) . "'"; + } + + function QMagic($string) + { + return $this->qstr($string, get_magic_quotes_gpc()); + } + + /** + * Returns concatenated string + * Usage: $db->Concat($str1,$str2); + * + * @return concatenated string + */ + function Concat() + { + $arr = func_get_args(); + return implode("||", $arr); + } + + function IfNull( $field, $ifNull ) + { + return " coalesce($field, $ifNull) "; + } + + /** + * Closes database connection + * Usage: $db->close(); + * + * @access public + */ + + function Close() + { + @pg_close( $this->connectionId ); + $this->connectionId = false; + } + + /** + * Returns All Records in an array + * + * Usage: $db->GetAll($sql); + * @access public + */ + + function &GetAll($sql, $inputarr = false) + { + $data =& $this->GetArray($sql, $inputarr); + return $data; + } + + /** + * Returns All Records in an array + * + * Usage: $db->GetArray($sql); + * @access public + */ + + function &GetArray($sql, $inputarr = false) + { + $data = false; + $result =& $this->Execute($sql, $inputarr); + if ($result) + { + $data =& $result->GetArray(); + $result->Close(); + } + return $data; + } + + /** + * Executes SQL query and instantiates resultset methods + * + * @access private + * @return mixed Resultset methods + */ + + function &do_query( $sql, $offset, $nrows, $inputarr=false ) + { + global $ADODB_FETCH_MODE; + $sql = str_replace('`', '"', $sql); + $sql = str_replace("\x1C", "`", $sql); + $sql = str_replace('IS_DELETED', 'is_deleted', $sql); + $sql = str_replace("HIGH_PRIORITY", "", $sql); + $false = false; + + $offsetStr = ''; + $limitStr = ''; + if ($offset != -1 || $nrows != -1) + { + $offsetStr = ($offset >= 0) ? " OFFSET " . ((integer)$offset) : ''; + $limitStr = ($nrows >= 0) ? " LIMIT " . ((integer)$nrows) : ''; + } + + if ($inputarr && is_array($inputarr)) { + $sqlarr = explode('?', $sql); + if (!is_array(reset($inputarr))) $inputarr = array($inputarr); + foreach($inputarr as $arr) { + $sql = ''; $i = 0; + foreach($arr as $v) { + $sql .= $sqlarr[$i]; + switch(gettype($v)){ + case 'string': + $sql .= $this->qstr($v); + break; + case 'double': + $sql .= str_replace(',', '.', $v); + break; + case 'boolean': + $sql .= $v ? "'t'" : "'f'"; + break; + default: + if ($v === null) + $sql .= 'NULL'; + else $sql .= $v; + } + $i += 1; + } + $sql .= $sqlarr[$i]; + if ($i+1 != sizeof($sqlarr)) + return $false; + $this->sql = $sql . "$limitStr$offsetStr"; + $time_start = array_sum(explode(' ', microtime())); + $this->query_count++; + $resultId = @pg_query( $this->sql); + $time_total = (array_sum(explode(' ', microtime())) - $time_start); + $this->query_time_total += $time_total; + if($this->debug_console) + { + $this->query_list[] = $this->sql; + $this->query_list_time[] = $time_total; + $this->query_list_errors[] = $this->ErrorMsg(); + } + if($this->debug) + { + $this->outp($sql . "$limitStr$offsetStr"); + } + if ($resultId === false) { // error handling if query fails + if ($fn = $this->raiseErrorFn) + $fn($this->dbtype, 'EXECUTE', $this->ErrorNo(), $this->ErrorMsg(), $this->sql, $inputarr, $this); + return $false; + } + } + } + else + { + $this->sql = $sql . "$limitStr$offsetStr"; + $time_start = array_sum(explode(' ', microtime())); + $this->query_count++; + $resultId = @pg_query( $this->sql); + $time_total = (array_sum(explode(' ', microtime())) - $time_start); + $this->query_time_total += $time_total; + if($this->debug_console) + { + $this->query_list[] = $this->sql; + $this->query_list_time[] = $time_total; + $this->query_list_errors[] = $this->ErrorMsg(); + } + if($this->debug) + { + $this->outp($sql . "$limitStr$offsetStr"); + } + } + + if ($resultId === false) { // error handling if query fails + if ($fn = $this->raiseErrorFn) + $fn($this->dbtype, 'EXECUTE', $this->ErrorNo(), $this->ErrorMsg(), $this->sql, $inputarr, $this); + return $false; + } + + if (@pg_numfields( $resultId ) <= 0) { // return simplified recordset for inserts/updates/deletes with lower overhead + $recordset = new ADORecordSet_empty(); + $this->record_set = $recordset; + return $recordset; + } + + $resultset_name = $this->last_module_name . "_ResultSet"; + $recordset = new $resultset_name( $resultId, $this->connectionId ); + $this->record_set = $recordset; + + $recordset->_currentRow = 0; + + switch ($ADODB_FETCH_MODE) + { + case ADODB_FETCH_NUM: $recordset->fetchMode = PGSQL_NUM; break; + case ADODB_FETCH_ASSOC:$recordset->fetchMode = PGSQL_ASSOC; break; + default: + case ADODB_FETCH_DEFAULT: + case ADODB_FETCH_BOTH:$recordset->fetchMode = PGSQL_BOTH; break; + } + + $recordset->_numOfRows = @pg_numrows( $resultId ); + if( $recordset->_numOfRows == 0) + { + $recordset->EOF = true; + } + $recordset->_numOfFields = @pg_numfields( $resultId ); + $recordset->_fetch(); + + return $recordset; + } +} + +class postgres8_driver_ResultSet +{ + var $connectionId; + var $fields; + var $resultId; + var $_currentRow = 0; + var $_numOfRows = -1; + var $_numOfFields = -1; + var $fetchMode; + var $EOF; + + /** + * pgsqlResultSet Constructor + * + * @access private + * @param string $record + * @param string $resultId + */ + + function postgres8_driver_ResultSet( $resultId, $connectionId ) + { + $this->fields = array(); + $this->connectionId = $connectionId; + $this->record = array(); + $this->resultId = $resultId; + $this->EOF = false; + } + + /** + * Frees resultset + * + * @access public + */ + + function close() + { + pg_free_result( $this->resultId ); + $this->fields = array(); + $this->resultId = false; + } + + /** + * Returns field name from select query + * + * @access public + * @param string $field + * @return string Field name + */ + + function fields( $field ) + { + if(empty($field)) + { + return $this->fields; + } + else + { + return $this->fields[$field]; + } + } + + /** + * Returns numrows from select query + * + * @access public + * @return integer Numrows + */ + + function RecordCount() + { + return $this->_numOfRows; + } + + /** + * Returns num of fields from select query + * + * @access public + * @return integer numfields + */ + + function FieldCount() + { + return $this->_numOfFields; + } + + /** + * Returns next record + * + * @access public + */ + + function MoveNext() + { + if (@$this->fields = pg_fetch_array($this->resultId, NULL, $this->fetchMode)) { + $this->_currentRow += 1; + return true; + } + if (!$this->EOF) { + $this->_currentRow += 1; + $this->EOF = true; + } + return false; + } + + /** + * Move to the first row in the recordset. Many databases do NOT support this. + * + * @return true or false + */ + + function MoveFirst() + { + if ($this->_currentRow == 0) return true; + return $this->Move(0); + } + + /** + * Returns the Last Record + * + * @access public + */ + + function MoveLast() + { + if ($this->EOF) return false; + return $this->Move($this->_numOfRows - 1); + } + + /** + * Random access to a specific row in the recordset. Some databases do not support + * access to previous rows in the databases (no scrolling backwards). + * + * @param rowNumber is the row to move to (0-based) + * + * @return true if there still rows available, or false if there are no more rows (EOF). + */ + + function Move($rowNumber = 0) + { + if ($rowNumber == $this->_currentRow) return true; + $this->EOF = false; + if ($this->_numOfRows > 0){ + if ($rowNumber >= $this->_numOfRows - 1){ + $rowNumber = $this->_numOfRows - 1; + } + } + + if ($this->_seek($rowNumber)) { + $this->_currentRow = $rowNumber; + if ($this->_fetch()) { + return true; + } + $this->fields = false; + } + $this->EOF = true; + return false; + } + + /** + * Perform Seek to specific row + * + * @access private + */ + + function _seek($row) + { + if ($this->_numOfRows == 0) return false; + return @pg_result_seek($this->resultId,$row); + } + + /** + * Fills field array with first database element when query initially executed + * + * @access private + */ + + function _fetch() + { + $this->fields = @pg_fetch_array($this->resultId, NULL, $this->fetchMode); + return is_array($this->fields); + } + + /** + * Check to see if last record reached + * + * @access public + */ + + function EOF() + { + if( $this->_currentRow < $this->_numOfRows) + { + return false; + } + else + { + $this->EOF = true; + return true; + } + } + + /** + * Returns All Records in an array + * + * @access public + * @param [nRows] is the number of rows to return. -1 means every row. + */ + + function &GetArray($nRows = -1) + { + $results = array(); + $cnt = 0; + while (!$this->EOF && $nRows != $cnt) { + $results[] = $this->fields; + $this->MoveNext(); + $cnt++; + } + return $results; + } + + function &GetRows($nRows = -1) + { + $arr =& $this->GetArray($nRows); + return $arr; + } + + function &GetAll($nRows = -1) + { + $arr =& $this->GetArray($nRows); + return $arr; + } + + /** + * Fetch field information for a table. + * + * @return object containing the name, type and max_length + */ + function FetchField($fieldOffset = -1) + { + $fieldObject= new ADOFieldObject(); + $fieldObject->name = @pg_fieldname($this->resultId, $fieldOffset); + $fieldObject->type = @pg_fieldtype($this->resultId, $fieldOffset); + $fieldObject->max_length = @pg_fieldsize($this->resultId, $fieldOffset); + return $fieldObject; + } +} +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/postgres8/postgres8_extend_module.inc b/lib/adodb/adodbSQL_drivers/postgres8/postgres8_extend_module.inc new file mode 100644 index 0000000..c1096dc --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/postgres8/postgres8_extend_module.inc @@ -0,0 +1,147 @@ +Execute($sql, $inputarr); + if ($result) { + $data =& $result->GetAssoc($force_array, $first2cols); + $result->Close(); + } + return $data; + } + + /** + * Generates a sequence id and stores it in $this->genID; + * GenID is only available if $this->hasGenID = true; + * + * @param seqname name of sequence to use + * @param startID if sequence does not exist, start at this ID + * @return 0 if not supported, otherwise a sequence id + */ + + var $_genIDSQL = "SELECT NEXTVAL('%s')"; + var $_genSeqSQL = "CREATE SEQUENCE %s START %s"; + var $_dropSeqSQL = "DROP SEQUENCE %s"; + var $genID = 0; + + function GenID($seqname='adodbseq', $startID=1) + { + $getnext = sprintf($this->_genIDSQL, $seqname); + $holdtransOK = $this->transaction_status; + $save_handler = $this->raiseErrorFn; + $this->raiseErrorFn = ''; + @($result = $this->Execute($getnext)); + $this->raiseErrorFn = $save_handler; + + if (!$result) { + $this->transaction_status = $holdtransOK; + $createseq = $this->Execute(sprintf($this->_genSeqSQL, $seqname, $startID)); + $result = $this->Execute($getnext); + } + if ($result && !$result->EOF) + $this->genID = reset($result->fields); + else $this->genID = 0; + + if ($result) + $result->Close(); + + return $this->genID; + } + + function CreateSequence($seqname='adodbseq', $startID=1) + { + return $this->Execute(sprintf($this->_genSeqSQL, $seqname, $startID)); + } + + function DropSequence($seqname='adodbseq') + { + return $this->Execute(sprintf($this->_dropSeqSQL, $seqname)); + } + +} + +eval('class postgres8_extend_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class postgres8_extend_ResultSet extends postgres8_extend_resultset_EXTENDER +{ + function &GetAssoc($force_array = false, $first2cols = false) + { + $results = false; + + if ($this->_numOfFields > 1) { + $numIndex = isset($this->fields[0]); + $results = array(); + if (!$first2cols && ($this->_numOfFields > 2 || $force_array)) { + if ($numIndex) { + while (!$this->EOF) { + $results[trim($this->fields[0])] = array_slice($this->fields, 1); + $this->MoveNext(); + } + } else { + while (!$this->EOF) { + $results[trim(reset($this->fields))] = array_slice($this->fields, 1); + $this->MoveNext(); + } + } + } else { + if ($numIndex) { + while (!$this->EOF) { + $results[trim(($this->fields[0]))] = $this->fields[1]; + $this->MoveNext(); + } + } else { + while (!$this->EOF) { + $v1 = trim(reset($this->fields)); + $v2 = ''.next($this->fields); + $results[$v1] = $v2; + $this->MoveNext(); + } + } + } + } + return $results; + } + + function PO_RecordCount($table="", $condition="") + { + $lnumrows = $this->_numOfRows; + if($lnumrows == -1 && $this->connectionId) + { + if($table) + { + if ($condition) + $condition = " WHERE " . $condition; + $resultrows = &$this->connectionId->Execute("SELECT COUNT(*) FROM $table $condition"); + if ($resultrows) + $lnumrows = reset($resultrows->fields); + } + } + return $lnumrows; + } + + function CurrentRow() + { + return $this->_currentRow; + } + + function AbsolutePosition() + { + return $this->_currentRow; + } + + function NextRecordSet() + { + return false; + } + +} +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/postgres8/postgres8_meta_module.inc b/lib/adodb/adodbSQL_drivers/postgres8/postgres8_meta_module.inc new file mode 100644 index 0000000..87d9a72 --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/postgres8/postgres8_meta_module.inc @@ -0,0 +1,712 @@ + 0 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum"; + + // used when schema defined + var $metaColumnsSQL1 = "SELECT a.attname, t.typname, a.attlen, a.atttypmod, a.attnotnull, a.atthasdef, a.attnum +FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n +WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s')) + and c.relnamespace=n.oid and n.nspname='%s' + and a.attname not like '....%%' AND a.attnum > 0 + AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum"; + + // get primary key etc -- from Freek Dijkstra + var $metaKeySQL = "SELECT ic.relname AS index_name, a.attname AS column_name,i.indisunique AS unique_key, i.indisprimary AS primary_key + FROM pg_class bc, pg_class ic, pg_index i, pg_attribute a WHERE bc.oid = i.indrelid AND ic.oid = i.indexrelid AND (i.indkey[0] = a.attnum OR i.indkey[1] = a.attnum OR i.indkey[2] = a.attnum OR i.indkey[3] = a.attnum OR i.indkey[4] = a.attnum OR i.indkey[5] = a.attnum OR i.indkey[6] = a.attnum OR i.indkey[7] = a.attnum) AND a.attrelid = bc.oid AND bc.relname = '%s'"; + var $metaDefaultsSQL = "SELECT d.adnum as num, d.adsrc as def from pg_attrdef d, pg_class c where d.adrelid=c.oid and c.relname='%s' order by d.adnum"; + + function MetaError($err=false) + { + include_once(ADODB_DIR."/adodb-error.inc.php"); + if ($err === false) + $err = $this->ErrorNo(); + + return adodb_error($this->dataProvider,$this->databaseType,$err); + } + + function MetaErrorMsg($errno) + { + include_once(ADODB_DIR."/adodb-error.inc.php"); + return adodb_errormsg($errno); + } + + /** + * @returns an array with the primary key columns in it. + */ + function MetaPrimaryKeys($table, $owner=false) + { + // owner not used in base class - see oci8 + $p = array(); + $objs =& $this->MetaColumns($table); + if ($objs) { + foreach($objs as $v) { + if (!empty($v->primary_key)) + $p[] = $v->name; + } + } + if (sizeof($p)) return $p; + if (function_exists('ADODB_VIEW_PRIMARYKEYS')) + return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner); + return false; + } + + /** + * @returns assoc array where keys are tables, and values are foreign keys + */ + function MetaForeignKeys($table, $owner=false, $upper=false) + { + $sql = 'SELECT t.tgargs as args + FROM + pg_trigger t,pg_class c,pg_proc p + WHERE + t.tgenabled AND + t.tgrelid = c.oid AND + t.tgfoid = p.oid AND + p.proname = \'RI_FKey_check_ins\' AND + c.relname = \''.strtolower($table).'\' + ORDER BY + t.tgrelid'; + + $rs =& $this->Execute($sql); + + if (!$rs || $rs->EOF) return false; + + $arr =& $rs->GetArray(); + $a = array(); + foreach($arr as $v) { + $data = explode(chr(0), $v['args']); + $size = count($data)-1; //-1 because the last node is empty + for($i = 4; $i < $size; $i++) { + if ($upper) + $a[strtoupper($data[2])][] = strtoupper($data[$i].'='.$data[++$i]); + else + $a[$data[2]][] = $data[$i].'='.$data[++$i]; + } + } + return $a; + } + + // not the fastest implementation - quick and dirty - jlim + // for best performance, use the actual $rs->MetaType(). + function MetaType($t,$len=-1,$fieldobj=false) + { + if (empty($this->_metars)) { + $rsclass = $this->last_module_name . "_ResultSet"; + $this->_metars =& new $rsclass(false,$this->fetchMode); + } + + return $this->_metars->MetaType($t,$len,$fieldobj); + } + + /** + * return the databases that the driver can connect to. + * Some databases will return an empty array. + * + * @return an array of database names. + */ + function MetaDatabases() + { + global $ADODB_FETCH_MODE; + + if ($this->metaDatabasesSQL) { + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + + $arr = $this->GetCol($this->metaDatabasesSQL); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + return $arr; + } + + return false; + } + + /** + * @param ttype can either be 'VIEW' or 'TABLE' or false. + * If false, both views and tables are returned. + * "VIEW" returns only views + * "TABLE" returns only tables + * @param showSchema returns the schema/user with the table name, eg. USER.TABLE + * @param mask is the input mask - only supported by oci8 and postgresql + * + * @return array of tables for current database. + */ + function &MetaTables($ttype=false,$showSchema=false,$mask=false) + { + $info = $this->ServerInfo(); + if ($info['version'] >= 7.3) { + $this->metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%' + and schemaname not in ( 'pg_catalog','information_schema') + union + select viewname,'V' from pg_views where viewname not like 'pg\_%' and schemaname not in ( 'pg_catalog','information_schema') "; + } + if ($mask) { + $save = $this->metaTablesSQL; + $mask = $this->qstr(strtolower($mask)); + if ($info['version']>=7.3) + $this->metaTablesSQL = " +select tablename,'T' from pg_tables where tablename like $mask and schemaname not in ( 'pg_catalog','information_schema') + union +select viewname,'V' from pg_views where viewname like $mask and schemaname not in ( 'pg_catalog','information_schema') "; + else + $this->metaTablesSQL = " +select tablename,'T' from pg_tables where tablename like $mask + union +select viewname,'V' from pg_views where viewname like $mask"; + } + $ret =& $this->_MetaTables($ttype,$showSchema); + + if ($mask) { + $this->metaTablesSQL = $save; + } + return $ret; + } + + function &_MetaTables($ttype=false,$showSchema=false,$mask=false) + { + global $ADODB_FETCH_MODE; + + $false = false; + if ($mask) { + return $false; + } + if ($this->metaTablesSQL) { + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + + $rs = $this->Execute($this->metaTablesSQL); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if ($rs === false) return $false; + $arr =& $rs->GetArray(); + $arr2 = array(); + + if ($hast = ($ttype && isset($arr[0][1]))) { + $showt = strncmp($ttype,'T',1); + } + + for ($i=0; $i < sizeof($arr); $i++) { + if ($hast) { + if ($showt == 0) { + if (strncmp($arr[$i][1],'T',1) == 0) $arr2[] = trim($arr[$i][0]); + } else { + if (strncmp($arr[$i][1],'V',1) == 0) $arr2[] = trim($arr[$i][0]); + } + } else + $arr2[] = trim($arr[$i][0]); + } + $rs->Close(); + return $arr2; + } + return $false; + } + + function _findschema(&$table,&$schema) + { + if (!$schema && ($at = strpos($table,'.')) !== false) { + $schema = substr($table,0,$at); + $table = substr($table,$at+1); + } + } + + /** + * List columns in a database as an array of ADOFieldObjects. + * See top of file for definition of object. + * + * @param $table table name to query + * @param $normalize makes table name case-insensitive (required by some databases) + * @schema is optional database schema to use - not supported by all databases. + * + * @return array of ADOFieldObjects for current table. + */ + function &MetaColumns($table,$normalize=true) + { + global $ADODB_FETCH_MODE; + + $schema = false; + $false = false; + $this->_findschema($table,$schema); + + if ($normalize) $table = strtolower($table); + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + + if ($schema) $rs =& $this->Execute(sprintf($this->metaColumnsSQL1,$table,$table,$schema)); + else $rs =& $this->Execute(sprintf($this->metaColumnsSQL,$table,$table)); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if ($rs === false) { + return $false; + } + if (!empty($this->metaKeySQL)) { + // If we want the primary keys, we have to issue a separate query + // Of course, a modified version of the metaColumnsSQL query using a + // LEFT JOIN would have been much more elegant, but postgres does + // not support OUTER JOINS. So here is the clumsy way. + + $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; + + $rskey = $this->Execute(sprintf($this->metaKeySQL,($table))); + // fetch all result in once for performance. + $keys =& $rskey->GetArray(); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + $rskey->Close(); + unset($rskey); + } + + $rsdefa = array(); + if (!empty($this->metaDefaultsSQL)) { + $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; + $sql = sprintf($this->metaDefaultsSQL, ($table)); + $rsdef = $this->Execute($sql); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if ($rsdef) { + while (!$rsdef->EOF) { + $num = $rsdef->fields['num']; + $s = $rsdef->fields['def']; + if (strpos($s,'::')===false && substr($s, 0, 1) == "'") { /* quoted strings hack... for now... fixme */ + $s = substr($s, 1); + $s = substr($s, 0, strlen($s) - 1); + } + + $rsdefa[$num] = $s; + $rsdef->MoveNext(); + } + } else { + ADOConnection::outp( "==> SQL => " . $sql); + } + unset($rsdef); + } + + $retarr = array(); + while (!$rs->EOF) { + $fld = new ADOFieldObject(); + $fld->name = $rs->fields[0]; + $fld->type = $rs->fields[1]; + $fld->max_length = $rs->fields[2]; + $fld->attnum = $rs->fields[6]; + + if ($fld->max_length <= 0) $fld->max_length = $rs->fields[3]-4; + if ($fld->max_length <= 0) $fld->max_length = -1; + if ($fld->type == 'numeric') { + $fld->scale = $fld->max_length & 0xFFFF; + $fld->max_length >>= 16; + } + // dannym + // 5 hasdefault; 6 num-of-column + $fld->has_default = ($rs->fields[5] == 't'); + if ($fld->has_default) { + $fld->default_value = $rsdefa[$rs->fields[6]]; + } + + //Freek + $fld->not_null = $rs->fields[4] == 't'; + + + // Freek + if (is_array($keys)) { + foreach($keys as $key) { + if ($fld->name == $key['column_name'] AND $key['primary_key'] == 't') + $fld->primary_key = true; + if ($fld->name == $key['column_name'] AND $key['unique_key'] == 't') + $fld->unique = true; // What name is more compatible? + } + } + + if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld; + else $retarr[($normalize) ? strtoupper($fld->name) : $fld->name] = $fld; + + $rs->MoveNext(); + } + $rs->Close(); + if (empty($retarr)) + return $false; + else + return $retarr; + + } + + /** + * List indexes on a table as an array. + * @param table table name to query + * @param primary true to only show primary keys. Not actually used for most databases + * + * @return array of indexes on current table. Each element represents an index, and is itself an associative array. + + Array ( + [name_of_index] => Array + ( + [unique] => true or false + [columns] => Array + ( + [0] => firstname + [1] => lastname + ) + ) + */ + function &MetaIndexes ($table, $primary = FALSE) + { + global $ADODB_FETCH_MODE; + + $schema = false; + $this->_findschema($table,$schema); + + if ($schema) { // requires pgsql 7.3+ - pg_namespace used. + $sql = ' +SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns" +FROM pg_catalog.pg_class c +JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid +JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid + ,pg_namespace n +WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\')) and c.relnamespace=c2.relnamespace and c.relnamespace=n.oid and n.nspname=\'%s\''; + } else { + $sql = ' +SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns" +FROM pg_catalog.pg_class c +JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid +JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid +WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\'))'; + } + + if ($primary == FALSE) { + $sql .= ' AND i.indisprimary=false;'; + } + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== FALSE) { + $savem = $this->SetFetchMode(FALSE); + } + + $rs = $this->Execute(sprintf($sql,$table,$table,$schema)); + if (isset($savem)) { + $this->SetFetchMode($savem); + } + $ADODB_FETCH_MODE = $save; + + if (!is_object($rs)) { + $false = false; + return $false; + } + + $col_names = $this->MetaColumnNames($table,true,true); + //3rd param is use attnum, + // see http://sourceforge.net/tracker/index.php?func=detail&aid=1451245&group_id=42718&atid=433976 + $indexes = array(); + while ($row = $rs->FetchRow()) { + $columns = array(); + foreach (explode(' ', $row[2]) as $col) { + $columns[] = $col_names[$col]; + } + + $indexes[$row[0]] = array( + 'unique' => ($row[1] == 't'), + 'columns' => $columns + ); + } + return $indexes; + } + + /** + * List columns names in a table as an array. + * @param table table name to query + * + * @return array of column names for current table. + */ + function &MetaColumnNames($table, $numIndexes=false,$useattnum=false /* only for postgres */) + { + $objarr =& $this->MetaColumns($table); + if (!is_array($objarr)) { + $false = false; + return $false; + } + $arr = array(); + if ($numIndexes) { + $i = 0; + if ($useattnum) { + foreach($objarr as $v) + $arr[$v->attnum] = $v->name; + + } else + foreach($objarr as $v) $arr[$i++] = $v->name; + } else + foreach($objarr as $v) $arr[strtoupper($v->name)] = $v->name; + + return $arr; + } + + function MetaTransaction($mode,$db) + { + $mode = strtoupper($mode); + $mode = str_replace('ISOLATION LEVEL ','',$mode); + + switch($mode) { + + case 'READ UNCOMMITTED': + switch($db) { + case 'oci8': + case 'oracle': + return 'ISOLATION LEVEL READ COMMITTED'; + default: + return 'ISOLATION LEVEL READ UNCOMMITTED'; + } + break; + + case 'READ COMMITTED': + return 'ISOLATION LEVEL READ COMMITTED'; + break; + + case 'REPEATABLE READ': + switch($db) { + case 'oci8': + case 'oracle': + return 'ISOLATION LEVEL SERIALIZABLE'; + default: + return 'ISOLATION LEVEL REPEATABLE READ'; + } + break; + + case 'SERIALIZABLE': + return 'ISOLATION LEVEL SERIALIZABLE'; + break; + + default: + return $mode; + } + } + +} + +eval('class postgres8_meta_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class postgres8_meta_ResultSet extends postgres8_meta_resultset_EXTENDER +{ + /** + * Get the metatype of the column. This is used for formatting. This is because + * many databases use different names for the same type, so we transform the original + * type to our standardised version which uses 1 character codes: + * + * @param t is the type passed in. Normally is ADOFieldObject->type. + * @param len is the maximum length of that field. This is because we treat character + * fields bigger than a certain size as a 'B' (blob). + * @param fieldobj is the field object returned by the database driver. Can hold + * additional info (eg. primary_key for mysql). + * + * @return the general type of the data: + * C for character < 250 chars + * X for teXt (>= 250 chars) + * B for Binary + * N for numeric or floating point + * D for date + * T for timestamp + * L for logical/Boolean + * I for integer + * R for autoincrement counter/integer + * + * + */ + function MetaType($t,$len=-1,$fieldobj=false) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + $is_serial = is_object($fieldobj) && $fieldobj->primary_key && $fieldobj->unique && $fieldobj->has_default && substr($fieldobj->default_value,0,8) == 'nextval('; + switch (strtoupper($t)) { + case 'MONEY': // stupid, postgres expects money to be a string + case 'INTERVAL': + case 'CHAR': + case 'CHARACTER': + case 'VARCHAR': + case 'NAME': + case 'BPCHAR': + case '_VARCHAR': + case 'INET': + case 'MACADDR': + if ($len <= $this->blobSize) return 'C'; + case 'TEXT': + return 'X'; + case 'IMAGE': // user defined type + case 'BLOB': // user defined type + case 'BIT': // This is a bit string, not a single bit, so don't return 'L' + case 'VARBIT': + case 'BYTEA': + return 'B'; + case 'BOOL': + case 'BOOLEAN': + return 'L'; + case 'DATE': + return 'D'; + case 'TIMESTAMP WITHOUT TIME ZONE': + case 'TIME': + case 'DATETIME': + case 'TIMESTAMP': + case 'TIMESTAMPTZ': + return 'T'; + case 'INTEGER': return !$is_serial ? 'I' : 'R'; + case 'SMALLINT': + case 'INT2': return !$is_serial ? 'I2' : 'R'; + case 'INT4': return !$is_serial ? 'I4' : 'R'; + case 'BIGINT': + case 'INT8': return !$is_serial ? 'I8' : 'R'; + case 'OID': + case 'SERIAL': + return 'R'; + case 'FLOAT4': + case 'FLOAT8': + case 'DOUBLE PRECISION': + case 'REAL': + return 'F'; + default: + static $typeMap = array( + 'VARCHAR' => 'C', + 'VARCHAR2' => 'C', + 'CHAR' => 'C', + 'C' => 'C', + 'STRING' => 'C', + 'NCHAR' => 'C', + 'NVARCHAR' => 'C', + 'VARYING' => 'C', + 'BPCHAR' => 'C', + 'CHARACTER' => 'C', + 'INTERVAL' => 'C', # Postgres + 'MACADDR' => 'C', # postgres + ## + 'LONGCHAR' => 'X', + 'TEXT' => 'X', + 'NTEXT' => 'X', + 'M' => 'X', + 'X' => 'X', + 'CLOB' => 'X', + 'NCLOB' => 'X', + 'LVARCHAR' => 'X', + ## + 'BLOB' => 'B', + 'IMAGE' => 'B', + 'BINARY' => 'B', + 'VARBINARY' => 'B', + 'LONGBINARY' => 'B', + 'B' => 'B', + ## + 'YEAR' => 'D', // mysql + 'DATE' => 'D', + 'D' => 'D', + ## + 'UNIQUEIDENTIFIER' => 'C', # MS SQL Server + ## + 'TIME' => 'T', + 'TIMESTAMP' => 'T', + 'DATETIME' => 'T', + 'TIMESTAMPTZ' => 'T', + 'T' => 'T', + 'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql + ## + 'BOOL' => 'L', + 'BOOLEAN' => 'L', + 'BIT' => 'L', + 'L' => 'L', + ## + 'COUNTER' => 'R', + 'R' => 'R', + 'SERIAL' => 'R', // ifx + 'INT IDENTITY' => 'R', + ## + 'INT' => 'I', + 'INT2' => 'I', + 'INT4' => 'I', + 'INT8' => 'I', + 'INTEGER' => 'I', + 'INTEGER UNSIGNED' => 'I', + 'SHORT' => 'I', + 'TINYINT' => 'I', + 'SMALLINT' => 'I', + 'I' => 'I', + ## + 'LONG' => 'N', // interbase is numeric, oci8 is blob + 'BIGINT' => 'N', // this is bigger than PHP 32-bit integers + 'DECIMAL' => 'N', + 'DEC' => 'N', + 'REAL' => 'N', + 'DOUBLE' => 'N', + 'DOUBLE PRECISION' => 'N', + 'SMALLFLOAT' => 'N', + 'FLOAT' => 'N', + 'NUMBER' => 'N', + 'NUM' => 'N', + 'NUMERIC' => 'N', + 'MONEY' => 'N', + + ## informix 9.2 + 'SQLINT' => 'I', + 'SQLSERIAL' => 'I', + 'SQLSMINT' => 'I', + 'SQLSMFLOAT' => 'N', + 'SQLFLOAT' => 'N', + 'SQLMONEY' => 'N', + 'SQLDECIMAL' => 'N', + 'SQLDATE' => 'D', + 'SQLVCHAR' => 'C', + 'SQLCHAR' => 'C', + 'SQLDTIME' => 'T', + 'SQLINTERVAL' => 'N', + 'SQLBYTES' => 'B', + 'SQLTEXT' => 'X', + ## informix 10 + "SQLINT8" => 'I8', + "SQLSERIAL8" => 'I8', + "SQLNCHAR" => 'C', + "SQLNVCHAR" => 'C', + "SQLLVARCHAR" => 'X', + "SQLBOOL" => 'L' + ); + + $tmap = false; + $t = strtoupper($t); + $tmap = (isset($typeMap[$t])) ? $typeMap[$t] : 'N'; + if ($t == 'LONG' && $this->dataProvider == 'oci8') return 'B'; + return $tmap; + } + } + +} + +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/postgres8/postgres8_transaction_module.inc b/lib/adodb/adodbSQL_drivers/postgres8/postgres8_transaction_module.inc new file mode 100644 index 0000000..94bc45e --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/postgres8/postgres8_transaction_module.inc @@ -0,0 +1,128 @@ +transOff > 0) { + $this->transOff += 1; + return; + } + $this->transaction_status = true; + + if ($this->debug && $this->transCnt > 0) + ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans"); + + $this->BeginTrans(); + $this->transOff = 1; + } + + function BeginTrans() + { + if ($this->transOff) + return true; + + $this->transCnt += 1; + return @pg_Exec($this->connectionId, "begin"); + } + + function CompleteTrans($autoComplete = true) + { + if ($this->transOff > 1) { + $this->transOff -= 1; + return true; + } + $this->transOff = 0; + if ($this->transaction_status && $autoComplete) { + if (!$this->CommitTrans()) { + $this->transaction_status = false; + if ($this->debug) + ADOConnection::outp("Smart Commit failed"); + } else + if ($this->debug) + ADOConnection::outp("Smart Commit occurred"); + } else { + $this->RollbackTrans(); + if ($this->debug) + ADOCOnnection::outp("Smart Rollback occurred"); + } + return $this->transaction_status; + } + + function CommitTrans($ok=true) + { + if ($this->transOff) + return true; + + if (!$ok) + return $this->RollbackTrans(); + + $this->transCnt -= 1; + return @pg_Exec($this->connectionId, "commit"); + } + + function RollbackTrans() + { + if ($this->transOff) + return true; + + $this->transCnt -= 1; + return @pg_Exec($this->connectionId, "rollback"); + } + + function FailTrans() + { + if ($this->debug) + if ($this->transOff == 0) { + ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans"); + } else { + ADOConnection::outp("FailTrans was called"); + } + $this->transaction_status = false; + } + + function HasFailedTrans() + { + if ($this->transOff > 0) + return $this->transaction_status == false; + + return false; + } + + function RowLock($tables,$where,$flds='1 as ignore') + { + if (!$this->transCnt) + $this->BeginTrans(); + + return $this->GetOne("select $flds from $tables where $where for update"); + } + + function CommitLock($table) + { + return $this->CommitTrans(); + } + + function RollbackLock($table) + { + return $this->RollbackTrans(); + } + +} + +eval('class postgres8_transaction_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class postgres8_transaction_ResultSet extends postgres8_transaction_resultset_EXTENDER +{ +} +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/sqlite/sqlite_datadict.inc b/lib/adodb/adodbSQL_drivers/sqlite/sqlite_datadict.inc new file mode 100644 index 0000000..25fb13e --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/sqlite/sqlite_datadict.inc @@ -0,0 +1,67 @@ +debug) $this->outp("AlterColumnSQL not supported"); + return array(); + } + + function DropColumnSQL($tabname, $flds) + { + if ($this->debug) $this->outp("DropColumnSQL not supported"); + return array(); + } + +} + +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/sqlite/sqlite_date_module.inc b/lib/adodb/adodbSQL_drivers/sqlite/sqlite_date_module.inc new file mode 100644 index 0000000..bcf36dc --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/sqlite/sqlite_date_module.inc @@ -0,0 +1,241 @@ +_Execute("select $this->sysTimeStamp"); + if ($rs && !$rs->EOF) + return $this->UnixTimeStamp(reset($rs->fields)); + + return false; + } + + function OffsetDate($dayFraction, $date=false) + { + if (!$date) + $date = $this->sysDate; + + return '('.$date.'+'.$dayFraction.')'; + } + + function SetDateLocale($locale = 'En') + { + $this->locale = $locale; + switch (strtoupper($locale)) + { + case 'EN': + $this->fmtDate="'Y-m-d'"; + $this->fmtTimeStamp = "'Y-m-d H:i:s'"; + break; + + case 'US': + $this->fmtDate = "'m-d-Y'"; + $this->fmtTimeStamp = "'m-d-Y H:i:s'"; + break; + + case 'NL': + case 'FR': + case 'RO': + case 'IT': + $this->fmtDate="'d-m-Y'"; + $this->fmtTimeStamp = "'d-m-Y H:i:s'"; + break; + + case 'GE': + $this->fmtDate="'d.m.Y'"; + $this->fmtTimeStamp = "'d.m.Y H:i:s'"; + break; + + default: + $this->fmtDate="'Y-m-d'"; + $this->fmtTimeStamp = "'Y-m-d H:i:s'"; + break; + } + } + + function DBDate($date) + { + if (empty($date) && $date !== 0) + return 'null'; + + if (is_string($date) && !is_numeric($date)) { + if ($date === 'null' || strncmp($date, "'", 1) === 0) + return $date; + + if ($this->isoDates) + return "'$date'"; + + $date = $this->UnixDate($date); + } + + return adodb_date($this->fmtDate,$date); + } + + function DBTimeStamp($timestamp) + { + if (empty($timestamp) && $timestamp !== 0) + return 'null'; + + # strlen(14) allows YYYYMMDDHHMMSS format + if (!is_string($timestamp) || (is_numeric($timestamp) && strlen($timestamp)<14)) + return adodb_date($this->fmtTimeStamp, $timestamp); + + if ($timestamp === 'null') + return $timestamp; + + if ($this->isoDates && strlen($timestamp) !== 14) + return "'$timestamp'"; + + $timestamp = $this->UnixTimeStamp($timestamp); + return adodb_date($this->fmtTimeStamp, $timestamp); + } + + function UnixDate($v) + { + if (is_object($v)) { + // odbtp support + //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 ) + return adodb_mktime($v->hour, $v->minute, $v->second, $v->month, $v->day, $v->year); + } + + if (is_numeric($v) && strlen($v) !== 8) + return $v; + + if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", ($v), $rr)) + return false; + + if ($rr[1] <= TIMESTAMP_FIRST_YEAR) + return 0; + + // h-m-s-MM-DD-YY + return adodb_mktime(0, 0, 0, $rr[2], $rr[3], $rr[1]); + } + + function UnixTimeStamp($v) + { + if (is_object($v)) { + // odbtp support + //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 ) + return adodb_mktime($v->hour, $v->minute, $v->second, $v->month, $v->day, $v->year); + } + + if (!preg_match("|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ ,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", ($v), $rr)) + return false; + + if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) + return 0; + + // h-m-s-MM-DD-YY + if (!isset($rr[5])) + return adodb_mktime(0, 0, 0, $rr[2], $rr[3], $rr[1]); + else return adodb_mktime($rr[5], $rr[6], $rr[7], $rr[2], $rr[3], $rr[1]); + } + + function UserDate($v, $fmt='Y-m-d', $gmt=false) + { + $tt = $this->UnixDate($v); + + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + else if ($tt == 0) + return $this->emptyDate; + else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR + } + + return ($gmt) ? adodb_gmdate($fmt, $tt) : adodb_date($fmt, $tt); + } + + function UserTimeStamp($v, $fmt='Y-m-d H:i:s', $gmt=false) + { + if (!isset($v)) + return $this->emptyTimeStamp; + + # strlen(14) allows YYYYMMDDHHMMSS format + if (is_numeric($v) && strlen($v)<14) + return ($gmt) ? adodb_gmdate($fmt,$v) : adodb_date($fmt,$v); + + $tt = $this->UnixTimeStamp($v); + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + + if ($tt == 0) + return $this->emptyTimeStamp; + else return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt); + } + + function SQLDate($fmt, $col=false) + { + $fmt = $this->qstr($fmt); + return ($col) ? "adodb_date2($fmt,$col)" : "adodb_date($fmt)"; + } +} + +eval('class sqlite_date_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class sqlite_date_ResultSet extends sqlite_date_resultset_EXTENDER +{ + var $emptyTimeStamp = ' '; /// what to display when $time==0 + var $emptyDate = ' '; /// what to display when $time==0 + var $datetime = false; + + function UserTimeStamp($v, $fmt='Y-m-d H:i:s') + { + if (is_numeric($v) && strlen($v)<14) + return adodb_date($fmt,$v); + + $tt = $this->UnixTimeStamp($v); + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + + if ($tt === 0) + return $this->emptyTimeStamp; + else return adodb_date($fmt,$tt); + } + + function UserDate($v,$fmt='Y-m-d') + { + $tt = $this->UnixDate($v); + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) + return $v; + else if ($tt == 0) + return $this->emptyDate; + else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR + } + return adodb_date($fmt,$tt); + } + + function UnixDate($v) + { + return sqlite_date_ADOConnection::UnixDate($v); + } + + function UnixTimeStamp($v) + { + return sqlite_date_ADOConnection::UnixTimeStamp($v); + } + +} +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/sqlite/sqlite_driver.inc b/lib/adodb/adodbSQL_drivers/sqlite/sqlite_driver.inc new file mode 100644 index 0000000..21130fe --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/sqlite/sqlite_driver.inc @@ -0,0 +1,614 @@ +dbtype = 'sqlite'; + $this->dataProvider = 'sqlite'; + } + + /** + * Connection to database server and selected database + * + * @access private + */ + + function _connect($host = "", $username = "", $password = "", $database = "", $persistent, $forcenew) + { + if (!function_exists('sqlite_factory')) return false; + + $this->host = $host; + $this->username = $username; + $this->password = $password; + $this->database = ($database == "") ? $host : $database; + $this->persistent = $persistent; + $this->forcenewconnection = $forcenew; + + if($this->persistent == 1) + { + $this->connectionId = @sqlite_popen( $this->database ); + } + else + { + $this->connectionId = @sqlite_open( $this->database ); + } + + if ($this->connectionId === false) + { + if ($fn = $this->raiseErrorFn) + $fn($this->dbtype, 'CONNECT', $this->ErrorNo(), $this->ErrorMsg(), $this->host, $this->database, $this); + return false; + } + + return true; + } + + /** + * Choose a database to connect. + * + * @param dbname is the name of the database to select + * @return true or false + * @access public + */ + + function SelectDB($dbname) + { + $this->database = $dbname; + + $this->connectionId = sqlite_close( $this->connectionId ); + + if($this->persistent == 1) + { + $this->connectionId = @sqlite_popen( $this->database ); + } + else + { + $this->connectionId = @sqlite_open( $this->database ); + } + + if ($this->connectionId === false) + { + if ($fn = $this->raiseErrorFn) + $fn($this->dbtype, 'CONNECT', $this->ErrorNo(), $this->ErrorMsg(), $this->host, $this->database, $this); + return false; + } + + return true; + } + + /** + * Return database error message + * Usage: $errormessage =& $db->ErrorMsg(); + * + * @access public + */ + + function ErrorMsg() + { + $errorno = @sqlite_last_error( $this->connectionId ); + $error = ($errorno) ? sqlite_error_string($errorno) : ''; + return $error; + } + + /** + * Return database error number + * Usage: $errorbo =& $db->ErrorNo(); + * + * @access public + */ + + function ErrorNo() + { + return @sqlite_last_error($this->connectionId); + } + + /** + * Returns # of affected rows from insert/delete/update query + * + * @access public + * @return integer Affected rows + */ + + function Affected_Rows() + { + return @sqlite_changes( $this->connectionId ); + } + + /** + * Returns the last record id of an inserted item + * Usage: $db->Insert_ID(); + * + * @access public + */ + + function Insert_ID() + { + return @sqlite_last_insert_rowid($this->connectionId); + } + + /** + * Correctly quotes a string so that all strings are escape coded. + * An example is $db->qstr("Haven't a clue."); + * + * @param string the string to quote + * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc(). + * + * @return single-quoted string IE: 'Haven\'t a clue.' + */ + + function qstr($string, $magic_quotes=false) + { + // Ugly hack alert! Repalce backticks with some arbitrary character + $string = str_replace('`', "\x1C", $string); + if (!$magic_quotes) { + return "'".str_replace("'", "''", $string)."'"; + } + $string = str_replace("\\'", "''", str_replace('\\\\', '\\', str_replace('\\"', '"', $string))); + return "'" . $string . "'"; + } + + function QMagic($string) + { + return $this->qstr($string, get_magic_quotes_gpc()); + } + + /** + * Returns concatenated string + * Usage: $db->Concat($str1,$str2); + * + * @return concatenated string + */ + function Concat() + { + $arr = func_get_args(); + return implode("||", $arr); + } + + function IfNull( $field, $ifNull ) + { + return " CASE WHEN $field is null THEN $ifNull ELSE $field END "; + } + + /** + * Closes database connection + * Usage: $db->close(); + * + * @access public + */ + + function Close() + { + @sqlite_close( $this->connectionId ); + $this->connectionId = false; + } + + /** + * Returns All Records in an array + * + * Usage: $db->GetAll($sql); + * @access public + */ + + function &GetAll($sql, $inputarr = false) + { + $data =& $this->GetArray($sql, $inputarr); + return $data; + } + + /** + * Returns All Records in an array + * + * Usage: $db->GetArray($sql); + * @access public + */ + + function &GetArray($sql, $inputarr = false) + { + $data = false; + $result =& $this->Execute($sql, $inputarr); + if ($result) + { + $data =& $result->GetArray(); + $result->Close(); + } + return $data; + } + + /** + * Executes SQL query and instantiates resultset methods + * + * @access private + * @return mixed Resultset methods + */ + + function &do_query( $sql, $offset, $nrows, $inputarr=false ) + { + global $ADODB_FETCH_MODE; + $sql = str_replace('`by`', "'by'", $sql); + $sql = str_replace('`order`', '"order"', $sql); + $sql = str_replace('`when`', '"when"', $sql); + $sql = str_replace('`desc`', "'desc'", $sql); + $sql = str_replace('`', '', $sql); + $sql = str_replace("\x1C", "`", $sql); + if (strpos($sql, "(DISTINCT ipmd5)")) { + $sql = str_replace("(DISTINCT ipmd5) FROM " . KU_DBPREFIX . "posts", "(ipmd5) FROM (SELECT DISTINCT ipmd5 FROM " . KU_DBPREFIX . "posts", $sql); + $sql .= ")"; + } + $sql = str_replace('IS_DELETED', 'is_deleted', $sql); + $sql = str_replace("HIGH_PRIORITY", "", $sql); + + $false = false; + + $offsetStr = ''; + $limitStr = ''; + if ($offset != -1 || $nrows != -1) + { + $offsetStr = ($offset>=0) ? " OFFSET " . $offset . "," : ''; + $limitStr = ($nrows >= 0) ? " LIMIT ". $nrows : ($offset >= 0 ? ' LIMIT 999999999' : ''); + } + + if ($inputarr && is_array($inputarr)) { + $sqlarr = explode('?', $sql); + if (!is_array(reset($inputarr))) $inputarr = array($inputarr); + foreach($inputarr as $arr) { + $sql = ''; $i = 0; + foreach($arr as $v) { + $sql .= $sqlarr[$i]; + switch(gettype($v)){ + case 'string': + $sql .= $this->qstr($v); + break; + case 'double': + $sql .= str_replace(',', '.', $v); + break; + case 'boolean': + $sql .= $v ? 1 : 0; + break; + default: + if ($v === null) + $sql .= 'NULL'; + else $sql .= $v; + } + $i += 1; + } + $sql .= $sqlarr[$i]; + if ($i+1 != sizeof($sqlarr)) + return $false; + $this->sql = $sql . "$limitStr$offsetStr"; + $time_start = array_sum(explode(' ', microtime())); + $this->query_count++; + $resultId = @sqlite_query( $this->sql, $this->connectionId ); + $time_total = (array_sum(explode(' ', microtime())) - $time_start); + $this->query_time_total += $time_total; + if($this->debug_console) + { + $this->query_list[] = $this->sql; + $this->query_list_time[] = $time_total; + $this->query_list_errors[] = $this->ErrorMsg(); + } + if($this->debug) + { + $this->outp($sql . "$limitStr$offsetStr"); + } + if ($resultId === false) { // error handling if query fails + if ($fn = $this->raiseErrorFn) + $fn($this->dbtype, 'EXECUTE', $this->ErrorNo(), $this->ErrorMsg(), $this->sql, $inputarr, $this); + return $false; + } + } + } + else + { + $this->sql = $sql . "$limitStr$offsetStr"; + $time_start = array_sum(explode(' ', microtime())); + $this->query_count++; + $resultId = @sqlite_query( $this->sql, $this->connectionId ); + $time_total = (array_sum(explode(' ', microtime())) - $time_start); + $this->query_time_total += $time_total; + if($this->debug_console) + { + $this->query_list[] = $this->sql; + $this->query_list_time[] = $time_total; + $this->query_list_errors[] = $this->ErrorMsg(); + } + if($this->debug) + { + $this->outp($sql . "$limitStr$offsetStr"); + } + } + + if ($resultId === false) { // error handling if query fails + if ($fn = $this->raiseErrorFn) + $fn($this->dbtype, 'EXECUTE', $this->ErrorNo(), $this->ErrorMsg(), $this->sql, $inputarr, $this); + return $false; + } + + if ($resultId === true) { // return simplified recordset for inserts/updates/deletes with lower overhead + $recordset = new ADORecordSet_empty(); + return $recordset; + } + + $resultset_name = $this->last_module_name . "_ResultSet"; + $recordset = new $resultset_name( $resultId, $this->connectionId ); + + $recordset->_currentRow = 0; + + switch ($ADODB_FETCH_MODE) + { + case ADODB_FETCH_NUM: $recordset->fetchMode = SQLITE_NUM; break; + case ADODB_FETCH_ASSOC:$recordset->fetchMode = SQLITE_ASSOC; break; + default: + case ADODB_FETCH_DEFAULT: + case ADODB_FETCH_BOTH:$recordset->fetchMode = SQLITE_BOTH; break; + } + + $recordset->_numOfRows = @sqlite_num_rows( $resultId ); + if( $recordset->_numOfRows == 0) + { + $recordset->EOF = true; + } + $recordset->_numOfFields = @sqlite_num_fields( $resultId ); + $recordset->_fetch(); + + return $recordset; + } +} + +class sqlite_driver_ResultSet +{ + var $connectionId; + var $fields; + var $resultId; + var $_currentRow = 0; + var $_numOfRows = -1; + var $_numOfFields = -1; + var $fetchMode; + var $EOF; + + /** + * sqliteResultSet Constructor + * + * @access private + * @param string $record + * @param string $resultId + */ + + function sqlite_driver_ResultSet( $resultId, $connectionId ) + { + $this->fields = array(); + $this->connectionId = $connectionId; + $this->record = array(); + $this->resultId = $resultId; + $this->EOF = false; + } + + /** + * Frees resultset + * + * @access public + */ + + function close() + { + $this->fields = array(); + $this->resultId = false; + } + + /** + * Returns field name from select query + * + * @access public + * @param string $field + * @return string Field name + */ + + function fields( $field ) + { + if(empty($field)) + { + return $this->fields; + } + else + { + return $this->fields[$field]; + } + } + + /** + * Returns numrows from select query + * + * @access public + * @return integer Numrows + */ + + function RecordCount() + { + return $this->_numOfRows; + } + + /** + * Returns num of fields from select query + * + * @access public + * @return integer numfields + */ + + function FieldCount() + { + return $this->_numOfFields; + } + + /** + * Returns next record + * + * @access public + */ + + function MoveNext() + { + if (@$this->fields = sqlite_fetch_array($this->resultId,$this->fetchMode)) { + $this->_currentRow += 1; + return true; + } + if (!$this->EOF) { + $this->_currentRow += 1; + $this->EOF = true; + } + return false; + } + + /** + * Move to the first row in the recordset. Many databases do NOT support this. + * + * @return true or false + */ + + function MoveFirst() + { + if ($this->_currentRow == 0) return true; + return $this->Move(0); + } + + /** + * Returns the Last Record + * + * @access public + */ + + function MoveLast() + { + if ($this->EOF) return false; + return $this->Move($this->_numOfRows - 1); + } + + /** + * Random access to a specific row in the recordset. Some databases do not support + * access to previous rows in the databases (no scrolling backwards). + * + * @param rowNumber is the row to move to (0-based) + * + * @return true if there still rows available, or false if there are no more rows (EOF). + */ + + function Move($rowNumber = 0) + { + if ($rowNumber == $this->_currentRow) return true; + $this->EOF = false; + if ($this->_numOfRows > 0){ + if ($rowNumber >= $this->_numOfRows - 1){ + $rowNumber = $this->_numOfRows - 1; + } + } + + if ($this->_seek($rowNumber)) { + $this->_currentRow = $rowNumber; + if ($this->_fetch()) { + return true; + } + $this->fields = false; + } + $this->EOF = true; + return false; + } + + /** + * Perform Seek to specific row + * + * @access private + */ + + function _seek($row) + { + if ($this->_numOfRows == 0) return false; + return @sqlite_seek($this->resultId,$row); + } + + /** + * Fills field array with first database element when query initially executed + * + * @access private + */ + + function _fetch() + { + $this->fields = @sqlite_fetch_array($this->resultId,$this->fetchMode); + return is_array($this->fields); + } + + /** + * Check to see if last record reached + * + * @access public + */ + + function EOF() + { + if( $this->_currentRow < $this->_numOfRows) + { + return false; + } + else + { + $this->EOF = true; + return true; + } + } + + /** + * Returns All Records in an array + * + * @access public + * @param [nRows] is the number of rows to return. -1 means every row. + */ + + function &GetArray($nRows = -1) + { + $results = array(); + $cnt = 0; + while (!$this->EOF && $nRows != $cnt) { + $results[] = $this->fields; + $this->MoveNext(); + $cnt++; + } + return $results; + } + + function &GetRows($nRows = -1) + { + $arr =& $this->GetArray($nRows); + return $arr; + } + + function &GetAll($nRows = -1) + { + $arr =& $this->GetArray($nRows); + return $arr; + } + + /** + * Fetch field information for a table. + * + * @return object containing the name, type and max_length + */ + function FetchField($fieldOffset = -1) + { + $fieldObject = new ADOFieldObject; + $fieldObject->name = sqlite_field_name($this->resultId, $fieldOffset); + $fieldObject->type = 'VARCHAR'; + $fieldObject->max_length = -1; + return $fieldObject; + } +} +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/sqlite/sqlite_extend_module.inc b/lib/adodb/adodbSQL_drivers/sqlite/sqlite_extend_module.inc new file mode 100644 index 0000000..5312208 --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/sqlite/sqlite_extend_module.inc @@ -0,0 +1,153 @@ +Execute($sql, $inputarr); + if ($result) { + $data =& $result->GetAssoc($force_array, $first2cols); + $result->Close(); + } + return $data; + } + + /** + * Generates a sequence id and stores it in $this->genID; + * GenID is only available if $this->hasGenID = true; + * + * @param seqname name of sequence to use + * @param startID if sequence does not exist, start at this ID + * @return 0 if not supported, otherwise a sequence id + */ + + var $_genSeqSQL = "create table %s (id integer)"; + var $_dropSeqSQL = 'drop table %s'; + var $genID = 0; + + function GenID($seqname='adodbseq', $startID=1) + { + $MAXLOOPS = 100; + while (--$MAXLOOPS>=0) { + @($num = $this->GetOne("select id from $seq")); + if ($num === false) { + $this->Execute(sprintf($this->_genSeqSQL, $seq)); + $start -= 1; + $num = '0'; + $result = $this->Execute("insert into $seq values($start)"); + if (!$result) + return false; + } + $this->Execute("update $seq set id=id+1 where id=$num"); + + if ($this->affected_rows() > 0) { + $num += 1; + $this->genID = $num; + return $num; + } + } + if ($fn = $this->raiseErrorFn) { + $fn($this->databaseType, 'GENID',-32000,"Unable to generate unique id after $MAXLOOPS attempts", $seq, $num); + } + return false; + } + + function CreateSequence($seqname='adodbseq', $start=1) + { + $ok = $this->Execute(sprintf($this->_genSeqSQL, $seqname)); + if (!$ok) + return false; + $start -= 1; + return $this->Execute("insert into $seqname values($start)"); + } + + function DropSequence($seqname) + { + return $this->Execute(sprintf($this->_dropSeqSQL, $seqname)); + } + +} + +eval('class sqlite_extend_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class sqlite_extend_ResultSet extends sqlite_extend_resultset_EXTENDER +{ + function &GetAssoc($force_array = false, $first2cols = false) + { + $results = false; + + if ($this->_numOfFields > 1) { + $numIndex = isset($this->fields[0]); + $results = array(); + if (!$first2cols && ($this->_numOfFields > 2 || $force_array)) { + if ($numIndex) { + while (!$this->EOF) { + $results[trim($this->fields[0])] = array_slice($this->fields, 1); + $this->MoveNext(); + } + } else { + while (!$this->EOF) { + $results[trim(reset($this->fields))] = array_slice($this->fields, 1); + $this->MoveNext(); + } + } + } else { + if ($numIndex) { + while (!$this->EOF) { + $results[trim(($this->fields[0]))] = $this->fields[1]; + $this->MoveNext(); + } + } else { + while (!$this->EOF) { + $v1 = trim(reset($this->fields)); + $v2 = ''.next($this->fields); + $results[$v1] = $v2; + $this->MoveNext(); + } + } + } + } + return $results; + } + + function PO_RecordCount($table="", $condition="") + { + $lnumrows = $this->_numOfRows; + if($lnumrows == -1 && $this->connectionId) + { + if($table) + { + if ($condition) + $condition = " WHERE " . $condition; + $resultrows = &$this->connectionId->Execute("SELECT COUNT(*) FROM $table $condition"); + if ($resultrows) + $lnumrows = reset($resultrows->fields); + } + } + return $lnumrows; + } + + function CurrentRow() + { + return $this->_currentRow; + } + + function AbsolutePosition() + { + return $this->_currentRow; + } + + function NextRecordSet() + { + return false; + } + +} +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/sqlite/sqlite_meta_module.inc b/lib/adodb/adodbSQL_drivers/sqlite/sqlite_meta_module.inc new file mode 100644 index 0000000..f5c00fc --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/sqlite/sqlite_meta_module.inc @@ -0,0 +1,533 @@ +ErrorNo(); + + return adodb_error($this->dataProvider,$this->databaseType,$err); + } + + function MetaErrorMsg($errno) + { + include_once(ADODB_DIR."/adodb-error.inc.php"); + return adodb_errormsg($errno); + } + + /** + * @returns an array with the primary key columns in it. + */ + function MetaPrimaryKeys($table, $owner=false) + { + // owner not used in base class - see oci8 + $p = array(); + $objs =& $this->MetaColumns($table); + if ($objs) { + foreach($objs as $v) { + if (!empty($v->primary_key)) + $p[] = $v->name; + } + } + if (sizeof($p)) return $p; + if (function_exists('ADODB_VIEW_PRIMARYKEYS')) + return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner); + return false; + } + + /** + * @returns assoc array where keys are tables, and values are foreign keys + */ + function MetaForeignKeys($table, $owner=false, $upper=false) + { + return false; + } + + // not the fastest implementation - quick and dirty - jlim + // for best performance, use the actual $rs->MetaType(). + function MetaType($t,$len=-1,$fieldobj=false) + { + if (empty($this->_metars)) { + $rsclass = $this->last_module_name . "_ResultSet"; + $this->_metars =& new $rsclass(false,$this->fetchMode); + } + + return $this->_metars->MetaType($t,$len,$fieldobj); + } + + /** + * return the databases that the driver can connect to. + * Some databases will return an empty array. + * + * @return an array of database names. + */ + function MetaDatabases() + { + global $ADODB_FETCH_MODE; + + if ($this->metaDatabasesSQL) { + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + + $arr = $this->GetCol($this->metaDatabasesSQL); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + return $arr; + } + + return false; + } + + /** + * @param ttype can either be 'VIEW' or 'TABLE' or false. + * If false, both views and tables are returned. + * "VIEW" returns only views + * "TABLE" returns only tables + * @param showSchema returns the schema/user with the table name, eg. USER.TABLE + * @param mask is the input mask - only supported by oci8 and postgresql + * + * @return array of tables for current database. + */ + + function &MetaTables($ttype=false,$showSchema=false,$mask=false) + { + global $ADODB_FETCH_MODE; + + $false = false; + if ($mask) { + return $false; + } + if ($this->metaTablesSQL) { + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + + $rs = $this->Execute($this->metaTablesSQL); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if ($rs === false) return $false; + $arr =& $rs->GetArray(); + $arr2 = array(); + + if ($hast = ($ttype && isset($arr[0][1]))) { + $showt = strncmp($ttype,'T',1); + } + + for ($i=0; $i < sizeof($arr); $i++) { + if ($hast) { + if ($showt == 0) { + if (strncmp($arr[$i][1],'T',1) == 0) $arr2[] = trim($arr[$i][0]); + } else { + if (strncmp($arr[$i][1],'V',1) == 0) $arr2[] = trim($arr[$i][0]); + } + } else + $arr2[] = trim($arr[$i][0]); + } + $rs->Close(); + return $arr2; + } + return $false; + } + + function _findschema(&$table,&$schema) + { + if (!$schema && ($at = strpos($table,'.')) !== false) { + $schema = substr($table,0,$at); + $table = substr($table,$at+1); + } + } + + /** + * List columns in a database as an array of ADOFieldObjects. + * See top of file for definition of object. + * + * @param $table table name to query + * @param $normalize makes table name case-insensitive (required by some databases) + * @schema is optional database schema to use - not supported by all databases. + * + * @return array of ADOFieldObjects for current table. + */ + function &MetaColumns($tab) + { + global $ADODB_FETCH_MODE; + $false = false; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + $rs = $this->Execute("PRAGMA table_info('$tab')"); + if (isset($savem)) $this->SetFetchMode($savem); + if (!$rs) { + $ADODB_FETCH_MODE = $save; + return $false; + } + $arr = array(); + while ($r = $rs->FetchRow()) { + $type = explode('(',$r['type']); + $size = ''; + if (sizeof($type)==2) + $size = trim($type[1],')'); + $fn = strtoupper($r['name']); + $fld = new ADOFieldObject; + $fld->name = $r['name']; + $fld->type = $type[0]; + $fld->max_length = $size; + $fld->not_null = $r['notnull']; + $fld->default_value = $r['dflt_value']; + $fld->scale = 0; + if ($save == ADODB_FETCH_NUM) $arr[] = $fld; + else $arr[strtoupper($fld->name)] = $fld; + } + $rs->Close(); + $ADODB_FETCH_MODE = $save; + return $arr; + } + + /** + * List indexes on a table as an array. + * @param table table name to query + * @param primary true to only show primary keys. Not actually used for most databases + * + * @return array of indexes on current table. Each element represents an index, and is itself an associative array. + + Array ( + [name_of_index] => Array + ( + [unique] => true or false + [columns] => Array + ( + [0] => firstname + [1] => lastname + ) + ) + */ + function &MetaIndexes($table, $primary = FALSE, $owner=false) + { + $false = false; + // save old fetch mode + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== FALSE) { + $savem = $this->SetFetchMode(FALSE); + } + $SQL=sprintf("SELECT name,sql FROM sqlite_master WHERE type='index' AND tbl_name='%s'", strtolower($table)); + $rs = $this->Execute($SQL); + if (!is_object($rs)) { + if (isset($savem)) + $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + return $false; + } + + $indexes = array (); + while ($row = $rs->FetchRow()) { + if ($primary && preg_match("/primary/i",$row[1]) == 0) continue; + if (!isset($indexes[$row[0]])) { + + $indexes[$row[0]] = array( + 'unique' => preg_match("/unique/i",$row[1]), + 'columns' => array()); + } + /** + * There must be a more elegant way of doing this, + * the index elements appear in the SQL statement + * in cols[1] between parentheses + * e.g CREATE UNIQUE INDEX ware_0 ON warehouse (org,warehouse) + */ + $cols = explode("(",$row[1]); + $cols = explode(")",$cols[1]); + array_pop($cols); + $indexes[$row[0]]['columns'] = $cols; + } + if (isset($savem)) { + $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + } + return $indexes; + } + + /** + * List columns names in a table as an array. + * @param table table name to query + * + * @return array of column names for current table. + */ + function &MetaColumnNames($table, $numIndexes=false,$useattnum=false /* only for postgres */) + { + $objarr =& $this->MetaColumns($table); + if (!is_array($objarr)) { + $false = false; + return $false; + } + $arr = array(); + if ($numIndexes) { + $i = 0; + if ($useattnum) { + foreach($objarr as $v) + $arr[$v->attnum] = $v->name; + + } else + foreach($objarr as $v) $arr[$i++] = $v->name; + } else + foreach($objarr as $v) $arr[strtoupper($v->name)] = $v->name; + + return $arr; + } + + function MetaTransaction($mode,$db) + { + $mode = strtoupper($mode); + $mode = str_replace('ISOLATION LEVEL ','',$mode); + + switch($mode) { + + case 'READ UNCOMMITTED': + switch($db) { + case 'oci8': + case 'oracle': + return 'ISOLATION LEVEL READ COMMITTED'; + default: + return 'ISOLATION LEVEL READ UNCOMMITTED'; + } + break; + + case 'READ COMMITTED': + return 'ISOLATION LEVEL READ COMMITTED'; + break; + + case 'REPEATABLE READ': + switch($db) { + case 'oci8': + case 'oracle': + return 'ISOLATION LEVEL SERIALIZABLE'; + default: + return 'ISOLATION LEVEL REPEATABLE READ'; + } + break; + + case 'SERIALIZABLE': + return 'ISOLATION LEVEL SERIALIZABLE'; + break; + + default: + return $mode; + } + } + +} + +eval('class sqlite_meta_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class sqlite_meta_ResultSet extends sqlite_meta_resultset_EXTENDER +{ + /** + * Get the metatype of the column. This is used for formatting. This is because + * many databases use different names for the same type, so we transform the original + * type to our standardised version which uses 1 character codes: + * + * @param t is the type passed in. Normally is ADOFieldObject->type. + * @param len is the maximum length of that field. This is because we treat character + * fields bigger than a certain size as a 'B' (blob). + * @param fieldobj is the field object returned by the database driver. Can hold + * additional info (eg. primary_key for mysql). + * + * @return the general type of the data: + * C for character < 250 chars + * X for teXt (>= 250 chars) + * B for Binary + * N for numeric or floating point + * D for date + * T for timestamp + * L for logical/Boolean + * I for integer + * R for autoincrement counter/integer + * + * + */ + function MetaType($t,$len=-1,$fieldobj=false) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + + $len = -1; // mysql max_length is not accurate + switch (strtoupper($t)) { + case 'STRING': + case 'CHAR': + case 'VARCHAR': + case 'TINYBLOB': + case 'TINYTEXT': + case 'ENUM': + case 'SET': + if ($len <= $this->blobSize) return 'C'; + + case 'TEXT': + case 'LONGTEXT': + case 'MEDIUMTEXT': + return 'X'; + + // php_mysql extension always returns 'blob' even if 'text' + // so we have to check whether binary... + case 'IMAGE': + case 'LONGBLOB': + case 'BLOB': + case 'MEDIUMBLOB': + return !empty($fieldobj->binary) ? 'B' : 'X'; + + case 'YEAR': + case 'DATE': return 'D'; + + case 'TIME': + case 'DATETIME': + case 'TIMESTAMP': return 'T'; + + case 'INT': + case 'INTEGER': + case 'BIGINT': + case 'TINYINT': + case 'MEDIUMINT': + case 'SMALLINT': + + if (!empty($fieldobj->primary_key)) return 'R'; + else return 'I'; + + default: + static $typeMap = array( + 'VARCHAR' => 'C', + 'VARCHAR2' => 'C', + 'CHAR' => 'C', + 'C' => 'C', + 'STRING' => 'C', + 'NCHAR' => 'C', + 'NVARCHAR' => 'C', + 'VARYING' => 'C', + 'BPCHAR' => 'C', + 'CHARACTER' => 'C', + 'INTERVAL' => 'C', # Postgres + 'MACADDR' => 'C', # postgres + ## + 'LONGCHAR' => 'X', + 'TEXT' => 'X', + 'NTEXT' => 'X', + 'M' => 'X', + 'X' => 'X', + 'CLOB' => 'X', + 'NCLOB' => 'X', + 'LVARCHAR' => 'X', + ## + 'BLOB' => 'B', + 'IMAGE' => 'B', + 'BINARY' => 'B', + 'VARBINARY' => 'B', + 'LONGBINARY' => 'B', + 'B' => 'B', + ## + 'YEAR' => 'D', // mysql + 'DATE' => 'D', + 'D' => 'D', + ## + 'UNIQUEIDENTIFIER' => 'C', # MS SQL Server + ## + 'TIME' => 'T', + 'TIMESTAMP' => 'T', + 'DATETIME' => 'T', + 'TIMESTAMPTZ' => 'T', + 'T' => 'T', + 'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql + ## + 'BOOL' => 'L', + 'BOOLEAN' => 'L', + 'BIT' => 'L', + 'L' => 'L', + ## + 'COUNTER' => 'R', + 'R' => 'R', + 'SERIAL' => 'R', // ifx + 'INT IDENTITY' => 'R', + ## + 'INT' => 'I', + 'INT2' => 'I', + 'INT4' => 'I', + 'INT8' => 'I', + 'INTEGER' => 'I', + 'INTEGER UNSIGNED' => 'I', + 'SHORT' => 'I', + 'TINYINT' => 'I', + 'SMALLINT' => 'I', + 'I' => 'I', + ## + 'LONG' => 'N', // interbase is numeric, oci8 is blob + 'BIGINT' => 'N', // this is bigger than PHP 32-bit integers + 'DECIMAL' => 'N', + 'DEC' => 'N', + 'REAL' => 'N', + 'DOUBLE' => 'N', + 'DOUBLE PRECISION' => 'N', + 'SMALLFLOAT' => 'N', + 'FLOAT' => 'N', + 'NUMBER' => 'N', + 'NUM' => 'N', + 'NUMERIC' => 'N', + 'MONEY' => 'N', + + ## informix 9.2 + 'SQLINT' => 'I', + 'SQLSERIAL' => 'I', + 'SQLSMINT' => 'I', + 'SQLSMFLOAT' => 'N', + 'SQLFLOAT' => 'N', + 'SQLMONEY' => 'N', + 'SQLDECIMAL' => 'N', + 'SQLDATE' => 'D', + 'SQLVCHAR' => 'C', + 'SQLCHAR' => 'C', + 'SQLDTIME' => 'T', + 'SQLINTERVAL' => 'N', + 'SQLBYTES' => 'B', + 'SQLTEXT' => 'X', + ## informix 10 + "SQLINT8" => 'I8', + "SQLSERIAL8" => 'I8', + "SQLNCHAR" => 'C', + "SQLNVCHAR" => 'C', + "SQLLVARCHAR" => 'X', + "SQLBOOL" => 'L' + ); + + $tmap = false; + $t = strtoupper($t); + $tmap = (isset($typeMap[$t])) ? $typeMap[$t] : 'N'; + if ($t == 'LONG' && $this->dataProvider == 'oci8') return 'B'; + return $tmap; + } + } + +} + +?> \ No newline at end of file diff --git a/lib/adodb/adodbSQL_drivers/sqlite/sqlite_transaction_module.inc b/lib/adodb/adodbSQL_drivers/sqlite/sqlite_transaction_module.inc new file mode 100644 index 0000000..bc1e055 --- /dev/null +++ b/lib/adodb/adodbSQL_drivers/sqlite/sqlite_transaction_module.inc @@ -0,0 +1,132 @@ +transOff > 0) { + $this->transOff += 1; + return; + } + $this->transaction_status = true; + + if ($this->debug && $this->transCnt > 0) + ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans"); + + $this->BeginTrans(); + $this->transOff = 1; + } + + function BeginTrans() + { + if ($this->transOff) + return true; + + $ret = $this->Execute("BEGIN TRANSACTION"); + $this->transCnt += 1; + return true; + } + + function CompleteTrans($autoComplete = true) + { + if ($this->transOff > 1) { + $this->transOff -= 1; + return true; + } + $this->transOff = 0; + if ($this->transaction_status && $autoComplete) { + if (!$this->CommitTrans()) { + $this->transaction_status = false; + if ($this->debug) + ADOConnection::outp("Smart Commit failed"); + } else + if ($this->debug) + ADOConnection::outp("Smart Commit occurred"); + } else { + $this->RollbackTrans(); + if ($this->debug) + ADOCOnnection::outp("Smart Rollback occurred"); + } + return $this->transaction_status; + } + + function CommitTrans($ok=true) + { + if ($this->transOff) + return true; + + if (!$ok) + return $this->RollbackTrans(); + + $ret = $this->Execute("COMMIT"); + if ($this->transCnt>0) + $this->transCnt -= 1; + + return !empty($ret); + } + + function RollbackTrans() + { + if ($this->transOff) + return true; + + $ret = $this->Execute("ROLLBACK"); + if ($this->transCnt>0) + $this->transCnt -= 1; + + return !empty($ret); + } + + function FailTrans() + { + if ($this->debug) + if ($this->transOff == 0) { + ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans"); + } else { + ADOConnection::outp("FailTrans was called"); + } + $this->transaction_status = false; + } + + function HasFailedTrans() + { + if ($this->transOff > 0) + return $this->transaction_status == false; + + return false; + } + + function RowLock($tables,$where,$flds='1 as ignore') + { + return false; + } + + function CommitLock($table) + { + return $this->CommitTrans(); + } + + function RollbackLock($table) + { + return $this->RollbackTrans(); + } + +} + +eval('class sqlite_transaction_resultset_EXTENDER extends '. $last_module . '_ResultSet { }'); + +class sqlite_transaction_ResultSet extends sqlite_transaction_resultset_EXTENDER +{ +} +?> \ No newline at end of file diff --git a/lib/adodb/generic_modules/adodblite_module.inc b/lib/adodb/generic_modules/adodblite_module.inc new file mode 100644 index 0000000..f377c67 --- /dev/null +++ b/lib/adodb/generic_modules/adodblite_module.inc @@ -0,0 +1,41 @@ +Execute($sql, $inputarr); + if ($result) { + $data =& $result->GetToFieldArray($fieldname); + $result->Close(); + } + return $data; + } + +} + +eval('class adodblite_resultset_EXTENDER extends ' . $last_module . '_ResultSet { }'); + +class adodblite_ResultSet extends adodblite_resultset_EXTENDER +{ + function &GetToFieldArray($fieldname = false) + { + $results = false; + if(!$fieldname) + { + return $results; + } + + while (!$this->EOF) { + $results[$this->fields[$fieldname]] = $this->fields; + $this->MoveNext(); + } + return $results; + } + +} +?> \ No newline at end of file diff --git a/lib/adodb/generic_modules/menu_module.inc b/lib/adodb/generic_modules/menu_module.inc new file mode 100644 index 0000000..6f6fb21 --- /dev/null +++ b/lib/adodb/generic_modules/menu_module.inc @@ -0,0 +1,226 @@ +'; + if($blank1stItem) + if(is_string($blank1stItem)) + { + $barr = explode(':',$blank1stItem); + if(sizeof($barr) == 1) + $barr[] = ''; + $s .= "\n"; + } else $s .= "\n"; + + if($this->FieldCount() > 1) + $hasvalue=true; + else $compareFields0 = true; + + $value = ''; + $optgroup = null; + $firstgroup = true; + $fieldsize = $this->FieldCount(); + while(!$this->EOF) + { + $zval = rtrim(reset($this->fields)); + + if($blank1stItem && $zval=="") + { + $this->MoveNext(); + continue; + } + + if($fieldsize > 1) + { + if(isset($this->fields[1])) + $zval2 = rtrim($this->fields[1]); + else + $zval2 = rtrim(next($this->fields)); + } + $selected = ($compareFields0) ? $zval : $zval2; + + $group = ''; + if($fieldsize > 2) + { + $group = rtrim($this->fields[2]); + } + + if($optgroup != $group) + { + $optgroup = $group; + if($firstgroup) + { + $firstgroup = false; + $s .="\n"; + } + else + { + $s .="\n"; + $s .="\n"; + } + } + + if($hasvalue) + $value = " value='".htmlspecialchars($zval2)."'"; + + if(is_array($defstr)) + { + if(in_array($selected,$defstr)) + $s .= "\n'; + else + $s .= "\n'.htmlspecialchars($zval).''; + } + else + { + if(strcasecmp($selected,$defstr)==0) + $s .= "\n'; + else + $s .= "\n'.htmlspecialchars($zval).''; + } + $this->MoveNext(); + } // while + + // closing last optgroup + if($optgroup != null) + { + $s .= "\n"; + } + return $s ."\n\n"; + } + + function GetMenu2($name,$defstr='',$blank1stItem=true,$multiple=false,$size=0, $selectAttr='') + { + return $this->GetMenu($name, $defstr, $blank1stItem, $multiple, $size, $selectAttr, false); + } + + function GetMenu3($name, $defstr='', $blank1stItem=true, $multiple=false, $size=0, $selectAttr='') + { + $hasvalue = false; + + if($multiple or is_array($defstr)) + { + if($size==0) + $size=5; + $attr = ' multiple size="'.$size.'"'; + if(!strpos($name,'[]')) + $name .= '[]'; + } + else if($size) + $attr = ' size="'.$size.'"'; + else $attr =''; + + $s = '\n"; + } + +} + +?> \ No newline at end of file diff --git a/lib/adodb/generic_modules/object_module.inc b/lib/adodb/generic_modules/object_module.inc new file mode 100644 index 0000000..d8e7ae0 --- /dev/null +++ b/lib/adodb/generic_modules/object_module.inc @@ -0,0 +1,99 @@ +FetchObject(false); + return $object; + } + + function &FetchObject($isupper=true) + { + if (empty($this->_obj)) + { + $this->_obj = new ADOFetchObj(); + $this->_names = array(); + for ($i=0; $i <$this->_numOfFields; $i++) + { + $field = $this->FetchField($i); + $this->_names[] = $field->name; + } + } + $i = 0; + if (PHP_VERSION >= 5) + $object = clone($this->_obj); + else $object = $this->_obj; + + for ($i=0; $i <$this->_numOfFields; $i++) + { + $name = $this->_names[$i]; + if ($isupper) + $newname = strtoupper($name); + else $newname = $name; + + $object->$newname = $this->Fields($name); + } + return $object; + } + + function &FetchNextObj() + { + $object =& $this->FetchNextObject(false); + return $object; + } + + function &FetchNextObject($isupper=true) + { + $object = false; + if ($this->_numOfRows != 0 && !$this->EOF) { + $object = $this->FetchObject($isupper); + $this->_currentRow++; + if ($this->_fetch()) + return $object; + } + $this->EOF = true; + return $object; + } + + /* Load a list of database objects + * @param string The field name of a primary key + * @return array If key is empty as sequential list of returned records. + * If key is not empty then the returned array is indexed by the value + * the database key. Returns null if the query fails. + */ + function &loadObjectList( $key='' ) + { + $array = array(); + while ($row = $this->FetchNextObject(false)) + { + if ($key) + { + $array[$row->$key] = $row; + } + else + { + $array[] = $row; + } + } + return $array; + } + +} +?> \ No newline at end of file diff --git a/lib/adodb/generic_modules/pear_module.inc b/lib/adodb/generic_modules/pear_module.inc new file mode 100644 index 0000000..01a3465 --- /dev/null +++ b/lib/adodb/generic_modules/pear_module.inc @@ -0,0 +1,192 @@ +SetFetchMode($mode) + * + * @param mode The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM + * @returns The previous fetch mode + */ + function SetFetchMode($mode) + { + GLOBAL $ADODB_FETCH_MODE; + $old = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = $mode; + return $old; + } + + /** + * Returns the last record id of an inserted item + * Usage: $db->GetCol($sql); + * + * @access public + */ + + function GetCol($sql, $inputarr = false, $trim = false) + { + $data = false; + $result =& $this->do_query($sql, -1, -1, $inputarr); + if ($result) { + $data = array(); + while (!$result->EOF) { + $data[] = ($trim) ? trim(reset($result->fields)) : reset($result->fields); + $result->MoveNext(); + } + $result->Close(); + } + return $data; + } + + /** + * Return first element of first row of sql statement. Recordset is disposed + * for you. + * + * Usage: $db->GetOne($sql); + * @access public + */ + + function &GetOne($sql, $inputarr = false) + { + $data =& $this->GetRow($sql, $inputarr, true); + return $data; + } + + /** + * Return one row of sql statement. Recordset is disposed for you. + * + * Usage: $db->GetRow($sql); + * @access public + */ + + function &GetRow($sql, $inputarr = false, $getone = false) + { + $data = false; + $result =& $this->do_query($sql, -1, -1, $inputarr); + if ($result) { + if ($getone) + { + if (!$result->EOF) $data = reset($result->fields); + } + else + { + if (!$result->EOF) $data = $result->fields; + else $data = array(); + } + $result->Close(); + } + return $data; + } + + /** + * PEAR DB Compat - do not use internally + */ + function &Query($sql, $inputarr = false) + { + $rs =& $this->do_query($sql, -1, -1, $inputarr); + return $rs; + } + + /** + * PEAR DB Compat - do not use internally + */ + function &LimitQuery($sql, $offset, $nrows, $inputarr = false) + { + $rs =& $this->do_query($sql, $nrows, $offset, $inputarr); + return $rs; + } + + /** + * PEAR DB Compat - do not use internally + */ + function Disconnect() + { + return $this->Close(); + } + + /** + * PEAR DB Compat - do not use internally + */ + function ErrorNative() + { + return $this->ErrorNo(); + } + + /** + * PEAR DB Compat - do not use internally + */ + function Quote($string) + { + return $this->qstr($string, false); + } + +} + +eval('class pear_resultset_EXTENDER extends ' . $last_module . '_ResultSet { }'); + +class pear_ResultSet extends pear_resultset_EXTENDER +{ + /** + * PEAR DB Compatable Command + */ + function Free() + { + return $this->Close(); + } + + /** + * PEAR DB Compatable Command + */ + function NumRows() + { + return $this->_numOfRows; + } + + /** + * PEAR DB Compatable Command + */ + function NumCols() + { + return $this->_numOfFields; + } + + /** + * Fetch a row, returning false if no more rows. + * PEAR DB Compatable Command + * + * @return false or array containing the current record + */ + function FetchRow() + { + if ($this->EOF) { + $false = false; + return $false; + } + $arr = $this->fields; + $this->_currentRow++; + if (!$this->_fetch()) $this->EOF = true; + return $arr; + } + + /** + * Fetch a row, returning PEAR_Error if no more rows. + * PEAR DB Compatable Command + * + */ + function FetchInto(&$arr) + { + $false = false; + $true = 1; + if ($this->EOF) return $false; + $arr = $this->fields; + $this->MoveNext(); + return $true; + } + +} +?> \ No newline at end of file diff --git a/lib/adodb/license.txt b/lib/adodb/license.txt new file mode 100644 index 0000000..55ed0b1 --- /dev/null +++ b/lib/adodb/license.txt @@ -0,0 +1,144 @@ +GNU LESSER GENERAL PUBLIC LICENSE +Version 2.1, February 1999 + +Copyright (C) 1991, 1999 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. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + +Preamble +The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. + +This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. + +When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. + +To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. + +For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. + +We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. + +To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. + +Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. + +Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. + +When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. + +We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. + +For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. + +In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. + +Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. + +The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. + + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". + +A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. + +The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) + +"Source code" for a work means the preferred form of the work for making modifications to it. For a library, 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 library. + +Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. + +1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with the Library. + +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 Library or any portion of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. +b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. +c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. +d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. +(For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. + +3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. + +Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. + +This option is useful when you wish to copy part of the code of the Library into a program that is not a library. + +4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you 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. + +If distribution of 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 satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. + +5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. + +However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. + +When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. + +If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) + +Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. + +6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. + +You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: + + +a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) +b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. +c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. +d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. +e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. +For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be 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. + +It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. + +7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: + + +a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. +b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. +8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library 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. + +9. 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 Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. + +10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library 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 with this License. + +11. 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 Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library 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 Library. + +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. + +12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library 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. + +13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library 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 Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. + +14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, 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 + +15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/lib/dwoo.php b/lib/dwoo.php new file mode 100644 index 0000000..4ce4010 --- /dev/null +++ b/lib/dwoo.php @@ -0,0 +1,27 @@ + \ No newline at end of file diff --git a/lib/dwoo/Dwoo.compiled.php b/lib/dwoo/Dwoo.compiled.php new file mode 100644 index 0000000..34e682a --- /dev/null +++ b/lib/dwoo/Dwoo.compiled.php @@ -0,0 +1 @@ + array ( 'class' => 'Dwoo_Template_File', 'compiler' => null ), 'string' => array ( 'class' => 'Dwoo_Template_String', 'compiler' => null ) ); protected $loader = null; protected $template = null; protected $runtimePlugins; protected $data; protected $scope; protected $scopeTree; protected $stack; protected $curBlock; protected $buffer; protected $pluginProxy; public function __construct($compileDir = KU_CACHEDTEMPLATEDIR, $cacheDir = KU_CACHEDTEMPLATEDIR) { if ($compileDir !== null) { $this->setCompileDir($compileDir); } if ($cacheDir !== null) { $this->setCacheDir($cacheDir); } } public function __clone() { $this->template = null; unset($this->data); } public function output($tpl, $data = array(), Dwoo_ICompiler $compiler = null) { return $this->get($tpl, $data, $compiler, true); } public function get($_tpl, $data = array(), $_compiler = null, $_output = false) { if ($this->template instanceof Dwoo_ITemplate) { $proxy = clone $this; return $proxy->get($_tpl, $data, $_compiler, $_output); } if ($_tpl instanceof Dwoo_ITemplate) { } elseif (is_string($_tpl) && file_exists($_tpl)) { $_tpl = new Dwoo_Template_File($_tpl); } else { throw new Dwoo_Exception('Dwoo->get/Dwoo->output\'s first argument must be a Dwoo_ITemplate (i.e. Dwoo_Template_File) or a valid path to a template file', E_USER_NOTICE); } $this->template = $_tpl; if ($data instanceof Dwoo_IDataProvider) { $this->data = $data->getData(); } elseif (is_array($data)) { $this->data = $data; } else { throw new Dwoo_Exception('Dwoo->get/Dwoo->output\'s data argument must be a Dwoo_IDataProvider object (i.e. Dwoo_Data) or an associative array', E_USER_NOTICE); } $this->initGlobals($_tpl); $this->initRuntimeVars($_tpl); $file = $_tpl->getCachedTemplate($this); $doCache = $file === true; $cacheLoaded = is_string($file); if ($cacheLoaded === true) { if ($_output === true) { include $file; $this->template = null; } else { ob_start(); include $file; $this->template = null; return ob_get_clean(); } } else { if ($doCache === true) { $dynamicId = uniqid(); } $out = include $_tpl->getCompiledTemplate($this, $_compiler); if ($out === false) { $_tpl->forceCompilation(); $out = include $_tpl->getCompiledTemplate($this, $_compiler); } if ($doCache === true) { $out = preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '', $out); if (!class_exists('Dwoo_plugin_dynamic', false)) { $this->getLoader()->loadPlugin('dynamic'); } $out = Dwoo_Plugin_dynamic::unescape($out, $dynamicId); } foreach ($this->filters as $filter) { if (is_array($filter) && $filter[0] instanceof Dwoo_Filter) { $out = call_user_func($filter, $out); } else { $out = call_user_func($filter, $this, $out); } } if ($doCache === true) { $file = $_tpl->cache($this, $out); if ($_output === true) { include $file; $this->template = null; } else { ob_start(); include $file; $this->template = null; return ob_get_clean(); } } else { $this->template = null; if ($_output === true) { echo $out; } else { return $out; } } } } protected function initGlobals(Dwoo_ITemplate $tpl) { $this->globals = array ( 'version' => self::VERSION, 'ad' => 'Powered by Dwoo', 'now' => $_SERVER['REQUEST_TIME'], 'template' => $tpl->getName(), 'charset' => $this->charset, ); } protected function initRuntimeVars(Dwoo_ITemplate $tpl) { $this->runtimePlugins = array(); $this->scope =& $this->data; $this->scopeTree = array(); $this->stack = array(); $this->curBlock = null; $this->buffer = ''; } public function addPlugin($name, $callback, $compilable = false) { $compilable = $compilable ? self::COMPILABLE_PLUGIN : 0; if (is_array($callback)) { if (is_subclass_of(is_object($callback[0]) ? get_class($callback[0]) : $callback[0], 'Dwoo_Block_Plugin')) { $this->plugins[$name] = array('type'=>self::BLOCK_PLUGIN | $compilable, 'callback'=>$callback, 'class'=>(is_object($callback[0]) ? get_class($callback[0]) : $callback[0])); } else { $this->plugins[$name] = array('type'=>self::CLASS_PLUGIN | $compilable, 'callback'=>$callback, 'class'=>(is_object($callback[0]) ? get_class($callback[0]) : $callback[0]), 'function'=>$callback[1]); } } elseif (class_exists($callback, false)) { if (is_subclass_of($callback, 'Dwoo_Block_Plugin')) { $this->plugins[$name] = array('type'=>self::BLOCK_PLUGIN | $compilable, 'callback'=>$callback, 'class'=>$callback); } else { $this->plugins[$name] = array('type'=>self::CLASS_PLUGIN | $compilable, 'callback'=>$callback, 'class'=>$callback, 'function'=>'process'); } } elseif (function_exists($callback)) { $this->plugins[$name] = array('type'=>self::FUNC_PLUGIN | $compilable, 'callback'=>$callback); } else { throw new Dwoo_Exception('Callback could not be processed correctly, please check that the function/class you used exists'); } } public function removePlugin($name) { if (isset($this->plugins[$name])) { unset($this->plugins[$name]); } } public function addFilter($callback, $autoload = false) { if ($autoload) { $class = 'Dwoo_Filter_'.$callback; if (!class_exists($class, false) && !function_exists($class)) { try { $this->getLoader()->loadPlugin($callback); } catch (Dwoo_Exception $e) { if (strstr($callback, 'Dwoo_Filter_')) { throw new Dwoo_Exception('Wrong filter name : '.$callback.', the "Dwoo_Filter_" prefix should not be used, please only use "'.str_replace('Dwoo_Filter_', '', $callback).'"'); } else { throw new Dwoo_Exception('Wrong filter name : '.$callback.', when using autoload the filter must be in one of your plugin dir as "name.php" containg a class or function named "Dwoo_Filter_name"'); } } } if (class_exists($class, false)) { $callback = array(new $class($this), 'process'); } elseif (function_exists($class)) { $callback = $class; } else { throw new Dwoo_Exception('Wrong filter name : '.$callback.', when using autoload the filter must be in one of your plugin dir as "name.php" containg a class or function named "Dwoo_Filter_name"'); } $this->filters[] = $callback; } else { $this->filters[] = $callback; } } public function removeFilter($callback) { if (($index = array_search('Dwoo_Filter_'.$callback, $this->filters, true)) !== false) { unset($this->filters[$index]); } elseif (($index = array_search($callback, $this->filters, true)) !== false) { unset($this->filters[$index]); } else { $class = 'Dwoo_Filter_' . $callback; foreach ($this->filters as $index=>$filter) { if (is_array($filter) && $filter[0] instanceof $class) { unset($this->filters[$index]); break; } } } } public function addResource($name, $class, $compilerFactory = null) { if (strlen($name) < 2) { throw new Dwoo_Exception('Resource names must be at least two-character long to avoid conflicts with Windows paths'); } if (!class_exists($class)) { throw new Dwoo_Exception('Resource class does not exist'); } $interfaces = class_implements($class); if (in_array('Dwoo_ITemplate', $interfaces) === false) { throw new Dwoo_Exception('Resource class must implement Dwoo_ITemplate'); } $this->resources[$name] = array('class'=>$class, 'compiler'=>$compilerFactory); } public function removeResource($name) { unset($this->resources[$name]); if ($name==='file') { $this->resources['file'] = array('class'=>'Dwoo_Template_File', 'compiler'=>null); } } public function setLoader(Dwoo_ILoader $loader) { $this->loader = $loader; } public function getLoader() { if ($this->loader === null) { $this->loader = new Dwoo_Loader($this->getCompileDir()); } return $this->loader; } public function getCustomPlugins() { return $this->plugins; } public function getCacheDir() { if ($this->cacheDir === null) { $this->setCacheDir(dirname(__FILE__).DIRECTORY_SEPARATOR.'cache'.DIRECTORY_SEPARATOR); } return $this->cacheDir; } public function setCacheDir($dir) { $this->cacheDir = rtrim($dir, '/\\').DIRECTORY_SEPARATOR; if (is_writable($this->cacheDir) === false) { throw new Dwoo_Exception('The cache directory must be writable, chmod "'.$this->cacheDir.'" to make it writable'); } } public function getCompileDir() { if ($this->compileDir === null) { $this->setCompileDir(dirname(__FILE__).DIRECTORY_SEPARATOR.'compiled'.DIRECTORY_SEPARATOR); } return $this->compileDir; } public function setCompileDir($dir) { $this->compileDir = rtrim($dir, '/\\').DIRECTORY_SEPARATOR; if (is_writable($this->compileDir) === false) { throw new Dwoo_Exception('The compile directory must be writable, chmod "'.$this->compileDir.'" to make it writable'); } } public function getCacheTime() { return $this->cacheTime; } public function setCacheTime($seconds) { $this->cacheTime = (int) $seconds; } public function getCharset() { return $this->charset; } public function setCharset($charset) { $this->charset = strtolower((string) $charset); } public function getTemplate() { return $this->template; } public function setDefaultCompilerFactory($resourceName, $compilerFactory) { $this->resources[$resourceName]['compiler'] = $compilerFactory; } public function getDefaultCompilerFactory($resourceName) { return $this->resources[$resourceName]['compiler']; } public function setSecurityPolicy(Dwoo_Security_Policy $policy = null) { $this->securityPolicy = $policy; } public function getSecurityPolicy() { return $this->securityPolicy; } public function setPluginProxy(Dwoo_IPluginProxy $pluginProxy) { $this->pluginProxy = $pluginProxy; } public function getPluginProxy() { return $this->pluginProxy; } public function isCached(Dwoo_ITemplate $tpl) { return is_string($tpl->getCachedTemplate($this)); } public function clearCache($olderThan=-1) { $cacheDirs = new RecursiveDirectoryIterator($this->getCacheDir()); $cache = new RecursiveIteratorIterator($cacheDirs); $expired = time() - $olderThan; $count = 0; foreach ($cache as $file) { if ($cache->isDot() || $cache->isDir() || substr($file, -5) !== '.html') { continue; } if ($cache->getCTime() < $expired) { $count += unlink((string) $file) ? 1 : 0; } } return $count; } public function templateFactory($resourceName, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, Dwoo_ITemplate $parentTemplate = null) { if (isset($this->resources[$resourceName])) { return call_user_func(array($this->resources[$resourceName]['class'], 'templateFactory'), $this, $resourceId, $cacheTime, $cacheId, $compileId, $parentTemplate); } else { throw new Dwoo_Exception('Unknown resource type : '.$resourceName); } } public function isArray($value, $checkIsEmpty=false, $allowNonCountable=false) { if (is_array($value) === true) { if ($checkIsEmpty === false) { return true; } else { return count($value) > 0; } } elseif ($value instanceof Iterator || $value instanceof ArrayAccess) { if ($checkIsEmpty === false) { return true; } else { if ($allowNonCountable === false) { return count($value) > 0; } else { if ($value instanceof Countable) { return count($value) > 0; } else { $value->rewind(); return $value->valid(); } } } } return false; } public function triggerError($message, $level=E_USER_NOTICE) { if (!($tplIdentifier = $this->template->getResourceIdentifier())) { $tplIdentifier = $this->template->getResourceName(); } trigger_error('Dwoo error (in '.$tplIdentifier.') : '.$message, $level); } public function addStack($blockName, array $args=array()) { if (isset($this->plugins[$blockName])) { $class = $this->plugins[$blockName]['class']; } else { $class = 'Dwoo_Plugin_'.$blockName; } if ($this->curBlock !== null) { $this->curBlock->buffer(ob_get_contents()); ob_clean(); } else { $this->buffer .= ob_get_contents(); ob_clean(); } $block = new $class($this); $cnt = count($args); if ($cnt===0) { $block->init(); } elseif ($cnt===1) { $block->init($args[0]); } elseif ($cnt===2) { $block->init($args[0], $args[1]); } elseif ($cnt===3) { $block->init($args[0], $args[1], $args[2]); } elseif ($cnt===4) { $block->init($args[0], $args[1], $args[2], $args[3]); } else { call_user_func_array(array($block,'init'), $args); } $this->stack[] = $this->curBlock = $block; return $block; } public function delStack() { $args = func_get_args(); $this->curBlock->buffer(ob_get_contents()); ob_clean(); $cnt = count($args); if ($cnt===0) { $this->curBlock->end(); } elseif ($cnt===1) { $this->curBlock->end($args[0]); } elseif ($cnt===2) { $this->curBlock->end($args[0], $args[1]); } elseif ($cnt===3) { $this->curBlock->end($args[0], $args[1], $args[2]); } elseif ($cnt===4) { $this->curBlock->end($args[0], $args[1], $args[2], $args[3]); } else { call_user_func_array(array($this->curBlock, 'end'), $args); } $tmp = array_pop($this->stack); if (count($this->stack) > 0) { $this->curBlock = end($this->stack); $this->curBlock->buffer($tmp->process()); } else { $this->curBlock = null; echo $tmp->process(); } unset($tmp); } public function getParentBlock(Dwoo_Block_Plugin $block) { $index = array_search($block, $this->stack, true); if ($index !== false && $index > 0) { return $this->stack[$index-1]; } return false; } public function findBlock($type) { if (isset($this->plugins[$type])) { $type = $this->plugins[$type]['class']; } else { $type = 'Dwoo_Plugin_'.str_replace('Dwoo_Plugin_', '', $type); } $keys = array_keys($this->stack); while (($key = array_pop($keys)) !== false) { if ($this->stack[$key] instanceof $type) { return $this->stack[$key]; } } return false; } protected function getObjectPlugin($class) { if (isset($this->runtimePlugins[$class])) { return $this->runtimePlugins[$class]; } return $this->runtimePlugins[$class] = new $class($this); } public function classCall($plugName, array $params = array()) { $class = 'Dwoo_Plugin_'.$plugName; $plugin = $this->getObjectPlugin($class); $cnt = count($params); if ($cnt===0) { return $plugin->process(); } elseif ($cnt===1) { return $plugin->process($params[0]); } elseif ($cnt===2) { return $plugin->process($params[0], $params[1]); } elseif ($cnt===3) { return $plugin->process($params[0], $params[1], $params[2]); } elseif ($cnt===4) { return $plugin->process($params[0], $params[1], $params[2], $params[3]); } else { return call_user_func_array(array($plugin, 'process'), $params); } } public function arrayMap($callback, array $params) { if ($params[0] === $this) { $addThis = true; array_shift($params); } if ((is_array($params[0]) || ($params[0] instanceof Iterator && $params[0] instanceof ArrayAccess))) { if (empty($params[0])) { return $params[0]; } $out = array(); $cnt = count($params); if (isset($addThis)) { array_unshift($params, $this); $items = $params[1]; $keys = array_keys($items); if (is_string($callback) === false) { while (($i = array_shift($keys)) !== null) { $out[] = call_user_func_array($callback, array(1=>$items[$i]) + $params); } } elseif ($cnt===1) { while (($i = array_shift($keys)) !== null) { $out[] = $callback($this, $items[$i]); } } elseif ($cnt===2) { while (($i = array_shift($keys)) !== null) { $out[] = $callback($this, $items[$i], $params[2]); } } elseif ($cnt===3) { while (($i = array_shift($keys)) !== null) { $out[] = $callback($this, $items[$i], $params[2], $params[3]); } } else { while (($i = array_shift($keys)) !== null) { $out[] = call_user_func_array($callback, array(1=>$items[$i]) + $params); } } } else { $items = $params[0]; $keys = array_keys($items); if (is_string($callback) === false) { while (($i = array_shift($keys)) !== null) { $out[] = call_user_func_array($callback, array($items[$i]) + $params); } } elseif ($cnt===1) { while (($i = array_shift($keys)) !== null) { $out[] = $callback($items[$i]); } } elseif ($cnt===2) { while (($i = array_shift($keys)) !== null) { $out[] = $callback($items[$i], $params[1]); } } elseif ($cnt===3) { while (($i = array_shift($keys)) !== null) { $out[] = $callback($items[$i], $params[1], $params[2]); } } elseif ($cnt===4) { while (($i = array_shift($keys)) !== null) { $out[] = $callback($items[$i], $params[1], $params[2], $params[3]); } } else { while (($i = array_shift($keys)) !== null) { $out[] = call_user_func_array($callback, array($items[$i]) + $params); } } } return $out; } else { return $params[0]; } } public function readVarInto($varstr, $data) { if ($data === null) { return null; } if (is_array($varstr) === false) { preg_match_all('#(\[|->|\.)?([^.[\]-]+)\]?#i', $varstr, $m); } else { $m = $varstr; } unset($varstr); while (list($k, $sep) = each($m[1])) { if ($sep === '.' || $sep === '[' || $sep === '') { if ((is_array($data) || $data instanceof ArrayAccess) && isset($data[$m[2][$k]])) { $data = $data[$m[2][$k]]; } else { return null; } } else { if (is_object($data)) { $data = $data->$m[2][$k]; } else { return null; } } } return $data; } public function readParentVar($parentLevels, $varstr = null) { $tree = $this->scopeTree; $cur = $this->data; while ($parentLevels--!==0) { array_pop($tree); } while (($i = array_shift($tree)) !== null) { if (is_object($cur)) { $cur = $cur->$i; } else { $cur = $cur[$i]; } } if ($varstr!==null) { return $this->readVarInto($varstr, $cur); } else { return $cur; } } public function readVar($varstr) { if (is_array($varstr)===true) { $m = $varstr; unset($varstr); } else { if (strstr($varstr, '.') === false && strstr($varstr, '[') === false && strstr($varstr, '->') === false) { if ($varstr === 'dwoo') { return $this->globals; } elseif ($varstr === '__' || $varstr === '_root' ) { return $this->data; $varstr = substr($varstr, 6); } elseif ($varstr === '_' || $varstr === '_parent') { $varstr = '.'.$varstr; $tree = $this->scopeTree; $cur = $this->data; array_pop($tree); while (($i = array_shift($tree)) !== null) { if (is_object($cur)) { $cur = $cur->$i; } else { $cur = $cur[$i]; } } return $cur; } $cur = $this->scope; if (isset($cur[$varstr])) { return $cur[$varstr]; } else { return null; } } if (substr($varstr, 0, 1) === '.') { $varstr = 'dwoo'.$varstr; } preg_match_all('#(\[|->|\.)?([^.[\]-]+)\]?#i', $varstr, $m); } $i = $m[2][0]; if ($i === 'dwoo') { $cur = $this->globals; array_shift($m[2]); array_shift($m[1]); switch ($m[2][0]) { case 'get': $cur = $_GET; break; case 'post': $cur = $_POST; break; case 'session': $cur = $_SESSION; break; case 'cookies': case 'cookie': $cur = $_COOKIE; break; case 'server': $cur = $_SERVER; break; case 'env': $cur = $_ENV; break; case 'request': $cur = $_REQUEST; break; case 'const': array_shift($m[2]); if (defined($m[2][0])) { return constant($m[2][0]); } else { return null; } } if ($cur !== $this->globals) { array_shift($m[2]); array_shift($m[1]); } } elseif ($i === '__' || $i === '_root') { $cur = $this->data; array_shift($m[2]); array_shift($m[1]); } elseif ($i === '_' || $i === '_parent') { $tree = $this->scopeTree; $cur = $this->data; while (true) { array_pop($tree); array_shift($m[2]); array_shift($m[1]); if (current($m[2]) === '_' || current($m[2]) === '_parent') { continue; } while (($i = array_shift($tree)) !== null) { if (is_object($cur)) { $cur = $cur->$i; } else { $cur = $cur[$i]; } } break; } } else { $cur = $this->scope; } while (list($k, $sep) = each($m[1])) { if ($sep === '.' || $sep === '[' || $sep === '') { if ((is_array($cur) || $cur instanceof ArrayAccess) && isset($cur[$m[2][$k]])) { $cur = $cur[$m[2][$k]]; } else { return null; } } elseif ($sep === '->') { if (is_object($cur)) { $cur = $cur->$m[2][$k]; } else { return null; } } else { return null; } } return $cur; } public function assignInScope($value, $scope) { $tree =& $this->scopeTree; $data =& $this->data; if (!is_string($scope)) { return $this->triggerError('Assignments must be done into strings, ('.gettype($scope).') '.var_export($scope, true).' given', E_USER_ERROR); } if (strstr($scope, '.') === false && strstr($scope, '->') === false) { $this->scope[$scope] = $value; } else { preg_match_all('#(\[|->|\.)?([^.[\]-]+)\]?#i', $scope, $m); $cur =& $this->scope; $last = array(array_pop($m[1]), array_pop($m[2])); while (list($k, $sep) = each($m[1])) { if ($sep === '.' || $sep === '[' || $sep === '') { if (is_array($cur) === false) { $cur = array(); } $cur =& $cur[$m[2][$k]]; } elseif ($sep === '->') { if (is_object($cur) === false) { $cur = new stdClass; } $cur =& $cur->$m[2][$k]; } else { return false; } } if ($last[0] === '.' || $last[0] === '[' || $last[0] === '') { if (is_array($cur) === false) { $cur = array(); } $cur[$last[1]] = $value; } elseif ($last[0] === '->') { if (is_object($cur) === false) { $cur = new stdClass; } $cur->$last[1] = $value; } else { return false; } } } public function setScope($scope, $absolute = false) { $old = $this->scopeTree; if (is_string($scope)===true) { $scope = explode('.', $scope); } if ($absolute===true) { $this->scope =& $this->data; $this->scopeTree = array(); } while (($bit = array_shift($scope)) !== null) { if ($bit === '_' || $bit === '_parent') { array_pop($this->scopeTree); $this->scope =& $this->data; $cnt = count($this->scopeTree); for ($i=0;$i<$cnt;$i++) $this->scope =& $this->scope[$this->scopeTree[$i]]; } elseif ($bit === '__' || $bit === '_root') { $this->scope =& $this->data; $this->scopeTree = array(); } elseif (isset($this->scope[$bit])) { $this->scope =& $this->scope[$bit]; $this->scopeTree[] = $bit; } else { unset($this->scope); $this->scope = null; } } return $old; } public function getData() { return $this->data; } public function &getScope() { return $this->scope; } public function forceScope($scope) { return $this->setScope($scope, true); } } interface Dwoo_IPluginProxy { public function handles($name); public function getCode($name, $params); public function getCallback($name); public function getLoader($name); } interface Dwoo_ILoader { public function loadPlugin($class, $forceRehash = true); } class Dwoo_Loader implements Dwoo_ILoader { protected $paths = array(); protected $classPath = array(); protected $cacheDir; protected $corePluginDir; public function __construct($cacheDir) { $this->corePluginDir = DWOO_DIRECTORY . 'plugins'; $this->cacheDir = $cacheDir . DIRECTORY_SEPARATOR; $foo = @file_get_contents($this->cacheDir.'classpath.cache.d'.Dwoo::RELEASE_TAG.'.php'); if ($foo) { $this->classPath = unserialize($foo) + $this->classPath; } else { $this->rebuildClassPathCache($this->corePluginDir, $this->cacheDir.'classpath.cache.d'.Dwoo::RELEASE_TAG.'.php'); } } protected function rebuildClassPathCache($path, $cacheFile) { if ($cacheFile!==false) { $tmp = $this->classPath; $this->classPath = array(); } $list = glob($path.DIRECTORY_SEPARATOR.'*'); if (is_array($list)) { foreach ($list as $f) { if (is_dir($f)) { $this->rebuildClassPathCache($f, false); } else { $this->classPath[str_replace(array('function.','block.','modifier.','outputfilter.','filter.','prefilter.','postfilter.','pre.','post.','output.','shared.','helper.'), '', basename($f, '.php'))] = $f; } } } if ($cacheFile!==false) { if (!file_put_contents($cacheFile, serialize($this->classPath))) { throw new Dwoo_Exception('Could not write into '.$cacheFile.', either because the folder is not there (create it) or because of the chmod configuration (please ensure this directory is writable by php), alternatively you can change the directory used with $dwoo->setCompileDir() or provide a custom loader object with $dwoo->setLoader()'); } $this->classPath += $tmp; } } public function loadPlugin($class, $forceRehash = true) { if (!isset($this->classPath[$class]) || !(include $this->classPath[$class])) { if ($forceRehash) { $this->rebuildClassPathCache($this->corePluginDir, $this->cacheDir . 'classpath.cache.d'.Dwoo::RELEASE_TAG.'.php'); foreach ($this->paths as $path=>$file) { $this->rebuildClassPathCache($path, $file); } if (isset($this->classPath[$class])) { include $this->classPath[$class]; } else { throw new Dwoo_Exception('Plugin '.$class.' can not be found, maybe you forgot to bind it if it\'s a custom plugin ?', E_USER_NOTICE); } } else { throw new Dwoo_Exception('Plugin '.$class.' can not be found, maybe you forgot to bind it if it\'s a custom plugin ?', E_USER_NOTICE); } } } public function addDirectory($pluginDirectory) { $pluginDir = realpath($pluginDirectory); if (!$pluginDir) { throw new Dwoo_Exception('Plugin directory does not exist or can not be read : '.$pluginDirectory); } $cacheFile = $this->cacheDir . 'classpath-'.substr(strtr($pluginDir, '/\\:'.PATH_SEPARATOR, '----'), strlen($pluginDir) > 80 ? -80 : 0).'.d'.Dwoo::RELEASE_TAG.'.php'; $this->paths[$pluginDir] = $cacheFile; $foo = @file_get_contents($cacheFile); if ($foo) { $this->classPath = unserialize($foo) + $this->classPath; } else { $this->rebuildClassPathCache($pluginDir, $cacheFile); } } } class Dwoo_Exception extends Exception { } class Dwoo_Security_Policy { const PHP_ENCODE = 1; const PHP_REMOVE = 2; const PHP_ALLOW = 3; const CONST_DISALLOW = false; const CONST_ALLOW = true; protected $allowedPhpFunctions = array ( 'str_repeat', 'number_format', 'htmlentities', 'htmlspecialchars', 'long2ip', 'strlen', 'list', 'empty', 'count', 'sizeof', 'in_array', 'is_array', ); protected $allowedDirectories = array(); protected $phpHandling = self::PHP_REMOVE; protected $constHandling = self::CONST_DISALLOW; public function allowPhpFunction($func) { if (is_array($func)) foreach ($func as $fname) $this->allowedPhpFunctions[strtolower($fname)] = true; else $this->allowedPhpFunctions[strtolower($func)] = true; } public function disallowPhpFunction($func) { if (is_array($func)) foreach ($func as $fname) unset($this->allowedPhpFunctions[strtolower($fname)]); else unset($this->allowedPhpFunctions[strtolower($func)]); } public function getAllowedPhpFunctions() { return $this->allowedPhpFunctions; } public function allowDirectory($path) { if (is_array($path)) foreach ($path as $dir) $this->allowedDirectories[realpath($dir)] = true; else $this->allowedDirectories[realpath($path)] = true; } public function disallowDirectory($path) { if (is_array($path)) foreach ($path as $dir) unset($this->allowedDirectories[realpath($dir)]); else unset($this->allowedDirectories[realpath($path)]); } public function getAllowedDirectories() { return $this->allowedDirectories; } public function setPhpHandling($level = self::PHP_REMOVE) { $this->phpHandling = $level; } public function getPhpHandling() { return $this->phpHandling; } public function setConstantHandling($level = self::CONST_DISALLOW) { $this->constHandling = $level; } public function getConstantHandling() { return $this->constHandling; } } class Dwoo_Security_Exception extends Dwoo_Exception { } interface Dwoo_IElseable { } interface Dwoo_ICompilable { } interface Dwoo_ICompiler { public function compile(Dwoo $dwoo, Dwoo_ITemplate $template); public function setCustomPlugins(array $customPlugins); public function setSecurityPolicy(Dwoo_Security_Policy $policy = null); } interface Dwoo_IDataProvider { public function getData(); } interface Dwoo_ITemplate { public function getCacheTime(); public function setCacheTime($seconds = null); public function getCachedTemplate(Dwoo $dwoo); public function cache(Dwoo $dwoo, $output); public function clearCache(Dwoo $dwoo, $olderThan = -1); public function getCompiledTemplate(Dwoo $dwoo, Dwoo_ICompiler $compiler = null); public function getName(); public function getResourceName(); public function getResourceIdentifier(); public function getSource(); public function getUid(); public function getCompiler(); public static function templateFactory(Dwoo $dwoo, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, Dwoo_ITemplate $parentTemplate = null); } interface Dwoo_ICompilable_Block { } abstract class Dwoo_Plugin { protected $dwoo; public function __construct(Dwoo $dwoo) { $this->dwoo = $dwoo; } public static function paramsToAttributes(array $params, $delim = '\'') { if (isset($params['*'])) { $params = array_merge($params, $params['*']); unset($params['*']); } $out = ''; foreach ($params as $attr=>$val) { $out .= ' '.$attr.'='; if (trim($val, '"\'')=='' || $val=='null') { $out .= str_replace($delim, '\\'.$delim, '""'); } elseif (substr($val, 0, 1) === $delim && substr($val, -1) === $delim) { $out .= str_replace($delim, '\\'.$delim, '"'.substr($val, 1, -1).'"'); } else { $out .= str_replace($delim, '\\'.$delim, '"') . $delim . '.'.$val.'.' . $delim . str_replace($delim, '\\'.$delim, '"'); } } return ltrim($out); } } abstract class Dwoo_Block_Plugin extends Dwoo_Plugin { protected $buffer = ''; public function buffer($input) { $this->buffer .= $input; } public function end() { } public function process() { return $this->buffer; } public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) { return Dwoo_Compiler::PHP_OPEN.$prepend.'$this->addStack("'.$type.'", array('.Dwoo_Compiler::implode_r($compiler->getCompiledParams($params)).'));'.$append.Dwoo_Compiler::PHP_CLOSE; } public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) { return $content . Dwoo_Compiler::PHP_OPEN.$prepend.'$this->delStack();'.$append.Dwoo_Compiler::PHP_CLOSE; } } abstract class Dwoo_Filter { protected $dwoo; public function __construct(Dwoo $dwoo) { $this->dwoo = $dwoo; } abstract public function process($input); } abstract class Dwoo_Processor { protected $compiler; public function __construct(Dwoo_Compiler $compiler) { $this->compiler = $compiler; } abstract public function process($input); } class Dwoo_Template_String implements Dwoo_ITemplate { protected $name; protected $compileId; protected $cacheId; protected $cacheTime; protected $compilationEnforced; protected static $cache = array('cached'=>array(), 'compiled'=>array()); protected $compiler; protected $chmod = 0777; public function __construct($templateString, $cacheTime = null, $cacheId = null, $compileId = null) { $this->template = $templateString; if (function_exists('hash')) { $this->name = hash('md4', $templateString); } else { $this->name = md5($templateString); } $this->cacheTime = $cacheTime; if ($compileId !== null) { $this->compileId = str_replace('../', '__', strtr($compileId, '\\%?=!:;'.PATH_SEPARATOR, '/-------')); } if ($cacheId !== null) { $this->cacheId = str_replace('../', '__', strtr($cacheId, '\\%?=!:;'.PATH_SEPARATOR, '/-------')); } } public function getCacheTime() { return $this->cacheTime; } public function setCacheTime($seconds = null) { $this->cacheTime = $seconds; } public function getChmod() { return $this->chmod; } public function setChmod($mask = null) { $this->chmod = $mask; } public function getName() { return $this->name; } public function getResourceName() { return 'string'; } public function getResourceIdentifier() { return false; } public function getSource() { return $this->template; } public function getUid() { return $this->name; } public function getCompiler() { return $this->compiler; } public function forceCompilation() { $this->compilationEnforced = true; } public function getCachedTemplate(Dwoo $dwoo) { if ($this->cacheTime !== null) { $cacheLength = $this->cacheTime; } else { $cacheLength = $dwoo->getCacheTime(); } if ($cacheLength === 0) { return false; } $cachedFile = $this->getCacheFilename($dwoo); if (isset(self::$cache['cached'][$this->cacheId]) === true && file_exists($cachedFile)) { return $cachedFile; } elseif ($this->compilationEnforced !== true && file_exists($cachedFile) && ($cacheLength === -1 || filemtime($cachedFile) > ($_SERVER['REQUEST_TIME'] - $cacheLength))) { self::$cache['cached'][$this->cacheId] = true; return $cachedFile; } else { return true; } } public function cache(Dwoo $dwoo, $output) { $cacheDir = $dwoo->getCacheDir(); $cachedFile = $this->getCacheFilename($dwoo); $temp = tempnam($cacheDir, 'temp'); if (!($file = @fopen($temp, 'wb'))) { $temp = $cacheDir . DIRECTORY_SEPARATOR . uniqid('temp'); if (!($file = @fopen($temp, 'wb'))) { trigger_error('Error writing temporary file \''.$temp.'\'', E_USER_WARNING); return false; } } fwrite($file, $output); fclose($file); $this->makeDirectory(dirname($cachedFile)); if (!@rename($temp, $cachedFile)) { @unlink($cachedFile); @rename($temp, $cachedFile); } if ($this->chmod !== null) { chmod($cachedFile, $this->chmod); } self::$cache['cached'][$this->cacheId] = true; return $cachedFile; } public function clearCache(Dwoo $dwoo, $olderThan = -1) { $cachedFile = $this->getCacheFilename($dwoo); return !file_exists($cachedFile) || (filectime($cachedFile) < (time() - $olderThan) && unlink($cachedFile)); } public function getCompiledTemplate(Dwoo $dwoo, Dwoo_ICompiler $compiler = null) { $compiledFile = $this->getCompiledFilename($dwoo); if ($this->compilationEnforced !== true && isset(self::$cache['compiled'][$this->compileId]) === true) { } elseif ($this->compilationEnforced !== true && $this->isValidCompiledFile($compiledFile)) { self::$cache['compiled'][$this->compileId] = true; } else { $this->compilationEnforced = false; if ($compiler === null) { $compiler = $dwoo->getDefaultCompilerFactory($this->getResourceName()); if ($compiler === null || $compiler === array('Dwoo_Compiler', 'compilerFactory')) { if (class_exists('Dwoo_Compiler', false) === false) { include DWOO_DIRECTORY . 'Dwoo/Compiler.php'; } $compiler = Dwoo_Compiler::compilerFactory(); } else { $compiler = call_user_func($compiler); } } $this->compiler = $compiler; $compiler->setCustomPlugins($dwoo->getCustomPlugins()); $compiler->setSecurityPolicy($dwoo->getSecurityPolicy()); $this->makeDirectory(dirname($compiledFile)); file_put_contents($compiledFile, $compiler->compile($dwoo, $this)); if ($this->chmod !== null) { chmod($compiledFile, $this->chmod); } self::$cache['compiled'][$this->compileId] = true; } return $compiledFile; } protected function isValidCompiledFile($file) { return file_exists($file); } public static function templateFactory(Dwoo $dwoo, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, Dwoo_ITemplate $parentTemplate = null) { return new self($resourceId, $cacheTime, $cacheId, $compileId); } protected function getCompiledFilename(Dwoo $dwoo) { if ($this->compileId===null) { $this->compileId = $this->name; } return $dwoo->getCompileDir() . $this->compileId.'.d'.Dwoo::RELEASE_TAG.'.php'; } protected function getCacheFilename(Dwoo $dwoo) { if ($this->cacheId === null) { if (isset($_SERVER['REQUEST_URI']) === true) { $cacheId = $_SERVER['REQUEST_URI']; } elseif (isset($_SERVER['SCRIPT_FILENAME']) && isset($_SERVER['argv'])) { $cacheId = $_SERVER['SCRIPT_FILENAME'].'-'.implode('-', $_SERVER['argv']); } else { $cacheId = ''; } $this->getCompiledFilename($dwoo); $this->cacheId = str_replace('../', '__', $this->compileId . strtr($cacheId, '\\%?=!:;'.PATH_SEPARATOR, '/-------')); } return $dwoo->getCacheDir() . $this->cacheId.'.html'; } protected function makeDirectory($path) { if (is_dir($path) === true) { return; } if ($this->chmod !== null) { mkdir($path, $this->chmod, true); } else { mkdir($path, 0777, true); } } } class Dwoo_Template_File extends Dwoo_Template_String { protected $file; protected $includePath = null; protected $resolvedPath = null; public function __construct($file, $cacheTime = null, $cacheId = null, $compileId = null, $includePath = null) { $this->file = $file; $this->name = basename($file); $this->cacheTime = $cacheTime; if ($compileId !== null) { $this->compileId = str_replace('../', '__', strtr($compileId, '\\%?=!:;'.PATH_SEPARATOR, '/-------')); } if ($cacheId !== null) { $this->cacheId = str_replace('../', '__', strtr($cacheId, '\\%?=!:;'.PATH_SEPARATOR, '/-------')); } if (is_string($includePath)) { $this->includePath = array($includePath); } elseif (is_array($includePath)) { $this->includePath = $includePath; } } public function setIncludePath($paths) { if (is_array($paths) === false) { $paths = array($paths); } $this->includePath = $paths; $this->resolvedPath = null; } public function getIncludePath() { return $this->includePath; } protected function isValidCompiledFile($file) { return parent::isValidCompiledFile($file) && (int)$this->getUid() <= filemtime($file); } public function getSource() { return file_get_contents($this->getResourceIdentifier()); } public function getResourceName() { return 'file'; } public function getResourceIdentifier() { if ($this->resolvedPath !== null) { return $this->resolvedPath; } elseif ($this->includePath === null) { return $this->file; } else { foreach ($this->includePath as $path) { if (file_exists($path.DIRECTORY_SEPARATOR.$this->file) === true) { $this->resolvedPath = $path . DIRECTORY_SEPARATOR . $this->file; return $this->resolvedPath; } } throw new Dwoo_Exception('Template "'.$this->file.'" could not be found in any of your include path(s)'); } } public function getUid() { return (string) filemtime($this->getResourceIdentifier()); } public static function templateFactory(Dwoo $dwoo, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, Dwoo_ITemplate $parentTemplate = null) { if (DIRECTORY_SEPARATOR === '\\') { $resourceId = str_replace(array("\t", "\n", "\r", "\f", "\v"), array('\\t', '\\n', '\\r', '\\f', '\\v'), $resourceId); } $resourceId = strtr($resourceId, '\\', '/'); $includePath = null; if (file_exists($resourceId) === false) { if ($parentTemplate === null) { $parentTemplate = $dwoo->getTemplate(); } if ($parentTemplate instanceof Dwoo_Template_File) { if ($includePath = $parentTemplate->getIncludePath()) { if (strstr($resourceId, '../')) { throw new Dwoo_Exception('When using an include path you can not reference a template into a parent directory (using ../)'); } } else { $resourceId = dirname($parentTemplate->getResourceIdentifier()).DIRECTORY_SEPARATOR.$resourceId; if (file_exists($resourceId) === false) { return null; } } } else { return null; } } if ($policy = $dwoo->getSecurityPolicy()) { while (true) { if (preg_match('{^([a-z]+?)://}i', $resourceId)) { throw new Dwoo_Security_Exception('The security policy prevents you to read files from external sources : '.$resourceId.'.'); } if ($includePath) { break; } $resourceId = realpath($resourceId); $dirs = $policy->getAllowedDirectories(); foreach ($dirs as $dir=>$dummy) { if (strpos($resourceId, $dir) === 0) { break 2; } } throw new Dwoo_Security_Exception('The security policy prevents you to read '.$resourceId.''); } } return new Dwoo_Template_File($resourceId, $cacheTime, $cacheId, $compileId, $includePath); } protected function getCompiledFilename(Dwoo $dwoo) { if ($this->compileId===null) { $this->compileId = str_replace('../', '__', strtr($this->getResourceIdentifier(), '\\:', '/-')); } return $dwoo->getCompileDir() . $this->compileId.'.d'.Dwoo::RELEASE_TAG.'.php'; } } class Dwoo_Data implements Dwoo_IDataProvider { protected $data = array(); public function getData() { return $this->data; } public function clear($name = null) { if ($name === null) { $this->data = array(); } elseif (is_array($name)) { foreach ($name as $index) unset($this->data[$index]); } else { unset($this->data[$name]); } } public function setData(array $data) { $this->data = $data; } public function mergeData(array $data) { $args = func_get_args(); while (list(,$v) = each($args)) { if (is_array($v)) { $this->data = array_merge($this->data, $v); } } } public function assign($name, $val = null) { if (is_array($name)) { reset($name); while (list($k,$v) = each($name)) $this->data[$k] = $v; } else { $this->data[$name] = $val; } } public function __set($name, $value) { $this->assign($name, $value); } public function assignByRef($name, &$val) { $this->data[$name] =& $val; } public function append($name, $val = null, $merge = false) { if (is_array($name)) { foreach ($name as $key=>$val) { if (isset($this->data[$key]) && !is_array($this->data[$key])) { settype($this->data[$key], 'array'); } if ($merge === true && is_array($val)) { $this->data[$key] = $val + $this->data[$key]; } else { $this->data[$key][] = $val; } } } elseif ($val !== null) { if (isset($this->data[$name]) && !is_array($this->data[$name])) { settype($this->data[$name], 'array'); } if ($merge === true && is_array($val)) { $this->data[$name] = $val + $this->data[$name]; } else { $this->data[$name][] = $val; } } } public function appendByRef($name, &$val, $merge = false) { if (isset($this->data[$name]) && !is_array($this->data[$name])) { settype($this->data[$name], 'array'); } if ($merge === true && is_array($val)) { foreach ($val as $key => &$val) { $this->data[$name][$key] =& $val; } } else { $this->data[$name][] =& $val; } } public function isAssigned($name) { return isset($this->data[$name]); } public function __isset($name) { return isset($this->data[$name]); } public function unassign($name) { unset($this->data[$name]); } public function __unset($name) { unset($this->data[$name]); } public function get($name) { return $this->__get($name); } public function __get($name) { if (isset($this->data[$name])) { return $this->data[$name]; } else { throw new Dwoo_Exception('Tried to read a value that was not assigned yet : "'.$name.'"'); } } } \ No newline at end of file diff --git a/lib/dwoo/Dwoo/Compilation/Exception.php b/lib/dwoo/Dwoo/Compilation/Exception.php new file mode 100644 index 0000000..180b51f --- /dev/null +++ b/lib/dwoo/Dwoo/Compilation/Exception.php @@ -0,0 +1,38 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Compilation_Exception extends Dwoo_Exception +{ + protected $compiler; + protected $template; + + public function __construct(Dwoo_Compiler $compiler, $message) + { + $this->compiler = $compiler; + $this->template = $compiler->getDwoo()->getTemplate(); + parent::__construct('Compilation error at line '.$compiler->getLine().' in "'.$this->template->getResourceName().':'.$this->template->getResourceIdentifier().'" : '.$message); + } + + public function getCompiler() + { + return $this->compiler; + } + + public function getTemplate() + { + return $this->template; + } +} diff --git a/lib/dwoo/Dwoo/Compiler.php b/lib/dwoo/Dwoo/Compiler.php new file mode 100644 index 0000000..c53bfcd --- /dev/null +++ b/lib/dwoo/Dwoo/Compiler.php @@ -0,0 +1,2854 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.1 + * @date 2008-12-24 + * @package Dwoo + */ +class Dwoo_Compiler implements Dwoo_ICompiler +{ + /** + * constant that represents a php opening tag + * + * use it in case it needs to be adjusted + * + * @var string + */ + const PHP_OPEN = ""; + + /** + * boolean flag to enable or disable debugging output + * + * @var bool + */ + public $debug = false; + + /** + * left script delimiter + * + * @var string + */ + protected $ld = '{'; + + /** + * left script delimiter with escaped regex meta characters + * + * @var string + */ + protected $ldr = '\\{'; + + /** + * right script delimiter + * + * @var string + */ + protected $rd = '}'; + + /** + * right script delimiter with escaped regex meta characters + * + * @var string + */ + protected $rdr = '\\}'; + + /** + * defines whether the nested comments should be parsed as nested or not + * + * defaults to false (classic block comment parsing as in all languages) + * + * @var bool + */ + protected $allowNestedComments = false; + + /** + * defines whether opening and closing tags can contain spaces before valid data or not + * + * turn to true if you want to be sloppy with the syntax, but when set to false it allows + * to skip javascript and css tags as long as they are in the form "{ something", which is + * nice. default is false. + * + * @var bool + */ + protected $allowLooseOpenings = false; + + /** + * defines whether the compiler will automatically html-escape variables or not + * + * default is false + * + * @var bool + */ + protected $autoEscape = false; + + /** + * security policy object + * + * @var Dwoo_Security_Policy + */ + protected $securityPolicy; + + /** + * stores the custom plugins registered with this compiler + * + * @var array + */ + protected $customPlugins = array(); + + /** + * stores the pre- and post-processors callbacks + * + * @var array + */ + protected $processors = array('pre'=>array(), 'post'=>array()); + + /** + * stores a list of plugins that are used in the currently compiled + * template, and that are not compilable. these plugins will be loaded + * during the template's runtime if required. + * + * it is a 1D array formatted as key:pluginName value:pluginType + * + * @var array + */ + protected $usedPlugins; + + /** + * stores the template undergoing compilation + * + * @var string + */ + protected $template; + + /** + * stores the current pointer position inside the template + * + * @var int + */ + protected $pointer; + + /** + * stores the data within which the scope moves + * + * @var array + */ + protected $data; + + /** + * variable scope of the compiler, set to null if + * it can not be resolved to a static string (i.e. if some + * plugin defines a new scope based on a variable array key) + * + * @var mixed + */ + protected $scope; + + /** + * variable scope tree, that allows to rebuild the current + * scope if required, i.e. when going to a parent level + * + * @var array + */ + protected $scopeTree; + + /** + * block plugins stack, accessible through some methods + * + * @see findBlock + * @see getCurrentBlock + * @see addBlock + * @see addCustomBlock + * @see injectBlock + * @see removeBlock + * @see removeTopBlock + * + * @var array + */ + protected $stack = array(); + + /** + * current block at the top of the block plugins stack, + * accessible through getCurrentBlock + * + * @see getCurrentBlock + * + * @var Dwoo_Block_Plugin + */ + protected $curBlock; + + /** + * current dwoo object that uses this compiler, or null + * + * @var Dwoo + */ + protected $dwoo; + + /** + * holds an instance of this class, used by getInstance when you don't + * provide a custom compiler in order to save resources + * + * @var Dwoo_Compiler + */ + protected static $instance; + + /** + * sets the delimiters to use in the templates + * + * delimiters can be multi-character strings but should not be one of those as they will + * make it very hard to work with templates or might even break the compiler entirely : "\", "$", "|", ":" and finally "#" only if you intend to use config-vars with the #var# syntax. + * + * @param string $left left delimiter + * @param string $right right delimiter + */ + public function setDelimiters($left, $right) + { + $this->ld = $left; + $this->rd = $right; + $this->ldr = preg_quote($left, '/'); + $this->rdr = preg_quote($right, '/'); + } + + /** + * returns the left and right template delimiters + * + * @return array containing the left and the right delimiters + */ + public function getDelimiters() + { + return array($this->ld, $this->rd); + } + + /** + * sets the way to handle nested comments, if set to true + * {* foo {* some other *} comment *} will be stripped correctly. + * + * if false it will remove {* foo {* some other *} and leave "comment *}" alone, + * this is the default behavior + * + * @param bool $allow allow nested comments or not, defaults to true (but the default internal value is false) + */ + public function setNestedCommentsHandling($allow = true) { + $this->allowNestedComments = (bool) $allow; + } + + /** + * returns the nested comments handling setting + * + * @see setNestedCommentsHandling + * @return bool true if nested comments are allowed + */ + public function getNestedCommentsHandling() { + return $this->allowNestedComments; + } + + /** + * sets the tag openings handling strictness, if set to true, template tags can + * contain spaces before the first function/string/variable such as { $foo} is valid. + * + * if set to false (default setting), { $foo} is invalid but that is however a good thing + * as it allows css (i.e. #foo { color:red; }) to be parsed silently without triggering + * an error, same goes for javascript. + * + * @param bool $allow true to allow loose handling, false to restore default setting + */ + public function setLooseOpeningHandling($allow = false) + { + $this->allowLooseOpenings = (bool) $allow; + } + + /** + * returns the tag openings handling strictness setting + * + * @see setLooseOpeningHandling + * @return bool true if loose tags are allowed + */ + public function getLooseOpeningHandling() + { + return $this->allowLooseOpenings; + } + + /** + * changes the auto escape setting + * + * if enabled, the compiler will automatically html-escape variables, + * unless they are passed through the safe function such as {$var|safe} + * or {safe $var} + * + * default setting is disabled/false + * + * @param bool $enabled set to true to enable, false to disable + */ + public function setAutoEscape($enabled) + { + $this->autoEscape = (bool) $enabled; + } + + /** + * returns the auto escape setting + * + * default setting is disabled/false + * + * @return bool + */ + public function getAutoEscape() + { + return $this->autoEscape; + } + + /** + * adds a preprocessor to the compiler, it will be called + * before the template is compiled + * + * @param mixed $callback either a valid callback to the preprocessor or a simple name if the autoload is set to true + * @param bool $autoload if set to true, the preprocessor is auto-loaded from one of the plugin directories, else you must provide a valid callback + */ + public function addPreProcessor($callback, $autoload = false) + { + if ($autoload) { + $name = str_replace('Dwoo_Processor_', '', $callback); + $class = 'Dwoo_Processor_'.$name; + + if (class_exists($class, false)) { + $callback = array(new $class($this), 'process'); + } elseif (function_exists($class)) { + $callback = $class; + } else { + $callback = array('autoload'=>true, 'class'=>$class, 'name'=>$name); + } + + $this->processors['pre'][] = $callback; + } else { + $this->processors['pre'][] = $callback; + } + } + + /** + * removes a preprocessor from the compiler + * + * @param mixed $callback either a valid callback to the preprocessor or a simple name if it was autoloaded + */ + public function removePreProcessor($callback) + { + if (($index = array_search($callback, $this->processors['pre'], true)) !== false) { + unset($this->processors['pre'][$index]); + } elseif (($index = array_search('Dwoo_Processor_'.str_replace('Dwoo_Processor_', '', $callback), $this->processors['pre'], true)) !== false) { + unset($this->processors['pre'][$index]); + } else { + $class = 'Dwoo_Processor_' . str_replace('Dwoo_Processor_', '', $callback); + foreach ($this->processors['pre'] as $index=>$proc) { + if (is_array($proc) && ($proc[0] instanceof $class) || (isset($proc['class']) && $proc['class'] == $class)) { + unset($this->processors['pre'][$index]); + break; + } + } + } + } + + /** + * adds a postprocessor to the compiler, it will be called + * before the template is compiled + * + * @param mixed $callback either a valid callback to the postprocessor or a simple name if the autoload is set to true + * @param bool $autoload if set to true, the postprocessor is auto-loaded from one of the plugin directories, else you must provide a valid callback + */ + public function addPostProcessor($callback, $autoload = false) + { + if ($autoload) { + $name = str_replace('Dwoo_Processor_', '', $callback); + $class = 'Dwoo_Processor_'.$name; + + if (class_exists($class, false)) { + $callback = array(new $class($this), 'process'); + } elseif (function_exists($class)) { + $callback = $class; + } else { + $callback = array('autoload'=>true, 'class'=>$class, 'name'=>$name); + } + + $this->processors['post'][] = $callback; + } else { + $this->processors['post'][] = $callback; + } + } + + /** + * removes a postprocessor from the compiler + * + * @param mixed $callback either a valid callback to the postprocessor or a simple name if it was autoloaded + */ + public function removePostProcessor($callback) + { + if (($index = array_search($callback, $this->processors['post'], true)) !== false) { + unset($this->processors['post'][$index]); + } elseif (($index = array_search('Dwoo_Processor_'.str_replace('Dwoo_Processor_', '', $callback), $this->processors['post'], true)) !== false) { + unset($this->processors['post'][$index]); + } else { + $class = 'Dwoo_Processor_' . str_replace('Dwoo_Processor_', '', $callback); + foreach ($this->processors['post'] as $index=>$proc) { + if (is_array($proc) && ($proc[0] instanceof $class) || (isset($proc['class']) && $proc['class'] == $class)) { + unset($this->processors['post'][$index]); + break; + } + } + } + } + + /** + * internal function to autoload processors at runtime if required + * + * @param string $class the class/function name + * @param string $name the plugin name (without Dwoo_Plugin_ prefix) + */ + protected function loadProcessor($class, $name) + { + if (!class_exists($class, false) && !function_exists($class)) { + try { + $this->dwoo->getLoader()->loadPlugin($name); + } catch (Dwoo_Exception $e) { + throw new Dwoo_Exception('Processor '.$name.' could not be found in your plugin directories, please ensure it is in a file named '.$name.'.php in the plugin directory'); + } + } + + if (class_exists($class, false)) { + return array(new $class($this), 'process'); + } + + if (function_exists($class)) { + return $class; + } + + throw new Dwoo_Exception('Wrong processor name, when using autoload the processor must be in one of your plugin dir as "name.php" containg a class or function named "Dwoo_Processor_name"'); + } + + /** + * adds the custom plugins loaded into Dwoo to the compiler so it can load them + * + * @see Dwoo::addPlugin + * @param array $customPlugins an array of custom plugins + */ + public function setCustomPlugins(array $customPlugins) + { + $this->customPlugins = $customPlugins; + } + + /** + * sets the security policy object to enforce some php security settings + * + * use this if untrusted persons can modify templates, + * set it on the Dwoo object as it will be passed onto the compiler automatically + * + * @param Dwoo_Security_Policy $policy the security policy object + */ + public function setSecurityPolicy(Dwoo_Security_Policy $policy = null) + { + $this->securityPolicy = $policy; + } + + /** + * returns the current security policy object or null by default + * + * @return Dwoo_Security_Policy|null the security policy object if any + */ + public function getSecurityPolicy() + { + return $this->securityPolicy; + } + + /** + * sets the pointer position + * + * @param int $position the new pointer position + * @param bool $isOffset if set to true, the position acts as an offset and not an absolute position + */ + public function setPointer($position, $isOffset = false) + { + if ($isOffset) { + $this->pointer += $position; + } else { + $this->pointer = $position; + } + } + + /** + * returns the current pointer position, only available during compilation of a template + * + * @return int + */ + public function getPointer() + { + return $this->pointer; + } + + /** + * sets the line number + * + * @param int $number the new line number + * @param bool $isOffset if set to true, the position acts as an offset and not an absolute position + */ + public function setLine($number, $isOffset = false) + { + if ($isOffset) { + $this->line += $number; + } else { + $this->line = $number; + } + } + + /** + * returns the current line number, only available during compilation of a template + * + * @return int + */ + public function getLine() + { + return $this->line; + } + + /** + * returns the dwoo object that initiated this template compilation, only available during compilation of a template + * + * @return Dwoo + */ + public function getDwoo() + { + return $this->dwoo; + } + + /** + * overwrites the template that is being compiled + * + * @param string $newSource the template source that must replace the current one + * @param bool $fromPointer if set to true, only the source from the current pointer position is replaced + * @return string the template or partial template + */ + public function setTemplateSource($newSource, $fromPointer = false) + { + if ($fromPointer === true) { + $this->templateSource = substr($this->templateSource, 0, $this->pointer) . $newSource; + } else { + $this->templateSource = $newSource; + } + } + + /** + * returns the template that is being compiled + * + * @param mixed $fromPointer if set to true, only the source from the current pointer + * position is returned, if a number is given it overrides the current pointer + * @return string the template or partial template + */ + public function getTemplateSource($fromPointer = false) + { + if ($fromPointer === true) { + return substr($this->templateSource, $this->pointer); + } elseif (is_numeric($fromPointer)) { + return substr($this->templateSource, $fromPointer); + } else { + return $this->templateSource; + } + } + + /** + * compiles the provided string down to php code + * + * @param string $tpl the template to compile + * @return string a compiled php string + */ + public function compile(Dwoo $dwoo, Dwoo_ITemplate $template) + { + // init vars + $tpl = $template->getSource(); + $ptr = 0; + $this->dwoo = $dwoo; + $this->template = $template; + $this->templateSource =& $tpl; + $this->pointer =& $ptr; + + while (true) { + // if pointer is at the beginning, reset everything, that allows a plugin to externally reset the compiler if everything must be reparsed + if ($ptr===0) { + // resets variables + $this->usedPlugins = array(); + $this->data = array(); + $this->scope =& $this->data; + $this->scopeTree = array(); + $this->stack = array(); + $this->line = 1; + // add top level block + $compiled = $this->addBlock('topLevelBlock', array(), 0); + $this->stack[0]['buffer'] = ''; + + if ($this->debug) echo 'COMPILER INIT
'; + + if ($this->debug) echo 'PROCESSING PREPROCESSORS ('.count($this->processors['pre']).')
'; + + // runs preprocessors + foreach ($this->processors['pre'] as $preProc) { + if (is_array($preProc) && isset($preProc['autoload'])) { + $preProc = $this->loadProcessor($preProc['class'], $preProc['name']); + } + if (is_array($preProc) && $preProc[0] instanceof Dwoo_Processor) { + $tpl = call_user_func($preProc, $tpl); + } else { + $tpl = call_user_func($preProc, $this, $tpl); + } + } + unset($preProc); + + // show template source if debug + if ($this->debug) echo '
'.print_r(htmlentities($tpl), true).'

'; + + // strips php tags if required by the security policy + if ($this->securityPolicy !== null) { + $search = array('{<\?php.*?\?>}'); + if (ini_get('short_open_tags')) { + $search = array('{<\?.*?\?>}', '{<%.*?%>}'); + } + switch($this->securityPolicy->getPhpHandling()) { + + case Dwoo_Security_Policy::PHP_ALLOW: + break; + case Dwoo_Security_Policy::PHP_ENCODE: + $tpl = preg_replace_callback($search, array($this, 'phpTagEncodingHelper'), $tpl); + break; + case Dwoo_Security_Policy::PHP_REMOVE: + $tpl = preg_replace($search, '', $tpl); + + } + } + } + + $pos = strpos($tpl, $this->ld, $ptr); + + if ($pos === false) { + $this->push(substr($tpl, $ptr), 0); + break; + } elseif (substr($tpl, $pos-1, 1) === '\\' && substr($tpl, $pos-2, 1) !== '\\') { + $this->push(substr($tpl, $ptr, $pos-$ptr-1) . $this->ld); + $ptr = $pos+strlen($this->ld); + } elseif (preg_match('/^'.$this->ldr . ($this->allowLooseOpenings ? '\s*' : '') . 'literal' . ($this->allowLooseOpenings ? '\s*' : '') . $this->rdr.'/s', substr($tpl, $pos), $litOpen)) { + if (!preg_match('/'.$this->ldr . ($this->allowLooseOpenings ? '\s*' : '') . '\/literal' . ($this->allowLooseOpenings ? '\s*' : '') . $this->rdr.'/s', $tpl, $litClose, PREG_OFFSET_CAPTURE, $pos)) { + throw new Dwoo_Compilation_Exception($this, 'The {literal} blocks must be closed explicitly with {/literal}'); + } + $endpos = $litClose[0][1]; + $this->push(substr($tpl, $ptr, $pos-$ptr) . substr($tpl, $pos + strlen($litOpen[0]), $endpos-$pos-strlen($litOpen[0]))); + $ptr = $endpos+strlen($litClose[0][0]); + } else { + if (substr($tpl, $pos-2, 1) === '\\' && substr($tpl, $pos-1, 1) === '\\') { + $this->push(substr($tpl, $ptr, $pos-$ptr-1)); + $ptr = $pos; + } + + $this->push(substr($tpl, $ptr, $pos-$ptr)); + $ptr = $pos; + + $pos += strlen($this->ld); + if ($this->allowLooseOpenings) { + while (substr($tpl, $pos, 1) === ' ') { + $pos+=1; + } + } else { + if (substr($tpl, $pos, 1) === ' ' || substr($tpl, $pos, 1) === "\r" || substr($tpl, $pos, 1) === "\n" || substr($tpl, $pos, 1) === "\t") { + $ptr = $pos; + $this->push($this->ld); + continue; + } + } + + // check that there is an end tag present + if (strpos($tpl, $this->rd, $pos) === false) { + throw new Dwoo_Compilation_Exception($this, 'A template tag was not closed, started with "'.substr($tpl, $ptr, 30).'"'); + } + + + $ptr += strlen($this->ld); + $subptr = $ptr; + + while (true) { + $parsed = $this->parse($tpl, $subptr, null, false, 'root', $subptr); + + // reload loop if the compiler was reset + if ($ptr === 0) { + continue 2; + } + + $len = $subptr - $ptr; + $this->push($parsed, substr_count(substr($tpl, $ptr, $len), "\n")); + $ptr += $len; + + if ($parsed === false) { + break; + } + } + + // adds additional line breaks between php closing and opening tags because the php parser removes those if there is just a single line break + if (substr($this->curBlock['buffer'], -2) === '?>' && preg_match('{^(([\r\n])([\r\n]?))}', substr($tpl, $ptr, 3), $m)) { + if ($m[3] === '') { + $ptr+=1; + $this->push($m[1].$m[1], 1); + } else { + $ptr+=2; + $this->push($m[1]."\n", 2); + } + } + } + } + + $compiled .= $this->removeBlock('topLevelBlock'); + + if ($this->debug) echo 'PROCESSING POSTPROCESSORS
'; + + foreach ($this->processors['post'] as $postProc) { + if (is_array($postProc) && isset($postProc['autoload'])) { + $postProc = $this->loadProcessor($postProc['class'], $postProc['name']); + } + if (is_array($postProc) && $postProc[0] instanceof Dwoo_Processor) { + $compiled = call_user_func($postProc, $compiled); + } else { + $compiled = call_user_func($postProc, $this, $compiled); + } + } + unset($postProc); + + if ($this->debug) echo 'COMPILATION COMPLETE : MEM USAGE : '.memory_get_usage().'
'; + + $output = "usedPlugins as $plugin=>$type) { + if ($type & Dwoo::CUSTOM_PLUGIN) { + continue; + } + + switch($type) { + + case Dwoo::BLOCK_PLUGIN: + case Dwoo::CLASS_PLUGIN: + $output .= "if (class_exists('Dwoo_Plugin_$plugin', false)===false)\n\t\$this->getLoader()->loadPlugin('$plugin');\n"; + break; + case Dwoo::FUNC_PLUGIN: + $output .= "if (function_exists('Dwoo_Plugin_$plugin')===false)\n\t\$this->getLoader()->loadPlugin('$plugin');\n"; + break; + case Dwoo::SMARTY_MODIFIER: + $output .= "if (function_exists('smarty_modifier_$plugin')===false)\n\t\$this->getLoader()->loadPlugin('$plugin');\n"; + break; + case Dwoo::SMARTY_FUNCTION: + $output .= "if (function_exists('smarty_function_$plugin')===false)\n\t\$this->getLoader()->loadPlugin('$plugin');\n"; + break; + case Dwoo::SMARTY_BLOCK: + $output .= "if (function_exists('smarty_block_$plugin')===false)\n\t\$this->getLoader()->loadPlugin('$plugin');\n"; + break; + case Dwoo::PROXY_PLUGIN: + $output .= $this->getDwoo()->getPluginProxy()->getPreloader($plugin); + break; + default: + throw new Dwoo_Compilation_Exception($this, 'Type error for '.$plugin.' with type'.$type); + + } + } + + $output .= $compiled."\n?>"; + + $output = preg_replace('/(?\s*)<\?xml#is', '$1', $output); + + if ($this->debug) { + echo '
';
+			$lines = preg_split('{\r\n|\n|
}', highlight_string(($output), true)); + array_shift($lines); + foreach ($lines as $i=>$line) { + echo ($i+1).'. '.$line."\r\n"; + } + } + if ($this->debug) echo '
'; + + $this->template = $this->dwoo = null; + $tpl = null; + + return $output; + } + + /** + * adds compiled content to the current block + * + * @param string $content the content to push + * @param int $lineCount newlines count in content, optional + */ + public function push($content, $lineCount = null) + { + if ($lineCount === null) { + $lineCount = substr_count($content, "\n"); + } + + if ($this->curBlock['buffer'] === null && count($this->stack) > 1) { + // buffer is not initialized yet (the block has just been created) + $this->stack[count($this->stack)-2]['buffer'] .= (string) $content; + $this->curBlock['buffer'] = ''; + } else { + if (!isset($this->curBlock['buffer'])) { + throw new Dwoo_Compilation_Exception($this, 'The template has been closed too early, you probably have an extra block-closing tag somewhere'); + } + // append current content to current block's buffer + $this->curBlock['buffer'] .= (string) $content; + } + $this->line += $lineCount; + } + + /** + * sets the scope + * + * set to null if the scope becomes "unstable" (i.e. too variable or unknown) so that + * variables are compiled in a more evaluative way than just $this->scope['key'] + * + * @param mixed $scope a string i.e. "level1.level2" or an array i.e. array("level1", "level2") + * @param bool $absolute if true, the scope is set from the top level scope and not from the current scope + * @return array the current scope tree + */ + public function setScope($scope, $absolute = false) + { + $old = $this->scopeTree; + + if ($scope===null) { + unset($this->scope); + $this->scope = null; + } + + if (is_array($scope)===false) { + $scope = explode('.', $scope); + } + + if ($absolute===true) { + $this->scope =& $this->data; + $this->scopeTree = array(); + } + + while (($bit = array_shift($scope)) !== null) { + if ($bit === '_parent' || $bit === '_') { + array_pop($this->scopeTree); + reset($this->scopeTree); + $this->scope =& $this->data; + $cnt = count($this->scopeTree); + for ($i=0;$i<$cnt;$i++) + $this->scope =& $this->scope[$this->scopeTree[$i]]; + } elseif ($bit === '_root' || $bit === '__') { + $this->scope =& $this->data; + $this->scopeTree = array(); + } elseif (isset($this->scope[$bit])) { + $this->scope =& $this->scope[$bit]; + $this->scopeTree[] = $bit; + } else { + $this->scope[$bit] = array(); + $this->scope =& $this->scope[$bit]; + $this->scopeTree[] = $bit; + } + } + + return $old; + } + + /** + * forces an absolute scope + * + * @deprecated + * @param mixed $scope a scope as a string or array + * @return array the current scope tree + */ + public function forceScope($scope) + { + return $this->setScope($scope, true); + } + + /** + * adds a block to the top of the block stack + * + * @param string $type block type (name) + * @param array $params the parameters array + * @param int $paramtype the parameters type (see mapParams), 0, 1 or 2 + * @return string the preProcessing() method's output + */ + public function addBlock($type, array $params, $paramtype) + { + $class = 'Dwoo_Plugin_'.$type; + if (class_exists($class, false) === false) { + $this->dwoo->getLoader()->loadPlugin($type); + } + + $params = $this->mapParams($params, array($class, 'init'), $paramtype); + + $this->stack[] = array('type' => $type, 'params' => $params, 'custom' => false, 'class' => $class, 'buffer' => null); + $this->curBlock =& $this->stack[count($this->stack)-1]; + return call_user_func(array($class,'preProcessing'), $this, $params, '', '', $type); + } + + /** + * adds a custom block to the top of the block stack + * + * @param string $type block type (name) + * @param array $params the parameters array + * @param int $paramtype the parameters type (see mapParams), 0, 1 or 2 + * @return string the preProcessing() method's output + */ + public function addCustomBlock($type, array $params, $paramtype) + { + $callback = $this->customPlugins[$type]['callback']; + if (is_array($callback)) { + $class = is_object($callback[0]) ? get_class($callback[0]) : $callback[0]; + } else { + $class = $callback; + } + + $params = $this->mapParams($params, array($class, 'init'), $paramtype); + + $this->stack[] = array('type' => $type, 'params' => $params, 'custom' => true, 'class' => $class, 'buffer' => null); + $this->curBlock =& $this->stack[count($this->stack)-1]; + return call_user_func(array($class,'preProcessing'), $this, $params, '', '', $type); + } + + /** + * injects a block at the top of the plugin stack without calling its preProcessing method + * + * used by {else} blocks to re-add themselves after having closed everything up to their parent + * + * @param string $type block type (name) + * @param array $params parameters array + */ + public function injectBlock($type, array $params) + { + $class = 'Dwoo_Plugin_'.$type; + if (class_exists($class, false) === false) { + $this->dwoo->getLoader()->loadPlugin($type); + } + $this->stack[] = array('type' => $type, 'params' => $params, 'custom' => false, 'class' => $class, 'buffer' => null); + $this->curBlock =& $this->stack[count($this->stack)-1]; + } + + /** + * removes the closest-to-top block of the given type and all other + * blocks encountered while going down the block stack + * + * @param string $type block type (name) + * @return string the output of all postProcessing() method's return values of the closed blocks + */ + public function removeBlock($type) + { + $output = ''; + + $pluginType = $this->getPluginType($type); + if ($pluginType & Dwoo::SMARTY_BLOCK) { + $type = 'smartyinterface'; + } + while (true) { + while ($top = array_pop($this->stack)) { + if ($top['custom']) { + $class = $top['class']; + } else { + $class = 'Dwoo_Plugin_'.$top['type']; + } + if (count($this->stack)) { + $this->curBlock =& $this->stack[count($this->stack)-1]; + $this->push(call_user_func(array($class, 'postProcessing'), $this, $top['params'], '', '', $top['buffer']), 0); + } else { + $null = null; + $this->curBlock =& $null; + $output = call_user_func(array($class, 'postProcessing'), $this, $top['params'], '', '', $top['buffer']); + } + + if ($top['type'] === $type) { + break 2; + } + } + + throw new Dwoo_Compilation_Exception($this, 'Syntax malformation, a block of type "'.$type.'" was closed but was not opened'); + break; + } + + return $output; + } + + /** + * returns a reference to the first block of the given type encountered and + * optionally closes all blocks until it finds it + * + * this is mainly used by {else} plugins to close everything that was opened + * between their parent and themselves + * + * @param string $type the block type (name) + * @param bool $closeAlong whether to close all blocks encountered while going down the block stack or not + * @return &array the array is as such: array('type'=>pluginName, 'params'=>parameter array, + * 'custom'=>bool defining whether it's a custom plugin or not, for internal use) + */ + public function &findBlock($type, $closeAlong = false) + { + if ($closeAlong===true) { + while ($b = end($this->stack)) { + if ($b['type']===$type) { + return $this->stack[key($this->stack)]; + } + $this->push($this->removeTopBlock(), 0); + } + } else { + end($this->stack); + while ($b = current($this->stack)) { + if ($b['type']===$type) { + return $this->stack[key($this->stack)]; + } + prev($this->stack); + } + } + + throw new Dwoo_Compilation_Exception($this, 'A parent block of type "'.$type.'" is required and can not be found'); + } + + /** + * returns a reference to the current block array + * + * @return &array the array is as such: array('type'=>pluginName, 'params'=>parameter array, + * 'custom'=>bool defining whether it's a custom plugin or not, for internal use) + */ + public function &getCurrentBlock() + { + return $this->curBlock; + } + + /** + * removes the block at the top of the stack and calls its postProcessing() method + * + * @return string the postProcessing() method's output + */ + public function removeTopBlock() + { + $o = array_pop($this->stack); + if ($o === null) { + throw new Dwoo_Compilation_Exception($this, 'Syntax malformation, a block of unknown type was closed but was not opened.'); + } + if ($o['custom']) { + $class = $o['class']; + } else { + $class = 'Dwoo_Plugin_'.$o['type']; + } + + $this->curBlock =& $this->stack[count($this->stack)-1]; + + return call_user_func(array($class, 'postProcessing'), $this, $o['params'], '', '', $o['buffer']); + } + + /** + * returns the compiled parameters (for example a variable's compiled parameter will be "$this->scope['key']") out of the given parameter array + * + * @param array $params parameter array + * @return array filtered parameters + */ + public function getCompiledParams(array $params) + { + foreach ($params as $k=>$p) { + if (is_array($p)) { + $params[$k] = $p[0]; + } + } + return $params; + } + + /** + * returns the real parameters (for example a variable's real parameter will be its key, etc) out of the given parameter array + * + * @param array $params parameter array + * @return array filtered parameters + */ + public function getRealParams(array $params) + { + foreach ($params as $k=>$p) { + if (is_array($p)) { + $params[$k] = $p[1]; + } + } + return $params; + } + + /** + * entry point of the parser, it redirects calls to other parse* functions + * + * @param string $in the string within which we must parse something + * @param int $from the starting offset of the parsed area + * @param int $to the ending offset of the parsed area + * @param mixed $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by default + * @param string $curBlock the current parser-block being processed + * @param mixed $pointer a reference to a pointer that will be increased by the amount of characters parsed, or null by default + * @return string parsed values + */ + protected function parse($in, $from, $to, $parsingParams = false, $curBlock='', &$pointer = null) + { + if ($to === null) { + $to = strlen($in); + } + $first = substr($in, $from, 1); + + if ($first === false) { + throw new Dwoo_Compilation_Exception($this, 'Unexpected EOF, a template tag was not closed'); + } + + while ($first===" " || $first==="\n" || $first==="\t" || $first==="\r") { + if ($curBlock === 'root' && substr($in, $from, strlen($this->rd)) === $this->rd) { + // end template tag + $pointer += strlen($this->rd); + if ($this->debug) echo 'TEMPLATE PARSING ENDED
'; + return false; + } + $from++; + if ($pointer !== null) { + $pointer++; + } + if ($from >= $to) { + if (is_array($parsingParams)) { + return $parsingParams; + } else { + return ''; + } + } + $first = $in[$from]; + } + + $substr = substr($in, $from, $to-$from); + + if ($this->debug) echo '
PARSE CALL : PARSING "'.htmlentities(substr($in, $from, min($to-$from, 50))).(($to-$from) > 50 ? '...':'').'" @ '.$from.':'.$to.' in '.$curBlock.' : pointer='.$pointer.'
'; + $parsed = ""; + + if ($curBlock === 'root' && $first === '*') { + $src = $this->getTemplateSource(); + $startpos = $this->getPointer() - strlen($this->ld); + if (substr($src, $startpos, strlen($this->ld)) === $this->ld) { + do { + $char = substr($src, --$startpos, 1); + if ($char == "\n") { + $startpos++; + $whitespaceStart = true; + break; + } + } while ($char == ' ' || $char == "\t"); + + if (!isset($whitespaceStart)) { + $startpos = $this->getPointer(); + } else { + $pointer -= $this->getPointer() - $startpos; + } + + if ($this->allowNestedComments && strpos($src, $this->ld.'*', $this->getPointer()) !== false) { + $comOpen = $this->ld.'*'; + $comClose = '*'.$this->rd; + $level = 1; + $start = $startpos; + $ptr = $this->getPointer() + '*'; + + while ($level > 0 && $ptr < strlen($src)) { + $open = strpos($src, $comOpen, $ptr); + $close = strpos($src, $comClose, $ptr); + + if ($open !== false && $close !== false) { + if ($open < $close) { + $ptr = $open + strlen($comOpen); + $level++; + } else { + $ptr = $close + strlen($comClose); + $level--; + } + } elseif ($open !== false) { + $ptr = $open + strlen($comOpen); + $level++; + } elseif ($close !== false) { + $ptr = $close + strlen($comClose); + $level--; + } else { + $ptr = strlen($src); + } + } + $endpos = $ptr - strlen('*'.$this->rd); + } else { + $endpos = strpos($src, '*'.$this->rd, $startpos); + if ($endpos == false) { + throw new Dwoo_Compilation_Exception($this, 'Un-ended comment'); + } + } + $pointer += $endpos - $startpos + strlen('*'.$this->rd); + if (isset($whitespaceStart) && preg_match('#^[\t ]*\r?\n#', substr($src, $endpos+strlen('*'.$this->rd)), $m)) { + $pointer += strlen($m[0]); + $this->curBlock['buffer'] = substr($this->curBlock['buffer'], 0, strlen($this->curBlock['buffer']) - ($this->getPointer() - $startpos - strlen($this->ld))); + } + return false; + } + } + + if ($first==='$') { + // var + $out = $this->parseVar($in, $from, $to, $parsingParams, $curBlock, $pointer); + $parsed = 'var'; + } elseif ($first==='%' && preg_match('#^%[a-z]#i', $substr)) { + // const + $out = $this->parseConst($in, $from, $to, $parsingParams, $curBlock, $pointer); + } elseif ($first==='"' || $first==="'") { + // string + $out = $this->parseString($in, $from, $to, $parsingParams, $curBlock, $pointer); + } elseif (preg_match('/^[a-z][a-z0-9_]*(?:::[a-z][a-z0-9_]*)?('.(is_array($parsingParams)||$curBlock!='root'?'':'\s+[^(]|').'\s*\(|\s*'.$this->rdr.'|\s*;)/i', $substr)) { + // func + $out = $this->parseFunction($in, $from, $to, $parsingParams, $curBlock, $pointer); + $parsed = 'func'; + } elseif ($first === ';') { + // instruction end + if ($this->debug) echo 'END OF INSTRUCTION
'; + if ($pointer !== null) { + $pointer++; + } + return $this->parse($in, $from+1, $to, false, 'root', $pointer); + } elseif ($curBlock === 'root' && preg_match('#^/([a-z][a-z0-9_]*)?#i', $substr, $match)) { + // close block + if (!empty($match[1]) && $match[1] == 'else') { + throw new Dwoo_Compilation_Exception($this, 'Else blocks must not be closed explicitly, they are automatically closed when their parent block is closed'); + } + if (!empty($match[1]) && $match[1] == 'elseif') { + throw new Dwoo_Compilation_Exception($this, 'Elseif blocks must not be closed explicitly, they are automatically closed when their parent block is closed or a new else/elseif block is declared after them'); + } + if ($pointer !== null) { + $pointer += strlen($match[0]); + } + if (empty($match[1])) { + if ($this->curBlock['type'] == 'else' || $this->curBlock['type'] == 'elseif') { + $pointer -= strlen($match[0]); + } + if ($this->debug) echo 'TOP BLOCK CLOSED
'; + return $this->removeTopBlock(); + } else { + if ($this->debug) echo 'BLOCK OF TYPE '.$match[1].' CLOSED
'; + return $this->removeBlock($match[1]); + } + } elseif ($curBlock === 'root' && substr($substr, 0, strlen($this->rd)) === $this->rd) { + // end template tag + if ($this->debug) echo 'TAG PARSING ENDED
'; + $pointer += strlen($this->rd); + return false; + } elseif (is_array($parsingParams) && preg_match('#^([a-z0-9_]+\s*=)(?:\s+|[^=]).*#i', $substr, $match)) { + // named parameter + if ($this->debug) echo 'NAMED PARAM FOUND
'; + $len = strlen($match[1]); + while (substr($in, $from+$len, 1)===' ') { + $len++; + } + if ($pointer !== null) { + $pointer += $len; + } + + $output = array(trim(substr(trim($match[1]), 0, -1)), $this->parse($in, $from+$len, $to, false, 'namedparam', $pointer)); + + $parsingParams[] = $output; + return $parsingParams; + } elseif ($substr!=='' && (is_array($parsingParams) || $curBlock === 'namedparam' || $curBlock === 'condition')) { + // unquoted string, bool or number + $out = $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer); + } else { + // parse error + throw new Dwoo_Compilation_Exception($this, 'Parse error in "'.substr($in, $from, $to-$from).'"'); + } + + if (empty($out)) { + return ''; + } + + $substr = substr($in, $pointer, $to-$pointer); + + // var parsed, check if any var-extension applies + if ($parsed==='var' && $curBlock !== 'condition') { + if (preg_match('#^\s*([/%+*-])\s*([0-9]|\$)#', $substr, $match)) { + if($this->debug) echo 'PARSING POST-VAR EXPRESSION '.$substr.'
'; + // parse expressions + $pointer += strlen($match[0]) - 1; + if (is_array($parsingParams)) { + if ($match[2] == '$') { + $expr = $this->parseVar($in, $pointer, $to, array(), $curBlock, $pointer); + } else { + $expr = $this->parseOthers($in, $pointer, $to, array(), 'expression', $pointer); + } + $out[count($out)-1][0] .= $match[1] . $expr[0][0]; + $out[count($out)-1][1] .= $match[1] . $expr[0][1]; + } else { + if ($match[2] == '$') { + $out .= $match[1] . $this->parseVar($in, $pointer, $to, false, $curBlock, $pointer); + } else { + $out .= $match[1] . $this->parseOthers($in, $pointer, $to, false, 'expression', $pointer); + } + } + } else if ($curBlock === 'root' && preg_match('#^(\s*(?:[+/*%-]=|=|\+\+|--)\s*)(.*)#', $substr, $match)) { + if($this->debug) echo 'PARSING POST-VAR ASSIGNMENT '.$substr.'
'; + // parse assignment + $value = $match[2]; + $operator = trim($match[1]); + if (substr($value, 0, 1) == '=') { + throw new Dwoo_Compilation_Exception($this, 'Unexpected "=" in '.$substr.''); + } + + if ($pointer !== null) { + $pointer += strlen($match[1]); + } + $parts = array(); + $parts = $this->parse($value, 0, strlen($value), $parts, 'condition', $pointer); + + // load if plugin + try { + $this->getPluginType('if'); + } catch (Dwoo_Exception $e) { + throw new Dwoo_Compilation_Exception($this, 'Assignments require the "if" plugin to be accessible'); + } + + $parts = $this->mapParams($parts, array('Dwoo_Plugin_if', 'init'), 1); + $parts = $this->getCompiledParams($parts); + + $value = Dwoo_Plugin_if::replaceKeywords($parts['*'], $this); + + $out = Dwoo_Compiler::PHP_OPEN. $out . $operator . implode(' ', $value) . Dwoo_Compiler::PHP_CLOSE; + } + } + + if ($curBlock !== 'modifier' && ($parsed === 'func' || $parsed === 'var') && preg_match('#^\|@?[a-z0-9_]+(:.*)?#i', $substr, $match)) { + // parse modifier on funcs or vars + $srcPointer = $pointer; + if (is_array($parsingParams)) { + $tmp = $this->replaceModifiers(array(null, null, $out[count($out)-1][0], $match[0]), 'var', $pointer); + $out[count($out)-1][0] = $tmp; + $out[count($out)-1][1] .= substr($substr, $srcPointer, $srcPointer - $pointer); + } else { + $out = $this->replaceModifiers(array(null, null, $out, $match[0]), 'var', $pointer); + } + } + + // func parsed, check if any func-extension applies + if ($parsed==='func' && preg_match('#^->[a-z0-9_]+(\s*\(.+|->[a-z].*)?#is', $substr, $match)) { + // parse method call or property read + $ptr = 0; + + if (is_array($parsingParams)) { + $output = $this->parseMethodCall($out[count($out)-1][1], $match[0], $curBlock, $ptr); + + $out[count($out)-1][0] .= substr($match[0], 0, $ptr); + $out[count($out)-1][1] .= $output; + } else { + $out = $this->parseMethodCall($out, $match[0], $curBlock, $ptr); + } + + $pointer += $ptr; + } + + if ($curBlock === 'root' && substr($out, 0, strlen(self::PHP_OPEN)) !== self::PHP_OPEN) { + return self::PHP_OPEN .'echo '.$out.';'. self::PHP_CLOSE; + } else { + return $out; + } + } + + /** + * parses a function call + * + * @param string $in the string within which we must parse something + * @param int $from the starting offset of the parsed area + * @param int $to the ending offset of the parsed area + * @param mixed $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by default + * @param string $curBlock the current parser-block being processed + * @param mixed $pointer a reference to a pointer that will be increased by the amount of characters parsed, or null by default + * @return string parsed values + */ + protected function parseFunction($in, $from, $to, $parsingParams = false, $curBlock='', &$pointer = null) + { + $cmdstr = substr($in, $from, $to-$from); + preg_match('/^([a-z][a-z0-9_]*(?:::[a-z][a-z0-9_]*)?)(\s*'.$this->rdr.'|\s*;)?/i', $cmdstr, $match); + + if (empty($match[1])) { + throw new Dwoo_Compilation_Exception($this, 'Parse error, invalid function name : '.substr($cmdstr, 0, 15)); + } + + $func = $match[1]; + + if (!empty($match[2])) { + $cmdstr = $match[1]; + } + + if ($this->debug) echo 'FUNC FOUND ('.$func.')
'; + + $paramsep = ''; + + if (is_array($parsingParams) || $curBlock != 'root') { + $paramspos = strpos($cmdstr, '('); + $paramsep = ')'; + } elseif(preg_match_all('#[a-z0-9_]+(\s*\(|\s+[^(])#', $cmdstr, $match, PREG_OFFSET_CAPTURE)) { + $paramspos = $match[1][0][1]; + $paramsep = substr($match[1][0][0], -1) === '(' ? ')':''; + if($paramsep === ')') { + $paramspos += strlen($match[1][0][0]) - 1; + if(substr($cmdstr, 0, 2) === 'if' || substr($cmdstr, 0, 6) === 'elseif') { + $paramsep = ''; + if(strlen($match[1][0][0]) > 1) { + $paramspos--; + } + } + } + } else { + $paramspos = false; + } + + $state = 0; + + if ($paramspos === false) { + $params = array(); + + if ($curBlock !== 'root') { + return $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer); + } + } else { + $whitespace = strlen(substr($cmdstr, strlen($func), $paramspos-strlen($func))); + $paramstr = substr($cmdstr, $paramspos+1); + if (substr($paramstr, -1, 1) === $paramsep) { + $paramstr = substr($paramstr, 0, -1); + } + + if (strlen($paramstr)===0) { + $params = array(); + $paramstr = ''; + } else { + $ptr = 0; + $params = array(); + if ($func === 'empty') { + $params = $this->parseVar($paramstr, $ptr, strlen($paramstr), $params, 'root', $ptr); + } else { + while ($ptr < strlen($paramstr)) { + while (true) { + if ($ptr >= strlen($paramstr)) { + break 2; + } + + if ($func !== 'if' && $func !== 'elseif' && $paramstr[$ptr] === ')') { + if ($this->debug) echo 'PARAM PARSING ENDED, ")" FOUND, POINTER AT '.$ptr.'
'; + break 2; + } elseif ($paramstr[$ptr] === ';') { + $ptr++; + if ($this->debug) echo 'PARAM PARSING ENDED, ";" FOUND, POINTER AT '.$ptr.'
'; + break 2; + } elseif ($func !== 'if' && $func !== 'elseif' && $paramstr[$ptr] === '/') { + if ($this->debug) echo 'PARAM PARSING ENDED, "/" FOUND, POINTER AT '.$ptr.'
'; + break 2; + } elseif (substr($paramstr, $ptr, strlen($this->rd)) === $this->rd) { + if ($this->debug) echo 'PARAM PARSING ENDED, RIGHT DELIMITER FOUND, POINTER AT '.$ptr.'
'; + break 2; + } + + if ($paramstr[$ptr] === ' ' || $paramstr[$ptr] === ',' || $paramstr[$ptr] === "\r" || $paramstr[$ptr] === "\n" || $paramstr[$ptr] === "\t") { + $ptr++; + } else { + break; + } + } + + if ($this->debug) echo 'FUNC START PARAM PARSING WITH POINTER AT '.$ptr.'
'; + + if ($func === 'if' || $func === 'elseif' || $func === 'tif') { + $params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'condition', $ptr); + } else { + $params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'function', $ptr); + } + + if ($this->debug) echo 'PARAM PARSED, POINTER AT '.$ptr.' ('.substr($paramstr, $ptr-1, 3).')
'; + } + } + $paramstr = substr($paramstr, 0, $ptr); + $state = 0; + foreach ($params as $k=>$p) { + if (is_array($p) && is_array($p[1])) { + $state |= 2; + } else { + if (($state & 2) && preg_match('#^(["\'])(.+?)\1$#', $p[0], $m)) { + $params[$k] = array($m[2], array('true', 'true')); + } else { + if ($state & 2) { + throw new Dwoo_Compilation_Exception($this, 'You can not use an unnamed parameter after a named one'); + } + $state |= 1; + } + } + } + } + } + + if ($pointer !== null) { + $pointer += (isset($paramstr) ? strlen($paramstr) : 0) + (')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1)) + strlen($func) + (isset($whitespace) ? $whitespace : 0); + if ($this->debug) echo 'FUNC ADDS '.((isset($paramstr) ? strlen($paramstr) : 0) + (')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1)) + strlen($func)).' TO POINTER
'; + } + + if ($curBlock === 'method' || $func === 'do' || strstr($func, '::') !== false) { + $pluginType = Dwoo::NATIVE_PLUGIN; + } else { + $pluginType = $this->getPluginType($func); + } + + // blocks + if ($pluginType & Dwoo::BLOCK_PLUGIN) { + if ($curBlock !== 'root' || is_array($parsingParams)) { + throw new Dwoo_Compilation_Exception($this, 'Block plugins can not be used as other plugin\'s arguments'); + } + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + return $this->addCustomBlock($func, $params, $state); + } else { + return $this->addBlock($func, $params, $state); + } + } elseif ($pluginType & Dwoo::SMARTY_BLOCK) { + if ($curBlock !== 'root' || is_array($parsingParams)) { + throw new Dwoo_Compilation_Exception($this, 'Block plugins can not be used as other plugin\'s arguments'); + } + + if ($state & 2) { + array_unshift($params, array('__functype', array($pluginType, $pluginType))); + array_unshift($params, array('__funcname', array($func, $func))); + } else { + array_unshift($params, array($pluginType, $pluginType)); + array_unshift($params, array($func, $func)); + } + + return $this->addBlock('smartyinterface', $params, $state); + } + + // funcs + if ($pluginType & Dwoo::NATIVE_PLUGIN || $pluginType & Dwoo::SMARTY_FUNCTION || $pluginType & Dwoo::SMARTY_BLOCK) { + $params = $this->mapParams($params, null, $state); + } elseif ($pluginType & Dwoo::CLASS_PLUGIN) { + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $params = $this->mapParams($params, array($this->customPlugins[$func]['class'], $this->customPlugins[$func]['function']), $state); + } else { + $params = $this->mapParams($params, array('Dwoo_Plugin_'.$func, ($pluginType & Dwoo::COMPILABLE_PLUGIN) ? 'compile' : 'process'), $state); + } + } elseif ($pluginType & Dwoo::FUNC_PLUGIN) { + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $params = $this->mapParams($params, $this->customPlugins[$func]['callback'], $state); + } else { + $params = $this->mapParams($params, 'Dwoo_Plugin_'.$func.(($pluginType & Dwoo::COMPILABLE_PLUGIN) ? '_compile' : ''), $state); + } + } elseif ($pluginType & Dwoo::SMARTY_MODIFIER) { + $output = 'smarty_modifier_'.$func.'('.implode(', ', $params).')'; + } elseif ($pluginType & Dwoo::PROXY_PLUGIN) { + $params = $this->mapParams($params, $this->getDwoo()->getPluginProxy()->getCallback($func), $state); + } + + // only keep php-syntax-safe values for non-block plugins + foreach ($params as &$p) + $p = $p[0]; + if ($pluginType & Dwoo::NATIVE_PLUGIN) { + if ($func === 'do') { + if (isset($params['*'])) { + $output = implode(';', $params['*']).';'; + } else { + $output = ''; + } + + if (is_array($parsingParams) || $curBlock !== 'root') { + throw new Dwoo_Compilation_Exception($this, 'Do can not be used inside another function or block'); + } else { + return self::PHP_OPEN.$output.self::PHP_CLOSE; + } + } else { + if (isset($params['*'])) { + $output = $func.'('.implode(', ', $params['*']).')'; + } else { + $output = $func.'()'; + } + } + } elseif ($pluginType & Dwoo::FUNC_PLUGIN) { + if ($pluginType & Dwoo::COMPILABLE_PLUGIN) { + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $funcCompiler = $this->customPlugins[$func]['callback']; + } else { + $funcCompiler = 'Dwoo_Plugin_'.$func.'_compile'; + } + array_unshift($params, $this); + $output = call_user_func_array($funcCompiler, $params); + } else { + array_unshift($params, '$this'); + $params = self::implode_r($params); + + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $callback = $this->customPlugins[$func]['callback']; + $output = 'call_user_func(\''.$callback.'\', '.$params.')'; + } else { + $output = 'Dwoo_Plugin_'.$func.'('.$params.')'; + } + } + } elseif ($pluginType & Dwoo::CLASS_PLUGIN) { + if ($pluginType & Dwoo::COMPILABLE_PLUGIN) { + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $callback = $this->customPlugins[$func]['callback']; + if (!is_array($callback)) { + if (!method_exists($callback, 'compile')) { + throw new Dwoo_Exception('Custom plugin '.$func.' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use'); + } + if (($ref = new ReflectionMethod($callback, 'compile')) && $ref->isStatic()) { + $funcCompiler = array($callback, 'compile'); + } else { + $funcCompiler = array(new $callback, 'compile'); + } + } else { + $funcCompiler = $callback; + } + } else { + $funcCompiler = array('Dwoo_Plugin_'.$func, 'compile'); + array_unshift($params, $this); + } + $output = call_user_func_array($funcCompiler, $params); + } else { + $params = self::implode_r($params); + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $callback = $this->customPlugins[$func]['callback']; + if (!is_array($callback)) { + if (!method_exists($callback, 'process')) { + throw new Dwoo_Exception('Custom plugin '.$func.' must implement the "process" method to be usable, or you should provide a full callback to the method to use'); + } + if (($ref = new ReflectionMethod($callback, 'process')) && $ref->isStatic()) { + $output = 'call_user_func(array(\''.$callback.'\', \'process\'), '.$params.')'; + } else { + $output = 'call_user_func(array($this->getObjectPlugin(\''.$callback.'\'), \'process\'), '.$params.')'; + } + } elseif (is_object($callback[0])) { + $output = 'call_user_func(array($this->plugins[\''.$func.'\'][\'callback\'][0], \''.$callback[1].'\'), '.$params.')'; + } elseif (($ref = new ReflectionMethod($callback[0], $callback[1])) && $ref->isStatic()) { + $output = 'call_user_func(array(\''.$callback[0].'\', \''.$callback[1].'\'), '.$params.')'; + } else { + $output = 'call_user_func(array($this->getObjectPlugin(\''.$callback[0].'\'), \''.$callback[1].'\'), '.$params.')'; + } + if (empty($params)) { + $output = substr($output, 0, -3).')'; + } + } else { + $output = '$this->classCall(\''.$func.'\', array('.$params.'))'; + } + } + } elseif ($pluginType & Dwoo::PROXY_PLUGIN) { + $output = call_user_func(array($this->dwoo->getPluginProxy(), 'getCode'), $func, $params); + } elseif ($pluginType & Dwoo::SMARTY_FUNCTION) { + if (isset($params['*'])) { + $params = self::implode_r($params['*'], true); + } else { + $params = ''; + } + + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $callback = $this->customPlugins[$func]['callback']; + if (is_array($callback)) { + if (is_object($callback[0])) { + $output = 'call_user_func_array(array($this->plugins[\''.$func.'\'][\'callback\'][0], \''.$callback[1].'\'), array(array('.$params.'), $this))'; + } else { + $output = 'call_user_func_array(array(\''.$callback[0].'\', \''.$callback[1].'\'), array(array('.$params.'), $this))'; + } + } else { + $output = $callback.'(array('.$params.'), $this)'; + } + } else { + $output = 'smarty_function_'.$func.'(array('.$params.'), $this)'; + } + } + + if (is_array($parsingParams)) { + $parsingParams[] = array($output, $output); + return $parsingParams; + } elseif ($curBlock === 'namedparam') { + return array($output, $output); + } else { + return $output; + } + } + + /** + * parses a string + * + * @param string $in the string within which we must parse something + * @param int $from the starting offset of the parsed area + * @param int $to the ending offset of the parsed area + * @param mixed $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by default + * @param string $curBlock the current parser-block being processed + * @param mixed $pointer a reference to a pointer that will be increased by the amount of characters parsed, or null by default + * @return string parsed values + */ + protected function parseString($in, $from, $to, $parsingParams = false, $curBlock='', &$pointer = null) + { + $substr = substr($in, $from, $to-$from); + $first = $substr[0]; + + if ($this->debug) echo 'STRING FOUND (in '.htmlentities(substr($in, $from, min($to-$from, 50))).(($to-$from) > 50 ? '...':'').')
'; + $strend = false; + $o = $from+1; + while ($strend === false) { + $strend = strpos($in, $first, $o); + if ($strend === false) { + throw new Dwoo_Compilation_Exception($this, 'Unfinished string, started with '.substr($in, $from, $to-$from)); + } + if (substr($in, $strend-1, 1) === '\\') { + $o = $strend+1; + $strend = false; + } + } + if ($this->debug) echo 'STRING DELIMITED: '.substr($in, $from, $strend+1-$from).'
'; + + $srcOutput = substr($in, $from, $strend+1-$from); + + if ($pointer !== null) { + $pointer += strlen($srcOutput); + } + + $output = $this->replaceStringVars($srcOutput, $first); + + // handle modifiers + if ($curBlock !== 'modifier' && preg_match('#^((?:\|(?:@?[a-z0-9_]+(?::.*)*))+)#i', substr($substr, $strend+1-$from), $match)) { + $modstr = $match[1]; + + if ($curBlock === 'root' && substr($modstr, -1) === '}') { + $modstr = substr($modstr, 0, -1); + } + $modstr = str_replace('\\'.$first, $first, $modstr); + $ptr = 0; + $output = $this->replaceModifiers(array(null, null, $output, $modstr), 'string', $ptr); + + $strend += $ptr; + if ($pointer !== null) { + $pointer += $ptr; + } + $srcOutput .= substr($substr, $strend+1-$from, $ptr); + } + + if (is_array($parsingParams)) { + $parsingParams[] = array($output, substr($srcOutput, 1, -1)); + return $parsingParams; + } elseif ($curBlock === 'namedparam') { + return array($output, substr($srcOutput, 1, -1)); + } else { + return $output; + } + } + + /** + * parses a constant + * + * @param string $in the string within which we must parse something + * @param int $from the starting offset of the parsed area + * @param int $to the ending offset of the parsed area + * @param mixed $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by default + * @param string $curBlock the current parser-block being processed + * @param mixed $pointer a reference to a pointer that will be increased by the amount of characters parsed, or null by default + * @return string parsed values + */ + protected function parseConst($in, $from, $to, $parsingParams = false, $curBlock='', &$pointer = null) + { + $substr = substr($in, $from, $to-$from); + + if ($this->debug) { + echo 'CONST FOUND : '.$substr.'
'; + } + + if (!preg_match('#^%([a-z0-9_:]+)#i', $substr, $m)) { + throw new Dwoo_Compilation_Exception($this, 'Invalid constant'); + } + + if ($pointer !== null) { + $pointer += strlen($m[0]); + } + + $output = $this->parseConstKey($m[1], $curBlock); + + if (is_array($parsingParams)) { + $parsingParams[] = array($output, $m[1]); + return $parsingParams; + } elseif ($curBlock === 'namedparam') { + return array($output, $m[1]); + } else { + return $output; + } + } + + /** + * parses a constant + * + * @param string $key the constant to parse + * @param string $curBlock the current parser-block being processed + * @return string parsed constant + */ + protected function parseConstKey($key, $curBlock) + { + if ($this->securityPolicy !== null && $this->securityPolicy->getConstantHandling() === Dwoo_Security_Policy::CONST_DISALLOW) { + return 'null'; + } + + if ($curBlock !== 'root') { + $output = '(defined("'.$key.'") ? '.$key.' : null)'; + } else { + $output = $key; + } + + return $output; + } + + /** + * parses a variable + * + * @param string $in the string within which we must parse something + * @param int $from the starting offset of the parsed area + * @param int $to the ending offset of the parsed area + * @param mixed $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by default + * @param string $curBlock the current parser-block being processed + * @param mixed $pointer a reference to a pointer that will be increased by the amount of characters parsed, or null by default + * @return string parsed values + */ + protected function parseVar($in, $from, $to, $parsingParams = false, $curBlock='', &$pointer = null) + { + $substr = substr($in, $from, $to-$from); + + if (preg_match('#(\$?\.?[a-z0-9_:]*(?:(?:(?:\.|->)(?:[a-z0-9_:]+|(?R))|\[(?:[a-z0-9_:]+|(?R)|(["\'])[^\2]*\2)\]))*)' . // var key + ($curBlock==='root' || $curBlock==='function' || $curBlock==='namedparam' || $curBlock==='condition' || $curBlock==='variable' || $curBlock==='expression' ? '(\(.*)?' : '()') . // method call + ($curBlock==='root' || $curBlock==='function' || $curBlock==='namedparam' || $curBlock==='condition' || $curBlock==='variable' || $curBlock==='delimited_string' ? '((?:(?:[+/*%=-])(?:(?_:-]+(?:\([^)]*\))?|(?'))); + $key = substr($match[1], 1, strrpos($match[1], '->')-1); + $methodCall = substr($match[1], strrpos($match[1], '->')) . $match[3]; + } + + if ($hasModifiers) { + $matchedLength -= strlen($match[5]); + } + + if ($pointer !== null) { + $pointer += $matchedLength; + } + + // replace useless brackets by dot accessed vars + $key = preg_replace('#\[([^$%\[.>-]+)\]#', '.$1', $key); + + // prevent $foo->$bar calls because it doesn't seem worth the trouble + if (strpos($key, '->$') !== false) { + throw new Dwoo_Compilation_Exception($this, 'You can not access an object\'s property using a variable name.'); + } + + if ($this->debug) { + if ($hasMethodCall) { + echo 'METHOD CALL FOUND : $'.$key.substr($methodCall, 0, 30).'
'; + } else { + echo 'VAR FOUND : $'.$key.'
'; + } + } + + $key = str_replace('"', '\\"', $key); + + $cnt=substr_count($key, '$'); + if ($cnt > 0) { + $uid = 0; + $parsed = array($uid => ''); + $current =& $parsed; + $curTxt =& $parsed[$uid++]; + $tree = array(); + $chars = str_split($key, 1); + $inSplittedVar = false; + $bracketCount = 0; + + while (($char = array_shift($chars)) !== null) { + if ($char === '[') { + if (count($tree) > 0) { + $bracketCount++; + } else { + $tree[] =& $current; + $current[$uid] = array($uid+1 => ''); + $current =& $current[$uid++]; + $curTxt =& $current[$uid++]; + continue; + } + } elseif ($char === ']') { + if ($bracketCount > 0) { + $bracketCount--; + } else { + $current =& $tree[count($tree)-1]; + array_pop($tree); + if (current($chars) !== '[' && current($chars) !== false && current($chars) !== ']') { + $current[$uid] = ''; + $curTxt =& $current[$uid++]; + } + continue; + } + } elseif ($char === '$') { + if (count($tree) == 0) { + $curTxt =& $current[$uid++]; + $inSplittedVar = true; + } + } elseif (($char === '.' || $char === '-') && count($tree) == 0 && $inSplittedVar) { + $curTxt =& $current[$uid++]; + $inSplittedVar = false; + } + + $curTxt .= $char; + } + unset($uid, $current, $curTxt, $tree, $chars); + + if ($this->debug) echo 'RECURSIVE VAR REPLACEMENT : '.$key.'
'; + + $key = $this->flattenVarTree($parsed); + + if ($this->debug) echo 'RECURSIVE VAR REPLACEMENT DONE : '.$key.'
'; + + $output = preg_replace('#(^""\.|""\.|\.""$|(\()""\.|\.""(\)))#', '$2$3', '$this->readVar("'.$key.'")'); + } else { + $output = $this->parseVarKey($key, $hasModifiers ? 'modifier' : $curBlock); + } + + // methods + if ($hasMethodCall) { + $ptr = 0; + + $output = $this->parseMethodCall($output, $methodCall, $curBlock, $ptr); + + if ($pointer !== null) { + $pointer += $ptr; + } + $matchedLength += $ptr; + } + + if ($hasExpression) { + // expressions + preg_match_all('#(?:([+/*%=-])(=?-?[%$][a-z0-9.[\]>_:-]+(?:\([^)]*\))?|=?-?[0-9.,]+|\1))#i', $match[4], $expMatch); + + foreach ($expMatch[1] as $k=>$operator) { + if (substr($expMatch[2][$k], 0, 1)==='=') { + $assign = true; + if ($operator === '=') { + throw new Dwoo_Compilation_Exception($this, 'Invalid expression '.$substr.', can not use "==" in expressions'); + } + if ($curBlock !== 'root') { + throw new Dwoo_Compilation_Exception($this, 'Invalid expression '.$substr.', assignments can only be used in top level expressions like {$foo+=3} or {$foo="bar"}'); + } + $operator .= '='; + $expMatch[2][$k] = substr($expMatch[2][$k], 1); + } + + if (substr($expMatch[2][$k], 0, 1)==='-' && strlen($expMatch[2][$k]) > 1) { + $operator .= '-'; + $expMatch[2][$k] = substr($expMatch[2][$k], 1); + } + if (($operator==='+'||$operator==='-') && $expMatch[2][$k]===$operator) { + $output = '('.$output.$operator.$operator.')'; + break; + } elseif (substr($expMatch[2][$k], 0, 1) === '$') { + $output = '('.$output.' '.$operator.' '.$this->parseVar($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression').')'; + } elseif (substr($expMatch[2][$k], 0, 1) === '%') { + $output = '('.$output.' '.$operator.' '.$this->parseConst($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression').')'; + } elseif (!empty($expMatch[2][$k])) { + $output = '('.$output.' '.$operator.' '.str_replace(',', '.', $expMatch[2][$k]).')'; + } else { + throw new Dwoo_Compilation_Exception($this, 'Unfinished expression '.$substr.', missing var or number after math operator'); + } + } + } + + if ($this->autoEscape === true) { + $output = '(is_string($tmp='.$output.') ? htmlspecialchars($tmp, ENT_QUOTES, $this->charset) : $tmp)'; + } + + // handle modifiers + if ($curBlock !== 'modifier' && $hasModifiers) { + $ptr = 0; + $output = $this->replaceModifiers(array(null, null, $output, $match[5]), 'var', $ptr); + if ($pointer !== null) { + $pointer += $ptr; + } + $matchedLength += $ptr; + } + + if (is_array($parsingParams)) { + $parsingParams[] = array($output, $key); + return $parsingParams; + } elseif ($curBlock === 'namedparam') { + return array($output, $key); + } elseif ($curBlock === 'string' || $curBlock === 'delimited_string') { + return array($matchedLength, $output); + } elseif ($curBlock === 'expression' || $curBlock === 'variable') { + return $output; + } elseif (isset($assign)) { + return self::PHP_OPEN.$output.';'.self::PHP_CLOSE; + } else { + return $output; + } + } else { + if ($curBlock === 'string' || $curBlock === 'delimited_string') { + return array(0, ''); + } else { + throw new Dwoo_Compilation_Exception($this, 'Invalid variable name '.$substr.''); + } + } + } + + /** + * parses any number of chained method calls/property reads + * + * @param string $output the variable or whatever upon which the method are called + * @param string $methodCall method call source, starting at "->" + * @param string $curBlock the current parser-block being processed + * @param int $pointer a reference to a pointer that will be increased by the amount of characters parsed + * @return string parsed call(s)/read(s) + */ + protected function parseMethodCall($output, $methodCall, $curBlock, &$pointer) + { + $ptr = 0; + $len = strlen($methodCall); + + while ($ptr < $len) { + if (strpos($methodCall, '->', $ptr) === $ptr) { + $ptr += 2; + } + + if (in_array($methodCall[$ptr], array(';', '/', ' ', "\t", "\r", "\n", ')', '+', '*', '%', '=', '-', '|')) || substr($methodCall, $ptr, strlen($this->rd)) === $this->rd) { + // break char found + break; + } + + if(!preg_match('/^([a-z0-9_]+)(\(.*?\))?/i', substr($methodCall, $ptr), $methMatch)) { + throw new Dwoo_Compilation_Exception($this, 'Invalid method name : '.substr($methodCall, $ptr, 20)); + } + + if (empty($methMatch[2])) { + // property + if ($curBlock === 'root') { + $output .= '->'.$methMatch[1]; + } else { + $output = '(($tmp = '.$output.') ? $tmp->'.$methMatch[1].' : null)'; + } + $ptr += strlen($methMatch[1]); + } else { + // method + if (substr($methMatch[2], 0, 2) === '()') { + $parsedCall = '->'.$methMatch[1].'()'; + $ptr += strlen($methMatch[1]) + 2; + } else { + $parsedCall = '->'.$this->parseFunction($methodCall, $ptr, strlen($methodCall), false, 'method', $ptr); + } + if ($curBlock === 'root') { + $output .= $parsedCall; + } else { + $output = '(($tmp = '.$output.') ? $tmp'.$parsedCall.' : null)'; + } + } + } + + $pointer += $ptr; + return $output; + } + + /** + * parses a constant variable (a variable that doesn't contain another variable) and preprocesses it to save runtime processing time + * + * @param string $key the variable to parse + * @param string $curBlock the current parser-block being processed + * @return string parsed variable + */ + protected function parseVarKey($key, $curBlock) + { + if ($key === '') { + return '$this->scope'; + } + if (substr($key, 0, 1) === '.') { + $key = 'dwoo'.$key; + } + if (preg_match('#dwoo\.(get|post|server|cookies|session|env|request)((?:\.[a-z0-9_-]+)+)#i', $key, $m)) { + $global = strtoupper($m[1]); + if ($global === 'COOKIES') { + $global = 'COOKIE'; + } + $key = '$_'.$global; + foreach (explode('.', ltrim($m[2], '.')) as $part) + $key .= '['.var_export($part, true).']'; + if ($curBlock === 'root') { + $output = $key; + } else { + $output = '(isset('.$key.')?'.$key.':null)'; + } + } elseif (preg_match('#dwoo\.const\.([a-z0-9_:]+)#i', $key, $m)) { + return $this->parseConstKey($m[1], $curBlock); + } elseif ($this->scope !== null) { + if (strstr($key, '.') === false && strstr($key, '[') === false && strstr($key, '->') === false) { + if ($key === 'dwoo') { + $output = '$this->globals'; + } elseif ($key === '_root' || $key === '__') { + $output = '$this->data'; + } elseif ($key === '_parent' || $key === '_') { + $output = '$this->readParentVar(1)'; + } elseif ($key === '_key') { + $output = '$tmp_key'; + } else { + if ($curBlock === 'root') { + $output = '$this->scope["'.$key.'"]'; + } else { + $output = '(isset($this->scope["'.$key.'"]) ? $this->scope["'.$key.'"] : null)'; + } + } + } else { + preg_match_all('#(\[|->|\.)?([a-z0-9_]+|(\\\?[\'"])[^\3]*\3)\]?#i', $key, $m); + + $i = $m[2][0]; + if ($i === '_parent' || $i === '_') { + $parentCnt = 0; + + while (true) { + $parentCnt++; + array_shift($m[2]); + array_shift($m[1]); + if (current($m[2]) === '_parent') { + continue; + } + break; + } + + $output = '$this->readParentVar('.$parentCnt.')'; + } else { + if ($i === 'dwoo') { + $output = '$this->globals'; + array_shift($m[2]); + array_shift($m[1]); + } elseif ($i === '_root' || $i === '__') { + $output = '$this->data'; + array_shift($m[2]); + array_shift($m[1]); + } elseif ($i === '_key') { + $output = '$tmp_key'; + } else { + $output = '$this->scope'; + } + + while (count($m[1]) && $m[1][0] !== '->') { + $m[2][0] = preg_replace('/(^\\\([\'"])|\\\([\'"])$)/x', '$2$3', $m[2][0]); + if(substr($m[2][0], 0, 1) == '"' || substr($m[2][0], 0, 1) == "'") { + $output .= '['.$m[2][0].']'; + } else { + $output .= '["'.$m[2][0].'"]'; + } + array_shift($m[2]); + array_shift($m[1]); + } + + if ($curBlock !== 'root') { + $output = '(isset('.$output.') ? '.$output.':null)'; + } + } + + if (count($m[2])) { + unset($m[0]); + $output = '$this->readVarInto('.str_replace("\n", '', var_export($m, true)).', '.$output.')'; + } + } + } else { + preg_match_all('#(\[|->|\.)?([a-z0-9_]+)\]?#i', $key, $m); + unset($m[0]); + $output = '$this->readVar('.str_replace("\n", '', var_export($m, true)).')'; + } + + return $output; + } + + /** + * flattens a variable tree, this helps in parsing very complex variables such as $var.foo[$foo.bar->baz].baz, + * it computes the contents of the brackets first and works out from there + * + * @param array $tree the variable tree parsed by he parseVar() method that must be flattened + * @param bool $recursed leave that to false by default, it is only for internal use + * @return string flattened tree + */ + protected function flattenVarTree(array $tree, $recursed=false) + { + $out = $recursed ? '".$this->readVarInto(' : ''; + foreach ($tree as $bit) { + if (is_array($bit)) { + $out.='.'.$this->flattenVarTree($bit, false); + } else { + $key = str_replace('"', '\\"', $bit); + + if (substr($key, 0, 1)==='$') { + $out .= '".'.$this->parseVar($key, 0, strlen($key), false, 'variable').'."'; + } else { + $cnt = substr_count($key, '$'); + + if ($this->debug) echo 'PARSING SUBVARS IN : '.$key.'
'; + if ($cnt > 0) { + while (--$cnt >= 0) { + if (isset($last)) { + $last = strrpos($key, '$', - (strlen($key) - $last + 1)); + } else { + $last = strrpos($key, '$'); + } + preg_match('#\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*'. + '((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', substr($key, $last), $submatch); + + $len = strlen($submatch[0]); + $key = substr_replace( + $key, + preg_replace_callback( + '#(\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*)'. + '((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', + array($this, 'replaceVarKeyHelper'), substr($key, $last, $len) + ), + $last, + $len + ); + if ($this->debug) echo 'RECURSIVE VAR REPLACEMENT DONE : '.$key.'
'; + } + unset($last); + + $out .= $key; + } else { + $out .= $key; + } + } + } + } + $out .= $recursed ? ')."' : ''; + return $out; + } + + /** + * helper function that parses a variable + * + * @param array $match the matched variable, array(1=>"string match") + * @return string parsed variable + */ + protected function replaceVarKeyHelper($match) + { + return '".'.$this->parseVar($match[0], 0, strlen($match[0]), false, 'variable').'."'; + } + + /** + * parses various constants, operators or non-quoted strings + * + * @param string $in the string within which we must parse something + * @param int $from the starting offset of the parsed area + * @param int $to the ending offset of the parsed area + * @param mixed $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by default + * @param string $curBlock the current parser-block being processed + * @param mixed $pointer a reference to a pointer that will be increased by the amount of characters parsed, or null by default + * @return string parsed values + */ + protected function parseOthers($in, $from, $to, $parsingParams = false, $curBlock='', &$pointer = null) + { + $first = $in[$from]; + $substr = substr($in, $from, $to-$from); + + $end = strlen($substr); + + if ($curBlock === 'condition') { + $breakChars = array('(', ')', ' ', '||', '&&', '|', '&', '>=', '<=', '===', '==', '=', '!==', '!=', '<<', '<', '>>', '>', '^', '~', ',', '+', '-', '*', '/', '%', '!', '?', ':', $this->rd, ';'); + } elseif ($curBlock === 'modifier') { + $breakChars = array(' ', ',', ')', ':', '|', "\r", "\n", "\t", ";", $this->rd); + } elseif ($curBlock === 'expression') { + $breakChars = array('/', '%', '+', '-', '*', ' ', ',', ')', "\r", "\n", "\t", ";", $this->rd); + } else { + $breakChars = array(' ', ',', ')', "\r", "\n", "\t", ";", $this->rd); + } + + $breaker = false; + while (list($k,$char) = each($breakChars)) { + $test = strpos($substr, $char); + if ($test !== false && $test < $end) { + $end = $test; + $breaker = $k; + } + } + + if ($curBlock === 'condition') { + if ($end === 0 && $breaker !== false) { + $end = strlen($breakChars[$breaker]); + } + } + + if ($end !== false) { + $substr = substr($substr, 0, $end); + } + + if ($pointer !== null) { + $pointer += strlen($substr); + } + + $src = $substr; + + if (strtolower($substr) === 'false' || strtolower($substr) === 'no' || strtolower($substr) === 'off') { + if ($this->debug) echo 'BOOLEAN(FALSE) PARSED
'; + $substr = 'false'; + } elseif (strtolower($substr) === 'true' || strtolower($substr) === 'yes' || strtolower($substr) === 'on') { + if ($this->debug) echo 'BOOLEAN(TRUE) PARSED
'; + $substr = 'true'; + } elseif ($substr === 'null' || $substr === 'NULL') { + if ($this->debug) echo 'NULL PARSED
'; + $substr = 'null'; + } elseif (is_numeric($substr)) { + $substr = (float) $substr; + if ((int) $substr == $substr) { + $substr = (int) $substr; + } + if ($this->debug) echo 'NUMBER ('.$substr.') PARSED
'; + } elseif (preg_match('{^-?(\d+|\d*(\.\d+))\s*([/*%+-]\s*-?(\d+|\d*(\.\d+)))+$}', $substr)) { + if ($this->debug) echo 'SIMPLE MATH PARSED
'; + $substr = '('.$substr.')'; + } elseif ($curBlock === 'condition' && array_search($substr, $breakChars, true) !== false) { + if ($this->debug) echo 'BREAKCHAR ('.$substr.') PARSED
'; + //$substr = '"'.$substr.'"'; + } else { + $substr = $this->replaceStringVars('\''.str_replace('\'', '\\\'', $substr).'\'', '\'', $curBlock); + + if ($this->debug) echo 'BLABBER ('.$substr.') CASTED AS STRING
'; + } + + if (is_array($parsingParams)) { + $parsingParams[] = array($substr, $src); + return $parsingParams; + } elseif ($curBlock === 'namedparam') { + return array($substr, $src); + } elseif ($curBlock === 'expression') { + return $substr; + } else { + throw new Exception('Something went wrong'); + } + } + + /** + * replaces variables within a parsed string + * + * @param string $string the parsed string + * @param string $first the first character parsed in the string, which is the string delimiter (' or ") + * @param string $curBlock the current parser-block being processed + * @return string the original string with variables replaced + */ + protected function replaceStringVars($string, $first, $curBlock='') + { + $pos = 0; + if ($this->debug) echo 'STRING VAR REPLACEMENT : '.$string.'
'; + // replace vars + while (($pos = strpos($string, '$', $pos)) !== false) { + $prev = substr($string, $pos-1, 1); + if ($prev === '\\') { + $pos++; + continue; + } + + $var = $this->parse($string, $pos, null, false, ($curBlock === 'modifier' ? 'modifier' : ($prev === '`' ? 'delimited_string':'string'))); + $len = $var[0]; + $var = $this->parse(str_replace('\\'.$first, $first, $string), $pos, null, false, ($curBlock === 'modifier' ? 'modifier' : ($prev === '`' ? 'delimited_string':'string'))); + + if ($prev === '`' && substr($string, $pos+$len, 1) === '`') { + $string = substr_replace($string, $first.'.'.$var[1].'.'.$first, $pos-1, $len+2); + } else { + $string = substr_replace($string, $first.'.'.$var[1].'.'.$first, $pos, $len); + } + $pos += strlen($var[1]) + 2; + if ($this->debug) echo 'STRING VAR REPLACEMENT DONE : '.$string.'
'; + } + + // handle modifiers + // TODO Obsolete? + $string = preg_replace_callback('#("|\')\.(.+?)\.\1((?:\|(?:@?[a-z0-9_]+(?:(?::("|\').+?\4|:[^`]*))*))+)#i', array($this, 'replaceModifiers'), $string); + + // replace escaped dollar operators by unescaped ones if required + if ($first==="'") { + $string = str_replace('\\$', '$', $string); + } + + return $string; + } + + /** + * replaces the modifiers applied to a string or a variable + * + * @param array $m the regex matches that must be array(1=>"double or single quotes enclosing a string, when applicable", 2=>"the string or var", 3=>"the modifiers matched") + * @param string $curBlock the current parser-block being processed + * @return string the input enclosed with various function calls according to the modifiers found + */ + protected function replaceModifiers(array $m, $curBlock = null, &$pointer = null) + { + if ($this->debug) echo 'PARSING MODIFIERS : '.$m[3].'
'; + + if ($pointer !== null) { + $pointer += strlen($m[3]); + } + // remove first pipe + $cmdstrsrc = substr($m[3], 1); + // remove last quote if present + if (substr($cmdstrsrc, -1, 1) === $m[1]) { + $cmdstrsrc = substr($cmdstrsrc, 0, -1); + $add = $m[1]; + } + + $output = $m[2]; + + $continue = true; + while (strlen($cmdstrsrc) > 0 && $continue) { + if ($cmdstrsrc[0] === '|') { + $cmdstrsrc = substr($cmdstrsrc, 1); + continue; + } + if ($cmdstrsrc[0] === ' ' || $cmdstrsrc[0] === ';' || substr($cmdstrsrc, 0, strlen($this->rd)) === $this->rd) { + if ($this->debug) echo 'MODIFIER PARSING ENDED, RIGHT DELIMITER or ";" FOUND
'; + $continue = false; + if ($pointer !== null) { + $pointer -= strlen($cmdstrsrc); + } + break; + } + $cmdstr = $cmdstrsrc; + $paramsep = ':'; + if (!preg_match('/^(@{0,2}[a-z][a-z0-9_]*)(:)?/i', $cmdstr, $match)) { + throw new Dwoo_Compilation_Exception($this, 'Invalid modifier name, started with : '.substr($cmdstr, 0, 10)); + } + $paramspos = !empty($match[2]) ? strlen($match[1]) : false; + $func = $match[1]; + + $state = 0; + if ($paramspos === false) { + $cmdstrsrc = substr($cmdstrsrc, strlen($func)); + $params = array(); + if ($this->debug) echo 'MODIFIER ('.$func.') CALLED WITH NO PARAMS
'; + } else { + $paramstr = substr($cmdstr, $paramspos+1); + if (substr($paramstr, -1, 1) === $paramsep) { + $paramstr = substr($paramstr, 0, -1); + } + + $ptr = 0; + $params = array(); + while ($ptr < strlen($paramstr)) { + if ($this->debug) echo 'MODIFIER ('.$func.') START PARAM PARSING WITH POINTER AT '.$ptr.'
'; + if ($this->debug) echo $paramstr.'--'.$ptr.'--'.strlen($paramstr).'--modifier
'; + $params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'modifier', $ptr); + if ($this->debug) echo 'PARAM PARSED, POINTER AT '.$ptr.'
'; + + if ($ptr >= strlen($paramstr)) { + if ($this->debug) echo 'PARAM PARSING ENDED, PARAM STRING CONSUMED
'; + break; + } + + if ($paramstr[$ptr] === ' ' || $paramstr[$ptr] === '|' || $paramstr[$ptr] === ';' || substr($paramstr, $ptr, strlen($this->rd)) === $this->rd) { + if ($this->debug) echo 'PARAM PARSING ENDED, " ", "|", RIGHT DELIMITER or ";" FOUND, POINTER AT '.$ptr.'
'; + if ($paramstr[$ptr] !== '|') { + $continue = false; + if ($pointer !== null) { + $pointer -= strlen($paramstr) - $ptr; + } + } + $ptr++; + break; + } + if ($ptr < strlen($paramstr) && $paramstr[$ptr] === ':') { + $ptr++; + } + } + $cmdstrsrc = substr($cmdstrsrc, strlen($func)+1+$ptr); + $paramstr = substr($paramstr, 0, $ptr); + foreach ($params as $k=>$p) { + if (is_array($p) && is_array($p[1])) { + $state |= 2; + } else { + if (($state & 2) && preg_match('#^(["\'])(.+?)\1$#', $p[0], $m)) { + $params[$k] = array($m[2], array('true', 'true')); + } else { + if ($state & 2) { + throw new Dwoo_Compilation_Exception($this, 'You can not use an unnamed parameter after a named one'); + } + $state |= 1; + } + } + } + } + + // check if we must use array_map with this plugin or not + $mapped = false; + if (substr($func, 0, 1) === '@') { + $func = substr($func, 1); + $mapped = true; + } + + $pluginType = $this->getPluginType($func); + + if ($state & 2) { + array_unshift($params, array('value', array($output, $output))); + } else { + array_unshift($params, array($output, $output)); + } + + if ($pluginType & Dwoo::NATIVE_PLUGIN) { + $params = $this->mapParams($params, null, $state); + + $params = $params['*'][0]; + + $params = self::implode_r($params); + + if ($mapped) { + $output = '$this->arrayMap(\''.$func.'\', array('.$params.'))'; + } else { + $output = $func.'('.$params.')'; + } + } elseif ($pluginType & Dwoo::PROXY_PLUGIN) { + $params = $this->mapParams($params, $this->getDwoo()->getPluginProxy()->getCallback($func), $state); + foreach ($params as &$p) + $p = $p[0]; + $output = call_user_func(array($this->dwoo->getPluginProxy(), 'getCode'), $func, $params); + } elseif ($pluginType & Dwoo::SMARTY_MODIFIER) { + $params = $this->mapParams($params, null, $state); + $params = $params['*'][0]; + + $params = self::implode_r($params); + + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $callback = $this->customPlugins[$func]['callback']; + if (is_array($callback)) { + if (is_object($callback[0])) { + $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array').'(array($this->plugins[\''.$func.'\'][\'callback\'][0], \''.$callback[1].'\'), array('.$params.'))'; + } else { + $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array').'(array(\''.$callback[0].'\', \''.$callback[1].'\'), array('.$params.'))'; + } + } elseif ($mapped) { + $output = '$this->arrayMap(\''.$callback.'\', array('.$params.'))'; + } else { + $output = $callback.'('.$params.')'; + } + } elseif ($mapped) { + $output = '$this->arrayMap(\'smarty_modifier_'.$func.'\', array('.$params.'))'; + } else { + $output = 'smarty_modifier_'.$func.'('.$params.')'; + } + } else { + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $callback = $this->customPlugins[$func]['callback']; + $pluginName = $callback; + } else { + $pluginName = 'Dwoo_Plugin_'.$func; + + if ($pluginType & Dwoo::CLASS_PLUGIN) { + $callback = array($pluginName, ($pluginType & Dwoo::COMPILABLE_PLUGIN) ? 'compile' : 'process'); + } else { + $callback = $pluginName . (($pluginType & Dwoo::COMPILABLE_PLUGIN) ? '_compile' : ''); + } + } + + $params = $this->mapParams($params, $callback, $state); + + foreach ($params as &$p) + $p = $p[0]; + + if ($pluginType & Dwoo::FUNC_PLUGIN) { + if ($pluginType & Dwoo::COMPILABLE_PLUGIN) { + if ($mapped) { + throw new Dwoo_Compilation_Exception($this, 'The @ operator can not be used on compiled plugins.'); + } + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $funcCompiler = $this->customPlugins[$func]['callback']; + } else { + $funcCompiler = 'Dwoo_Plugin_'.$func.'_compile'; + } + array_unshift($params, $this); + $output = call_user_func_array($funcCompiler, $params); + } else { + array_unshift($params, '$this'); + + $params = self::implode_r($params); + if ($mapped) { + $output = '$this->arrayMap(\''.$pluginName.'\', array('.$params.'))'; + } else { + $output = $pluginName.'('.$params.')'; + } + } + } else { + if ($pluginType & Dwoo::COMPILABLE_PLUGIN) { + if ($mapped) { + throw new Dwoo_Compilation_Exception($this, 'The @ operator can not be used on compiled plugins.'); + } + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $callback = $this->customPlugins[$func]['callback']; + if (!is_array($callback)) { + if (!method_exists($callback, 'compile')) { + throw new Dwoo_Exception('Custom plugin '.$func.' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use'); + } + if (($ref = new ReflectionMethod($callback, 'compile')) && $ref->isStatic()) { + $funcCompiler = array($callback, 'compile'); + } else { + $funcCompiler = array(new $callback, 'compile'); + } + } else { + $funcCompiler = $callback; + } + } else { + $funcCompiler = array('Dwoo_Plugin_'.$func, 'compile'); + array_unshift($params, $this); + } + $output = call_user_func_array($funcCompiler, $params); + } else { + $params = self::implode_r($params); + + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + if (is_object($callback[0])) { + $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array').'(array($this->plugins[\''.$func.'\'][\'callback\'][0], \''.$callback[1].'\'), array('.$params.'))'; + } else { + $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array').'(array(\''.$callback[0].'\', \''.$callback[1].'\'), array('.$params.'))'; + } + } elseif ($mapped) { + $output = '$this->arrayMap(array($this->getObjectPlugin(\'Dwoo_Plugin_'.$func.'\'), \'process\'), array('.$params.'))'; + } else { + $output = '$this->classCall(\''.$func.'\', array('.$params.'))'; + } + } + } + } + } + + if ($curBlock === 'var' || $m[1] === null) { + return $output; + } elseif ($curBlock === 'string' || $curBlock === 'root') { + return $m[1].'.'.$output.'.'.$m[1].(isset($add)?$add:null); + } + } + + /** + * recursively implodes an array in a similar manner as var_export() does but with some tweaks + * to handle pre-compiled values and the fact that we do not need to enclose everything with + * "array" and do not require top-level keys to be displayed + * + * @param array $params the array to implode + * @param bool $recursiveCall if set to true, the function outputs key names for the top level + * @return string the imploded array + */ + public static function implode_r(array $params, $recursiveCall = false) + { + $out = ''; + foreach ($params as $k=>$p) { + if (is_array($p)) { + $out2 = 'array('; + foreach ($p as $k2=>$v) + $out2 .= var_export($k2, true).' => '.(is_array($v) ? 'array('.self::implode_r($v, true).')' : $v).', '; + $p = rtrim($out2, ', ').')'; + } + if ($recursiveCall) { + $out .= var_export($k, true).' => '.$p.', '; + } else { + $out .= $p.', '; + } + } + return rtrim($out, ', '); + } + + /** + * returns the plugin type of a plugin and adds it to the used plugins array if required + * + * @param string $name plugin name, as found in the template + * @return int type as a multi bit flag composed of the Dwoo plugin types constants + */ + protected function getPluginType($name) + { + $pluginType = -1; + + if (($this->securityPolicy === null && (function_exists($name) || strtolower($name) === 'isset' || strtolower($name) === 'empty')) || + ($this->securityPolicy !== null && in_array(strtolower($name), $this->securityPolicy->getAllowedPhpFunctions()) !== false)) { + $phpFunc = true; + } + + while ($pluginType <= 0) { + if (isset($this->customPlugins[$name])) { + $pluginType = $this->customPlugins[$name]['type'] | Dwoo::CUSTOM_PLUGIN; + } elseif (class_exists('Dwoo_Plugin_'.$name, false) !== false) { + if (is_subclass_of('Dwoo_Plugin_'.$name, 'Dwoo_Block_Plugin')) { + $pluginType = Dwoo::BLOCK_PLUGIN; + } else { + $pluginType = Dwoo::CLASS_PLUGIN; + } + $interfaces = class_implements('Dwoo_Plugin_'.$name, false); + if (in_array('Dwoo_ICompilable', $interfaces) !== false || in_array('Dwoo_ICompilable_Block', $interfaces) !== false) { + $pluginType |= Dwoo::COMPILABLE_PLUGIN; + } + } elseif (function_exists('Dwoo_Plugin_'.$name) !== false) { + $pluginType = Dwoo::FUNC_PLUGIN; + } elseif (function_exists('Dwoo_Plugin_'.$name.'_compile')) { + $pluginType = Dwoo::FUNC_PLUGIN | Dwoo::COMPILABLE_PLUGIN; + } elseif (function_exists('smarty_modifier_'.$name) !== false) { + $pluginType = Dwoo::SMARTY_MODIFIER; + } elseif (function_exists('smarty_function_'.$name) !== false) { + $pluginType = Dwoo::SMARTY_FUNCTION; + } elseif (function_exists('smarty_block_'.$name) !== false) { + $pluginType = Dwoo::SMARTY_BLOCK; + } else { + if ($pluginType===-1) { + try { + $this->dwoo->getLoader()->loadPlugin($name, isset($phpFunc)===false); + } catch (Exception $e) { + if (isset($phpFunc)) { + $pluginType = Dwoo::NATIVE_PLUGIN; + } elseif (is_object($this->dwoo->getPluginProxy()) && $this->dwoo->getPluginProxy()->handles($name)) { + $pluginType = Dwoo::PROXY_PLUGIN; + break; + } else { + throw $e; + } + } + } else { + throw new Dwoo_Exception('Plugin "'.$name.'" could not be found'); + } + $pluginType++; + } + } + + if (($pluginType & Dwoo::COMPILABLE_PLUGIN) === 0 && ($pluginType & Dwoo::NATIVE_PLUGIN) === 0 && ($pluginType & Dwoo::PROXY_PLUGIN) === 0) { + $this->usedPlugins[$name] = $pluginType; + } + + return $pluginType; + } + + /** + * runs htmlentities over the matched blocks when the security policy enforces that + * + * @param array $match matched php block + * @return string the htmlentities-converted string + */ + protected function phpTagEncodingHelper($match) + { + return htmlspecialchars($match[0]); + } + + /** + * maps the parameters received from the template onto the parameters required by the given callback + * + * @param array $params the array of parameters + * @param callback $callback the function or method to reflect on to find out the required parameters + * @param int $callType the type of call in the template, 0 = no params, 1 = php-style call, 2 = named parameters call + * @return array parameters sorted in the correct order with missing optional parameters filled + */ + protected function mapParams(array $params, $callback, $callType=2) + { + $map = $this->getParamMap($callback); + + $paramlist = array(); + + // transforms the parameter array from (x=>array('paramname'=>array(values))) to (paramname=>array(values)) + $ps = array(); + foreach ($params as $p) { + if (is_array($p[1])) { + $ps[$p[0]] = $p[1]; + } else { + $ps[] = $p; + } + } + + // loops over the param map and assigns values from the template or default value for unset optional params + while (list($k,$v) = each($map)) { + if ($v[0] === '*') { + // "rest" array parameter, fill every remaining params in it and then break + if (count($ps) === 0) { + if ($v[1]===false) { + throw new Dwoo_Compilation_Exception($this, 'Rest argument missing for '.str_replace(array('Dwoo_Plugin_', '_compile'), '', (is_array($callback) ? $callback[0] : $callback))); + } else { + break; + } + } + $tmp = array(); + $tmp2 = array(); + foreach ($ps as $i=>$p) { + $tmp[$i] = $p[0]; + $tmp2[$i] = $p[1]; + } + $paramlist[$v[0]] = array($tmp, $tmp2); + unset($tmp, $tmp2, $i, $p); + break; + } elseif (isset($ps[$v[0]])) { + // parameter is defined as named param + $paramlist[$v[0]] = $ps[$v[0]]; + unset($ps[$v[0]]); + } elseif (isset($ps[$k])) { + // parameter is defined as ordered param + $paramlist[$v[0]] = $ps[$k]; + unset($ps[$k]); + } elseif ($v[1]===false) { + // parameter is not defined and not optional, throw error + throw new Dwoo_Compilation_Exception($this, 'Argument '.$k.'/'.$v[0].' missing for '.str_replace(array('Dwoo_Plugin_', '_compile'), '', (is_array($callback) ? $callback[0] : $callback))); + } elseif ($v[2]===null) { + // enforce lowercased null if default value is null (php outputs NULL with var export) + $paramlist[$v[0]] = array('null', null); + } else { + // outputs default value with var_export + $paramlist[$v[0]] = array(var_export($v[2], true), $v[2]); + } + } + + return $paramlist; + } + + /** + * returns the parameter map of the given callback, it filters out entries typed as Dwoo and Dwoo_Compiler and turns the rest parameter into a "*" + * + * @param callback $callback the function/method to reflect on + * @return array processed parameter map + */ + protected function getParamMap($callback) + { + if (is_null($callback)) { + return array(array('*', true)); + } + if (is_array($callback)) { + $ref = new ReflectionMethod($callback[0], $callback[1]); + } else { + $ref = new ReflectionFunction($callback); + } + + $out = array(); + foreach ($ref->getParameters() as $param) { + if (($class = $param->getClass()) !== null && $class->name === 'Dwoo') { + continue; + } + if (($class = $param->getClass()) !== null && $class->name === 'Dwoo_Compiler') { + continue; + } + if ($param->getName() === 'rest' && $param->isArray() === true) { + $out[] = array('*', $param->isOptional(), null); + } + $out[] = array($param->getName(), $param->isOptional(), $param->isOptional() ? $param->getDefaultValue() : null); + } + + return $out; + } + + /** + * returns a default instance of this compiler, used by default by all Dwoo templates that do not have a + * specific compiler assigned and when you do not override the default compiler factory function + * + * @see Dwoo::setDefaultCompilerFactory() + * @return Dwoo_Compiler + */ + public static function compilerFactory() + { + if (self::$instance === null) { + self::$instance = new self; + } + return self::$instance; + } +} diff --git a/lib/dwoo/plugins/builtin/blocks/a.php b/lib/dwoo/plugins/builtin/blocks/a.php new file mode 100644 index 0000000..7f25f05 --- /dev/null +++ b/lib/dwoo/plugins/builtin/blocks/a.php @@ -0,0 +1,67 @@ + + * * href : the target URI where the link must point + * * rest : any other attributes you want to add to the tag can be added as named parameters + * + * + * Example : + * + * + * {* Create a simple link out of an url variable and add a special class attribute: *} + * + * {a $url class="external" /} + * + * {* Mark a link as active depending on some other variable : *} + * + * {a $link.url class=tif($link.active "active"); $link.title /} + * + * {* This is similar to: {$link.title} *} + * + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_a extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init($href, array $rest=array()) + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + $p = $compiler->getCompiledParams($params); + + $out = Dwoo_Compiler::PHP_OPEN . 'echo \'\';' . Dwoo_Compiler::PHP_CLOSE; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $p = $compiler->getCompiledParams($params); + + // no content was provided so use the url as display text + if ($content == "") { + // merge into the href if href is a string + if (substr($p['href'], -1) === '"' || substr($p['href'], -1) === '\'') { + return Dwoo_Compiler::PHP_OPEN . 'echo '.substr($p['href'], 0, -1).''.substr($p['href'], -1).';'.Dwoo_Compiler::PHP_CLOSE; + } + // otherwise append + return Dwoo_Compiler::PHP_OPEN . 'echo '.$p['href'].'.\'\';'.Dwoo_Compiler::PHP_CLOSE; + } + + // return content + return $content . ''; + } +} diff --git a/lib/dwoo/plugins/builtin/blocks/auto_escape.php b/lib/dwoo/plugins/builtin/blocks/auto_escape.php new file mode 100644 index 0000000..0f550cb --- /dev/null +++ b/lib/dwoo/plugins/builtin/blocks/auto_escape.php @@ -0,0 +1,61 @@ + + * * enabled : if set to "on", "enable", true or 1 then the compiler autoescaping is enabled inside this block. set to "off", "disable", false or 0 to disable it + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_auto_escape extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + protected static $stack = array(); + + public function init($enabled) + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + $params = $compiler->getCompiledParams($params); + switch(strtolower(trim((string) $params['enabled'], '"\''))) { + + case 'on': + case 'true': + case 'enabled': + case 'enable': + case '1': + $enable = true; + break; + case 'off': + case 'false': + case 'disabled': + case 'disable': + case '0': + $enable = false; + break; + default: + throw new Dwoo_Compilation_Exception($compiler, 'Auto_Escape : Invalid parameter ('.$params['enabled'].'), valid parameters are "enable"/true or "disable"/false'); + + } + + self::$stack[] = $compiler->getAutoEscape(); + $compiler->setAutoEscape($enable); + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $compiler->setAutoEscape(array_pop(self::$stack)); + return $content; + } +} diff --git a/lib/dwoo/plugins/builtin/blocks/block.php b/lib/dwoo/plugins/builtin/blocks/block.php new file mode 100644 index 0000000..656e558 --- /dev/null +++ b/lib/dwoo/plugins/builtin/blocks/block.php @@ -0,0 +1,34 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_block extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init($name='') + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + return $content; + } +} diff --git a/lib/dwoo/plugins/builtin/blocks/capture.php b/lib/dwoo/plugins/builtin/blocks/capture.php new file mode 100644 index 0000000..b2921af --- /dev/null +++ b/lib/dwoo/plugins/builtin/blocks/capture.php @@ -0,0 +1,61 @@ + + * * name : capture name, used to read the value afterwards + * * assign : if set, the value is also saved in the given variable + * * cat : if true, the value is appended to the previous one (if any) instead of overwriting it + * + * If the cat parameter is true, the content + * will be appended to the existing content + * + * Example : + * + * + * {capture "foo"} + * Anything in here won't show, it will be saved for later use.. + * {/capture} + * Output was : {$.capture.foo} + * + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_capture extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init($name = 'default', $assign = null, $cat = false, $trim = false) + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + return Dwoo_Compiler::PHP_OPEN.$prepend.'ob_start();'.$append.Dwoo_Compiler::PHP_CLOSE; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $params = $compiler->getCompiledParams($params); + + $out = $content . Dwoo_Compiler::PHP_OPEN.$prepend."\n".'$tmp = ob_get_clean();'; + if ($params['trim'] !== 'false' && $params['trim'] !== 0) { + $out .= "\n".'$tmp = trim($tmp);'; + } + if ($params['cat'] === 'true' || $params['cat'] === 1) { + $out .= "\n".'$tmp = $this->readVar(\'dwoo.capture.\'.'.$params['name'].') . $tmp;'; + } + if ($params['assign'] !== 'null') { + $out .= "\n".'$this->scope['.$params['assign'].'] = $tmp;'; + } + return $out . "\n".'$this->globals[\'capture\']['.$params['name'].'] = $tmp;'.$append.Dwoo_Compiler::PHP_CLOSE; + } +} diff --git a/lib/dwoo/plugins/builtin/blocks/dynamic.php b/lib/dwoo/plugins/builtin/blocks/dynamic.php new file mode 100644 index 0000000..74886ac --- /dev/null +++ b/lib/dwoo/plugins/builtin/blocks/dynamic.php @@ -0,0 +1,60 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_dynamic extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init() + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $output = Dwoo_Compiler::PHP_OPEN . + 'if($doCache) {'."\n\t". + 'echo \''. + str_replace('\'', '\\\'', $content) . + '\';'. + "\n} else {\n\t"; + if(substr($content, 0, strlen(Dwoo_Compiler::PHP_OPEN)) == Dwoo_Compiler::PHP_OPEN) { + $output .= substr($content, strlen(Dwoo_Compiler::PHP_OPEN)); + } else { + $output .= Dwoo_Compiler::PHP_CLOSE . $content; + } + if(substr($output, -strlen(Dwoo_Compiler::PHP_CLOSE)) == Dwoo_Compiler::PHP_CLOSE) { + $output = substr($output, 0, -strlen(Dwoo_Compiler::PHP_CLOSE)); + } else { + $output .= Dwoo_Compiler::PHP_OPEN; + } + $output .= "\n}". Dwoo_Compiler::PHP_CLOSE; + + return $output; + } + + public static function unescape($output, $dynamicId) + { + return preg_replace_callback('/(.+?)<\/dwoo:dynamic_'.$dynamicId.'>/', array('self', 'unescapePhp'), $output); + } + + public static function unescapePhp($match) + { + return preg_replace('{<\?php /\*'.$match[1].'\*/ echo \'(.+?)\'; \?>}', '$1', $match[2]); + } +} diff --git a/lib/dwoo/plugins/builtin/blocks/else.php b/lib/dwoo/plugins/builtin/blocks/else.php new file mode 100644 index 0000000..8598c77 --- /dev/null +++ b/lib/dwoo/plugins/builtin/blocks/else.php @@ -0,0 +1,63 @@ + + * {foreach $array val} + * $array is not empty so we display it's values : {$val} + * {else} + * if this shows, it means that $array is empty or doesn't exist. + * {/foreach} + * + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_else extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init() + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + $preContent = ''; + while (true) { + $preContent .= $compiler->removeTopBlock(); + $block =& $compiler->getCurrentBlock(); + $interfaces = class_implements($block['class'], false); + if (in_array('Dwoo_IElseable', $interfaces) !== false) { + break; + } + } + + $params['initialized'] = true; + $compiler->injectBlock($type, $params); + return $preContent; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + if (!isset($params['initialized'])) { + return ''; + } + + $block =& $compiler->getCurrentBlock(); + $block['params']['hasElse'] = Dwoo_Compiler::PHP_OPEN."else {\n".Dwoo_Compiler::PHP_CLOSE . $content . Dwoo_Compiler::PHP_OPEN."\n}".Dwoo_Compiler::PHP_CLOSE; + return ''; + } +} diff --git a/lib/dwoo/plugins/builtin/blocks/elseif.php b/lib/dwoo/plugins/builtin/blocks/elseif.php new file mode 100644 index 0000000..76b5e44 --- /dev/null +++ b/lib/dwoo/plugins/builtin/blocks/elseif.php @@ -0,0 +1,60 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_elseif extends Dwoo_Plugin_if implements Dwoo_ICompilable_Block, Dwoo_IElseable +{ + public function init(array $rest) + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + $preContent = ''; + while (true) { + $preContent .= $compiler->removeTopBlock(); + $block =& $compiler->getCurrentBlock(); + $interfaces = class_implements($block['class'], false); + if (in_array('Dwoo_IElseable', $interfaces) !== false) { + break; + } + } + + $params['initialized'] = true; + $compiler->injectBlock($type, $params); + return $preContent; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + if (!isset($params['initialized'])) { + return ''; + } + + $params = $compiler->getCompiledParams($params); + + $pre = Dwoo_Compiler::PHP_OPEN."elseif (".implode(' ', self::replaceKeywords($params['*'], $compiler)).") {\n" . Dwoo_Compiler::PHP_CLOSE; + $post = Dwoo_Compiler::PHP_OPEN."\n}".Dwoo_Compiler::PHP_CLOSE; + + if (isset($params['hasElse'])) { + $post .= $params['hasElse']; + } + + $block =& $compiler->getCurrentBlock(); + $block['params']['hasElse'] = $pre . $content . $post; + return ''; + } +} diff --git a/lib/dwoo/plugins/builtin/blocks/for.php b/lib/dwoo/plugins/builtin/blocks/for.php new file mode 100644 index 0000000..e2ffa7f --- /dev/null +++ b/lib/dwoo/plugins/builtin/blocks/for.php @@ -0,0 +1,123 @@ + + * * name : for name to access it's iterator variables through {$.for.name.var} see {@link http://wiki.dwoo.org/index.php/IteratorVariables} for details + * * from : array to iterate from (which equals 0) or a number as a start value + * * to : value to stop iterating at (equals count($array) by default if you set an array in from) + * * step : defines the incrementation of the pointer at each iteration + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_for extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block, Dwoo_IElseable +{ + public static $cnt=0; + + public function init($name, $from, $to=null, $step=1, $skip=0) + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + // get block params and save the current template pointer to use it in the postProcessing method + $currentBlock =& $compiler->getCurrentBlock(); + $currentBlock['params']['tplPointer'] = $compiler->getPointer(); + + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $params = $compiler->getCompiledParams($params); + $tpl = $compiler->getTemplateSource($params['tplPointer']); + + // assigns params + $from = $params['from']; + $name = $params['name']; + $step = $params['step']; + $to = $params['to']; + + // evaluates which global variables have to be computed + $varName = '$dwoo.for.'.trim($name, '"\'').'.'; + $shortVarName = '$.for.'.trim($name, '"\'').'.'; + $usesAny = strpos($tpl, $varName) !== false || strpos($tpl, $shortVarName) !== false; + $usesFirst = strpos($tpl, $varName.'first') !== false || strpos($tpl, $shortVarName.'first') !== false; + $usesLast = strpos($tpl, $varName.'last') !== false || strpos($tpl, $shortVarName.'last') !== false; + $usesIndex = strpos($tpl, $varName.'index') !== false || strpos($tpl, $shortVarName.'index') !== false; + $usesIteration = $usesFirst || $usesLast || strpos($tpl, $varName.'iteration') !== false || strpos($tpl, $shortVarName.'iteration') !== false; + $usesShow = strpos($tpl, $varName.'show') !== false || strpos($tpl, $shortVarName.'show') !== false; + $usesTotal = $usesLast || strpos($tpl, $varName.'total') !== false || strpos($tpl, $shortVarName.'total') !== false; + + // gets foreach id + $cnt = self::$cnt++; + + // builds pre processing output for + $out = Dwoo_Compiler::PHP_OPEN . "\n".'$_for'.$cnt.'_from = '.$from.';'. + "\n".'$_for'.$cnt.'_to = '.$to.';'. + "\n".'$_for'.$cnt.'_step = abs('.$step.');'. + "\n".'if (is_numeric($_for'.$cnt.'_from) && !is_numeric($_for'.$cnt.'_to)) { $this->triggerError(\'For requires the to parameter when using a numerical from\'); }'. + "\n".'$tmp_shows = $this->isArray($_for'.$cnt.'_from, true) || (is_numeric($_for'.$cnt.'_from) && (abs(($_for'.$cnt.'_from - $_for'.$cnt.'_to)/$_for'.$cnt.'_step) !== 0 || $_for'.$cnt.'_from == $_for'.$cnt.'_to));'; + // adds foreach properties + if ($usesAny) { + $out .= "\n".'$this->globals["for"]['.$name.'] = array'."\n("; + if ($usesIndex) $out .="\n\t".'"index" => 0,'; + if ($usesIteration) $out .="\n\t".'"iteration" => 1,'; + if ($usesFirst) $out .="\n\t".'"first" => null,'; + if ($usesLast) $out .="\n\t".'"last" => null,'; + if ($usesShow) $out .="\n\t".'"show" => $tmp_shows,'; + if ($usesTotal) $out .="\n\t".'"total" => $this->isArray($_for'.$cnt.'_from) ? floor(count($_for'.$cnt.'_from) / $_for'.$cnt.'_step) : (is_numeric($_for'.$cnt.'_from) ? abs(($_for'.$cnt.'_to + 1 - $_for'.$cnt.'_from)/$_for'.$cnt.'_step) : 0),'; + $out.="\n);\n".'$_for'.$cnt.'_glob =& $this->globals["for"]['.$name.'];'; + } + // checks if for must be looped + $out .= "\n".'if ($tmp_shows)'."\n{"; + // set from/to to correct values if an array was given + $out .= "\n\t".'if ($this->isArray($_for'.$cnt.'_from, true)) { + $_for'.$cnt.'_to = is_numeric($_for'.$cnt.'_to) ? $_for'.$cnt.'_to - $_for'.$cnt.'_step : count($_for'.$cnt.'_from) - 1; + $_for'.$cnt.'_from = 0; + }'; + // reverse from and to if needed + $out .= "\n\t".'if ($_for'.$cnt.'_from > $_for'.$cnt.'_to) { + $tmp = $_for'.$cnt.'_from; + $_for'.$cnt.'_from = $_for'.$cnt.'_to; + $_for'.$cnt.'_to = $tmp; + } + for ($this->scope['.$name.'] = $_for'.$cnt.'_from; $this->scope['.$name.'] <= $_for'.$cnt.'_to; $this->scope['.$name.'] += $_for'.$cnt.'_step)'."\n\t{"; + // updates properties + if ($usesIndex) { + $out.="\n\t\t".'$_for'.$cnt.'_glob["index"] = $this->scope['.$name.'];'; + } + if ($usesFirst) { + $out .= "\n\t\t".'$_for'.$cnt.'_glob["first"] = (string) ($_for'.$cnt.'_glob["iteration"] === 1);'; + } + if ($usesLast) { + $out .= "\n\t\t".'$_for'.$cnt.'_glob["last"] = (string) ($_for'.$cnt.'_glob["iteration"] === $_for'.$cnt.'_glob["total"]);'; + } + $out .= "\n/* -- for start output */\n".Dwoo_Compiler::PHP_CLOSE; + + + // build post processing output and cache it + $postOut = Dwoo_Compiler::PHP_OPEN . '/* -- for end output */'; + // update properties + if ($usesIteration) { + $postOut.="\n\t\t".'$_for'.$cnt.'_glob["iteration"]+=1;'; + } + // end loop + $postOut .= "\n\t}\n}\n".Dwoo_Compiler::PHP_CLOSE; + + if (isset($params['hasElse'])) { + $postOut .= $params['hasElse']; + } + + return $out . $content . $postOut; + } +} diff --git a/lib/dwoo/plugins/builtin/blocks/foreach.php b/lib/dwoo/plugins/builtin/blocks/foreach.php new file mode 100644 index 0000000..412e844 --- /dev/null +++ b/lib/dwoo/plugins/builtin/blocks/foreach.php @@ -0,0 +1,148 @@ + + * * from : the array that you want to iterate over + * * key : variable name for the key (or for the item if item is not defined) + * * item : variable name for each item + * * name : foreach name to access it's iterator variables through {$.foreach.name.var} see {@link http://wiki.dwoo.org/index.php/IteratorVariables} for details + * + * Example : + * + * + * {foreach $array val} + * {$val.something} + * {/foreach} + * + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.1 + * @date 2008-12-24 + * @package Dwoo + */ +class Dwoo_Plugin_foreach extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block, Dwoo_IElseable +{ + public static $cnt=0; + + public function init($from, $key=null, $item=null, $name='default', $implode=null) + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + // get block params and save the current template pointer to use it in the postProcessing method + $currentBlock =& $compiler->getCurrentBlock(); + $currentBlock['params']['tplPointer'] = $compiler->getPointer(); + + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $params = $compiler->getCompiledParams($params); + $tpl = $compiler->getTemplateSource($params['tplPointer']); + + // assigns params + $src = $params['from']; + + if ($params['item'] !== 'null') { + if ($params['key'] !== 'null') { + $key = $params['key']; + } + $val = $params['item']; + } elseif ($params['key'] !== 'null') { + $val = $params['key']; + } else { + throw new Dwoo_Compilation_Exception($compiler, 'Foreach item parameter missing'); + } + $name = $params['name']; + + if (substr($val, 0, 1) !== '"' && substr($val, 0, 1) !== '\'') { + throw new Dwoo_Compilation_Exception($compiler, 'Foreach item parameter must be of type string'); + } + if (isset($key) && substr($val, 0, 1) !== '"' && substr($val, 0, 1) !== '\'') { + throw new Dwoo_Compilation_Exception($compiler, 'Foreach key parameter must be of type string'); + } + + // evaluates which global variables have to be computed + $varName = '$dwoo.foreach.'.trim($name, '"\'').'.'; + $shortVarName = '$.foreach.'.trim($name, '"\'').'.'; + $usesAny = strpos($tpl, $varName) !== false || strpos($tpl, $shortVarName) !== false; + $usesFirst = strpos($tpl, $varName.'first') !== false || strpos($tpl, $shortVarName.'first') !== false; + $usesLast = strpos($tpl, $varName.'last') !== false || strpos($tpl, $shortVarName.'last') !== false; + $usesIndex = $usesFirst || strpos($tpl, $varName.'index') !== false || strpos($tpl, $shortVarName.'index') !== false; + $usesIteration = $usesLast || strpos($tpl, $varName.'iteration') !== false || strpos($tpl, $shortVarName.'iteration') !== false; + $usesShow = strpos($tpl, $varName.'show') !== false || strpos($tpl, $shortVarName.'show') !== false; + $usesTotal = $usesLast || strpos($tpl, $varName.'total') !== false || strpos($tpl, $shortVarName.'total') !== false; + + // override globals vars if implode is used + if ($params['implode'] !== 'null') { + $implode = $params['implode']; + $usesAny = true; + $usesLast = true; + $usesIteration = true; + $usesTotal = true; + } + + // gets foreach id + $cnt = self::$cnt++; + + // build pre content output + $pre = Dwoo_Compiler::PHP_OPEN . "\n".'$_fh'.$cnt.'_data = '.$src.';'; + // adds foreach properties + if ($usesAny) { + $pre .= "\n".'$this->globals["foreach"]['.$name.'] = array'."\n("; + if ($usesIndex) $pre .="\n\t".'"index" => 0,'; + if ($usesIteration) $pre .="\n\t".'"iteration" => 1,'; + if ($usesFirst) $pre .="\n\t".'"first" => null,'; + if ($usesLast) $pre .="\n\t".'"last" => null,'; + if ($usesShow) $pre .="\n\t".'"show" => $this->isArray($_fh'.$cnt.'_data, true, true),'; + if ($usesTotal) $pre .="\n\t".'"total" => $this->isArray($_fh'.$cnt.'_data) ? count($_fh'.$cnt.'_data) : 0,'; + $pre.="\n);\n".'$_fh'.$cnt.'_glob =& $this->globals["foreach"]['.$name.'];'; + } + // checks if foreach must be looped + $pre .= "\n".'if ($this->isArray($_fh'.$cnt.'_data'.(isset($params['hasElse']) ? ', true, true' : '').') === true)'."\n{"; + // iterates over keys + $pre .= "\n\t".'foreach ($_fh'.$cnt.'_data as '.(isset($key)?'$this->scope['.$key.']=>':'').'$this->scope['.$val.'])'."\n\t{"; + // updates properties + if ($usesFirst) { + $pre .= "\n\t\t".'$_fh'.$cnt.'_glob["first"] = (string) ($_fh'.$cnt.'_glob["index"] === 0);'; + } + if ($usesLast) { + $pre .= "\n\t\t".'$_fh'.$cnt.'_glob["last"] = (string) ($_fh'.$cnt.'_glob["iteration"] === $_fh'.$cnt.'_glob["total"]);'; + } + $pre .= "\n/* -- foreach start output */\n".Dwoo_Compiler::PHP_CLOSE; + + // build post content output + $post = Dwoo_Compiler::PHP_OPEN . "\n"; + + if (isset($implode)) { + $post .= '/* -- implode */'."\n".'if (!$_fh'.$cnt.'_glob["last"]) {'. + "\n\t".'echo '.$implode.";\n}\n"; + } + $post .= '/* -- foreach end output */'; + // update properties + if ($usesIndex) { + $post.="\n\t\t".'$_fh'.$cnt.'_glob["index"]+=1;'; + } + if ($usesIteration) { + $post.="\n\t\t".'$_fh'.$cnt.'_glob["iteration"]+=1;'; + } + // end loop + $post .= "\n\t}\n}".Dwoo_Compiler::PHP_CLOSE; + if (isset($params['hasElse'])) { + $post .= $params['hasElse']; + } + + return $pre . $content . $post; + } +} diff --git a/lib/dwoo/plugins/builtin/blocks/foreachelse.php b/lib/dwoo/plugins/builtin/blocks/foreachelse.php new file mode 100644 index 0000000..9cb35d8 --- /dev/null +++ b/lib/dwoo/plugins/builtin/blocks/foreachelse.php @@ -0,0 +1,43 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_foreachelse extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init() + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + $with =& $compiler->findBlock('foreach', true); + + $params['initialized'] = true; + $compiler->injectBlock($type, $params); + + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + if (!isset($params['initialized'])) { + return ''; + } + + $block =& $compiler->getCurrentBlock(); + $block['params']['hasElse'] = Dwoo_Compiler::PHP_OPEN."else {\n".Dwoo_Compiler::PHP_CLOSE . $content . Dwoo_Compiler::PHP_OPEN."\n}".Dwoo_Compiler::PHP_CLOSE; + return ''; + } +} diff --git a/lib/dwoo/plugins/builtin/blocks/forelse.php b/lib/dwoo/plugins/builtin/blocks/forelse.php new file mode 100644 index 0000000..8ef3730 --- /dev/null +++ b/lib/dwoo/plugins/builtin/blocks/forelse.php @@ -0,0 +1,43 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_forelse extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init() + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + $with =& $compiler->findBlock('for', true); + + $params['initialized'] = true; + $compiler->injectBlock($type, $params); + + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + if (!isset($params['initialized'])) { + return ''; + } + + $block =& $compiler->getCurrentBlock(); + $block['params']['hasElse'] = Dwoo_Compiler::PHP_OPEN."else {\n".Dwoo_Compiler::PHP_CLOSE . $content . Dwoo_Compiler::PHP_OPEN."\n}".Dwoo_Compiler::PHP_CLOSE; + return ''; + } +} diff --git a/lib/dwoo/plugins/builtin/blocks/if.php b/lib/dwoo/plugins/builtin/blocks/if.php new file mode 100644 index 0000000..6354438 --- /dev/null +++ b/lib/dwoo/plugins/builtin/blocks/if.php @@ -0,0 +1,180 @@ + == + * neq || ne -> != + * >= || ge -> >= + * <= || le -> <= + * > -> > + * < -> < + * mod -> % + * not -> ! + * X is [not] div by Y -> (X % Y) == 0 + * X is [not] even [by Y] -> (X % 2) == 0 || ((X/Y) % 2) == 0 + * X is [not] odd [by Y] -> (X % 2) != 0 || ((X/Y) % 2) != 0 + * + * This software is provided 'as-is', without any express || implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_if extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block, Dwoo_IElseable +{ + public function init(array $rest) + { + } + + public static function replaceKeywords(array $params, Dwoo_Compiler $compiler) + { + $p = array(); + + reset($params); + while (list($k,$v) = each($params)) { + $v = (string) $v; + if(substr($v, 0, 1) === '"' || substr($v, 0, 1) === '\'') { + $vmod = strtolower(substr($v, 1, -1)); + } else { + $vmod = strtolower($v); + } + switch($vmod) { + + case 'and': + $p[] = '&&'; + break; + case 'or': + $p[] = '||'; + break; + case '==': + case 'eq': + $p[] = '=='; + break; + case '<>': + case '!=': + case 'ne': + case 'neq': + $p[] = '!='; + break; + case '>=': + case 'gte': + case 'ge': + $p[] = '>='; + break; + case '<=': + case 'lte': + case 'le': + $p[] = '<='; + break; + case '>': + case 'gt': + $p[] = '>'; + break; + case '<': + case 'lt': + $p[] = '<'; + break; + case '===': + $p[] = '==='; + break; + case '!==': + $p[] = '!=='; + break; + case 'is': + if (isset($params[$k+1]) && strtolower(trim($params[$k+1], '"\'')) === 'not') { + $negate = true; + next($params); + } else { + $negate = false; + } + $ptr = 1+(int)$negate; + if (!isset($params[$k+$ptr])) { + $params[$k+$ptr] = ''; + } else { + $params[$k+$ptr] = trim($params[$k+$ptr], '"\''); + } + switch($params[$k+$ptr]) { + + case 'div': + if (isset($params[$k+$ptr+1]) && strtolower(trim($params[$k+$ptr+1], '"\'')) === 'by') { + $p[] = ' % '.$params[$k+$ptr+2].' '.($negate?'!':'=').'== 0'; + next($params); + next($params); + next($params); + } else { + throw new Dwoo_Compilation_Exception($compiler, 'If : Syntax error : syntax should be "if $a is [not] div by $b", found '.$params[$k-1].' is '.($negate?'not ':'').'div '.$params[$k+$ptr+1].' '.$params[$k+$ptr+2]); + } + break; + case 'even': + $a = array_pop($p); + if (isset($params[$k+$ptr+1]) && strtolower(trim($params[$k+$ptr+1], '"\'')) === 'by') { + $b = $params[$k+$ptr+2]; + $p[] = '('.$a .' / '.$b.') % 2 '.($negate?'!':'=').'== 0'; + next($params); + next($params); + } else { + $p[] = $a.' % 2 '.($negate?'!':'=').'== 0'; + } + next($params); + break; + case 'odd': + $a = array_pop($p); + if (isset($params[$k+$ptr+1]) && strtolower(trim($params[$k+$ptr+1], '"\'')) === 'by') { + $b = $params[$k+$ptr+2]; + $p[] = '('.$a .' / '.$b.') % 2 '.($negate?'=':'!').'== 0'; + next($params); + next($params); + } else { + $p[] = $a.' % 2 '.($negate?'=':'!').'== 0'; + } + next($params); + break; + default: + throw new Dwoo_Compilation_Exception($compiler, 'If : Syntax error : syntax should be "if $a is [not] (div|even|odd) [by $b]", found '.$params[$k-1].' is '.$params[$k+$ptr+1]); + + } + break; + case '%': + case 'mod': + $p[] = '%'; + break; + case '!': + case 'not': + $p[] = '!'; + break; + default: + $p[] = $v; + + } + } + + return $p; + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $params = $compiler->getCompiledParams($params); + + $pre = Dwoo_Compiler::PHP_OPEN.'if ('.implode(' ', self::replaceKeywords($params['*'], $compiler)).") {\n".Dwoo_Compiler::PHP_CLOSE; + + $post = Dwoo_Compiler::PHP_OPEN."\n}".Dwoo_Compiler::PHP_CLOSE; + + if (isset($params['hasElse'])) { + $post .= $params['hasElse']; + } + + return $pre . $content . $post; + } +} diff --git a/lib/dwoo/plugins/builtin/blocks/loop.php b/lib/dwoo/plugins/builtin/blocks/loop.php new file mode 100644 index 0000000..3e3ea34 --- /dev/null +++ b/lib/dwoo/plugins/builtin/blocks/loop.php @@ -0,0 +1,124 @@ + + * * from : the array that you want to iterate over + * * name : loop name to access it's iterator variables through {$.loop.name.var} see {@link http://wiki.dwoo.org/index.php/IteratorVariables} for details + * + * Example : + * + * instead of a foreach block such as : + * + * + * {foreach $variable value} + * {$value.foo} {$value.bar} + * {/foreach} + * + * + * you can do : + * + * + * {loop $variable} + * {$foo} {$bar} + * {/loop} + * + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_loop extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block, Dwoo_IElseable +{ + public static $cnt=0; + + public function init($from, $name='default') + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + // get block params and save the current template pointer to use it in the postProcessing method + $currentBlock =& $compiler->getCurrentBlock(); + $currentBlock['params']['tplPointer'] = $compiler->getPointer(); + + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $params = $compiler->getCompiledParams($params); + $tpl = $compiler->getTemplateSource($params['tplPointer']); + + // assigns params + $src = $params['from']; + $name = $params['name']; + + // evaluates which global variables have to be computed + $varName = '$dwoo.loop.'.trim($name, '"\'').'.'; + $shortVarName = '$.loop.'.trim($name, '"\'').'.'; + $usesAny = strpos($tpl, $varName) !== false || strpos($tpl, $shortVarName) !== false; + $usesFirst = strpos($tpl, $varName.'first') !== false || strpos($tpl, $shortVarName.'first') !== false; + $usesLast = strpos($tpl, $varName.'last') !== false || strpos($tpl, $shortVarName.'last') !== false; + $usesIndex = $usesFirst || strpos($tpl, $varName.'index') !== false || strpos($tpl, $shortVarName.'index') !== false; + $usesIteration = $usesLast || strpos($tpl, $varName.'iteration') !== false || strpos($tpl, $shortVarName.'iteration') !== false; + $usesShow = strpos($tpl, $varName.'show') !== false || strpos($tpl, $shortVarName.'show') !== false; + $usesTotal = $usesLast || strpos($tpl, $varName.'total') !== false || strpos($tpl, $shortVarName.'total') !== false; + + // gets foreach id + $cnt = self::$cnt++; + + // builds pre processing output + $pre = Dwoo_Compiler::PHP_OPEN . "\n".'$_loop'.$cnt.'_data = '.$src.';'; + // adds foreach properties + if ($usesAny) { + $pre .= "\n".'$this->globals["loop"]['.$name.'] = array'."\n("; + if ($usesIndex) $pre .="\n\t".'"index" => 0,'; + if ($usesIteration) $pre .="\n\t".'"iteration" => 1,'; + if ($usesFirst) $pre .="\n\t".'"first" => null,'; + if ($usesLast) $pre .="\n\t".'"last" => null,'; + if ($usesShow) $pre .="\n\t".'"show" => $this->isArray($_loop'.$cnt.'_data, true, true),'; + if ($usesTotal) $pre .="\n\t".'"total" => $this->isArray($_loop'.$cnt.'_data) ? count($_loop'.$cnt.'_data) : 0,'; + $pre.="\n);\n".'$_loop'.$cnt.'_glob =& $this->globals["loop"]['.$name.'];'; + } + // checks if the loop must be looped + $pre .= "\n".'if ($this->isArray($_loop'.$cnt.'_data'.(isset($params['hasElse']) ? ', true, true' : '').') === true)'."\n{"; + // iterates over keys + $pre .= "\n\t".'foreach ($_loop'.$cnt.'_data as $tmp_key => $this->scope["-loop-"])'."\n\t{"; + // updates properties + if ($usesFirst) { + $pre .= "\n\t\t".'$_loop'.$cnt.'_glob["first"] = (string) ($_loop'.$cnt.'_glob["index"] === 0);'; + } + if ($usesLast) { + $pre .= "\n\t\t".'$_loop'.$cnt.'_glob["last"] = (string) ($_loop'.$cnt.'_glob["iteration"] === $_loop'.$cnt.'_glob["total"]);'; + } + $pre .= "\n\t\t".'$_loop'.$cnt.'_scope = $this->setScope(array("-loop-"));' . "\n/* -- loop start output */\n".Dwoo_Compiler::PHP_CLOSE; + + // build post processing output and cache it + $post = Dwoo_Compiler::PHP_OPEN . "\n".'/* -- loop end output */'."\n\t\t".'$this->setScope($_loop'.$cnt.'_scope, true);'; + // update properties + if ($usesIndex) { + $post.="\n\t\t".'$_loop'.$cnt.'_glob["index"]+=1;'; + } + if ($usesIteration) { + $post.="\n\t\t".'$_loop'.$cnt.'_glob["iteration"]+=1;'; + } + // end loop + $post .= "\n\t}\n}\n" . Dwoo_Compiler::PHP_CLOSE; + if (isset($params['hasElse'])) { + $post .= $params['hasElse']; + } + + return $pre . $content . $post; + } +} diff --git a/lib/dwoo/plugins/builtin/blocks/section.php b/lib/dwoo/plugins/builtin/blocks/section.php new file mode 100644 index 0000000..edc1ad7 --- /dev/null +++ b/lib/dwoo/plugins/builtin/blocks/section.php @@ -0,0 +1,131 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_section extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block, Dwoo_IElseable +{ + public static $cnt=0; + + public function init($name, $loop, $start = null, $step = null, $max = null, $show = true) + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $output = Dwoo_Compiler::PHP_OPEN; + $params = $compiler->getCompiledParams($params); + + // assigns params + $loop = $params['loop']; + $start = $params['start']; + $max = $params['max']; + $name = $params['name']; + $step = $params['step']; + $show = $params['show']; + + // gets unique id + $cnt = self::$cnt++; + + $output .= '$this->globals[\'section\']['.$name.'] = array();'."\n". + '$_section'.$cnt.' =& $this->globals[\'section\']['.$name.'];'."\n"; + + if ($loop !== 'null') { + $output .= '$_section'.$cnt.'[\'loop\'] = is_array($tmp = '.$loop.') ? count($tmp) : max(0, (int) $tmp);'."\n"; + } else { + $output .= '$_section'.$cnt.'[\'loop\'] = 1;'."\n"; + } + + if ($show !== 'null') { + $output .= '$_section'.$cnt.'[\'show\'] = '.$show.";\n"; + } else { + $output .= '$_section'.$cnt.'[\'show\'] = true;'."\n"; + } + + if ($name !== 'null') { + $output .= '$_section'.$cnt.'[\'name\'] = '.$name.";\n"; + } else { + $output .= '$_section'.$cnt.'[\'name\'] = true;'."\n"; + } + + if ($max !== 'null') { + $output .= '$_section'.$cnt.'[\'max\'] = (int)'.$max.";\n". + 'if($_section'.$cnt.'[\'max\'] < 0) { $_section'.$cnt.'[\'max\'] = $_section'.$cnt.'[\'loop\']; }'."\n"; + } else { + $output .= '$_section'.$cnt.'[\'max\'] = $_section'.$cnt.'[\'loop\'];'."\n"; + } + + if ($step !== 'null') { + $output .= '$_section'.$cnt.'[\'step\'] = (int)'.$step.' == 0 ? 1 : (int) '.$step.";\n"; + } else { + $output .= '$_section'.$cnt.'[\'step\'] = 1;'."\n"; + } + + if ($start !== 'null') { + $output .= '$_section'.$cnt.'[\'start\'] = (int)'.$start.";\n"; + } else { + $output .= '$_section'.$cnt.'[\'start\'] = $_section'.$cnt.'[\'step\'] > 0 ? 0 : $_section'.$cnt.'[\'loop\'] - 1;'."\n". + 'if ($_section'.$cnt.'[\'start\'] < 0) { $_section'.$cnt.'[\'start\'] = max($_section'.$cnt.'[\'step\'] > 0 ? 0 : -1, $_section'.$cnt.'[\'loop\'] + $_section'.$cnt.'[\'start\']); } '."\n". + 'else { $_section'.$cnt.'[\'start\'] = min($_section'.$cnt.'[\'start\'], $_section'.$cnt.'[\'step\'] > 0 ? $_section'.$cnt.'[\'loop\'] : $_section'.$cnt.'[\'loop\'] -1); }'."\n"; + } + +/* if ($usesAny) { + $output .= "\n".'$this->globals["section"]['.$name.'] = array'."\n("; + if ($usesIndex) $output .="\n\t".'"index" => 0,'; + if ($usesIteration) $output .="\n\t".'"iteration" => 1,'; + if ($usesFirst) $output .="\n\t".'"first" => null,'; + if ($usesLast) $output .="\n\t".'"last" => null,'; + if ($usesShow) $output .="\n\t".'"show" => ($this->isArray($_for'.$cnt.'_from, true)) || (is_numeric($_for'.$cnt.'_from) && $_for'.$cnt.'_from != $_for'.$cnt.'_to),'; + if ($usesTotal) $output .="\n\t".'"total" => $this->isArray($_for'.$cnt.'_from) ? count($_for'.$cnt.'_from) - $_for'.$cnt.'_skip : (is_numeric($_for'.$cnt.'_from) ? abs(($_for'.$cnt.'_to + 1 - $_for'.$cnt.'_from)/$_for'.$cnt.'_step) : 0),'; + $out.="\n);\n".'$_section'.$cnt.'[\'glob\'] =& $this->globals["section"]['.$name.'];'."\n\n"; + } +*/ + + $output .= 'if ($_section'.$cnt.'[\'show\']) {'."\n"; + if ($start === 'null' && $step === 'null' && $max === 'null') { + $output .= ' $_section'.$cnt.'[\'total\'] = $_section'.$cnt.'[\'loop\'];'."\n"; + } else { + $output .= ' $_section'.$cnt.'[\'total\'] = min(ceil(($_section'.$cnt.'[\'step\'] > 0 ? $_section'.$cnt.'[\'loop\'] - $_section'.$cnt.'[\'start\'] : $_section'.$cnt.'[\'start\'] + 1) / abs($_section'.$cnt.'[\'step\'])), $_section'.$cnt.'[\'max\']);'."\n"; + } + $output .= ' if ($_section'.$cnt.'[\'total\'] == 0) {'."\n". + ' $_section'.$cnt.'[\'show\'] = false;'."\n". + ' }'."\n". + '} else {'."\n". + ' $_section'.$cnt.'[\'total\'] = 0;'."\n}\n"; + $output .= 'if ($_section'.$cnt.'[\'show\']) {'."\n"; + $output .= "\t".'for ($this->scope['.$name.'] = $_section'.$cnt.'[\'start\'], $_section'.$cnt.'[\'iteration\'] = 1; '. + '$_section'.$cnt.'[\'iteration\'] <= $_section'.$cnt.'[\'total\']; '. + '$this->scope['.$name.'] += $_section'.$cnt.'[\'step\'], $_section'.$cnt.'[\'iteration\']++) {'."\n"; + $output .= "\t\t".'$_section'.$cnt.'[\'rownum\'] = $_section'.$cnt.'[\'iteration\'];'."\n"; + $output .= "\t\t".'$_section'.$cnt.'[\'index_prev\'] = $this->scope['.$name.'] - $_section'.$cnt.'[\'step\'];'."\n"; + $output .= "\t\t".'$_section'.$cnt.'[\'index_next\'] = $this->scope['.$name.'] + $_section'.$cnt.'[\'step\'];'."\n"; + $output .= "\t\t".'$_section'.$cnt.'[\'first\'] = ($_section'.$cnt.'[\'iteration\'] == 1);'."\n"; + $output .= "\t\t".'$_section'.$cnt.'[\'last\'] = ($_section'.$cnt.'[\'iteration\'] == $_section'.$cnt.'[\'total\']);'."\n"; + + $output .= Dwoo_Compiler::PHP_CLOSE . $content . Dwoo_Compiler::PHP_OPEN; + + $output .= "\n\t}\n} " . Dwoo_Compiler::PHP_CLOSE; + + if (isset($params['hasElse'])) { + $output .= $params['hasElse']; + } + + return $output; + } +} diff --git a/lib/dwoo/plugins/builtin/blocks/smartyinterface.php b/lib/dwoo/plugins/builtin/blocks/smartyinterface.php new file mode 100644 index 0000000..72e5e0c --- /dev/null +++ b/lib/dwoo/plugins/builtin/blocks/smartyinterface.php @@ -0,0 +1,61 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_smartyinterface extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init($__funcname, $__functype, array $rest=array()) {} + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + $params = $compiler->getCompiledParams($params); + $func = $params['__funcname']; + $pluginType = $params['__functype']; + $paramsOut = ''; + if(isset($params['*'])) { + $params = $params['*']; + foreach ($params as $i=>$p) { + $paramsOut .= var_export($i, true).' => '.$p.','; + } + } + + + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $customPlugins = $compiler->getDwoo()->getCustomPlugins(); + $callback = $customPlugins[$func]['callback']; + if (is_array($callback)) { + if (is_object($callback[0])) { + $callback = '$this->customPlugins[\''.$func.'\'][0]->'.$callback[1].'('; + } else { + $callback = ''.$callback[0].'::'.$callback[1].'('; + } + } else { + $callback = $callback.'('; + } + } else { + $callback = 'smarty_block_'.$func.'('; + } + + $curBlock =& $compiler->getCurrentBlock(); + $curBlock['params']['postOut'] = Dwoo_Compiler::PHP_OPEN.' $_block_content = ob_get_clean(); $_block_repeat=false; echo '.$callback.'$_tag_stack[count($_tag_stack)-1], $_block_content, $this, $_block_repeat); } array_pop($_tag_stack);'.Dwoo_Compiler::PHP_CLOSE; + + return Dwoo_Compiler::PHP_OPEN.$prepend.' if (!isset($_tag_stack)){ $_tag_stack = array(); } $_tag_stack[] = array('.$paramsOut.'); $_block_repeat=true; '.$callback.'$_tag_stack[count($_tag_stack)-1], null, $this, $_block_repeat); while ($_block_repeat) { ob_start();'.Dwoo_Compiler::PHP_CLOSE; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + return $content . $params['postOut']; + } +} diff --git a/lib/dwoo/plugins/builtin/blocks/strip.php b/lib/dwoo/plugins/builtin/blocks/strip.php new file mode 100644 index 0000000..988ba85 --- /dev/null +++ b/lib/dwoo/plugins/builtin/blocks/strip.php @@ -0,0 +1,50 @@ + + * * mode : sets the content being stripped, available mode are 'default' or 'js' + * for javascript, which strips the comments to prevent syntax errors + * + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_strip extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init($mode = "default") + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $params = $compiler->getCompiledParams($params); + + $mode = trim($params['mode'], '"\''); + switch ($mode) { + case 'js': + case 'javascript': + $content = preg_replace('#(? + * * wrap : maximum line length + * * wrap_char : the character(s) to use to break the line + * * wrap_cut : if true, the words that are longer than $wrap are cut instead of overflowing + * * indent : amount of $indent_char to insert before every line + * * indent_char : character(s) to insert before every line + * * indent_first : amount of additional $indent_char to insert before the first line of each paragraphs + * * style : some predefined formatting styles that set up every required variables, can be "email" or "html" + * * assign : if set, the formatted text is assigned to that variable instead of being output + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_textformat extends Dwoo_Block_Plugin +{ + protected $wrap; + protected $wrapChar; + protected $wrapCut; + protected $indent; + protected $indChar; + protected $indFirst; + protected $assign; + + public function init($wrap=80, $wrap_char="\r\n", $wrap_cut=false, $indent=0, $indent_char=" ", $indent_first=0, $style="", $assign="") + { + if ($indent_char === 'tab') { + $indent_char = "\t"; + } + + switch($style) { + + case 'email': + $wrap = 72; + $indent_first = 0; + break; + case 'html': + $wrap_char = '
'; + $indent_char = $indent_char == "\t" ? '    ':' '; + break; + + } + + $this->wrap = (int) $wrap; + $this->wrapChar = (string) $wrap_char; + $this->wrapCut = (bool) $wrap_cut; + $this->indent = (int) $indent; + $this->indChar = (string) $indent_char; + $this->indFirst = (int) $indent_first + $this->indent; + $this->assign = (string) $assign; + } + + public function process() + { + // gets paragraphs + $pgs = explode("\n", str_replace(array("\r\n", "\r"), "\n", $this->buffer)); + + while (list($i,) = each($pgs)) { + if (empty($pgs[$i])) { + continue; + } + + // removes line breaks and extensive white space + $pgs[$i] = preg_replace(array('#\s+#', '#^\s*(.+?)\s*$#m'), array(' ', '$1'), str_replace("\n", '', $pgs[$i])); + + // wordwraps + indents lines + $pgs[$i] = str_repeat($this->indChar, $this->indFirst) . + wordwrap( + $pgs[$i], + max($this->wrap - $this->indent, 1), + $this->wrapChar . str_repeat($this->indChar, $this->indent), + $this->wrapCut + ); + } + + if ($this->assign !== '') { + $this->dwoo->assignInScope(implode($this->wrapChar . $this->wrapChar, $pgs), $this->assign); + } else { + return implode($this->wrapChar . $this->wrapChar, $pgs); + } + } +} diff --git a/lib/dwoo/plugins/builtin/blocks/topLevelBlock.php b/lib/dwoo/plugins/builtin/blocks/topLevelBlock.php new file mode 100644 index 0000000..bc706a5 --- /dev/null +++ b/lib/dwoo/plugins/builtin/blocks/topLevelBlock.php @@ -0,0 +1,32 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +final class Dwoo_Plugin_topLevelBlock extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init() + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + return 'ob_start(); /* template body */ '.Dwoo_Compiler::PHP_CLOSE; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + return $content . Dwoo_Compiler::PHP_OPEN.' /* end template body */'."\n".'return $this->buffer . ob_get_clean();'; + } +} diff --git a/lib/dwoo/plugins/builtin/blocks/with.php b/lib/dwoo/plugins/builtin/blocks/with.php new file mode 100644 index 0000000..79b6cc1 --- /dev/null +++ b/lib/dwoo/plugins/builtin/blocks/with.php @@ -0,0 +1,76 @@ + + * * var : the variable name to move into + * + * Example : + * + * instead of the following : + * + * + * {if $long.boring.prefix} + * {$long.boring.prefix.val} - {$long.boring.prefix.secondVal} - {$long.boring.prefix.thirdVal} + * {/if} + * + * + * you can use : + * + * + * {with $long.boring.prefix} + * {$val} - {$secondVal} - {$thirdVal} + * {/with} + * + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_with extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block, Dwoo_IElseable +{ + protected static $cnt=0; + + public function init($var) + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $rparams = $compiler->getRealParams($params); + $cparams = $compiler->getCompiledParams($params); + + $compiler->setScope($rparams['var']); + + + $pre = Dwoo_Compiler::PHP_OPEN. 'if ('.$cparams['var'].')'."\n{\n". + '$_with'.(self::$cnt).' = $this->setScope("'.$rparams['var'].'");'. + "\n/* -- start with output */\n".Dwoo_Compiler::PHP_CLOSE; + + $post = Dwoo_Compiler::PHP_OPEN. "\n/* -- end with output */\n". + '$this->setScope($_with'.(self::$cnt++).', true);'. + "\n}\n".Dwoo_Compiler::PHP_CLOSE; + + if (isset($params['hasElse'])) { + $post .= $params['hasElse']; + } + + return $pre . $content . $post; + } +} diff --git a/lib/dwoo/plugins/builtin/blocks/withelse.php b/lib/dwoo/plugins/builtin/blocks/withelse.php new file mode 100644 index 0000000..43b3c1c --- /dev/null +++ b/lib/dwoo/plugins/builtin/blocks/withelse.php @@ -0,0 +1,43 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_withelse extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init() + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + $with =& $compiler->findBlock('with', true); + + $params['initialized'] = true; + $compiler->injectBlock($type, $params); + + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + if (!isset($params['initialized'])) { + return ''; + } + + $block =& $compiler->getCurrentBlock(); + $block['params']['hasElse'] = Dwoo_Compiler::PHP_OPEN."else {\n".Dwoo_Compiler::PHP_CLOSE . $content . Dwoo_Compiler::PHP_OPEN."\n}".Dwoo_Compiler::PHP_CLOSE; + return ''; + } +} diff --git a/lib/dwoo/plugins/builtin/filters/html_format.php b/lib/dwoo/plugins/builtin/filters/html_format.php new file mode 100644 index 0000000..e9967dc --- /dev/null +++ b/lib/dwoo/plugins/builtin/filters/html_format.php @@ -0,0 +1,175 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Filter_html_format extends Dwoo_Filter +{ + /** + * tab count to auto-indent the source + * + * @var int + */ + protected static $tabCount = -1; + + /** + * stores the additional data (following a tag) of the last call to open/close/singleTag + * + * @var string + */ + protected static $lastCallAdd = ''; + + /** + * formats the input using the singleTag/closeTag/openTag functions + * + * It is auto indenting the whole code, excluding + + '; +} + + + + +/** + * A ReCaptchaResponse is returned from recaptcha_check_answer() + */ +class ReCaptchaResponse { + var $is_valid; + var $error; +} + + +/** + * Calls an HTTP POST function to verify if the user's guess was correct + * @param string $privkey + * @param string $remoteip + * @param string $challenge + * @param string $response + * @param array $extra_params an array of extra variables to post to the server + * @return ReCaptchaResponse + */ +function recaptcha_check_answer ($privkey, $remoteip, $challenge, $response, $extra_params = array()) +{ + if ($privkey == null || $privkey == '') { + die ("To use reCAPTCHA you must get an API key from https://www.google.com/recaptcha/admin/create"); + } + + if ($remoteip == null || $remoteip == '') { + die ("For security reasons, you must pass the remote ip to reCAPTCHA"); + } + + + + //discard spam submissions + if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0) { + $recaptcha_response = new ReCaptchaResponse(); + $recaptcha_response->is_valid = false; + $recaptcha_response->error = 'incorrect-captcha-sol'; + return $recaptcha_response; + } + + $response = _recaptcha_http_post (RECAPTCHA_VERIFY_SERVER, "/recaptcha/api/verify", + array ( + 'privatekey' => $privkey, + 'remoteip' => $remoteip, + 'challenge' => $challenge, + 'response' => $response + ) + $extra_params + ); + + $answers = explode ("\n", $response [1]); + $recaptcha_response = new ReCaptchaResponse(); + + if (trim ($answers [0]) == 'true') { + $recaptcha_response->is_valid = true; + } + else { + $recaptcha_response->is_valid = false; + $recaptcha_response->error = $answers [1]; + } + return $recaptcha_response; + +} + +/** + * gets a URL where the user can sign up for reCAPTCHA. If your application + * has a configuration page where you enter a key, you should provide a link + * using this function. + * @param string $domain The domain where the page is hosted + * @param string $appname The name of your application + */ +function recaptcha_get_signup_url ($domain = null, $appname = null) { + return "https://www.google.com/recaptcha/admin/create?" . _recaptcha_qsencode (array ('domains' => $domain, 'app' => $appname)); +} + +function _recaptcha_aes_pad($val) { + $block_size = 16; + $numpad = $block_size - (strlen ($val) % $block_size); + return str_pad($val, strlen ($val) + $numpad, chr($numpad)); +} + +/* Mailhide related code */ + +function _recaptcha_aes_encrypt($val,$ky) { + if (! function_exists ("mcrypt_encrypt")) { + die ("To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed."); + } + $mode=MCRYPT_MODE_CBC; + $enc=MCRYPT_RIJNDAEL_128; + $val=_recaptcha_aes_pad($val); + return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); +} + + +function _recaptcha_mailhide_urlbase64 ($x) { + return strtr(base64_encode ($x), '+/', '-_'); +} + +/* gets the reCAPTCHA Mailhide url for a given email, public key and private key */ +function recaptcha_mailhide_url($pubkey, $privkey, $email) { + if ($pubkey == '' || $pubkey == null || $privkey == "" || $privkey == null) { + die ("To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " . + "you can do so at http://www.google.com/recaptcha/mailhide/apikey"); + } + + + $ky = pack('H*', $privkey); + $cryptmail = _recaptcha_aes_encrypt ($email, $ky); + + return "http://www.google.com/recaptcha/mailhide/d?k=" . $pubkey . "&c=" . _recaptcha_mailhide_urlbase64 ($cryptmail); +} + +/** + * gets the parts of the email to expose to the user. + * eg, given johndoe@example,com return ["john", "example.com"]. + * the email is then displayed as john...@example.com + */ +function _recaptcha_mailhide_email_parts ($email) { + $arr = preg_split("/@/", $email ); + + if (strlen ($arr[0]) <= 4) { + $arr[0] = substr ($arr[0], 0, 1); + } else if (strlen ($arr[0]) <= 6) { + $arr[0] = substr ($arr[0], 0, 3); + } else { + $arr[0] = substr ($arr[0], 0, 4); + } + return $arr; +} + +/** + * Gets html to display an email address given a public an private key. + * to get a key, go to: + * + * http://www.google.com/recaptcha/mailhide/apikey + */ +function recaptcha_mailhide_html($pubkey, $privkey, $email) { + $emailparts = _recaptcha_mailhide_email_parts ($email); + $url = recaptcha_mailhide_url ($pubkey, $privkey, $email); + + return htmlentities($emailparts[0]) . "...@" . htmlentities ($emailparts [1]); + +} + + +?> diff --git a/spainter_all.jar b/spainter_all.jar new file mode 100644 index 0000000..3bc2cd2 Binary files /dev/null and b/spainter_all.jar differ diff --git a/spam.txt b/spam.txt new file mode 100644 index 0000000..e69de29 diff --git a/threadwatch.php b/threadwatch.php new file mode 100644 index 0000000..80414be --- /dev/null +++ b/threadwatch.php @@ -0,0 +1,149 @@ +GetAll("SELECT HIGH_PRIORITY `id`, `name` FROM `" . KU_DBPREFIX . "boards` WHERE `name` = " . $tc_db->qstr($_GET['board']) . ""); + $boardid = $results[0][0]; + $boardname = $results[0][1]; +} +if (isset($_GET['do'])) { + switch($_GET['do']) { + case 'addthread': + $viewing_thread_is_watched = $tc_db->GetOne("SELECT COUNT(*) FROM `" . KU_DBPREFIX . "watchedthreads` WHERE `ip` = '" . $_SERVER['REMOTE_ADDR'] . "' AND `board` = " . $tc_db->qstr($_GET['board']) . " AND `threadid` = " . $tc_db->qstr($_GET['threadid']) . ""); + if ($viewing_thread_is_watched == 0) { + $newestreplyid = $tc_db->GetOne('SELECT `id` FROM `'.KU_DBPREFIX.'posts` WHERE `boardid` = ' . $boardid . ' AND `IS_DELETED` = 0 AND `parentid` = '.$tc_db->qstr($_GET['threadid']).' ORDER BY `id` DESC LIMIT 1'); + $newestreplyid = max(0, $newestreplyid); + + $tc_db->Execute("INSERT INTO `" . KU_DBPREFIX . "watchedthreads` ( `threadid` , `board` , `ip` , `lastsawreplyid` ) VALUES ( " . $tc_db->qstr($_GET['threadid']) . " , " . $tc_db->qstr($_GET['board']) . " , '" . $_SERVER['REMOTE_ADDR'] . "' , " . $newestreplyid . " )"); + + if (KU_APC) apc_delete('watchedthreads|' . $_SERVER['REMOTE_ADDR'] . '|' . $_GET['board']); + } + break; + + case 'removethread': + $viewing_thread_is_watched = $tc_db->GetOne("SELECT COUNT(*) FROM `" . KU_DBPREFIX . "watchedthreads` WHERE `ip` = '" . $_SERVER['REMOTE_ADDR'] . "' AND `board` = " . $tc_db->qstr($_GET['board']) . " AND `threadid` = " . $tc_db->qstr($_GET['threadid']) . ""); + if ($viewing_thread_is_watched > 0) { + $tc_db->Execute("DELETE FROM `" . KU_DBPREFIX . "watchedthreads` WHERE `ip` = '" . $_SERVER['REMOTE_ADDR'] . "' AND `board` = " . $tc_db->qstr($_GET['board']) . " AND `threadid` = " . $tc_db->qstr($_GET['threadid']) . ""); + + if (KU_APC) apc_delete('watchedthreads|' . $_SERVER['REMOTE_ADDR'] . '|' . $_GET['board']); + } + break; + + default: + $output .= 'Invalid operation'; + } +} else { + /* If the user is sending this request while viewing a thread, check if it is a thread they are watching, and if so, update it to show they have viewed all current replies */ + if ($_GET['threadid'] > 0) { + $viewing_thread_is_watched = $tc_db->GetOne("SELECT COUNT(*) FROM `" . KU_DBPREFIX . "watchedthreads` WHERE `ip` = '" . $_SERVER['REMOTE_ADDR'] . "' AND `board` = " . $tc_db->qstr($_GET['board']) . " AND `threadid` = " . $tc_db->qstr($_GET['threadid']) . ""); + if ($viewing_thread_is_watched > 0) { + $newestreplyid = $tc_db->GetOne('SELECT `id` FROM `'.KU_DBPREFIX.'posts` WHERE `boardid` = ' . $boardid . ' AND `IS_DELETED` = 0 AND `parentid` = '.$tc_db->qstr($_GET['threadid']).' ORDER BY `id` DESC LIMIT 1'); + $newestreplyid = max(0, $newestreplyid); + + $tc_db->Execute("UPDATE `" . KU_DBPREFIX . "watchedthreads` SET `lastsawreplyid` = " . $newestreplyid . " WHERE `ip` = '" . $_SERVER['REMOTE_ADDR'] . "' AND `board` = " . $tc_db->qstr($_GET['board']) . " AND `threadid` = " . $tc_db->qstr($_GET['threadid']) . ""); + + if (KU_APC) apc_delete('watchedthreads|' . $_SERVER['REMOTE_ADDR'] . '|' . $_GET['board']); + } + } + + $cached = false; + if (KU_APC) { + $cache_threadwatch = apc_fetch('watchedthreads|' . $_SERVER['REMOTE_ADDR'] . '|' . $_GET['board']); + if ($cache_threadwatch !== false) { + $cached = true; + $output .= $cache_threadwatch; + } + } + + if (!$cached) { + $watched_threads = $tc_db->GetAll("SELECT `threadid` , `lastsawreplyid` FROM `" . KU_DBPREFIX . "watchedthreads` WHERE `ip` = '" . $_SERVER['REMOTE_ADDR'] . "' AND `board` = " . $tc_db->qstr($_GET['board']) . " ORDER BY `lastsawreplyid` DESC"); + if (count($watched_threads) > 0) { + foreach ($watched_threads as $watched_thread) { + $threadinfo = $tc_db->GetAll('SELECT `subject` , `name` , `tripcode` FROM `'.KU_DBPREFIX.'posts` WHERE `boardid` = ' . $boardid . ' AND `IS_DELETED` = 0 AND `id` = ' . $watched_thread['threadid'] . ' LIMIT 1'); + + $threadinfo = $threadinfo[0]; + + $output .= '' . $watched_thread['threadid'] . ' - '; + + if ($threadinfo['subject'] != '') { + $output .= '' . $threadinfo['subject'] . ' - '; + } + + $output .= ''; + + + if ($threadinfo['name'] == '' && $threadinfo['tripcode'] == '') { + $output .= "Anonymous"; + } else if ( $threadinfo['name'] == '' && $threadinfo['tripcode'] != '') { + /* Just display the tripcode, no added html */ + } else { + $output .= $threadinfo['name']; + } + + $output .= ''; + + if ($tripcode != '') { + $output .= '!' . $threadinfo['tripcode'] . ''; + } + + + $numnewreplies = $tc_db->GetOne('SELECT COUNT(*) FROM `'.KU_DBPREFIX.'posts` WHERE `boardid` = ' . $boardid . ' AND `IS_DELETED` = 0 AND `parentid` = ' . $watched_thread['threadid'] . ' AND `id` > ' . $watched_thread['lastsawreplyid'] . ' LIMIT 1'); + + if ($numnewreplies > 0) { + $output .= '' . $numnewreplies . ' new repl'; + if ($numnewreplies != 1) { + $output .= 'ies'; + } else { + $output .= 'y'; + } + $output .= ''; + } else { + $output .= ' 0'; + } + + $output .= ' X
'; + } + } else { + $output .= 'None.
'; + } + + if (KU_APC) apc_store('watchedthreads|' . $_SERVER['REMOTE_ADDR'] . '|' . $_GET['board'], $output, 600); + } +} + +echo $output; + +?> \ No newline at end of file diff --git a/tz.php b/tz.php new file mode 100644 index 0000000..894b381 --- /dev/null +++ b/tz.php @@ -0,0 +1,1482 @@ +=0; $l--) + { + $allsize1[$l]=floor($size/pow(1024,$l)); + $allsize[$l]=$allsize1[$l]-$allsize1[$l+1]*1024; + } + + $len=count($allsize); + + for($j = $len-1; $j >=0; $j--) + { + $fsize=$fsize.$allsize[$j].$danwei[$j]; + } + return $fsize; +} + +function valid_email($str) +{ + return ( ! preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $str)) ? FALSE : TRUE; +} + +//检测PHP设置参数 +function show($varName) +{ + switch($result = get_cfg_var($varName)) + { + case 0: + return '×'; + break; + + case 1: + return ''; + break; + + default: + return $result; + break; + } +} + +//保留服务器性能测试结果 +$valInt = isset($_POST['pInt']) ? $_POST['pInt'] : "未测试"; +$valFloat = isset($_POST['pFloat']) ? $_POST['pFloat'] : "未测试"; +$valIo = isset($_POST['pIo']) ? $_POST['pIo'] : "未测试"; + +if ($_GET['act'] == "phpinfo") +{ + phpinfo(); + exit(); +} +elseif($_POST['act'] == "整型测试") +{ + $valInt = test_int(); +} +elseif($_POST['act'] == "浮点测试") +{ + $valFloat = test_float(); +} +elseif($_POST['act'] == "IO测试") +{ + $valIo = test_io(); +} +//网速测试-开始 +elseif($_POST['act']=="开始测试") +{ +?> + + "; + } + ?> + +"; + Echo "这里显示系统所支持的所有函数,和自定义函数\n"; + print_r($arr); + echo ""; + exit(); +}elseif($_GET['act'] == "disable_functions") +{ + $disFuns=get_cfg_var("disable_functions"); + if(empty($disFuns)) + { + $arr = '×'; + } + else + { + $arr = $disFuns; + } + Function php() + { + } + echo "
";
+	Echo "这里显示系统被禁用的函数\n";
+	print_r($arr);
+	echo "
"; + exit(); +} + +//MySQL检测 +if ($_POST['act'] == 'MySQL检测') +{ + $host = isset($_POST['host']) ? trim($_POST['host']) : ''; + $port = isset($_POST['port']) ? (int) $_POST['port'] : ''; + $login = isset($_POST['login']) ? trim($_POST['login']) : ''; + $password = isset($_POST['password']) ? trim($_POST['password']) : ''; + $host = preg_match('~[^a-z0-9\-\.]+~i', $host) ? '' : $host; + $port = intval($port) ? intval($port) : ''; + $login = preg_match('~[^a-z0-9\_\-]+~i', $login) ? '' : htmlspecialchars($login); + $password = is_string($password) ? htmlspecialchars($password) : ''; +} +elseif ($_POST['act'] == '函数检测') +{ + $funRe = "函数".$_POST['funName']."支持状况检测结果:".isfun1($_POST['funName']); +} +elseif ($_POST['act'] == '邮件检测') +{ + $mailRe = "邮件发送检测结果:发送"; + if($_SERVER['SERVER_PORT']==80){$mailContent = "http://".$_SERVER['SERVER_NAME'].($_SERVER['PHP_SELF'] ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']);} + else{$mailContent = "http://".$_SERVER['SERVER_NAME'].":".$_SERVER['SERVER_PORT'].($_SERVER['PHP_SELF'] ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']);} + $mailRe .= (false !== @mail($_POST["mailAdd"], $mailContent, "This is a test mail!")) ? "完成":"失败"; +} + +//网络速度测试 +if(isset($_POST['speed'])) +{ + $speed=round(100/($_POST['speed']/1000),2); +} +elseif($_GET['speed']=="0") +{ + $speed=6666.67; +} +elseif(isset($_GET['speed']) and $_GET['speed']>0) +{ + $speed=round(100/($_GET['speed']/1000),2); //下载速度:$speed kb/s +} +else +{ + $speed=" 未探测 "; +} + + +// 检测函数支持 +function isfun($funName = '') +{ + if (!$funName || trim($funName) == '' || preg_match('~[^a-z0-9\_]+~i', $funName, $tmp)) return '错误'; + return (false !== function_exists($funName)) ? '' : '×'; +} +function isfun1($funName = '') +{ + if (!$funName || trim($funName) == '' || preg_match('~[^a-z0-9\_]+~i', $funName, $tmp)) return '错误'; + return (false !== function_exists($funName)) ? '√' : '×'; +} + +//整数运算能力测试 +function test_int() +{ + $timeStart = gettimeofday(); + for($i = 0; $i < 3000000; $i++) + { + $t = 1+1; + } + $timeEnd = gettimeofday(); + $time = ($timeEnd["usec"]-$timeStart["usec"])/1000000+$timeEnd["sec"]-$timeStart["sec"]; + $time = round($time, 3)."秒"; + return $time; +} + +//浮点运算能力测试 +function test_float() +{ + //得到圆周率值 + $t = pi(); + $timeStart = gettimeofday(); + + for($i = 0; $i < 3000000; $i++) + { + //开平方 + sqrt($t); + } + + $timeEnd = gettimeofday(); + $time = ($timeEnd["usec"]-$timeStart["usec"])/1000000+$timeEnd["sec"]-$timeStart["sec"]; + $time = round($time, 3)."秒"; + return $time; +} + +//IO能力测试 +function test_io() +{ + $fp = @fopen(PHPSELF, "r"); + $timeStart = gettimeofday(); + for($i = 0; $i < 10000; $i++) + { + @fread($fp, 10240); + @rewind($fp); + } + $timeEnd = gettimeofday(); + @fclose($fp); + $time = ($timeEnd["usec"]-$timeStart["usec"])/1000000+$timeEnd["sec"]-$timeStart["sec"]; + $time = round($time, 3)."秒"; + return($time); +} + +function GetCoreInformation() {$data = file('/proc/stat');$cores = array();foreach( $data as $line ) {if( preg_match('/^cpu[0-9]/', $line) ){$info = explode(' ', $line);$cores[]=array('user'=>$info[1],'nice'=>$info[2],'sys' => $info[3],'idle'=>$info[4],'iowait'=>$info[5],'irq' => $info[6],'softirq' => $info[7]);}}return $cores;} +function GetCpuPercentages($stat1, $stat2) {if(count($stat1)!==count($stat2)){return;}$cpus=array();for( $i = 0, $l = count($stat1); $i < $l; $i++) { $dif = array(); $dif['user'] = $stat2[$i]['user'] - $stat1[$i]['user'];$dif['nice'] = $stat2[$i]['nice'] - $stat1[$i]['nice']; $dif['sys'] = $stat2[$i]['sys'] - $stat1[$i]['sys'];$dif['idle'] = $stat2[$i]['idle'] - $stat1[$i]['idle'];$dif['iowait'] = $stat2[$i]['iowait'] - $stat1[$i]['iowait'];$dif['irq'] = $stat2[$i]['irq'] - $stat1[$i]['irq'];$dif['softirq'] = $stat2[$i]['softirq'] - $stat1[$i]['softirq'];$total = array_sum($dif);$cpu = array();foreach($dif as $x=>$y) $cpu[$x] = round($y / $total * 100, 2);$cpus['cpu' . $i] = $cpu;}return $cpus;} +$stat1 = GetCoreInformation();sleep(1);$stat2 = GetCoreInformation();$data = GetCpuPercentages($stat1, $stat2); +$cpu_show = $data['cpu0']['user']."%us, ".$data['cpu0']['sys']."%sy, ".$data['cpu0']['nice']."%ni, ".$data['cpu0']['idle']."%id, ".$data['cpu0']['iowait']."%wa, ".$data['cpu0']['irq']."%irq, ".$data['cpu0']['softirq']."%softirq"; +function makeImageUrl($title, $data) {$api='http://api.yahei.net/tz/cpu_show.php?id=';$url.=$data['user'].',';$url.=$data['nice'].',';$url.=$data['sys'].',';$url.=$data['idle'].',';$url.=$data['iowait'];$url.='&chdl=User|Nice|Sys|Idle|Iowait&chdlp=b&chl=';$url.=$data['user'].'%25|';$url.=$data['nice'].'%25|';$url.=$data['sys'].'%25|';$url.=$data['idle'].'%25|';$url.=$data['iowait'].'%25';$url.='&chtt=Core+'.$title;return $api.base64_encode($url);} +if($_GET['act'] == "cpu_percentage"){echo "
图片加载慢,请耐心等待!

";foreach( $data as $k => $v ) {echo '';}echo "
";exit();} + +// 根据不同系统取得CPU相关信息 +switch(PHP_OS) +{ + case "Linux": + $sysReShow = (false !== ($sysInfo = sys_linux()))?"show":"none"; + break; + + case "FreeBSD": + $sysReShow = (false !== ($sysInfo = sys_freebsd()))?"show":"none"; + break; +/* + case "WINNT": + $sysReShow = (false !== ($sysInfo = sys_windows()))?"show":"none"; + break; +*/ + default: + break; +} + +//linux系统探测 +function sys_linux() +{ + // CPU + if (false === ($str = @file("/proc/cpuinfo"))) return false; + $str = implode("", $str); + @preg_match_all("/model\s+name\s{0,}\:+\s{0,}([\w\s\)\(\@.-]+)([\r\n]+)/s", $str, $model); + @preg_match_all("/cpu\s+MHz\s{0,}\:+\s{0,}([\d\.]+)[\r\n]+/", $str, $mhz); + @preg_match_all("/cache\s+size\s{0,}\:+\s{0,}([\d\.]+\s{0,}[A-Z]+[\r\n]+)/", $str, $cache); + @preg_match_all("/bogomips\s{0,}\:+\s{0,}([\d\.]+)[\r\n]+/", $str, $bogomips); + if (false !== is_array($model[1])) + { + $res['cpu']['num'] = sizeof($model[1]); + /* + for($i = 0; $i < $res['cpu']['num']; $i++) + { + $res['cpu']['model'][] = $model[1][$i].' ('.$mhz[1][$i].')'; + $res['cpu']['mhz'][] = $mhz[1][$i]; + $res['cpu']['cache'][] = $cache[1][$i]; + $res['cpu']['bogomips'][] = $bogomips[1][$i]; + }*/ + if($res['cpu']['num']==1) + $x1 = ''; + else + $x1 = ' ×'.$res['cpu']['num']; + $mhz[1][0] = ' | 频率:'.$mhz[1][0]; + $cache[1][0] = ' | 二级缓存:'.$cache[1][0]; + $bogomips[1][0] = ' | Bogomips:'.$bogomips[1][0]; + $res['cpu']['model'][] = $model[1][0].$mhz[1][0].$cache[1][0].$bogomips[1][0].$x1; + if (false !== is_array($res['cpu']['model'])) $res['cpu']['model'] = implode("
", $res['cpu']['model']); + if (false !== is_array($res['cpu']['mhz'])) $res['cpu']['mhz'] = implode("
", $res['cpu']['mhz']); + if (false !== is_array($res['cpu']['cache'])) $res['cpu']['cache'] = implode("
", $res['cpu']['cache']); + if (false !== is_array($res['cpu']['bogomips'])) $res['cpu']['bogomips'] = implode("
", $res['cpu']['bogomips']); + } + + // NETWORK + + // UPTIME + if (false === ($str = @file("/proc/uptime"))) return false; + $str = explode(" ", implode("", $str)); + $str = trim($str[0]); + $min = $str / 60; + $hours = $min / 60; + $days = floor($hours / 24); + $hours = floor($hours - ($days * 24)); + $min = floor($min - ($days * 60 * 24) - ($hours * 60)); + if ($days !== 0) $res['uptime'] = $days."天"; + if ($hours !== 0) $res['uptime'] .= $hours."小时"; + $res['uptime'] .= $min."分钟"; + + // MEMORY + if (false === ($str = @file("/proc/meminfo"))) return false; + $str = implode("", $str); + preg_match_all("/MemTotal\s{0,}\:+\s{0,}([\d\.]+).+?MemFree\s{0,}\:+\s{0,}([\d\.]+).+?Cached\s{0,}\:+\s{0,}([\d\.]+).+?SwapTotal\s{0,}\:+\s{0,}([\d\.]+).+?SwapFree\s{0,}\:+\s{0,}([\d\.]+)/s", $str, $buf); + preg_match_all("/Buffers\s{0,}\:+\s{0,}([\d\.]+)/s", $str, $buffers); + + $res['memTotal'] = round($buf[1][0]/1024, 2); + $res['memFree'] = round($buf[2][0]/1024, 2); + $res['memBuffers'] = round($buffers[1][0]/1024, 2); + $res['memCached'] = round($buf[3][0]/1024, 2); + $res['memUsed'] = $res['memTotal']-$res['memFree']; + $res['memPercent'] = (floatval($res['memTotal'])!=0)?round($res['memUsed']/$res['memTotal']*100,2):0; + + $res['memRealUsed'] = $res['memTotal'] - $res['memFree'] - $res['memCached'] - $res['memBuffers']; //真实内存使用 + $res['memRealFree'] = $res['memTotal'] - $res['memRealUsed']; //真实空闲 + $res['memRealPercent'] = (floatval($res['memTotal'])!=0)?round($res['memRealUsed']/$res['memTotal']*100,2):0; //真实内存使用率 + + $res['memCachedPercent'] = (floatval($res['memCached'])!=0)?round($res['memCached']/$res['memTotal']*100,2):0; //Cached内存使用率 + + $res['swapTotal'] = round($buf[4][0]/1024, 2); + $res['swapFree'] = round($buf[5][0]/1024, 2); + $res['swapUsed'] = round($res['swapTotal']-$res['swapFree'], 2); + $res['swapPercent'] = (floatval($res['swapTotal'])!=0)?round($res['swapUsed']/$res['swapTotal']*100,2):0; + + // LOAD AVG + if (false === ($str = @file("/proc/loadavg"))) return false; + $str = explode(" ", implode("", $str)); + $str = array_chunk($str, 4); + $res['loadAvg'] = implode(" ", $str[0]); + + return $res; +} + +//FreeBSD系统探测 +function sys_freebsd() +{ + //CPU + if (false === ($res['cpu']['num'] = get_key("hw.ncpu"))) return false; + $res['cpu']['model'] = get_key("hw.model"); + //LOAD AVG + if (false === ($res['loadAvg'] = get_key("vm.loadavg"))) return false; + //UPTIME + if (false === ($buf = get_key("kern.boottime"))) return false; + $buf = explode(' ', $buf); + $sys_ticks = time() - intval($buf[3]); + $min = $sys_ticks / 60; + $hours = $min / 60; + $days = floor($hours / 24); + $hours = floor($hours - ($days * 24)); + $min = floor($min - ($days * 60 * 24) - ($hours * 60)); + if ($days !== 0) $res['uptime'] = $days."天"; + if ($hours !== 0) $res['uptime'] .= $hours."小时"; + $res['uptime'] .= $min."分钟"; + //MEMORY + if (false === ($buf = get_key("hw.physmem"))) return false; + $res['memTotal'] = round($buf/1024/1024, 2); + + $str = get_key("vm.vmtotal"); + preg_match_all("/\nVirtual Memory[\:\s]*\(Total[\:\s]*([\d]+)K[\,\s]*Active[\:\s]*([\d]+)K\)\n/i", $str, $buff, PREG_SET_ORDER); + preg_match_all("/\nReal Memory[\:\s]*\(Total[\:\s]*([\d]+)K[\,\s]*Active[\:\s]*([\d]+)K\)\n/i", $str, $buf, PREG_SET_ORDER); + + $res['memRealUsed'] = round($buf[0][2]/1024, 2); + $res['memCached'] = round($buff[0][2]/1024, 2); + $res['memUsed'] = round($buf[0][1]/1024, 2) + $res['memCached']; + $res['memFree'] = $res['memTotal'] - $res['memUsed']; + $res['memPercent'] = (floatval($res['memTotal'])!=0)?round($res['memUsed']/$res['memTotal']*100,2):0; + + $res['memRealPercent'] = (floatval($res['memTotal'])!=0)?round($res['memRealUsed']/$res['memTotal']*100,2):0; + + return $res; +} + +//取得参数值 FreeBSD +function get_key($keyName) +{ + return do_command('sysctl', "-n $keyName"); +} + +//确定执行文件位置 FreeBSD +function find_command($commandName) +{ + $path = array('/bin', '/sbin', '/usr/bin', '/usr/sbin', '/usr/local/bin', '/usr/local/sbin'); + foreach($path as $p) + { + if (@is_executable("$p/$commandName")) return "$p/$commandName"; + } + return false; +} + +//执行系统命令 FreeBSD +function do_command($commandName, $args) +{ + $buffer = ""; + if (false === ($command = find_command($commandName))) return false; + if ($fp = @popen("$command $args", 'r')) + { + while (!@feof($fp)) + { + $buffer .= @fgets($fp, 4096); + } + return trim($buffer); + } + return false; +} + +//windows系统探测 +function sys_windows() +{ + if (PHP_VERSION >= 5) + { + $objLocator = new COM("WbemScripting.SWbemLocator"); + $wmi = $objLocator->ConnectServer(); + $prop = $wmi->get("Win32_PnPEntity"); + } + else + { + return false; + } + + //CPU + $cpuinfo = GetWMI($wmi,"Win32_Processor", array("Name","L2CacheSize","NumberOfCores")); + $res['cpu']['num'] = $cpuinfo[0]['NumberOfCores']; + if (null == $res['cpu']['num']) + { + $res['cpu']['num'] = 1; + }/* + for ($i=0;$i<$res['cpu']['num'];$i++) + { + $res['cpu']['model'] .= $cpuinfo[0]['Name']."
"; + $res['cpu']['cache'] .= $cpuinfo[0]['L2CacheSize']."
"; + }*/ + $cpuinfo[0]['L2CacheSize'] = ' ('.$cpuinfo[0]['L2CacheSize'].')'; + if($res['cpu']['num']==1) + $x1 = ''; + else + $x1 = ' ×'.$res['cpu']['num']; + $res['cpu']['model'] = $cpuinfo[0]['Name'].$cpuinfo[0]['L2CacheSize'].$x1; + // SYSINFO + $sysinfo = GetWMI($wmi,"Win32_OperatingSystem", array('LastBootUpTime','TotalVisibleMemorySize','FreePhysicalMemory','Caption','CSDVersion','SerialNumber','InstallDate')); + $sysinfo[0]['Caption']=iconv('GBK', 'UTF-8',$sysinfo[0]['Caption']); + $sysinfo[0]['CSDVersion']=iconv('GBK', 'UTF-8',$sysinfo[0]['CSDVersion']); + $res['win_n'] = $sysinfo[0]['Caption']." ".$sysinfo[0]['CSDVersion']." 序列号:{$sysinfo[0]['SerialNumber']} 于".date('Y年m月d日H:i:s',strtotime(substr($sysinfo[0]['InstallDate'],0,14)))."安装"; + //UPTIME + $res['uptime'] = $sysinfo[0]['LastBootUpTime']; + + $sys_ticks = 3600*8 + time() - strtotime(substr($res['uptime'],0,14)); + $min = $sys_ticks / 60; + $hours = $min / 60; + $days = floor($hours / 24); + $hours = floor($hours - ($days * 24)); + $min = floor($min - ($days * 60 * 24) - ($hours * 60)); + if ($days !== 0) $res['uptime'] = $days."天"; + if ($hours !== 0) $res['uptime'] .= $hours."小时"; + $res['uptime'] .= $min."分钟"; + + //MEMORY + $res['memTotal'] = round($sysinfo[0]['TotalVisibleMemorySize']/1024,2); + $res['memFree'] = round($sysinfo[0]['FreePhysicalMemory']/1024,2); + $res['memUsed'] = $res['memTotal']-$res['memFree']; //上面两行已经除以1024,这行不用再除了 + $res['memPercent'] = round($res['memUsed'] / $res['memTotal']*100,2); + + $swapinfo = GetWMI($wmi,"Win32_PageFileUsage", array('AllocatedBaseSize','CurrentUsage')); + + // LoadPercentage + $loadinfo = GetWMI($wmi,"Win32_Processor", array("LoadPercentage")); + $res['loadAvg'] = $loadinfo[0]['LoadPercentage']; + + return $res; +} + +function GetWMI($wmi,$strClass, $strValue = array()) +{ + $arrData = array(); + + $objWEBM = $wmi->Get($strClass); + $arrProp = $objWEBM->Properties_; + $arrWEBMCol = $objWEBM->Instances_(); + foreach($arrWEBMCol as $objItem) + { + @reset($arrProp); + $arrInstance = array(); + foreach($arrProp as $propItem) + { + eval("\$value = \$objItem->" . $propItem->Name . ";"); + if (empty($strValue)) + { + $arrInstance[$propItem->Name] = trim($value); + } + else + { + if (in_array($propItem->Name, $strValue)) + { + $arrInstance[$propItem->Name] = trim($value); + } + } + } + $arrData[] = $arrInstance; + } + return $arrData; +} + +//比例条 +function bar($percent) +{ +?> +
 
+"$du",'freeSpace'=>"$df",'hdPercent'=>"$hdPercent",'barhdPercent'=>"$hdPercent%",'TotalMemory'=>"$mt",'UsedMemory'=>"$mu",'FreeMemory'=>"$mf",'CachedMemory'=>"$mc",'Buffers'=>"$mb",'TotalSwap'=>"$st",'swapUsed'=>"$su",'swapFree'=>"$sf",'loadAvg'=>"$load",'uptime'=>"$uptime",'freetime'=>"$freetime",'bjtime'=>"$bjtime",'stime'=>"$stime",'memRealPercent'=>"$memRealPercent",'memRealUsed'=>"$memRealUsed",'memRealFree'=>"$memRealFree",'memPercent'=>"$memPercent%",'memCachedPercent'=>"$memCachedPercent",'barmemCachedPercent'=>"$memCachedPercent%",'swapPercent'=>"$swapPercent",'barmemRealPercent'=>"$memRealPercent%",'barswapPercent'=>"$swapPercent%",'NetOut2'=>"$NetOut[2]",'NetOut3'=>"$NetOut[3]",'NetOut4'=>"$NetOut[4]",'NetOut5'=>"$NetOut[5]",'NetOut6'=>"$NetOut[6]",'NetOut7'=>"$NetOut[7]",'NetOut8'=>"$NetOut[8]",'NetOut9'=>"$NetOut[9]",'NetOut10'=>"$NetOut[10]",'NetInput2'=>"$NetInput[2]",'NetInput3'=>"$NetInput[3]",'NetInput4'=>"$NetInput[4]",'NetInput5'=>"$NetInput[5]",'NetInput6'=>"$NetInput[6]",'NetInput7'=>"$NetInput[7]",'NetInput8'=>"$NetInput[8]",'NetInput9'=>"$NetInput[9]",'NetInput10'=>"$NetInput[10]",'NetOutSpeed2'=>"$NetOutSpeed[2]",'NetOutSpeed3'=>"$NetOutSpeed[3]",'NetOutSpeed4'=>"$NetOutSpeed[4]",'NetOutSpeed5'=>"$NetOutSpeed[5]",'NetInputSpeed2'=>"$NetInputSpeed[2]",'NetInputSpeed3'=>"$NetInputSpeed[3]",'NetInputSpeed4'=>"$NetInputSpeed[4]",'NetInputSpeed5'=>"$NetInputSpeed[5]"); + $jarr=json_encode($arr); + $_GET['callback'] = htmlspecialchars($_GET['callback']); + echo $_GET['callback'],'(',$jarr,')'; + exit; +} +?> + + + +<?php echo $title.$version; ?> + + + + + + + + + +
+ + + + + + + + + + + + + + + +
PHP参数组件支持第三方组件数据库支持性能检测网速检测MySQL检测函数检测邮件检测探针下载
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
服务器参数
服务器域名/IP地址 - ()  你的IP地址是:
服务器标识
服务器操作系统  内核版本:服务器解译引擎
服务器语言服务器端口
服务器主机名绝对路径
管理员邮箱探针路径
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
服务器实时数据
服务器当前时间服务器已运行时间
CPU型号 [核]
CPU使用状况查看图表";}else{echo "暂时只支持Linux系统";}?> +
硬盘使用状况 + 总空间  G, + 已用  G, + 空闲  G, + 使用率 % +
 
+
内存使用状况 + + 物理内存:共 + + , 已用 + + , 空闲 + + , 使用率 + +
 
+0) +{ +?> + Cache化内存为 + , 使用率 + + % | Buffers缓冲为 +
 
+ + 真实内存使用 + + , 真实内存空闲 + + , 使用率 + + % +
 
+0) +{ +?> + SWAP区:共 + + , 已使用 + + , 空闲 + + , 使用率 + + % +
 
+ + +
系统平均负载
+ + + + + + + + + + + + + + + +
网络使用状况
: 入网: 实时: 0B/s出网: 实时: 0B/s
+ + + + + + + + + +
PHP已编译模块检测
+$value) { + if ($key!=0 && $key%13==0) { + echo '
'; + } + echo "$value  "; +} +?>
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PHP相关参数
PHP信息(phpinfo): + + ×' :"PHPINFO";?> + PHP版本(php_version):
PHP运行方式:脚本占用最大内存(memory_limit):
PHP安全模式(safe_mode):POST方法提交最大限制(post_max_size):
上传文件最大限制(upload_max_filesize):浮点型数据显示的有效位数(precision):
脚本超时时间(max_execution_time):socket超时时间(default_socket_timeout):
PHP页面根目录(doc_root):用户根目录(user_dir):
dl()函数(enable_dl):指定包含文件目录(include_path):
显示错误信息(display_errors):自定义全局变量(register_globals):
数据反斜杠转义(magic_quotes_gpc):"<?...?>"短标签(short_open_tag):
"<% %>"ASP风格标记(asp_tags):忽略重复错误信息(ignore_repeated_errors):
忽略重复的错误源(ignore_repeated_source):报告内存泄漏(report_memleaks):
自动字符串转义(magic_quotes_gpc):外部字符串自动转义(magic_quotes_runtime):
打开远程文件(allow_url_fopen):声明argv和argc变量(register_argc_argv):
Cookie 支持:√' : '×';?>拼写检查(ASpell Library):
高精度数学运算(BCMath):PREL相容语法(PCRE):
PDF文档支持:SNMP网络管理协议:
VMailMgr邮件处理:Curl支持:
SMTP支持:√' : '×';?>SMTP地址:×';?>
默认支持函数(enable_functions):请点这里查看详细!
被禁用的函数(disable_functions): +×'; +} +else +{ + //echo $disFuns; + $disFuns_array = explode(',',$disFuns); + foreach ($disFuns_array as $key=>$value) + { + if ($key!=0 && $key%5==0) { + echo '
'; + } + echo "$value  "; +} +} + +?> +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
组件支持
FTP支持:XML解析支持:
Session支持:Socket支持:
Calendar支持 + 允许URL打开文件:
GD库支持: + ×';} + ?>压缩文件支持(Zlib):
IMAP电子邮件系统函数库:历法运算函数库:
正则表达式函数库:WDDX支持:
Iconv编码转换:mbstring:
高精度数学运算:LDAP目录协议:
MCrypt加密处理:哈稀计算:
+ + + + + + + + + + + + + + + + + + + + + + + +
第三方组件
Zend版本×';}else{echo $zend_version;}?> + 2) +{ + echo "ZendGuardLoader[启用]"; +} +else +{ + echo "Zend Optimizer"; +} +?> + 2){echo (get_cfg_var("zend_loader.enable"))?'':'×';} else{if(function_exists('zend_optimizer_version')){ echo zend_optimizer_version();}else{ echo (get_cfg_var("zend_optimizer.optimization_level")||get_cfg_var("zend_extension_manager.optimizer_ts")||get_cfg_var("zend.ze1_compatibility_mode")||get_cfg_var("zend_extension_ts"))?'':'×';}}?>
eAccelerator×";} ?>ioncube×";}?>
XCache×";} ?>APC×";} ?>
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
数据库支持
MySQL 数据库: + + ODBC 数据库:
Oracle 数据库:SQL Server 数据库:
dBASE 数据库:mSQL 数据库:
SQLite 数据库:√ ';echo "SQLite3 Ver ";echo $sqliteVer[versionString];}else {echo isfun("sqlite_close");if(isfun("sqlite_close") == '') {echo "  版本: ".@sqlite_libversion();}}?>Hyperwave 数据库:
Postgre SQL 数据库:Informix 数据库:
DBA 数据库:DBM 数据库:
FilePro 数据库:SyBase 数据库:
+ + +
" method="post"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
服务器性能检测
参照对象整数运算能力检测
(1+1运算300万次)
浮点运算能力检测
(圆周率开平方300万次)
数据I/O能力检测
(读取10K文件1万次)
CPU信息
美国 LinodeVPS0.357秒0.802秒0.023秒4 x Xeon L5520 @ 2.27GHz
美国 PhotonVPS.com0.431秒1.024秒0.034秒8 x Xeon E5520 @ 2.27GHz
德国 SpaceRich.com0.421秒1.003秒0.038秒4 x Core i7 920 @ 2.67GHz
美国 RiZie.com0.521秒1.559秒0.054秒2 x Pentium4 3.00GHz
埃及 CitynetHost.com0.343秒0.761秒0.023秒2 x Core2Duo E4600 @ 2.40GHz
美国 IXwebhosting.com0.535秒1.607秒0.058秒4 x Xeon E5530 @ 2.40GHz
本台服务器


+ + + + + + + + + + + + +
网络速度测试
+
+ 向客户端传送1000k字节数据
+ 带宽比例按理想值计算 +
+ + + + + + + + + + + + + + + + + + +
带宽1M2M3M4M5M6M7M8M9M10M
+ + + + +
">">
+
+ ".$_GET['speed']." 毫秒,下载速度:"."".$speed.""." kb/s,需测试多次取平均值,超过10M直接看下载速度":" 未探测 " ?> + +
+ + + + + + + + + + +
MySQL数据库连接检测
+ 地址: + 端口: + 用户名: + 密码: + + +
+ alert('连接到MySql数据库正常')"; + } else { + echo ""; + } + } else { + echo ""; + } + } + ?> + + + + + + + + + + + alert('$funRe')"; + } + ?> +
函数检测
+ 请输入您要检测的函数: + + + +
+ + + + + + + + + + + alert('$mailRe')"; + } + ?> +
邮件发送检测
+ 请输入您要检测的邮件地址: + + + +
+
+ + + + + + + +
Processed in seconds. memory usage.返回顶部
+ +
+ + \ No newline at end of file diff --git a/youarebanned.jpg b/youarebanned.jpg new file mode 100644 index 0000000..bfb0f5a Binary files /dev/null and b/youarebanned.jpg differ diff --git a/youarenotbanned.jpg b/youarenotbanned.jpg new file mode 100644 index 0000000..fb998c5 Binary files /dev/null and b/youarenotbanned.jpg differ diff --git "a/\350\257\273\346\210\221.png" "b/\350\257\273\346\210\221.png" new file mode 100644 index 0000000..bfb4fb3 Binary files /dev/null and "b/\350\257\273\346\210\221.png" differ