From aa36c490d2218814cb6faa20e31c10b5599d4483 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Wed, 7 Dec 2005 10:25:29 +0100 Subject: [PATCH 1/1] initial checkin darcs-hash:20051207092529-6e07b-ccd48731093a8d618db0a6e4c11b940f604a938f.gz --- COPYING | 340 +++ Contact_Vcard_Parse.php | 836 +++++++ README | 107 + TODO | 4 + config.php | 34 + entries.conf | 20 + entry.php | 186 ++ functions.php | 345 +++ help.php | 12 + img.php | 16 + import.php | 166 ++ importVCF.php | 127 + index.php | 102 + init.php | 39 + lang/de.php | 69 + lang/en.php | 68 + ldapab.schema | 51 + login.php | 26 + orgs.php | 14 + pix/copy.png | Bin 0 -> 590 bytes pix/delete.png | Bin 0 -> 951 bytes pix/edit.png | Bin 0 -> 1076 bytes pix/help.png | Bin 0 -> 1195 bytes pix/image.png | Bin 0 -> 760 bytes pix/import.png | Bin 0 -> 952 bytes pix/login.png | Bin 0 -> 1242 bytes pix/logout.png | Bin 0 -> 1398 bytes pix/new.png | Bin 0 -> 692 bytes pix/org.png | Bin 0 -> 1354 bytes pix/orgs.png | Bin 0 -> 1300 bytes pix/private.png | Bin 0 -> 856 bytes pix/public.png | Bin 0 -> 807 bytes pix/search.png | Bin 0 -> 1169 bytes pix/show.png | Bin 0 -> 1393 bytes pix/vcard.png | Bin 0 -> 1304 bytes slapd.example | 111 + smarty/Config_File.class.php | 365 +++ smarty/Smarty.class.php | 2010 ++++++++++++++++ smarty/Smarty_Compiler.class.php | 2123 +++++++++++++++++ smarty/core/core.assemble_plugin_filepath.php | 62 + smarty/core/core.assign_smarty_interface.php | 43 + smarty/core/core.create_dir_structure.php | 79 + smarty/core/core.display_debug_console.php | 60 + smarty/core/core.get_include_path.php | 44 + smarty/core/core.get_microtime.php | 23 + smarty/core/core.get_php_resource.php | 80 + smarty/core/core.is_secure.php | 59 + smarty/core/core.is_trusted.php | 50 + smarty/core/core.load_plugins.php | 125 + smarty/core/core.load_resource_plugin.php | 74 + smarty/core/core.process_cached_inserts.php | 71 + smarty/core/core.process_compiled_include.php | 32 + smarty/core/core.read_cache_file.php | 111 + smarty/core/core.rm_auto.php | 71 + smarty/core/core.rmdir.php | 55 + smarty/core/core.run_insert_handler.php | 71 + smarty/core/core.smarty_include_php.php | 50 + smarty/core/core.write_cache_file.php | 73 + smarty/core/core.write_compiled_include.php | 59 + smarty/core/core.write_compiled_resource.php | 37 + smarty/core/core.write_file.php | 48 + smarty/debug.tpl | 64 + smarty/plugins/block.textformat.php | 83 + smarty/plugins/function.assign.php | 38 + smarty/plugins/function.assign_debug_info.php | 39 + smarty/plugins/function.config_load.php | 130 + smarty/plugins/function.counter.php | 88 + smarty/plugins/function.cycle.php | 119 + smarty/plugins/function.debug.php | 35 + smarty/plugins/function.eval.php | 48 + smarty/plugins/function.fetch.php | 217 ++ smarty/plugins/function.html_checkboxes.php | 135 ++ smarty/plugins/function.html_image.php | 143 ++ smarty/plugins/function.html_options.php | 118 + smarty/plugins/function.html_radios.php | 138 ++ smarty/plugins/function.html_select_date.php | 243 ++ smarty/plugins/function.html_select_time.php | 163 ++ smarty/plugins/function.html_table.php | 113 + smarty/plugins/function.mailto.php | 140 ++ smarty/plugins/function.math.php | 82 + smarty/plugins/function.popup.php | 87 + smarty/plugins/function.popup_init.php | 39 + smarty/plugins/modifier.capitalize.php | 25 + smarty/plugins/modifier.cat.php | 33 + smarty/plugins/modifier.count_characters.php | 31 + smarty/plugins/modifier.count_paragraphs.php | 28 + smarty/plugins/modifier.count_sentences.php | 28 + smarty/plugins/modifier.count_words.php | 32 + smarty/plugins/modifier.date_format.php | 43 + smarty/plugins/modifier.debug_print_var.php | 57 + smarty/plugins/modifier.default.php | 31 + smarty/plugins/modifier.escape.php | 84 + smarty/plugins/modifier.indent.php | 27 + smarty/plugins/modifier.lower.php | 25 + smarty/plugins/modifier.nl2br.php | 35 + smarty/plugins/modifier.regex_replace.php | 29 + smarty/plugins/modifier.replace.php | 29 + smarty/plugins/modifier.spacify.php | 29 + smarty/plugins/modifier.string_format.php | 28 + smarty/plugins/modifier.strip.php | 33 + smarty/plugins/modifier.strip_tags.php | 31 + smarty/plugins/modifier.truncate.php | 43 + smarty/plugins/modifier.upper.php | 25 + smarty/plugins/modifier.wordwrap.php | 28 + .../plugins/outputfilter.trimwhitespace.php | 75 + .../plugins/shared.escape_special_chars.php | 30 + smarty/plugins/shared.make_timestamp.php | 43 + template.php | 163 ++ templates/blank.gif | Bin 0 -> 42 bytes templates/entry_edit.tpl | 179 ++ templates/entry_show.tpl | 120 + templates/entry_vcf.tpl | 19 + templates/error.tpl | 10 + templates/extended_edit.tpl | 20 + templates/extended_show.tpl | 22 + templates/footer.tpl | 42 + templates/header.tpl | 23 + templates/help.tpl | 43 + templates/import.tpl | 25 + templates/importVCF.tpl | 25 + templates/importVCF_entry.tpl | 39 + templates/import_entry.tpl | 39 + templates/ldaperror.tpl | 5 + templates/list.tpl | 14 + templates/list_entry.tpl | 25 + templates/list_filter.tpl | 50 + templates/login.tpl | 21 + templates/orgs.tpl | 18 + templates/pngbehavior.htc | 53 + templates/style.css | 92 + xml.php | 139 ++ 131 files changed, 12898 insertions(+) create mode 100644 COPYING create mode 100644 Contact_Vcard_Parse.php create mode 100644 README create mode 100644 TODO create mode 100644 config.php create mode 100644 entries.conf create mode 100644 entry.php create mode 100644 functions.php create mode 100644 help.php create mode 100644 img.php create mode 100644 import.php create mode 100644 importVCF.php create mode 100644 index.php create mode 100644 init.php create mode 100644 lang/de.php create mode 100644 lang/en.php create mode 100644 ldapab.schema create mode 100644 login.php create mode 100644 orgs.php create mode 100644 pix/copy.png create mode 100644 pix/delete.png create mode 100644 pix/edit.png create mode 100644 pix/help.png create mode 100644 pix/image.png create mode 100644 pix/import.png create mode 100644 pix/login.png create mode 100644 pix/logout.png create mode 100644 pix/new.png create mode 100644 pix/org.png create mode 100644 pix/orgs.png create mode 100644 pix/private.png create mode 100644 pix/public.png create mode 100644 pix/search.png create mode 100644 pix/show.png create mode 100644 pix/vcard.png create mode 100644 slapd.example create mode 100644 smarty/Config_File.class.php create mode 100644 smarty/Smarty.class.php create mode 100644 smarty/Smarty_Compiler.class.php create mode 100644 smarty/core/core.assemble_plugin_filepath.php create mode 100644 smarty/core/core.assign_smarty_interface.php create mode 100644 smarty/core/core.create_dir_structure.php create mode 100644 smarty/core/core.display_debug_console.php create mode 100644 smarty/core/core.get_include_path.php create mode 100644 smarty/core/core.get_microtime.php create mode 100644 smarty/core/core.get_php_resource.php create mode 100644 smarty/core/core.is_secure.php create mode 100644 smarty/core/core.is_trusted.php create mode 100644 smarty/core/core.load_plugins.php create mode 100644 smarty/core/core.load_resource_plugin.php create mode 100644 smarty/core/core.process_cached_inserts.php create mode 100644 smarty/core/core.process_compiled_include.php create mode 100644 smarty/core/core.read_cache_file.php create mode 100644 smarty/core/core.rm_auto.php create mode 100644 smarty/core/core.rmdir.php create mode 100644 smarty/core/core.run_insert_handler.php create mode 100644 smarty/core/core.smarty_include_php.php create mode 100644 smarty/core/core.write_cache_file.php create mode 100644 smarty/core/core.write_compiled_include.php create mode 100644 smarty/core/core.write_compiled_resource.php create mode 100644 smarty/core/core.write_file.php create mode 100644 smarty/debug.tpl create mode 100644 smarty/plugins/block.textformat.php create mode 100644 smarty/plugins/function.assign.php create mode 100644 smarty/plugins/function.assign_debug_info.php create mode 100644 smarty/plugins/function.config_load.php create mode 100644 smarty/plugins/function.counter.php create mode 100644 smarty/plugins/function.cycle.php create mode 100644 smarty/plugins/function.debug.php create mode 100644 smarty/plugins/function.eval.php create mode 100644 smarty/plugins/function.fetch.php create mode 100644 smarty/plugins/function.html_checkboxes.php create mode 100644 smarty/plugins/function.html_image.php create mode 100644 smarty/plugins/function.html_options.php create mode 100644 smarty/plugins/function.html_radios.php create mode 100644 smarty/plugins/function.html_select_date.php create mode 100644 smarty/plugins/function.html_select_time.php create mode 100644 smarty/plugins/function.html_table.php create mode 100644 smarty/plugins/function.mailto.php create mode 100644 smarty/plugins/function.math.php create mode 100644 smarty/plugins/function.popup.php create mode 100644 smarty/plugins/function.popup_init.php create mode 100644 smarty/plugins/modifier.capitalize.php create mode 100644 smarty/plugins/modifier.cat.php create mode 100644 smarty/plugins/modifier.count_characters.php create mode 100644 smarty/plugins/modifier.count_paragraphs.php create mode 100644 smarty/plugins/modifier.count_sentences.php create mode 100644 smarty/plugins/modifier.count_words.php create mode 100644 smarty/plugins/modifier.date_format.php create mode 100644 smarty/plugins/modifier.debug_print_var.php create mode 100644 smarty/plugins/modifier.default.php create mode 100644 smarty/plugins/modifier.escape.php create mode 100644 smarty/plugins/modifier.indent.php create mode 100644 smarty/plugins/modifier.lower.php create mode 100644 smarty/plugins/modifier.nl2br.php create mode 100644 smarty/plugins/modifier.regex_replace.php create mode 100644 smarty/plugins/modifier.replace.php create mode 100644 smarty/plugins/modifier.spacify.php create mode 100644 smarty/plugins/modifier.string_format.php create mode 100644 smarty/plugins/modifier.strip.php create mode 100644 smarty/plugins/modifier.strip_tags.php create mode 100644 smarty/plugins/modifier.truncate.php create mode 100644 smarty/plugins/modifier.upper.php create mode 100644 smarty/plugins/modifier.wordwrap.php create mode 100644 smarty/plugins/outputfilter.trimwhitespace.php create mode 100644 smarty/plugins/shared.escape_special_chars.php create mode 100644 smarty/plugins/shared.make_timestamp.php create mode 100644 template.php create mode 100644 templates/blank.gif create mode 100644 templates/entry_edit.tpl create mode 100644 templates/entry_show.tpl create mode 100644 templates/entry_vcf.tpl create mode 100644 templates/error.tpl create mode 100644 templates/extended_edit.tpl create mode 100644 templates/extended_show.tpl create mode 100644 templates/footer.tpl create mode 100644 templates/header.tpl create mode 100644 templates/help.tpl create mode 100644 templates/import.tpl create mode 100644 templates/importVCF.tpl create mode 100644 templates/importVCF_entry.tpl create mode 100644 templates/import_entry.tpl create mode 100644 templates/ldaperror.tpl create mode 100644 templates/list.tpl create mode 100644 templates/list_entry.tpl create mode 100644 templates/list_filter.tpl create mode 100644 templates/login.tpl create mode 100644 templates/orgs.tpl create mode 100644 templates/pngbehavior.htc create mode 100644 templates/style.css create mode 100644 xml.php diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..5b6e7c6 --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Contact_Vcard_Parse.php b/Contact_Vcard_Parse.php new file mode 100644 index 0000000..da1f16f --- /dev/null +++ b/Contact_Vcard_Parse.php @@ -0,0 +1,836 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Contact_Vcard_Parse.php,v 1.1 2004/06/01 08:48:59 gohr Exp $ + + +/** +* +* Parser for vCards. +* +* This class parses vCard 2.1 and 3.0 sources from file or text into a +* structured array. +* +* Usage: +* +* +* // include this class file +* require_once 'Contact_Vcard_Parse.php'; +* +* // instantiate a parser object +* $parse = new Contact_Vcard_Parse(); +* +* // parse a vCard file and store the data +* // in $cardinfo +* $cardinfo = $parse->fromFile('sample.vcf'); +* +* // view the card info array +* echo '
';
+*     print_r($cardinfo);
+*     echo '
'; +*
+* +* +* @author Paul M. Jones +* +* @package Contact_Vcard_Parse +* +* @version 1.30 +* +*/ + +class Contact_Vcard_Parse { + + + /** + * + * Reads a file for parsing, then sends it to $this->fromText() + * and returns the results. + * + * @access public + * + * @param array $filename The filename to read for vCard information. + * + * @return array An array of of vCard information extracted from the + * file. + * + * @see Contact_Vcard_Parse::fromText() + * + * @see Contact_Vcard_Parse::_fromArray() + * + */ + + function fromFile($filename, $decode_qp = true) + { + $text = $this->fileGetContents($filename); + + if ($text === false) { + return false; + } else { + // dump to, and get return from, the fromText() method. + return $this->fromText($text, $decode_qp); + } + } + + + /** + * + * Reads the contents of a file. Included for users whose PHP < 4.3.0. + * + * @access public + * + * @param array $filename The filename to read for vCard information. + * + * @return string|bool The contents of the file if it exists and is + * readable, or boolean false if not. + * + * @see Contact_Vcard_Parse::fromFile() + * + */ + + function fileGetContents($filename) + { + if (file_exists($filename) && + is_readable($filename)) { + + $text = ''; + $len = filesize($filename); + + $fp = fopen($filename, 'r'); + while ($line = fread($fp, filesize($filename))) { + $text .= $line; + } + fclose($fp); + + return $text; + + } else { + + return false; + + } + } + + + /** + * + * Prepares a block of text for parsing, then sends it through and + * returns the results from $this->fromArray(). + * + * @access public + * + * @param array $text A block of text to read for vCard information. + * + * @return array An array of vCard information extracted from the + * source text. + * + * @see Contact_Vcard_Parse::_fromArray() + * + */ + + function fromText($text, $decode_qp = true) + { + // convert all kinds of line endings to Unix-standard and get + // rid of double blank lines. + $this->convertLineEndings($text); + + // unfold lines. concat two lines where line 1 ends in \n and + // line 2 starts with a whitespace character. only removes + // the first whitespace character, leaves others in place. + $fold_regex = '(\n)([ |\t])'; + $text = preg_replace("/$fold_regex/i", "", $text); + + // massage for Macintosh OS X Address Book (remove nulls that + // Address Book puts in for unicode chars) + $text = str_replace("\x00", '', $text); + + // convert the resulting text to an array of lines + $lines = explode("\n", $text); + + // parse the array of lines and return vCard info + return $this->_fromArray($lines, $decode_qp); + } + + + /** + * + * Converts line endings in text. + * + * Takes any text block and converts all line endings to UNIX + * standard. DOS line endings are \r\n, Mac are \r, and UNIX is \n. + * + * NOTE: Acts on the text block in-place; does not return a value. + * + * @access public + * + * @param string $text The string on which to convert line endings. + * + * @return void + * + */ + + function convertLineEndings(&$text) + { + // DOS + $text = str_replace("\r\n", "\n", $text); + + // Mac + $text = str_replace("\r", "\n", $text); + } + + + /** + * + * Splits a string into an array at semicolons. Honors backslash- + * escaped semicolons (i.e., splits at ';' not '\;'). + * + * @access public + * + * @param string $text The string to split into an array. + * + * @param bool $convertSingle If splitting the string results in a + * single array element, return a string instead of a one-element + * array. + * + * @return mixed An array of values, or a single string. + * + */ + + function splitBySemi($text, $convertSingle = false) + { + // we use these double-backs (\\) because they get get converted + // to single-backs (\) by preg_split. the quad-backs (\\\\) end + // up as as double-backs (\\), which is what preg_split requires + // to indicate a single backslash (\). what a mess. + $regex = '(? ; + * \, => , + * literal \n => newline + * + * @access public + * + * @param mixed $text The text to unescape. + * + * @return void + * + */ + + function unescape(&$text) + { + if (is_array($text)) { + foreach ($text as $key => $val) { + $this->unescape($val); + $text[$key] = $val; + } + } else { + $text = str_replace('\;', ';', $text); + $text = str_replace('\,', ',', $text); + $text = str_replace('\n', "\n", $text); + } + } + + + /** + * + * Emulated destructor. + * + * @access private + * @return boolean true + * + */ + + function _Contact_Vcard_Parse() + { + return true; + } + + + /** + * + * Parses an array of source lines and returns an array of vCards. + * Each element of the array is itself an array expressing the types, + * parameters, and values of each part of the vCard. Processes both + * 2.1 and 3.0 vCard sources. + * + * @access private + * + * @param array $source An array of lines to be read for vCard + * information. + * + * @return array An array of of vCard information extracted from the + * source array. + * + */ + + function _fromArray($source, $decode_qp = true) + { + // the info array will hold all resulting vCard information. + $info = array(); + + // tells us whether the source text indicates the beginning of a + // new vCard with a BEGIN:VCARD tag. + $begin = false; + + // holds information about the current vCard being read from the + // source text. + $card = array(); + + // loop through each line in the source array + foreach ($source as $line) { + + // if the line is blank, skip it. + if (trim($line) == '') { + continue; + } + + // find the first instance of ':' on the line. The part + // to the left of the colon is the type and parameters; + // the part to the right of the colon is the value data. + $pos = strpos($line, ':'); + + // if there is no colon, skip the line. + if ($pos === false) { + continue; + } + + // get the left and right portions + $left = trim(substr($line, 0, $pos)); + $right = trim(substr($line, $pos+1, strlen($line))); + + // have we started yet? + if (! $begin) { + + // nope. does this line indicate the beginning of + // a new vCard? + if (strtoupper($left) == 'BEGIN' && + strtoupper($right) == 'VCARD') { + + // tell the loop that we've begun a new card + $begin = true; + } + + // regardless, loop to the next line of source. if begin + // is still false, the next loop will check the line. if + // begin has now been set to true, the loop will start + // collecting card info. + continue; + + } else { + + // yep, we've started, but we don't know how far along + // we are in the card. is this the ending line of the + // current vCard? + if (strtoupper($left) == 'END' && + strtoupper($right) == 'VCARD') { + + // yep, we're done. keep the info from the current + // card... + $info[] = $card; + + // ...and reset to grab a new card if one exists in + // the source array. + $begin = false; + $card = array(); + + } else { + + // we're not on an ending line, so collect info from + // this line into the current card. split the + // left-portion of the line into a type-definition + // (the kind of information) and parameters for the + // type. + $typedef = $this->_getTypeDef($left); + $params = $this->_getParams($left); + + // if we are decoding quoted-printable, do so now. + // QUOTED-PRINTABLE is not allowed in version 3.0, + // but we don't check for versioning, so we do it + // regardless. ;-) + $this->_decode_qp($params, $right); + + // now get the value-data from the line, based on + // the typedef + switch ($typedef) { + + case 'N': + // structured name of the person + $value = $this->_parseN($right); + break; + + case 'ADR': + // structured address of the person + $value = $this->_parseADR($right); + break; + + case 'NICKNAME': + // nicknames + $value = $this->_parseNICKNAME($right); + break; + + case 'ORG': + // organizations the person belongs to + $value = $this->_parseORG($right); + break; + + case 'CATEGORIES': + // categories to which this card is assigned + $value = $this->_parseCATEGORIES($right); + break; + + case 'GEO': + // geographic coordinates + $value = $this->_parseGEO($right); + break; + + default: + // by default, just grab the plain value. keep + // as an array to make sure *all* values are + // arrays. for consistency. ;-) + $value = array(array($right)); + break; + } + + // add the type, parameters, and value to the + // current card array. note that we allow multiple + // instances of the same type, which might be dumb + // in some cases (e.g., N). + $card[$typedef][] = array( + 'param' => $params, + 'value' => $value + ); + } + } + } + + $this->unescape($info); + return $info; + } + + + /** + * + * Takes a vCard line and extracts the Type-Definition for the line. + * + * @access private + * + * @param string $text A left-part (before-the-colon part) from a + * vCard line. + * + * @return string The type definition for the line. + * + */ + + function _getTypeDef($text) + { + // split the text by semicolons + $split = $this->splitBySemi($text); + + // only return first element (the typedef) + return $split[0]; + } + + + /** + * + * Finds the Type-Definition parameters for a vCard line. + * + * @access private + * + * @param string $text A left-part (before-the-colon part) from a + * vCard line. + * + * @return mixed An array of parameters. + * + */ + + function _getParams($text) + { + // split the text by semicolons into an array + $split = $this->splitBySemi($text); + + // drop the first element of the array (the type-definition) + array_shift($split); + + // set up an array to retain the parameters, if any + $params = array(); + + // loop through each parameter. the params may be in the format... + // "TYPE=type1,type2,type3" + // ...or... + // "TYPE=type1;TYPE=type2;TYPE=type3" + foreach ($split as $full) { + + // split the full parameter at the equal sign so we can tell + // the parameter name from the parameter value + $tmp = explode("=", $full); + + // the key is the left portion of the parameter (before + // '='). if in 2.1 format, the key may in fact be the + // parameter value, not the parameter name. + $key = strtoupper(trim($tmp[0])); + + // get the parameter name by checking to see if it's in + // vCard 2.1 or 3.0 format. + $name = $this->_getParamName($key); + + // list of all parameter values + $listall = trim($tmp[1]); + + // if there is a value-list for this parameter, they are + // separated by commas, so split them out too. + $list = $this->splitByComma($listall); + + // now loop through each value in the parameter and retain + // it. if the value is blank, that means it's a 2.1-style + // param, and the key itself is the value. + foreach ($list as $val) { + if (trim($val) != '') { + // 3.0 formatted parameter + $params[$name][] = trim($val); + } else { + // 2.1 formatted parameter + $params[$name][] = $key; + } + } + + // if, after all this, there are no parameter values for the + // parameter name, retain no info about the parameter (saves + // ram and checking-time later). + if (count($params[$name]) == 0) { + unset($params[$name]); + } + } + + // return the parameters array. + return $params; + } + + + /** + * + * Looks at the parameters of a vCard line; if one of them is + * ENCODING[] => QUOTED-PRINTABLE then decode the text in-place. + * + * @access private + * + * @param array $params A parameter array from a vCard line. + * + * @param string $text A right-part (after-the-colon part) from a + * vCard line. + * + * @return void + * + */ + + function _decode_qp(&$params, &$text) + { + // loop through each parameter + foreach ($params as $param_key => $param_val) { + + // check to see if it's an encoding param + if (trim(strtoupper($param_key)) == 'ENCODING') { + + // loop through each encoding param value + foreach ($param_val as $enc_key => $enc_val) { + + // if any of the values are QP, decode the text + // in-place and return + if (trim(strtoupper($enc_val)) == 'QUOTED-PRINTABLE') { + $text = quoted_printable_decode($text); + return; + } + } + } + } + } + + + /** + * + * Returns parameter names from 2.1-formatted vCards. + * + * The vCard 2.1 specification allows parameter values without a + * name. The parameter name is then determined from the unique + * parameter value. + * + * Shamelessly lifted from Frank Hellwig and his + * vCard PHP project . + * + * @access private + * + * @param string $value The first element in a parameter name-value + * pair. + * + * @return string The proper parameter name (TYPE, ENCODING, or + * VALUE). + * + */ + + function _getParamName($value) + { + static $types = array ( + 'DOM', 'INTL', 'POSTAL', 'PARCEL','HOME', 'WORK', + 'PREF', 'VOICE', 'FAX', 'MSG', 'CELL', 'PAGER', + 'BBS', 'MODEM', 'CAR', 'ISDN', 'VIDEO', + 'AOL', 'APPLELINK', 'ATTMAIL', 'CIS', 'EWORLD', + 'INTERNET', 'IBMMAIL', 'MCIMAIL', + 'POWERSHARE', 'PRODIGY', 'TLX', 'X400', + 'GIF', 'CGM', 'WMF', 'BMP', 'MET', 'PMB', 'DIB', + 'PICT', 'TIFF', 'PDF', 'PS', 'JPEG', 'QTIME', + 'MPEG', 'MPEG2', 'AVI', + 'WAVE', 'AIFF', 'PCM', + 'X509', 'PGP' + ); + + // CONTENT-ID added by pmj + static $values = array ( + 'INLINE', 'URL', 'CID', 'CONTENT-ID' + ); + + // 8BIT added by pmj + static $encodings = array ( + '7BIT', '8BIT', 'QUOTED-PRINTABLE', 'BASE64' + ); + + // changed by pmj to the following so that the name defaults to + // whatever the original value was. Frank Hellwig's original + // code was "$name = 'UNKNOWN'". + $name = $value; + + if (in_array($value, $types)) { + $name = 'TYPE'; + } elseif (in_array($value, $values)) { + $name = 'VALUE'; + } elseif (in_array($value, $encodings)) { + $name = 'ENCODING'; + } + + return $name; + } + + + /** + * + * Parses a vCard line value identified as being of the "N" + * (structured name) type-defintion. + * + * @access private + * + * @param string $text The right-part (after-the-colon part) of a + * vCard line. + * + * @return array An array of key-value pairs where the key is the + * portion-name and the value is the portion-value. The value itself + * may be an array as well if multiple comma-separated values were + * indicated in the vCard source. + * + */ + + function _parseN($text) + { + $tmp = $this->splitBySemi($text); + return array( + $this->splitByComma($tmp[0]), // family (last) + $this->splitByComma($tmp[1]), // given (first) + $this->splitByComma($tmp[2]), // addl (middle) + $this->splitByComma($tmp[3]), // prefix + $this->splitByComma($tmp[4]) // suffix + ); + } + + + /** + * + * Parses a vCard line value identified as being of the "ADR" + * (structured address) type-defintion. + * + * @access private + * + * @param string $text The right-part (after-the-colon part) of a + * vCard line. + * + * @return array An array of key-value pairs where the key is the + * portion-name and the value is the portion-value. The value itself + * may be an array as well if multiple comma-separated values were + * indicated in the vCard source. + * + */ + + function _parseADR($text) + { + $tmp = $this->splitBySemi($text); + return array( + $this->splitByComma($tmp[0]), // pob + $this->splitByComma($tmp[1]), // extend + $this->splitByComma($tmp[2]), // street + $this->splitByComma($tmp[3]), // locality (city) + $this->splitByComma($tmp[4]), // region (state) + $this->splitByComma($tmp[5]), // postcode (ZIP) + $this->splitByComma($tmp[6]) // country + ); + } + + + /** + * + * Parses a vCard line value identified as being of the "NICKNAME" + * (informal or descriptive name) type-defintion. + * + * @access private + * + * @param string $text The right-part (after-the-colon part) of a + * vCard line. + * + * @return array An array of nicknames. + * + */ + + function _parseNICKNAME($text) + { + return array($this->splitByComma($text)); + } + + + /** + * + * Parses a vCard line value identified as being of the "ORG" + * (organizational info) type-defintion. + * + * @access private + * + * @param string $text The right-part (after-the-colon part) of a + * vCard line. + * + * @return array An array of organizations; each element of the array + * is itself an array, which indicates primary organization and + * sub-organizations. + * + */ + + function _parseORG($text) + { + $tmp = $this->splitbySemi($text); + $list = array(); + foreach ($tmp as $val) { + $list[] = array($val); + } + + return $list; + } + + + /** + * + * Parses a vCard line value identified as being of the "CATEGORIES" + * (card-category) type-defintion. + * + * @access private + * + * @param string $text The right-part (after-the-colon part) of a + * vCard line. + * + * @return mixed An array of categories. + * + */ + + function _parseCATEGORIES($text) + { + return array($this->splitByComma($text)); + } + + + /** + * + * Parses a vCard line value identified as being of the "GEO" + * (geographic coordinate) type-defintion. + * + * @access private + * + * @param string $text The right-part (after-the-colon part) of a + * vCard line. + * + * @return mixed An array of lat-lon geocoords. + * + */ + + function _parseGEO($text) + { + $tmp = $this->splitBySemi($text); + return array( + array($tmp[0]), // lat + array($tmp[1]) // lon + ); + } +} + +?> \ No newline at end of file diff --git a/README b/README new file mode 100644 index 0000000..a69db64 --- /dev/null +++ b/README @@ -0,0 +1,107 @@ +=== ABOUT === + +LDAPab is a webbased address book for small companies. It features a public +address book which is writable for all company staff and a personal address +book for each staff member. LDAPab require an already setup LDAP server to +authenticate users. + +=== REQUIREMENTS === + +You need to have a running LDAP Server with some users (objectClass=posixUser) +in it. It is important that you already have these users because LDAPab uses +them to authenticate. + +You need a webserver (peferable Apache) with PHP4. PHP4 needs to be compiled +with LDAP support (compiled in or as extension) + +=== SETUP LDAPab === + +Copy the contents of the .tgz file to a directory below your webserver document +root. Make sure the webserver is able to write to the cache directory which is +used for the template engines cache files. A 'chmod 777 cache' will do. + +Open the config.php file in your favourite editor and edit the options +according to your needs. Some knowlege about LDAP may come in handy. + +=== SETUP THE LDAP SERVER === + +The following only describes what to do for open-ldap 2.0! If you use any +other LDAP server you're left to our own. + +You need to include the inetOrgPerson schema in you slapd.conf: + + include /etc/ldap/schema/inetorgperson.schema + +If youwant to use the extended schema (currently only for birthday support) you +need to copy the ldapab.schema file to /etc/ldap/schema/ and include it, too. +Be sure to enable the extended option in config.php. + + include /etc/ldap/schema/ldapab.schema + +To setup the access rights add the following statement to your slapd.conf. Of +course you have to replace "o=cosmocode,c=de" with your own root DN. The first +entry may have to adjusted also if your users aren't stored in a ou=people +entry. Make sure you include these lines before other access control lists that +match these parts of the ldap tree. If you are unsure have a look at the +included slapd.example file + + access to dn="(.*,)?ou=contacts,cn=([^,]+),ou=people,(.*)$" + by dn="cn=$2,ou=people,$3" write + by * none + + access to dn.subtree="ou=contacts,o=cosmocode,c=de" + by users write + by * read + +After this modifications you have to restart the slapd server. + +The last thing is to add the contacts leafs to your LDAP tree. You'll need to +add a global contacts leaf at top. + + eg: 'ou=contacts,o=cosmocode,c=de' + +And a contacts leaf for every user. + + eg: 'ou=contacts,cn=Joe Schmoe,ou=people,o=cosmocode,c=de' + + +If you made everything correct you can point your webbrowser to the newly +installed LDAPab and use it :-) If you encounter problems try to enable logging +in your LDAP server to see what the problem is. + +=== FEEDBACK, PATCHES, SUPPORT === + +This software was developed to satisfy a need in our company. We give it to the +public because it may be helpful to other companies with the same needs. +However this is not a supported product. We like to get feedback and patches +but we can't promise to answer, to fix bugs or include feature wishes. However +don't hesitate to contact us but understand that our core business has priority +over this project. + +To contact us send a mail to ldapab@cosmocode.de + +=== KNOWN BUGS === + +LDAPab was only tested with open-ldap 2.1 - there may be problems with other +LDAP Servers. + +=== LICENSE === + +LDAPab - An LDAP based Company Address Book +Copyright 2004 - CosmoCode GmbH + +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., 675 Mass Ave, Cambridge, MA 02139, USA. + +See COPYING for details diff --git a/TODO b/TODO new file mode 100644 index 0000000..10730a1 --- /dev/null +++ b/TODO @@ -0,0 +1,4 @@ + +Photoupload + +marker diff --git a/config.php b/config.php new file mode 100644 index 0000000..31419dc --- /dev/null +++ b/config.php @@ -0,0 +1,34 @@ + diff --git a/entries.conf b/entries.conf new file mode 100644 index 0000000..0809369 --- /dev/null +++ b/entries.conf @@ -0,0 +1,20 @@ +dn dn +sn name +givenName givenname +title title +o organization +physicalDeliveryOfficeName office +postalAddress street +postalCode zip +l location +telephoneNumber phone +facsimileTelephoneNumber fax +mobile mobile +pager pager +homePhone homephone +homePostalAddress homestreet +photo photo +jpegPhoto photo +labeledURI url +description note +manager manager diff --git a/entry.php b/entry.php new file mode 100644 index 0000000..a855053 --- /dev/null +++ b/entry.php @@ -0,0 +1,186 @@ +assign('error','No dn was given'); + $template = 'error.tpl'; + } + }elseif($_REQUEST[del]){ + _delEntry($dn); + }elseif(!_fetchData($dn)){ + $smarty->assign('error',"The requested entry '$dn' was not found"); + $template = 'error.tpl'; + } + + //prepare templates + $smarty->assign('dn',$dn); + $smarty->assign('managers',$users); + tpl_std(); + tpl_orgs(); + tpl_markers(); + //display templates + if($_REQUEST[mode]=='vcf'){ + $entry = $smarty->get_template_vars('entry'); + $filename = $entry[givenname].'_'.$entry[name].'.vcf'; + header("Content-Disposition: attachment; filename=\"$filename\""); + header("Content-type: text/x-vcard; name=\"$filename\""); + $smarty->display($template); + }else{ + $smarty->display('header.tpl'); + $smarty->display($template); + $smarty->display('footer.tpl'); + } + + //-------------------------------------------------------------- + + /** + * fetches the Data from the LDAP directory and assigns it to + * the global smarty object using tpl_entry() + */ + function _fetchData($dn){ + global $LDAP_CON; + global $conf; + global $smarty; + global $users; //contains the users for manager role + + $sr = ldap_search($LDAP_CON,$dn,'(objectClass=inetOrgPerson)'); + if(!ldap_count_entries($LDAP_CON,$sr)){ + return false; + } + $result = ldap_get_binentries($LDAP_CON, $sr); + $entry = $result[0]; + + //remove dn from entry when copy + if($_REQUEST[mode] == 'copy'){ + $entry[dn]=''; + } + + //assign entry to template: + tpl_entry($entry); + +/*print '
';
+print_r($entry);
+print '
';*/ + + // make username from dn for manager: + $smarty->assign('managername',$users[$entry[manager][0]]); + return true; + } + + /** + * saves the data from $_REQUEST[entry] to the LDAP directory + * + * returns given or constructed dn + */ + function _saveData(){ + global $LDAP_CON; + global $conf; + $entries = namedentries(); + $entries['mail']='mail'; //special field mail isn't in entries so we add it here + if($conf[extended]){ + $entries['marker']='marker'; //same for marker inextended schema + } + + $entry = $_REQUEST[entry]; + $dn = $_REQUEST[dn]; + //construct new dn + $now = time(); + $newdn = 'uid='.$now; + if($_REQUEST[type] == 'private'){ + $newdn .= ', '.$conf[privatebook].', '.$_SESSION[ldapab][binddn]; + }else{ + $newdn .= ', '.$conf[publicbook]; + } + $entry[cn] = $entry[givenname].' '.$entry[name];; + $entry = prepare_ldap_entry($entry); + +/*print '
';
+print_r($entry);
+print '
';*/ + + if(empty($dn)){ + //new entry + $entry[uid][] = $now; + $r = ldap_add($LDAP_CON,$newdn,$entry); + tpl_ldaperror(); + return $newdn; + }else{ + // in extended mode we have to make sure the right classes are set + if($conf[extended]){ + ldap_store_objectclasses($dn,array('inetOrgPerson','contactPerson')); + } + //modify entry (touches only our attributes) + foreach (array_keys($entries) as $key){ + if($key == 'dn'){ + continue; + }elseif(empty($entry[$key])){ + if($key == 'jpegPhoto' && !$_REQUEST['delphoto']){ + continue; + } + unset($del); + $del[$key]=array(); + $r = @ldap_mod_replace($LDAP_CON,$dn,$del); + tpl_ldaperror("del $key"); + }else{ + unset($add); + $add[$key]=$entry[$key]; + $r = @ldap_mod_replace($LDAP_CON,$dn,$add); + tpl_ldaperror("mod $key"); + } + } + return $dn; + } + } + + /** + * does as the name says - delete the whole entry + */ + function _delEntry($dn){ + global $LDAP_CON; + if(ldap_full_delete($LDAP_CON,$dn,true)){ + header("Location: index.php"); + exit; + } + } + + /** + * gets the binary data from an uploaded file + */ + function _getUploadData(){ + $file = $_FILES[photoupload]; + + if (is_uploaded_file($file[tmp_name])) { + if(preg_match('=image/p?jpe?g=',$file[type])){ + $fh = fopen($file[tmp_name],'r'); + $data = fread($fh,$file[size]); + fclose($fh); + unlink($file[tmp_name]); + return $data; + } + } + return ''; + } +?> diff --git a/functions.php b/functions.php new file mode 100644 index 0000000..e8ac472 --- /dev/null +++ b/functions.php @@ -0,0 +1,345 @@ +assign('USER',$_SESSION[ldapab][username]); +} + +/** + * Uses Username and Password from Session to initialize the LDAP handle + * If it fails it redirects to login.php + */ +function ldap_login(){ + if(!empty($_SESSION[ldapab][username])){ + //existing session! Check if valid + if($_COOKIE[ldapabconid] != $_SESSION[ldapab][conid]){ + //session hijacking detected + header('Location: login.php?username='); + exit; + } + } + + if(!do_ldap_bind($_SESSION[ldapab][username], + $_SESSION[ldapab][password], + $_SESSION[ldapab][binddn])){ + header('Location: login.php?username='); + exit; + } +} + +/** + * Creates a global LDAP connection handle called $LDAP_CON + */ +function do_ldap_bind($user,$pass,$dn=""){ + global $conf; + global $LDAP_CON; + + //create global connection to LDAP if nessessary + if(!$LDAP_CON){ + $LDAP_CON = ldap_connect($conf[ldapserver]); + if(!$LDAP_CON){ + die("couldn't connect to LDAP server"); + } + } + + if(empty($dn)){ + //anonymous bind to lookup users + if(!ldap_bind($LDAP_CON)){ + die("can not bind anonymously"); + } + + //when no user was given stay connected anonymous + if(empty($user)){ + set_session('','',''); + return true; + } + + //get dn for given user + $filter = str_replace('%u',$user,$conf[userfilter]); + $sr = ldap_search($LDAP_CON, $conf[usertree], $filter);; + $result = ldap_get_entries($LDAP_CON, $sr); + if($result['count'] != 1){ + set_session('','',''); + return false; + } + $dn = $result[0]['dn']; + } + + //bind with dn + if(ldap_bind($LDAP_CON,$dn,$pass)){ + //bind successful -> set up session + set_session($user,$pass,$dn); + return true; + } + //bind failed -> remove session + set_session('','',''); + return false; +} + +/** + * saves user data to Session + */ +function set_session($user,$pass,$dn){ + $rand = rand(); + $_SESSION[ldapab][username]=$user; + $_SESSION[ldapab][binddn] =$dn; + $_SESSION[ldapab][password]=$pass; + $_SESSION[ldapab][conid] =$rand; + setcookie('ldapabconid',$rand,time()+60*60*24); +} + +/** + * binary safe function to get all search result data. + * It will use ldap_get_values_len() instead and build the array + * note: it's similar with the array returned by ldap_get_entries() + * except it has no "count" elements + * + * @author: Original code by Ovidiu Geaboc + */ +function ldap_get_binentries($conn,$srchRslt){ + if(!@ldap_count_entries($conn,$srchRslt)){ + return null; + } + $entry = ldap_first_entry($conn, $srchRslt); + $i=0; + do { + $dn = ldap_get_dn($conn,$entry); + $attrs = ldap_get_attributes($conn, $entry); + for($j=0; $j<$attrs['count']; $j++) { + $vals = ldap_get_values_len($conn, $entry,$attrs[$j]); + for($k=0; $k<$vals['count']; $k++){ + $data[$i][$attrs[$j]][$k]=$vals[$k]; + } + } + $data[$i]['dn']=$dn; + $i++; + }while ($entry = ldap_next_entry($conn, $entry)); + + return $data; +} + +/** + * loads ldap names and their cleartext meanings from + * entries.conf file and returns it as hash + */ +function namedentries($flip=false){ + global $conf; + + $entries[dn] = 'dn'; + $entries[sn] = 'name'; + $entries[givenName] = 'givenname'; + $entries[title] = 'title'; + $entries[o] = 'organization'; + $entries[physicalDeliveryOfficeName] = 'office'; + $entries[postalAddress] = 'street'; + $entries[postalCode] = 'zip'; + $entries[l] = 'location'; + $entries[telephoneNumber] = 'phone'; + $entries[facsimileTelephoneNumber] = 'fax'; + $entries[mobile] = 'mobile'; + $entries[pager] = 'pager'; + $entries[homePhone] = 'homephone'; + $entries[homePostalAddress] = 'homestreet'; + $entries[jpegPhoto] = 'photo'; + $entries[labeledURI] = 'url'; + $entries[description] = 'note'; + $entries[manager] = 'manager'; + $entries[cn] = 'displayname'; + + if($conf[extended]){ + $entries[anniversary] = 'anniversary'; + } + + if($flip){ + $entries = array_reverse($entries); + $entries = array_flip($entries); + } + return $entries; +} + +/** + * Creates an array for submission to ldap from websitedata + */ +function prepare_ldap_entry($in){ + global $conf; + + //check dateformat + if(!preg_match('/\d\d\d\d-\d\d-\d\d/',$in[anniversary])){ + $in[anniversary]=''; + } + + $entries = namedentries(true); + foreach(array_keys($in) as $key){ + if(empty($entries[$key])){ + $keyname=$key; + }else{ + $keyname=$entries[$key]; + } + if(is_array($in[$key])){ + $out[$keyname] = $in[$key]; + }else{ + $out[$keyname][] = $in[$key]; + } + } + + //standard Objectclass + $out[objectclass][] = 'inetOrgPerson'; + if($conf[extended]){ + $out[objectclass][] = 'contactPerson'; + } + + utf8_encode_array($out); + + return clear_array($out); +} + +/** + * remove empty element from arrays recursively + * + * @author Original by + */ +function clear_array ( $a ) { + if ($a !== array()) { + $b = array(); + foreach ( $a as $key => $value ) { + if (is_array($value)) { + if (clear_array($value) !== false) { + $b[$key] = clear_array ( $value ); + } + } elseif ($value !== '') { + $b[$key] = $value; + } + } + if ($b !== array()) { + return $b; + } else { + return false; + } + } else { + return false; + } +} + +/** + * deletes an entryfrom ldap - optional with recursion + * + * @author Original by + */ +function ldap_full_delete($ds,$dn,$recursive=false){ + if($recursive == false){ + return(ldap_delete($ds,$dn)); + }else{ + //searching for sub entries + $sr=ldap_list($ds,$dn,"ObjectClass=*",array("")); + $info = ldap_get_entries($ds, $sr); + for($i=0;$i<$info['count'];$i++){ + //deleting recursively sub entries + $result=myldap_delete($ds,$info[$i]['dn'],$recursive); + if(!$result){ + //return result code, if delete fails + return($result); + } + } + return(ldap_delete($ds,$dn)); + } +} + +/** + * Returns all User Accounts as assoziative array + */ +function get_users(){ + global $conf; + global $LDAP_CON; + + $sr = ldap_list($LDAP_CON,$conf[usertree],"ObjectClass=inetOrgPerson"); + $result = ldap_get_binentries($LDAP_CON, $sr); + if(count($result)){ + foreach ($result as $entry){ + if(!empty($entry[sn][0])){ + $users[$entry[dn]] = $entry[givenName][0]." ".$entry[sn][0]; + } + } + } + return $users; +} + +/** + * makes sure the given DN contains exactly one space + * after each , + */ +function normalize_dn($dn){ + $dn = preg_replace('/,/',', ',$dn); + $dn = preg_replace('/,\s+/',', ',$dn); + return $dn; +} + +/** + * Merges the given classes with the existing ones + */ +function ldap_store_objectclasses($dn,$classes){ + global $conf; + global $LDAP_CON; + + $sr = ldap_search($LDAP_CON,$dn,"objectClass=*",array('objectClass')); + $result = ldap_get_binentries($LDAP_CON, $sr); + $set = $result[0][objectClass]; + $set = array_unique_renumber(array_merge($set,$classes)); + $add[objectClass] = $set; + + $r = @ldap_mod_replace($LDAP_CON,$dn,$add); + tpl_ldaperror(); + +/* print '
';
+  print_r($set);
+  print '
';*/ +} + +/** + * Makes array unique and renumbers the entries + * + * @author + */ +function array_unique_renumber($somearray){ + $tmparr = array_unique($somearray); + $i=0; + foreach ($tmparr as $v) { + $newarr[$i] = $v; + $i++; + } + return $newarr; +} + +/** + * Decodes UTF8 recursivly for the given array + */ +function utf8_decode_array(&$array) { + foreach (array_keys($array) as $key) { + if($key === 'dn') continue; + if($key === 'jpegPhoto') continue; + if (is_array($array[$key])) { + utf8_decode_array($array[$key]); + }else { + $array[$key] = utf8_decode($array[$key]); + } + } +} + +/** + * Encodes the given array to UTF8 recursively + */ +function utf8_encode_array(&$array) { + foreach (array_keys($array) as $key) { + if($key === 'dn') continue; + if($key === 'jpegPhoto') continue; + if (is_array($array[$key])) { + utf8_encode_array($array[$key]); + }else { + $array[$key] = utf8_encode($array[$key]); + } + } +} + +?> diff --git a/help.php b/help.php new file mode 100644 index 0000000..eaa5817 --- /dev/null +++ b/help.php @@ -0,0 +1,12 @@ +display('header.tpl'); + $smarty->display('help.tpl'); + $smarty->display('footer.tpl'); + +?> diff --git a/img.php b/img.php new file mode 100644 index 0000000..993a4fc --- /dev/null +++ b/img.php @@ -0,0 +1,16 @@ + diff --git a/import.php b/import.php new file mode 100644 index 0000000..d1753cf --- /dev/null +++ b/import.php @@ -0,0 +1,166 @@ +fromFile($_FILES['userfile']['tmp_name']); + }elseif(preg_match('/^addressbook\.xml$/i', $_FILES['userfile']['name'])){ + //parse Zaurus Addressbook + $contacts = XML_unserialize(@join('',@file($_FILES['userfile']['tmp_name']))); + }else{ + $error = "Only *.vcf or addressbook.xml are accepted"; + } + }else{ + switch($_FILES['userfile']['error']){ + case 0: //no error; possible file attack! + $error = "There was a problem with your upload."; + break; + case 1: //uploaded file exceeds the upload_max_filesize directive in php.ini + $error = "The file you are trying to upload is too big."; + break; + case 2: //uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form + $error = "The file you are trying to upload is too big."; + break; + case 3: //uploaded file was only partially uploaded + $error = "The file you are trying upload was only partially uploaded."; + break; + case 4: //no file was uploaded + $error = "You must select a VCF file for upload."; + break; + default: //a default error, just in case! :) + $error = "There was a problem with your upload."; + break; + } + } + } + + //prepare templates for all found entries + $list = ''; + if(count($vcards)){ + foreach ($vcards as $vcard){ + $entry = vcard_entry($vcard); + $smarty->clear_all_assign(); + tpl_std(); + $smarty->assign('entry',$entry); + $list .= $smarty->fetch('import_entry.tpl'); + } + }elseif(count($contacts)){ + foreach ($contacts['AddressBook']['Contacts']['Contact'] as $contact){ + if (!is_array($contact)) continue; + $entry = zaurus_entry($contact); + $smarty->clear_all_assign(); + tpl_std(); + $smarty->assign('entry',$entry); + $list .= $smarty->fetch('import_entry.tpl'); + } + } + + //prepare templates + tpl_std(); + tpl_orgs(); + tpl_markers(); + $smarty->assign('error',$error); + $smarty->assign('list',$list); + //display templates + $smarty->display('header.tpl'); + $smarty->display('import.tpl'); + $smarty->display('footer.tpl'); + + +function zaurus_entry($cnct){ + $entry['name'] = $cnct['LastName']; + $entry['givenname'] = trim($cnct['FirstName'].' '.$cnct['MiddleName']); + $entry['title'] = $cnct['JobTitle']; + $entry['organization'] = $cnct['Company']; + $entry['office'] = $cnct['Office']; + $entry['note'] = $cnct['Notes']; + $entry['mail'] = split(' ',$cnct['Emails']); + $entry['street'] = $cnct['BusinessStreet']; + $entry['location'] = $cnct['BusinessCity']; + $entry['zip'] = $cnct['BusinessZip']; + $entry['homestreet'] = $cnct['HomeStreet']."\n". //str + $cnct['HomeZip']." ". //plz + $cnct['HomeCity']; //ort + $entry['homephone'] = $cnct['HomePhone']; + $entry['phone'] = $cnct['BusinessPhone']; + $entry['fax'] = empty($cnct['BusinessFax']) ? $cnct['HomeFax'] : $cnct['BusinessFax']; + $entry['mobile'] = empty($cnct['HomeMobile']) ? $cnct['BusinessMobile'] : $cnct['HomeMobile']; + $entry['fax'] = empty($cnct['BusinessFax']) ? $cnct['HomeFax'] : $cnct['BusinessFax']; + +# $entry['anniversary'] = $cnt['']; + + utf8_decode_array($entry); + return $entry; +} + +function vcard_entry($vcf){ + $entry['name'] = $vcf['N'][0]['value'][0][0]; + $entry['givenname'] = trim($vcf['N'][0]['value'][1][0].' '.$vcf['N'][0]['value'][2][0]); + $entry['title'] = $vcf['N'][0]['value'][3][0]; + $entry['organization'] = $vcf['ORG'][0]['value'][0][0]; + $entry['office'] = $vcf['ORG'][0]['value'][1][0]; + $entry['note'] = $vcf['NOTE'][0]['value'][0][0]; + $entry['url'] = $vcf['URL'][0]['value'][0][0]; + $bday = $vcf['BDAY'][0]['value'][0][0]; + $entry['anniversary'] = substr($bday,0,4).'-'.substr($bday,4,2).'-'.substr($bday,6,2); + + foreach($vcf['TEL'] as $tel){ + if( empty($entry['phone']) && + array_search('WORK',$tel['param']['TYPE']) !== FALSE && + array_search('VOICE',$tel['param']['TYPE']) !== FALSE){ + // Work phone + $entry['phone'] = $tel['value'][0][0]; + }elseif(empty($entry['fax']) && + array_search('FAX',$tel['param']['TYPE']) !== FALSE){ + $entry['fax'] = $tel['value'][0][0]; + }elseif(empty($entry['mobile']) && + array_search('CELL',$tel['param']['TYPE']) !== FALSE){ + $entry['mobile'] = $tel['value'][0][0]; + }elseif(empty($entry['pager']) && + array_search('PAGER',$tel['param']['TYPE']) !== FALSE){ + $entry['pager'] = $tel['value'][0][0]; + }elseif(empty($entry['homephone']) && + array_search('HOME',$tel['param']['TYPE']) !== FALSE && + array_search('VOICE',$tel['param']['TYPE']) !== FALSE){ + $entry['homephone'] = $tel['value'][0][0]; + } + } + foreach($vcf['EMAIL'] as $mail){ + $entry['mail'][] = $mail['value'][0][0]; + } + foreach($vcf['ADR'] as $adr){ + if(array_search('HOME',$adr['param']['TYPE']) !== FALSE){ + $entry['homestreet'] = $adr['value'][2][0]."\n". //str + $adr['value'][5][0]." ". //plz + $adr['value'][3][0]; //ort + + }elseif(array_search('WORK',$adr['param']['TYPE']) !== FALSE){ + $entry['street'] = $adr['value'][2][0]; + $entry['location'] = $adr['value'][3][0]; + $entry['zip'] = $adr['value'][5][0]; + } + } + +/* + print '
';
+  print_r($entry);
+  print '
'; +*/ + + return $entry; +} + + +?> diff --git a/importVCF.php b/importVCF.php new file mode 100644 index 0000000..bc9ea65 --- /dev/null +++ b/importVCF.php @@ -0,0 +1,127 @@ +fromFile($_FILES['userfile']['tmp_name']); + }else{ + switch($_FILES['userfile']['error']){ + case 0: //no error; possible file attack! + $error = "There was a problem with your upload."; + break; + case 1: //uploaded file exceeds the upload_max_filesize directive in php.ini + $error = "The file you are trying to upload is too big."; + break; + case 2: //uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form + $error = "The file you are trying to upload is too big."; + break; + case 3: //uploaded file was only partially uploaded + $error = "The file you are trying upload was only partially uploaded."; + break; + case 4: //no file was uploaded + $error = "You must select a VCF file for upload."; + break; + default: //a default error, just in case! :) + $error = "There was a problem with your upload."; + break; + } + } + }else{ + $error = "Only VCF extension is allowed"; + } + } + + //prepare templates for all found VCARDs + $list = ''; + if (count($vcards)){ + foreach ($vcards as $vcard){ + $entry = vcard_entry($vcard); + $smarty->clear_all_assign(); + tpl_std(); + $smarty->assign('entry',$entry); + $list .= $smarty->fetch('importVCF_entry.tpl'); + } + } + + //prepare templates + tpl_std(); + tpl_orgs(); + tpl_markers(); + $smarty->assign('error',$error); + $smarty->assign('list',$list); + //display templates + $smarty->display('header.tpl'); + $smarty->display('importVCF.tpl'); + $smarty->display('footer.tpl'); + + +function vcard_entry($vcf){ + $entry['name'] = $vcf['N'][0]['value'][0][0]; + $entry['givenname'] = trim($vcf['N'][0]['value'][1][0].' '.$vcf['N'][0]['value'][2][0]); + $entry['title'] = $vcf['N'][0]['value'][3][0]; + $entry['organization'] = $vcf['ORG'][0]['value'][0][0]; + $entry['office'] = $vcf['ORG'][0]['value'][1][0]; + $entry['note'] = $vcf['NOTE'][0]['value'][0][0]; + $entry['url'] = $vcf['URL'][0]['value'][0][0]; + $bday = $vcf['BDAY'][0]['value'][0][0]; + $entry['anniversary'] = substr($bday,0,4).'-'.substr($bday,4,2).'-'.substr($bday,6,2); + + foreach($vcf['TEL'] as $tel){ + if( empty($entry['phone']) && + array_search('WORK',$tel['param']['TYPE']) !== FALSE && + array_search('VOICE',$tel['param']['TYPE']) !== FALSE){ + // Work phone + $entry['phone'] = $tel['value'][0][0]; + }elseif(empty($entry['fax']) && + array_search('FAX',$tel['param']['TYPE']) !== FALSE){ + $entry['fax'] = $tel['value'][0][0]; + }elseif(empty($entry['mobile']) && + array_search('CELL',$tel['param']['TYPE']) !== FALSE){ + $entry['mobile'] = $tel['value'][0][0]; + }elseif(empty($entry['pager']) && + array_search('PAGER',$tel['param']['TYPE']) !== FALSE){ + $entry['pager'] = $tel['value'][0][0]; + }elseif(empty($entry['homephone']) && + array_search('HOME',$tel['param']['TYPE']) !== FALSE && + array_search('VOICE',$tel['param']['TYPE']) !== FALSE){ + $entry['homephone'] = $tel['value'][0][0]; + } + } + foreach($vcf['EMAIL'] as $mail){ + $entry['mail'][] = $mail['value'][0][0]; + } + foreach($vcf['ADR'] as $adr){ + if(array_search('HOME',$adr['param']['TYPE']) !== FALSE){ + $entry['homestreet'] = $adr['value'][2][0]."\n". //str + $adr['value'][5][0]." ". //plz + $adr['value'][3][0]; //ort + + }elseif(array_search('WORK',$adr['param']['TYPE']) !== FALSE){ + $entry['street'] = $adr['value'][2][0]; + $entry['location'] = $adr['value'][3][0]; + $entry['plz'] = $adr['value'][5][0]; + } + } + +/* + print '
';
+  print_r($entry);
+  print '
'; +*/ + + return $entry; +} + + +?> diff --git a/index.php b/index.php new file mode 100644 index 0000000..3f09573 --- /dev/null +++ b/index.php @@ -0,0 +1,102 @@ + display page + header("Location: entry.php?dn=".$result[0][dn]); + exit; + }elseif(count($result)){ + $keys = array_keys($result); + uksort($keys,"_namesort"); + foreach($keys as $key){ + tpl_entry($result[$key]); + $list .= $smarty->fetch('list_entry.tpl'); + } + } + + //save location in session + $_SESSION[ldapab][lastlocation]=$_SERVER["REQUEST_URI"]; + + //prepare templates + tpl_std(); + tpl_markers(); + $smarty->assign('list',$list); + //display templates + $smarty->display('header.tpl'); + $smarty->display('list_filter.tpl'); + $smarty->display('list.tpl'); + $smarty->display('footer.tpl'); + + //------- functions -----------// + + /** + * callback function to sort entries by name + * uses global $result + */ + function _namesort($a,$b){ + global $result; + $x = $result[$a][sn][0].$result[$a][givenName][0]; + $y = $result[$b][sn][0].$result[$b][givenName][0]; + return(strcasecmp($x,$y)); + } + + + /** + * Creates an LDAP filter from given request variables search or filter + */ + function _makeldapfilter(){ + //handle given filter + + $filter = $_REQUEST['filter']; + $search = $_REQUEST['search']; + $org = $_REQUEST['org']; + $marker = $_REQUEST['marker']; + $_SESSION[ldapab][filter] = $filter; + if(empty($filter)) $filter='a'; + + if(!empty($marker)){ + $marker = utf8_encode($marker); + $ldapfilter = "(&(objectClass=contactPerson)(marker=$marker))"; + }elseif(!empty($search)){ + $search = trim($search); + $words=preg_split('/\s+/',$search); + $filter=''; + foreach($words as $word){ + $word = utf8_encode($word); + $filter .= "(|(|(sn=*$word*)(givenName=*$word*))(o=*$word*))"; + } + $ldapfilter = "(&(objectClass=inetOrgPerson)$filter)"; + }elseif(!empty($org)){ + $org = utf8_encode($org); + $ldapfilter = "(&(objectClass=inetOrgPerson)(o=$org))"; + }elseif($filter=='other'){ + $other=''; + for ($i=ord('a');$i<=ord('z');$i++){ + $other .= '(!(sn='.chr($i).'*))'; + } + $ldapfilter = "(&(objectClass=inetOrgPerson)$other)"; + }else{ + $filter = utf8_encode($filter); + $ldapfilter = "(&(objectClass=inetOrgPerson)(sn=$filter*))"; + } + return $ldapfilter; + } +?> diff --git a/init.php b/init.php new file mode 100644 index 0000000..14bd24f --- /dev/null +++ b/init.php @@ -0,0 +1,39 @@ +compile_dir = './cache'; + $smarty->use_sub_dirs = 0; + $smarty->template_dir = './templates'; + $smarty->force_compile = $conf[smartycompile]; +?> diff --git a/lang/de.php b/lang/de.php new file mode 100644 index 0000000..10bc0a5 --- /dev/null +++ b/lang/de.php @@ -0,0 +1,69 @@ + diff --git a/lang/en.php b/lang/en.php new file mode 100644 index 0000000..b8838ca --- /dev/null +++ b/lang/en.php @@ -0,0 +1,68 @@ + diff --git a/ldapab.schema b/ldapab.schema new file mode 100644 index 0000000..19f2060 --- /dev/null +++ b/ldapab.schema @@ -0,0 +1,51 @@ +# LDAP 2 Schema +# +# This is a schema extension for the LDAPab Addressbook by +# CosmoCode GmbH www.cosmocode.de +# +# CosmoCode owns the following MIB Block: +# iso.org.dod.internet.private.enterprise.16331.* +# +# CosmoCode currently uses the following OID hierachy to organize the IDs: +# +# defined in cosmo4ML.schema +# 1.3.6.1.4.1.16331.1 formel CMS (cosmo4ML prefix) +# 1.3.6.1.4.1.16331.1.1 SNMP (not used) +# 1.3.6.1.4.1.16331.1.2 LDAP +# 1.3.6.1.4.1.16331.1.2.1 AttributeTypes +# 1.3.6.1.4.1.16331.1.2.2 ObjectClasses +# +# defined in ldapab.schema: +# 1.3.6.1.4.1.16331.2 LDAPab +# 1.3.6.1.4.1.16331.2.1 SNMP (not used) +# 1.3.6.1.4.1.16331.2.2 LDAP +# 1.3.6.1.4.1.16331.2.2.1 AttributeTypes +# 1.3.6.1.4.1.16331.2.2.2 ObjectClasses + + +# OID macros for ease of use: +objectIdentifier cosmocodeOID 1.3.6.1.4.1.16331 +objectIdentifier LDAPab cosmocodeOID:2.2 + + +attributetype ( 1.3.6.1.4.1.16331.2.2.1.1 NAME 'anniversary' + DESC 'Holds Birthdays etc.' + EQUALITY caseIgnoreMatch + ORDERING caseIgnoreOrderingMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.16331.2.2.1.2 NAME 'marker' + DESC 'marking flag' + EQUALITY caseIgnoreMatch + ORDERING caseIgnoreOrderingMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} + ) + +objectclass ( 1.3.6.1.4.1.16331.2.2.2.1 NAME 'contactPerson' + DESC 'Contact - Addressbook entry' + AUXILIARY + MAY ( anniversary $ marker ) + ) diff --git a/login.php b/login.php new file mode 100644 index 0000000..f7ad08e --- /dev/null +++ b/login.php @@ -0,0 +1,26 @@ +assign('msg',$msg); + //display templates + $smarty->display('header.tpl'); + $smarty->display('login.tpl'); + $smarty->display('footer.tpl'); +?> diff --git a/orgs.php b/orgs.php new file mode 100644 index 0000000..272c972 --- /dev/null +++ b/orgs.php @@ -0,0 +1,14 @@ +display('header.tpl'); + $smarty->display('orgs.tpl'); + $smarty->display('footer.tpl'); + + +?> diff --git a/pix/copy.png b/pix/copy.png new file mode 100644 index 0000000000000000000000000000000000000000..eac4d8c93b175b18dac347b6be58035619b2b757 GIT binary patch literal 590 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fEa{HEjtmUzPnffIy#(?lOI#yL zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+AuIMKJavL45_%4^ymM7`@=`O`TrR| zU`#(3lkVa7EhR;Pk%2{kyJzA0^$g;FzP`3UJm3Dm#J-xJ#||7h!Xh@?y8L&25Dz8*HJcOB%*fQiIh{pWnfXpaK)@WEO3`;kNjz*E3Su#BO}VV> zhwa()^|jmj<@X!a{Q5HW;isq8E;}U@8fFyio+jvF-1JgEexGs8|9{M9)Wm>ph!byq zvA_Pman0{<%x|g$%nUCc@o>En#OuJ2D8b`X%d@}!aM026HlXt+OwD2dT75S_fNkfe z=jZ1qm}zSpN3LW88hxSp!TI_B9mM}ORkXKCx*BVOL<5>0-M0@g_`~Qf#dCO%SJo;< z4h50e`u|N$O$A1(YFB}lcO3*;?Rx1ipuohS&~TyYk-iDj|K^YT z>u0PxJ}v9U&B(?_Iu73d4qjyhhFg)rff&Xj-6I7)&V@^*CMZit3fi#%Lm*;JlYt(? zDG>v2$91lLrvLvr#&CXO6c#>|(7?bX?X$w7<*7-`O139a0W}Siw0M9n5Y}upUl+p6 zZTDmW1Bb#S9yPP84Gazp6H^Szopr0CV=>Q~&?~ literal 0 HcmV?d00001 diff --git a/pix/delete.png b/pix/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..6fb193f0619a41842a8111dbfc97e9cfec35a9e7 GIT binary patch literal 951 zcmV;o14#UdP)D4F(wqN;#llNs12vi~arkm*L6N zSKt%_l3TN84Te5|0AeE6#o&l!W&|7hk{J^~HD zcb$Q2aSH?2kxdM|^E<$Xg7AmzW`^%pF2IOo0*5m;01!Y-=vnw5pD@Eer*MYA?4L1;k zza>{N{PGF~=0YZjp^Qvm3$Ouz075aC5eYIqxXHly{5itlk6#(smn~pm{PYo+R1i7x z-+%0p2M|D5{lR>ECj;AzX1JmM{{a)vhi?qbr_M46_<1rgefk7W+u$6@h&?C(0*DEl zp{z)T{w(fb_%?Ml!+%CD28M4y`OB9W`29T@7(af*o2dW-2-DzgE8vFyD(PhS?H$JO zS5uGS+nSvW|M~eLi63Y<+p)uV4F(7x41<4HOk(&aBE#^jw3FeFPZ(VMubw``r_B(< zzf76I@WaC!ufYHT#DbpO7`S*C{?6G7j-Y?Q90$UXybUy5SC8TCy{AAXkORz#kgSe9 z@&Ez|#b7p8MACs72+Femp_Z@!BkKQuCNLXV9Dyxh{DZxQ0tg@$NU6odP+Hl>KurJ; ZU;r@5PZawLhx`Bl002ovPDHLkV1f)SrDgyC literal 0 HcmV?d00001 diff --git a/pix/edit.png b/pix/edit.png new file mode 100644 index 0000000000000000000000000000000000000000..ce8b226710bc4bdd74059a5d46487cdf6743f3ef GIT binary patch literal 1076 zcmV-41k3x0P)`K`fBk0o`}ZHi$4_4wbT36RFbLQ)JUM;k!HwN#8dDzpU%-F^ z00a=j`OEkIV*`Kx{rms*`>+2WKmYju_Wig2*VlCY|8pn=RxK-(D@{@p*oARuvqf#C^I;tvqN`pxj{(k+H3Pkt=Kr5_-Gm>38Ep!p2{ z?@eZ4lLT^JfRqCT-f%L!6E>A09Gr2y6x##taG^28K`U3|~I| zW7yANz;NrWp4loG5urU1k#mey8F^hp68228P=pmH&VS^Dtb0@SQ<4J`$Mj7{JL27XSz#oCbqk^L`!!gBUjh z!_U7!TR@@4&G1PpfI)(p864cew2sqYfB?d2@SiJ-7}#_L85rJzRQ+aP_{zg@@BSAC z*^F!kCU!QkYe6{@H3bO)BZA@Y|NrlP0|XEYZr9FaU=#%g!?$lh5q2QvXL!!0&Y;XE z$ng8mU!Wn7VgO_T&_HgmcfkH&_y^>_0|+1%6vLq4$K`bl9I`wN3?G5gAQhjv7#>`H zz#tvj4>phm7!<$%{AT#_U~KirY`7a)MJW{^KWfv#i?VqoC)Vfgh=gW=k>{|ub! z2HHM;6wSm_mVkW<3h2*3 z1OLLr0RjlC!TV1WiE&p&W#`1c=o&I1S_xWR0!%y2;!?_h}c|NVm$^gx3_7{+E~_{#v~ uF);pN#Az@<0I`5-iPFk825JL<00RKz*@!b6gg3tc0000YF`^5o zChb)K8aN+_9e%KKGkoO{WiZneVqo|WME}7A!}aSg7`{Jv$iVdWHOP_!K+6-~UC4ZZ zYz{yGp%|=|v@hWQzkl<8uy6~g8L2VE+X^xGs9^We;l~UNb9X&wIJo901Jj$AAAmkd z{CFdO156$ufZztJC4&t8zy2eSI76zxIzzl63s{_)iGe|ihk=0u$bI_u2g9px3=BNn z9B>OxKKRK{(t3#D`{gU3U<&+lzZ7gZKmajA4Bf8)G<5qX9&wJ8AZ-R8H715{zZt+- z5NL)lC&UmwE*6INDZ3ezwN>HrLfkA2M&`;4doO-u`2GC32P==$%HN;&egFs{CXfcO z_gT3Fd|lKT%%m8=u7cqYKTw0RhPhyc*l^FitW0*F~PVXpzu z;0``*U4}q?U}OPZfsCJgW?=XSjI;YUA23vOZD-(=R%DP=QN&Qk#>T?%icOf|+0pX~ z%xrcW0Ro8S|G&TaKUjGfOqB!~UVgzIQ9Hrn3JhAo3Sd4qbq_x=F#M2`XZR;9%JBc$ zvwVO6VgV(quY#fsLO}1l_=>7HRFi>0h7ZCP;)H~E!SwSCe-sVDV();#bm=t%!=3jG z3_t%u)G;ZmGcZ1S>;MozAcGZnLLbHLs9s?tk5pD<{J1_$r-p6ou<6~fX@)H!mVDYbyS2M72`ZI7U z7{k>*U9*wl&$DMAfXqY?A0U9>#io$K^Z;PeThFVe#vtKf$H2_NPE;!S^X)ss{S_M- z-W)#-;syd;3obSR0tls`7tov(04kk0MT7(t-5nSNl;rRl`u6%=h8s&aFnoRlb7>#E zpa%#bjH-!OsTWwk{h1F;Ee<^5A`IfdvR6b+9-Q{T$qz`px_X!4>FLW1A0L7v>HySG zl&T3JfEaPPhEu%70BAuzu);*COo2r#IGsWboCq`!Yh?-$U;w6N`1tF4c>DkW002ov JPDHLkV1ml?7-s+g literal 0 HcmV?d00001 diff --git a/pix/image.png b/pix/image.png new file mode 100644 index 0000000000000000000000000000000000000000..fdf537038fb8615d7e4c0ec243fedcbb2da1e265 GIT binary patch literal 760 zcmVz@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ;Zb?KzRCwBA?C^QBY98aOvS+hL<1z zFns*_hk=`uk>U8wFAO)I{b2a{`wzp{A3*%`FT=NAe;B?2*`L1uW_U5jjA6or2@C)M zcpQTh06-{&3Pme){xh`yW~oU~2l2g&*xypkb|VeQ!m0sEaiJ@{M zk`eZ8P=>`$?)jWBL-s=GX@1kMFw55pA7#*;My1f0tn8!bLS4&*&qYh z+1VNR`1lx(9zD!3W8FOl7Jg-hOV^e&6y&5aaB^{jT?hjJ0mOtJuONSd0LUN#etrfu z4S5DNO&JDBaWP=*{Aaj(_b$V(UAy4w0Rjl_g5N-Yf-p$q+qZ8SZr!>Cbg~jdSsW)Y za9;vdcmrMdo8ifmCt#Pt06+l24Pato0%MTBLHOLcbKtNL6cl9O;S~f2>hC-2;n53j67=ysdl`FwCKmfrFkdl%@2@6odfrSYu z9e`r!;K73o;o;$6aZoZYEG*;$2q3rtTwGi@GYrT8WM@M)vw?yRAb{Wofc%XQaB^}Y qYlf#~fB<5F2@(sCHG=>^fB^u^xEg#MahdL(G;vAMHeO*EpfuQ$jgBD0q>2iog9G0GsmZa9MG|csz?(jESx+-P$j70OGV8ny^-}w$|6vB z<<{*jnujJ?xp*~OJahaZVCx`oSO3|_f(WEea85{FOq*;Zym0JMRxVz>3p7X0j{_DF z#0iNL66X*RoIsK|8WRa=8l{?#a^rc&AuPxJU= zhj?-RVCHH6+8EGZt39(=z&T-k;|}W^clI&+eC6`pw-!(C(>$#+1cF**8WBlShn0au zgx40H0U!kB*6nQyub3H^f4dHF1o#8!?vo;@)irET3y~;8>Vy!Ko!x>94}Qvp=0`Xu z2m&ybc5-3vDYs~Ke(lWm{~S=UqefSU11Sfbr-ljnI&;N$X5>}6x& z(&=C0SwmI1^yT*h#?*R7w!7VuV6mAWWbe>!w=pw92ms8_&(rJmD9e(Gi3!TG#Cy-` z>MH24E2^kLz2Zbz+I^c=t3?O_?>*gam$fTvo|_#+9=jzW#QN&)$9g6wqTZTb0HVWl%MgSj2`V5#kX2{{Brif7pnY z8-0m;KnJ+i|LVyr3XKz3ff}F{c;DM*#(y z!r$wOeF<*UJ{l*S&KeCgZS8jk9@hW5@Br3#cv=i?ErvTAlP}dCXea6wbvj9AH>(#Uqk2e}SJeWakaYY1XMl=Bg5h01j1HH`v%$^yt z=iM(@=okES>QA0}>kG;Nm#oXVbaDbOkT^)yfkG8+H8>IlP@yBjgg|e@Iso23_A@ON zT25#sN?q1W&-Ve?JlVlJBT*$40~5v#x5;schKojq&;<!%#{qARSC)~Yl3oS3C zs)QIg_~mgv_{tazONb35^&X3najjaowf7a^LoUZNGj|v-jXvEDlP% zSFDOuwh9~!GJ&pBB-GqI)x`n7EtSmu-X~8y+BgM39gV3ACg`?OZn|m{A0M72Pn0kc zinv-a5oeLi85R{=zRr6`Px9)AhdIBUlA>f@NY$u=@%WwBaND(01T#b%n<7HBoC*(6 zh2~(5I-&%;G}1b`V|_R0!gfZYLgoagLRnUNv4j zfW;aJ3e0?araxWOf%SPx+bf;aF)Bw4iZP?%h*4QlRyCmtPz4APsUw-dhHlOU?UbW` z3^{yi0qSZRnDM|Yt?vE^-F}7(v$Epbv+q1Z(cis!qTOpJ-q#kXqA@lY2ct5hh}PsZ+VUI4##4(m zbv4bzy8S$V@7`5$1B(7jz@fRN!TKRc7fjCchy~R1AOHXW07*qoM6N<$ Ef-@K*z5oCK literal 0 HcmV?d00001 diff --git a/pix/logout.png b/pix/logout.png new file mode 100644 index 0000000000000000000000000000000000000000..119e5ef7fea11ac9c0ae3f507c0e660825cda646 GIT binary patch literal 1398 zcmV-+1&R8JP)Y(^46#6hy3syn&K~a=CSSf>8=`a@Qq_xvbG9S4&lT0!h&x_|Os z1J_HISCj0upKbRppaZaoh<;}*JpHv3vuCQ0J*x5e2tG~3dj&j#0)pZ}J(}mJ_o#Y6 zQC00UHt1ell0RK(ocYOS_hkWiVKn^W^9x7cDL(V0Pa0RXyLJ;r5oa;Z;qw%qW*~|Q z0$g0g1|cdS#vsNJjFjo^B;wzC*Sz`h+M^cW$!hei7@u3<a4pML>B_4va?mC=E=RY5rb7Vue0X{wGJt#SMEd$g992&-eD9`F6$ z=Rg%3muX%95B;qsrB6*!s!i@gbw6TNR230L;_`m<-lrIAK@75&HEX~aOyKZ7CrkTa z26`9kV36Yj5vxan0J7fTeH7se#R1gX{hK0Y05Ap@#kep6?-A=THbDLV-cVqd*)A3J$jO?*TxnK7#j@0)?%ZOJWVK19VHx{ptHF~va^jV!~^hN#HxzsIj&e{ zd-Wr>uY3T;a`dau6IDh?JG-Pw8-Oh7(r>q@+;@cOFMk7oUgHW`zlRAT)GMI4yVJ@e zMlfN4l|Q~t^~gNs2Tt+ObKmFc`CoDEo!_(m{sq!bi;0t;=g8yVB&<%*ZLZLG@2>>K z5xiG4_o%W59+p!C8^!E4SGn?=pK|QkZ&R5&#X~dmwAZeZbXpY0CMexI12!PpYI5!T zo8)76^x^q0O)rM|#O{lri?(BIymz4C7w zm;Of9PcUHt;{x@$lC`@iA`ZaylGRRQgJ7mcy1gTas4JADz1iTy-@Z!u-oupcyB~1@ z2Bo{%ptpMm7gw-R3F88_aap>zKB0Ycoe){I01pIaUGrMnwft5cRp&-ujx}eEV$)ZfwfmTfLWt4uXDnJU;z+{m_|k zVOHZ>1yp5F2*2NLcpW&0&(U0m14qf)U2Wf7$J}nq`Hjw*A2)YjKHz!i;%MQKnaI7E zML}I4WzX}5Z91^OyZgZQR22zAWcgZ>y>@Q1a{-Y50?KB7VQo*aM*si-07*qoM6N<$ Eg2p(hxc~qF literal 0 HcmV?d00001 diff --git a/pix/new.png b/pix/new.png new file mode 100644 index 0000000000000000000000000000000000000000..7be37e89a77c4f6df269bd74b30d69ea2edd59a2 GIT binary patch literal 692 zcmV;l0!#ggP)D4F(wqN;#llNs12vi~arkm*L6N zSKt%_l3TN84Te5|0AeE6#o&l!W&|7h0=tU=0tm%AMkELoV89yb{}DM7;%ZC)5I{_Lv+;kV?92$uFihaE zg<&Q}>_z|t5K$R~8~_kNG&2|=fbbiPrzppj<6r;5hr@0^`?Tj{pAsOJMlNkpKVR zzlr}D7#6%+=l%ho!2kiog3OVMKUnbpKf?u}W`j@a$_zifMHqfda2s%(e*T{E?Kg&x znZ^w4r=In5?zkfWRNjEkV1NK(L^kxBzIgwCpvmml-h6l$V<7NHfro+V=RXFHH$NE| znHU-Vu`@CJWcbU#GxgL5rq|yZ|NZ;_f#LuE2cNe296&c1Ab{WoOU4~M|2*B!fI$Qy zDRTHVgYcDi49rY_8JL(E8Ccj@7+3_k7~aSO@vUbJzj@dgm@hqNV0!W~@ykxX1;_>i z1P~L9@spX~fMElW@fL`G0S!IynnC>TI|eSnKMd^r{~1_${xLAJ{bKn0^#g~p7D^1itQCQd{%?=&Vt@c*fyMs+U++I~e19SEgG~Zx3j>4by^joh3ak(Q{bAm~ z@Sou$FevmHnHe1z85sq@Uj6lz!TLT6!>NBv4B!9#7eF@{Ab`LI|Ka60|6N_2fr0lw z*tJ}*zcX;~vm9XKXAL|UB?FIr`(;lAm{^$V8Ce+%K>WWz#rpih42R8?0yzGzTMvx% zgFg?3OaRFN1Q4Tmh13tRGmoSQwc8GlKOnZN3UJcp^w1Ab^-&uXK69`r{n~ z&-<$k9N!-@FuaEt{E3yF;e{Y?fZMFs^RXGcLXr^__6OL0F*5xA%gDfZ_ca5a6WYHCkJ%HIlnMG z_yaWl`a1@O|6-yHf1OPY{w*If?Mg_m6#Ze64V*JOT%lVr@ zp6CAq9!{nMtZd8=Sy-9;AADvsIQ#7XJ65rFABuKNMx9~oq=JO7b8Fb!3!aNpREqR1vnTO%OwVeH}Amd7$AU{;aU3DvIm?(z6$>&I1NAsa;!PQ z!1U}L!#@LH;UNoD_7K@?Kr9Y*A<#^Q=fHAc4$!4f-!EV|7n2E60uVr`LE*7U;Qzn> z`#~if5G4ZH2LCx(`hS+&3jDv!k5K3i&9mQu_%PI0D}e>gp+LBK00Bf0vD>Y2VD7*A zpJ5Zws>T2RGv(g=&up>cJY(63{|pa-VkbdPIQE~xXbDQ12M8c0LI#6e4+i=`tofCJ z@!Hh~KtV@_efKsn?7zpru=+Ry!^L}`ASguE2M|Ck1Pulj=8W5KKVZJ{QsMuXUkv|0 z{|x+hD)Iw^@zO$uNykA-CISt`DChwKh-k!YzFdIGY`Fok>Hz`_06+A`+)vkOxc~qF M07*qoM6N<$g1Pf^2mk;8 literal 0 HcmV?d00001 diff --git a/pix/orgs.png b/pix/orgs.png new file mode 100644 index 0000000000000000000000000000000000000000..7596e67a64ac95f5efef9af483395730bcd34837 GIT binary patch literal 1300 zcmV+v1?&2WP)2v(PS%W+({gsEaU2i}Rk33)V@9&}0&bagt*A_vc?cx{Cn_;(tH`fBpK;@Sl-^ z;nU}z3?hP@43{rGVc?gSWVm?s^-G4kOHRPl0t65!C>X96OB^_U=j#I@8DWO!ufH+~ z09~V@EL>oqEzW@K+CP6lhW}$wlNVsPcIPdFyfhyJKMxy&p$t0%CmVAwlo)tm1OT%0Tn3cw%{Vfo1*D#I7Rptlkn*#H5=gd8q^|NNbJ@;T5& z!0^0y?G=N%A}=t_z5yHh_wQdQ{SQq4{0*dm0S_u`K(7Aw>=lEjvntS#e+eM700Icb z;OG6?7fxS$e}O|B5{WP0{$h}k;sLts8{DNJnw6D_;lza(3?@2aV7{a%7ck7(7<7P< z$iTr04i10-V#X{yl7A{H3I_=N{=)F){dWduYk7v#7oPz&b3?=UKf|YQe;B@h{{;>L zQ22v=3zU2P`~$;RE`EW>uWc>@1P~Lt!N6R!VZ)K=+EdPEpxZ25rjL8QGAPg7(xG?+2FQwR% zAO5i>7)Y}*Jbv_+K^B<9egIu4$j`}e4jA^D%EAoH%*+h;o_u0Bbmlq3&HL|x$@Le* zKNfZdR-l9So_V4G5I~H$iaoZVg9RbZ^8K~~pBT8=nHYGunHdbVr5PSR`M~hw*FT2a z4}snW1_=nTiwZN`dC$mj`0PuDOM7l@017Px2p~qhWvb`y`Grwx30kc08Q9qv893Nk z8Gil#&+z%{FNR9k?b2A*j`-5TYt~($8JpViqRG=~3i3OL800D&8UW$r3>1My4C|k748Q*~Gu(X7%CPCs3x;$1?;c?I$FLA+*aCE|00G2Euqv?ItRNu7 zd0v>GLqJPIl;PybM;~6@dc6Rch$k}Kh<<=e8$bXt(yB5A2rvMOBkc>ezzB5!0000< KMNUMnLSTY%R7AS~ literal 0 HcmV?d00001 diff --git a/pix/private.png b/pix/private.png new file mode 100644 index 0000000000000000000000000000000000000000..55fb6ddf180f7a5c36b00cbc70bfdc649e648f05 GIT binary patch literal 856 zcmV-e1E>6nP)PbXFRCwBA z{Qv(y12SM_WQ4Q7g)=Dp`^!-OkC`EWQO-c%?{5Z%U-vG2`2Ce(15mtB_5i~Nm|Apm z00IasfQ*q0HTV+F@c!qD{Qv)6U;qFA^K&o;vA-;<`~S#;@BLj11_NB?00a;tHWz;l zWf1t!#BiS@ty_Ru(U1Wf`1Rlx!^85d2WqDo6tTG&Ab?n~Y5Mn{A%R8PM1YwaDE;a( zR)g8N7#R3%O%<;EJe{C(iD3b{JU{?pHTdse27eA|5e9~r7cnjU^^M{8%UeKvoq_r1 zPlmsL80>+<7zP6b5O#zA0E6VqT?U3fFHyb!`7OiGw~r96<^wxI0h<{B0ffuo5C301 zU|`^40*A}Le?U8a{sGee7+8_ieSHm9`v99600G2=!{CkI9{&X<4It+SBLmYfMg}%U zRt64cb`<>aJ`>2r2eFv}5I~H$((yw(hVv3O(gth-oLD38)6=gE*ET%AVEK^25L>DM z2q3I3hPpcO>5-QY-aiC}gMd67|K*TkczW>{*wFv~7#wlw2M8cWd^zuiF@pdwhZX$! z!w}CYEv5hp>yLL{T>#P>fp~(|W866pAb>Co{ua*I@Sho+jlq!ybQOaBkH!Z@Dli^? ze`9D=Iq|;%*&KiX!pMqWA{qYwJ~i+E|F5rz!oN<;`+vt4q!ra1fB?csZXlPkh{$5i z9M}M>m@ES$8>Tow0AU&o^d7_W^H>e}_v0hOuiN_={ye(~^wu{>>T1P~)u7bh?X zFt9P)@5}BJFj6pLzy@wTzQvH%p7sFfYDH`=1_&S)th)X%B$!#739yQ>GF<+48LJWo zVFm_sM{|Xf3?~zShA%*u1_&VR2LEU97u6MIxcK!VhSaw|-x#icxz2Fy^EHN_{69fL z_CSnbFhBrdHy8+Rv)pEQ@%06Y*qiTf7#@Coh!7A0lM2}M0|XE*gFoDVbDx2Up9wDT z``>SdfB*h50K*;uo`J~+*bD#&ASN6JZ~S}bFT;Pf|8UI0!NS1C#fE|z?}C%&L2L#9 z1P~+6bR5laUMfk-fJ2-EtIgjYeq(sC?8OCO#2I2s6#xN*%f%p&_-gs92mjCgXOL%; zhhwRKQVhS3{e~FIz~G2WGe7__;>~%{!1T<(Pyod7qKcy6NP2z$HORn?Ks*6o&I1S_ zOoP)H8-Q6Dl#LmH*_kl-48&g;8vif(-+(L(5I~q&I)~x^f`<$Kzxn-!C=5~yEK~lY zn*$I)n8^(oR|*0O3|GEgVIT&8)H3j5iUR}?)^vRC>p853eEj{9Vb9w=4Cg`d$o5^NGA8T^9j1%?c<^{a3Iaba8+H0|0lzPHn~aQ=nPbPK-5vETJT>rjaVEOlJVMK(-1O_4jKmakq81v?B zNO;X4-2YKfL4a9Un1P>{k%5JUk>US;28LgM{xh(?dd9%_>edB@Uq2I5QUWdzG8iC$ zzy?p6v^?Pzo9z7GDuxVVB1{aN9E=RCtPneY{rb} zVP0P31AGPp1Q1hu`+S90|M>fVDH}3KNis8ti?J|BOR_LX0cjCIW(H19Mus2XfzAfn zBPGqrz-?$K@arGrd_pb;2q31PKY!-`5LXir7Gz=&;%8=%5N2YK<^^JIMuy)&*D6Z0 zG6)DTgMGos1T;)+M&LFx&c0e0Ro8W{V$dP4rxiS%XolZ<_89W7*IkIh=D=N z!2Rz(g8)CsQYHpI9wr7ZHbw>+6IF(9-+sj7GZ-L%SiUlFD@brMfy0!EnSlX_7+8V$ z)sO!Syg-Avff4u{7z`{RR{$~4E(R$%F_6J{T?`OFEI--!8CZe3fN{g{^37j{_wWBQ zJOEn64D`ALHxmPpV&Gzc7|aYc_%9HD|Nawi7y|?l%iqs$fG&k3D}JC0Ie=aTxlEi3 z=zSpLGmy;*#B4|g{{rG~-@fBD7$AU{zQ4Ht0F%Ks3`LRpE`g5Vt(-8 z{10hS)teulzKW1BHee70CMzaJV0H!u2P-2Y(m>!g(9r(YSq$3R$_$K*j0cY$+j#?* z!2kgSFDo1zk^}gqW#(H%2Mg%fXoJ%1d;2&*)4`sBiBFD!m+377)2C+!Y9c}kdvAT&2vP$O zKx7%b>&BN0Dx6FYU*EYBpy%oWG+c&3fcXsr3(#;W9zlg8_rGie2q0#1gX7TMFBhbl zm>#~obveM;!T*uy)Ve0gA3=GOa3;+Sd$Ur3!Zy-LOlancd jMJtNo{)-4MuYdH3Dd5$2MuAVim>8rve=zVe{J6mU_vbSVuTrd z?b^MBTkl!>um9ja{hf{TCO) z5I|sq&tJUr|LQw7hVSg$3?jV$7=Q)>rT#Pg{ri{U&u<|8?>7SzBO}9G4&m9ncP~0J zefj7b8R_u=pTPhD#B%)jC50zHI2kx4Bp6ghm>4)Ym>Aet85sWk`_J(E_dkZO-~TbZ zd;gh%mzRTq?ZeyDPb%uOf1EivAE?(6pTPhD#Ps9Gul%=+JPZ>2KttJ?7{{RjyRt6TJ zD?u&=n!&&Wl;8t;odJk}<^v67WZ>gvWf0_NXOI#XWDt`Oa{d1OM?5}*0Ro8W<##3p zZZ-x6W+p}kMxddf&}9bVuYdkCumcTb1B$b=Ffeej0(}IO7X${0s){twA*==X3+jD%LnIkMiH-wk5DPQJ)!b}Mz+m{#@be!dgQl_^*cS}{|1o^} z^p)WkFk+dQm>8Ztdydn^00G3r_Vv|+AAgvD$%%pC^Vfe2zyAP(f|-%wFOdHeXa&eX zU??y!0}W;P^#{!V@%bwQA3rb9my9?K1_&Ugzn|Z1c>m@DI4IbFF8&MD|Mx!w*awV2 z5`_Q${>$(mWGFD1a4<75Tsw1}K}S~&Zw3JfAf}%`e>XlqcbefnFl^b`7=c~{8Tucb zj{p9H(BRw&b=;?qpBeV=I?TYs%f*1l!3+Qa#MIQ3`N33MhT-sr-3%Xo`~w>fQvdtU zKZajGm;MHN;XlxXf50U3=HnNJ*;7|BC@IM@d;x|vJ^&Cv;4FRN%KiWUfB#}wyx|ao zb&v;xvWgS~J1|wS0A0=u3J#E(V;33LE#AbSqou+iFE7FH_x()EAprgp}1ySR?w)s5>6Pd{)iaOp=F4iG?0D7L_22uL9n(+B_+6LqR! zxVv{F1G}IA1DBpZgP4XUgE-IEgpFBJ^I=K>0*DDCY#=2jBF3RKC_{kKEeH!61Tipb z7BQS$Fqwf}SPW>mAA^*(27{cy*M#NC5W@iihzWa?;*M=t#UN%F$Z+nP6T{)z6M=?H zfDM<^)nHH&`I;~{MruAl0HGKR3Rg&cLBkix`>-&E8U7Eb@TZ6g!}ZIr68FrQz`!mh z&A_GW#~=etHGi4d5&!}S#b7p8W?=2X1g2Sm`544z0%mUz&C1FGEJuJCSeUSY)G>og z4~C2t&lX%c|0;3YL|}EuEyS?vG$X@j00O6q%hwTnD@-#-in;GB#Q|28g3A$V5a0WR5M9J){LRX4DUcII-=j zbqE25f~_Lp#KDXcDrR;Qfl|;yD>CDp7zDe4-wK04pSJX^Y=4}4a&K~zbCP>*X==(k zhR0G5003is;@Wf<`z(MCyK3*{oiQ$2Buo5s4*;I51yI1rI@C3E%M))D1E8xoU{5>d z>iu&P(>DUJKM(+g3V_$7i=P5e$OGUR4!~*+0KNs)U-W(CTCG^WR-Cc#{x%0m3XSEM zz$r*wB9TaVR5vfrI@VmZ(#m2%##1o}LPlfgK}R^*) zISA4H4;j8M6gj+2U@2kq>s?hYvbbez%VIPs2c-@spRftlaycn*N%Xb2yFVsL63r}D zEY|RScP041Zndf5cnjf2UneDu*v1$+C9=r8kbd za{0A4H`|_=BGo@JqtKLVd3glwAB)v8hI|lm;UPY6_muF5`s4~^ONu^L0eW}@J9YME za~GB}YVViLt>PH_eUp(&=d|E}`*{cLXiFG^TpjF?wq@&0-P4j_$V|2(!r5o2bGOG? z4df+~sf1MH!M-zLh)o#IUqjyPpE`A{#u`I|AR#Y%N)BKOPsal+I>d7hKKPZkcWc1V zFOwLm_-*>w?+RXj1CCFL#|5QZY%VMF=ZL$28O9j%Z z@llh1PjscYGEZP^KIIjEE(1kxmtbhn{`s8zuiS!?BIN2W%TTwZq^EoCRlxr~auURi zs(a_K!A_^8(R`rHI#Be9dZw!b4K2jbl?)6mS8R7&pJyVKlaB0t^XXOMip}-bhHrUL zdmRj^E(b#9=YCuma`Q?$KU9rNGiP-*R_`jG)Q@xXujJtR5H{v7DeJdP6sCd-tnw8q-1Kp{Z`9b$UM zjD#vc9ADFL;Tk12;1}$Bhx2V-F3Sf*}!Z_ zxLpi!Zn&bV2in+@H*zn+HaRAz6LvQ2e6Yq&noCcU!mQ{Sa;7Yp?2_A^>?V(<$M#A# z`5h$@$^Rk5l&k>T47p1K??nUE@k5KP}yT1-64SULRNMO1ICQ z>X+;^IGisYY2Q7ORCQ**=#g}9gzKs!QHkJ3kk93v6^!%+(Y$aFT2Qm)s + * @access public + * @package Smarty + */ + +/* $Id: Config_File.class.php,v 1.1.1.1 2004/01/13 16:02:46 gohr Exp $ */ +/** + * Config file reading class + * @package Smarty + */ +class Config_File { + /**#@+ + * Options + * @var boolean + */ + /** + * Controls whether variables with the same name overwrite each other. + */ + var $overwrite = true; + + /** + * Controls whether config values of on/true/yes and off/false/no get + * converted to boolean values automatically. + */ + var $booleanize = true; + + /** + * Controls whether hidden config sections/vars are read from the file. + */ + var $read_hidden = true; + + /** + * Controls whether or not to fix mac or dos formatted newlines. + * If set to true, \r or \r\n will be changed to \n. + */ + var $fix_newlines = true; + /**#@-*/ + + /** @access private */ + var $_config_path = ""; + var $_config_data = array(); + /**#@-*/ + + /** + * Constructs a new config file class. + * + * @param string $config_path (optional) path to the config files + */ + function Config_File($config_path = NULL) + { + if (isset($config_path)) + $this->set_path($config_path); + } + + + /** + * Set the path where configuration files can be found. + * + * @param string $config_path path to the config files + */ + function set_path($config_path) + { + if (!empty($config_path)) { + if (!is_string($config_path) || !file_exists($config_path) || !is_dir($config_path)) { + $this->_trigger_error_msg("Bad config file path '$config_path'"); + return; + } + if(substr($config_path, -1) != DIRECTORY_SEPARATOR) { + $config_path .= DIRECTORY_SEPARATOR; + } + + $this->_config_path = $config_path; + } + } + + + /** + * Retrieves config info based on the file, section, and variable name. + * + * @param string $file_name config file to get info for + * @param string $section_name (optional) section to get info for + * @param string $var_name (optional) variable to get info for + * @return string|array a value or array of values + */ + function &get($file_name, $section_name = NULL, $var_name = NULL) + { + if (empty($file_name)) { + $this->_trigger_error_msg('Empty config file name'); + return; + } else { + $file_name = $this->_config_path . $file_name; + if (!isset($this->_config_data[$file_name])) + $this->load_file($file_name, false); + } + + if (!empty($var_name)) { + if (empty($section_name)) { + return $this->_config_data[$file_name]["vars"][$var_name]; + } else { + if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name])) + return $this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name]; + else + return array(); + } + } else { + if (empty($section_name)) { + return (array)$this->_config_data[$file_name]["vars"]; + } else { + if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"])) + return (array)$this->_config_data[$file_name]["sections"][$section_name]["vars"]; + else + return array(); + } + } + } + + + /** + * Retrieves config info based on the key. + * + * @param $file_name string config key (filename/section/var) + * @return string|array same as get() + * @uses get() retrieves information from config file and returns it + */ + function &get_key($config_key) + { + list($file_name, $section_name, $var_name) = explode('/', $config_key, 3); + $result = &$this->get($file_name, $section_name, $var_name); + return $result; + } + + /** + * Get all loaded config file names. + * + * @return array an array of loaded config file names + */ + function get_file_names() + { + return array_keys($this->_config_data); + } + + + /** + * Get all section names from a loaded file. + * + * @param string $file_name config file to get section names from + * @return array an array of section names from the specified file + */ + function get_section_names($file_name) + { + $file_name = $this->_config_path . $file_name; + if (!isset($this->_config_data[$file_name])) { + $this->_trigger_error_msg("Unknown config file '$file_name'"); + return; + } + + return array_keys($this->_config_data[$file_name]["sections"]); + } + + + /** + * Get all global or section variable names. + * + * @param string $file_name config file to get info for + * @param string $section_name (optional) section to get info for + * @return array an array of variables names from the specified file/section + */ + function get_var_names($file_name, $section = NULL) + { + if (empty($file_name)) { + $this->_trigger_error_msg('Empty config file name'); + return; + } else if (!isset($this->_config_data[$file_name])) { + $this->_trigger_error_msg("Unknown config file '$file_name'"); + return; + } + + if (empty($section)) + return array_keys($this->_config_data[$file_name]["vars"]); + else + return array_keys($this->_config_data[$file_name]["sections"][$section]["vars"]); + } + + + /** + * Clear loaded config data for a certain file or all files. + * + * @param string $file_name file to clear config data for + */ + function clear($file_name = NULL) + { + if ($file_name === NULL) + $this->_config_data = array(); + else if (isset($this->_config_data[$file_name])) + $this->_config_data[$file_name] = array(); + } + + + /** + * Load a configuration file manually. + * + * @param string $file_name file name to load + * @param boolean $prepend_path whether current config path should be + * prepended to the filename + */ + function load_file($file_name, $prepend_path = true) + { + if ($prepend_path && $this->_config_path != "") + $config_file = $this->_config_path . $file_name; + else + $config_file = $file_name; + + ini_set('track_errors', true); + $fp = @fopen($config_file, "r"); + if (!is_resource($fp)) { + $this->_trigger_error_msg("Could not open config file '$config_file'"); + return false; + } + + $contents = fread($fp, filesize($config_file)); + fclose($fp); + + if($this->fix_newlines) { + // fix mac/dos formatted newlines + $contents = preg_replace('!\r\n?!',"\n",$contents); + } + + $config_data = array(); + + /* replace all multi-line values by placeholders */ + if (preg_match_all('/"""(.*)"""/Us', $contents, $match)) { + $_triple_quotes = $match[1]; + $_i = 0; + $contents = preg_replace('/""".*"""/Use', '"\x1b\x1b\x1b".$_i++."\x1b\x1b\x1b"', $contents); + } else { + $_triple_quotes = null; + } + + /* Get global variables first. */ + if ($contents{0} != '[' && preg_match("/^(.*?)(\n\[|\Z)/s", $contents, $match)) + $config_data["vars"] = $this->_parse_config_block($match[1], $_triple_quotes); + + /* Get section variables. */ + $config_data["sections"] = array(); + preg_match_all("/^\[(.*?)\]/m", $contents, $match); + foreach ($match[1] as $section) { + if ($section{0} == '.' && !$this->read_hidden) + continue; + if (preg_match("/\[".preg_quote($section, '/')."\](.*?)(\n\[|\Z)/s", $contents, $match)) + if ($section{0} == '.') + $section = substr($section, 1); + $config_data["sections"][$section]["vars"] = $this->_parse_config_block($match[1], $_triple_quotes); + } + + $this->_config_data[$config_file] = $config_data; + + return true; + } + + /**#@+ @access private */ + /** + * @var string $config_block + */ + function _parse_config_block($config_block, $triple_quotes) + { + $vars = array(); + + /* First we grab the multi-line values. */ + if (preg_match_all("/^([^=\n]+)=\s*\x1b\x1b\x1b(\d+)\x1b\x1b\x1b\s*$/ms", $config_block, $match, PREG_SET_ORDER)) { + for ($i = 0; $i < count($match); $i++) { + $this->_set_config_var($vars, trim($match[$i][1]), $triple_quotes[$match[$i][2]], false); + } + $config_block = preg_replace("/^[^=\n]+=\s*\x1b\x1b\x1b\d+\x1b\x1b\x1b\s*$/ms", "", $config_block); + } + + + $config_lines = preg_split("/\n+/", $config_block); + + foreach ($config_lines as $line) { + if (preg_match("/^\s*(\.?\w+)\s*=(.*)/", $line, $match)) { + $var_value = preg_replace('/^([\'"])(.*)\1$/', '\2', trim($match[2])); + $this->_set_config_var($vars, trim($match[1]), $var_value, $this->booleanize); + } + } + + return $vars; + } + + /** + * @param array &$container + * @param string $var_name + * @param mixed $var_value + * @param boolean $booleanize determines whether $var_value is converted to + * to true/false + */ + function _set_config_var(&$container, $var_name, $var_value, $booleanize) + { + if ($var_name{0} == '.') { + if (!$this->read_hidden) + return; + else + $var_name = substr($var_name, 1); + } + + if (!preg_match("/^[a-zA-Z_]\w*$/", $var_name)) { + $this->_trigger_error_msg("Bad variable name '$var_name'"); + return; + } + + if ($booleanize) { + if (preg_match("/^(on|true|yes)$/i", $var_value)) + $var_value = true; + else if (preg_match("/^(off|false|no)$/i", $var_value)) + $var_value = false; + } + + if (!isset($container[$var_name]) || $this->overwrite) + $container[$var_name] = $var_value; + else { + settype($container[$var_name], 'array'); + $container[$var_name][] = $var_value; + } + } + + /** + * @uses trigger_error() creates a PHP warning/error + * @param string $error_msg + * @param integer $error_type one of + */ + function _trigger_error_msg($error_msg, $error_type = E_USER_WARNING) + { + trigger_error("Config_File error: $error_msg", $error_type); + } + /**#@-*/ +} + +?> diff --git a/smarty/Smarty.class.php b/smarty/Smarty.class.php new file mode 100644 index 0000000..7388dc3 --- /dev/null +++ b/smarty/Smarty.class.php @@ -0,0 +1,2010 @@ + + * @author Andrei Zmievski + * @package Smarty + * @version 2.6.0 + */ + +/* $Id: Smarty.class.php,v 1.1.1.1 2004/01/13 16:02:46 gohr Exp $ */ + +/** + * DIR_SEP isn't used anymore, but third party apps might + */ +if(!defined('DIR_SEP')) { + define('DIR_SEP', DIRECTORY_SEPARATOR); +} + +/** + * set SMARTY_DIR to absolute path to Smarty library files. + * if not defined, include_path will be used. Sets SMARTY_DIR only if user + * application has not already defined it. + */ + +if (!defined('SMARTY_DIR')) { + define('SMARTY_DIR', dirname(__FILE__) . DIRECTORY_SEPARATOR); +} + +define('SMARTY_PHP_PASSTHRU', 0); +define('SMARTY_PHP_QUOTE', 1); +define('SMARTY_PHP_REMOVE', 2); +define('SMARTY_PHP_ALLOW', 3); + +/** + * @package Smarty + */ +class Smarty +{ + /**#@+ + * Smarty Configuration Section + */ + + /** + * The name of the directory where templates are located. + * + * @var string + */ + var $template_dir = 'templates'; + + /** + * The directory where compiled templates are located. + * + * @var string + */ + var $compile_dir = 'templates_c'; + + /** + * The directory where config files are located. + * + * @var string + */ + var $config_dir = 'configs'; + + /** + * An array of directories searched for plugins. + * + * @var array + */ + var $plugins_dir = array('plugins'); + + /** + * If debugging is enabled, a debug console window will display + * when the page loads (make sure your browser allows unrequested + * popup windows) + * + * @var boolean + */ + var $debugging = false; + + /** + * This is the path to the debug console template. If not set, + * the default one will be used. + * + * @var string + */ + var $debug_tpl = ''; + + /** + * This determines if debugging is enable-able from the browser. + *
    + *
  • NONE => no debugging control allowed
  • + *
  • URL => enable debugging when SMARTY_DEBUG is found in the URL.
  • + *
+ * @link http://www.foo.dom/index.php?SMARTY_DEBUG + * @var string + */ + var $debugging_ctrl = 'NONE'; + + /** + * This tells Smarty whether to check for recompiling or not. Recompiling + * does not need to happen unless a template or config file is changed. + * Typically you enable this during development, and disable for + * production. + * + * @var boolean + */ + var $compile_check = true; + + /** + * This forces templates to compile every time. Useful for development + * or debugging. + * + * @var boolean + */ + var $force_compile = false; + + /** + * This enables template caching. + *
    + *
  • 0 = no caching
  • + *
  • 1 = use class cache_lifetime value
  • + *
  • 2 = use cache_lifetime in cache file
  • + *
+ * @var integer + */ + var $caching = 0; + + /** + * The name of the directory for cache files. + * + * @var string + */ + var $cache_dir = 'cache'; + + /** + * This is the number of seconds cached content will persist. + *
    + *
  • 0 = always regenerate cache
  • + *
  • -1 = never expires
  • + *
+ * + * @var integer + */ + var $cache_lifetime = 3600; + + /** + * Only used when $caching is enabled. If true, then If-Modified-Since headers + * are respected with cached content, and appropriate HTTP headers are sent. + * This way repeated hits to a cached page do not send the entire page to the + * client every time. + * + * @var boolean + */ + var $cache_modified_check = false; + + /** + * This determines how Smarty handles "" tags in templates. + * possible values: + *
    + *
  • SMARTY_PHP_PASSTHRU -> print tags as plain text
  • + *
  • SMARTY_PHP_QUOTE -> escape tags as entities
  • + *
  • SMARTY_PHP_REMOVE -> remove php tags
  • + *
  • SMARTY_PHP_ALLOW -> execute php tags
  • + *
+ * + * @var integer + */ + var $php_handling = SMARTY_PHP_PASSTHRU; + + /** + * This enables template security. When enabled, many things are restricted + * in the templates that normally would go unchecked. This is useful when + * untrusted parties are editing templates and you want a reasonable level + * of security. (no direct execution of PHP in templates for example) + * + * @var boolean + */ + var $security = false; + + /** + * This is the list of template directories that are considered secure. This + * is used only if {@link $security} is enabled. One directory per array + * element. {@link $template_dir} is in this list implicitly. + * + * @var array + */ + var $secure_dir = array(); + + /** + * These are the security settings for Smarty. They are used only when + * {@link $security} is enabled. + * + * @var array + */ + var $security_settings = array( + 'PHP_HANDLING' => false, + 'IF_FUNCS' => array('array', 'list', + 'isset', 'empty', + 'count', 'sizeof', + 'in_array', 'is_array', + 'true','false'), + 'INCLUDE_ANY' => false, + 'PHP_TAGS' => false, + 'MODIFIER_FUNCS' => array('count'), + 'ALLOW_CONSTANTS' => false + ); + + /** + * This is an array of directories where trusted php scripts reside. + * {@link $security} is disabled during their inclusion/execution. + * + * @var array + */ + var $trusted_dir = array(); + + /** + * The left delimiter used for the template tags. + * + * @var string + */ + var $left_delimiter = '{'; + + /** + * The right delimiter used for the template tags. + * + * @var string + */ + var $right_delimiter = '}'; + + /** + * The order in which request variables are registered, similar to + * variables_order in php.ini E = Environment, G = GET, P = POST, + * C = Cookies, S = Server + * + * @var string + */ + var $request_vars_order = "EGPCS"; + + /** + * Indicates wether $HTTP_*_VARS[] (request_use_auto_globals=false) + * are uses as request-vars or $_*[]-vars. note: if + * request_use_auto_globals is true, then $request_vars_order has + * no effect, but the php-ini-value "gpc_order" + * + * @var boolean + */ + var $request_use_auto_globals = false; + + /** + * Set this if you want different sets of compiled files for the same + * templates. This is useful for things like different languages. + * Instead of creating separate sets of templates per language, you + * set different compile_ids like 'en' and 'de'. + * + * @var string + */ + var $compile_id = null; + + /** + * This tells Smarty whether or not to use sub dirs in the cache/ and + * templates_c/ directories. sub directories better organized, but + * may not work well with PHP safe mode enabled. + * + * @var boolean + * + */ + var $use_sub_dirs = true; + + /** + * This is a list of the modifiers to apply to all template variables. + * Put each modifier in a separate array element in the order you want + * them applied. example: array('escape:"htmlall"'); + * + * @var array + */ + var $default_modifiers = array(); + + /** + * This is the resource type to be used when not specified + * at the beginning of the resource path. examples: + * $smarty->display('file:index.tpl'); + * $smarty->display('db:index.tpl'); + * $smarty->display('index.tpl'); // will use default resource type + * {include file="file:index.tpl"} + * {include file="db:index.tpl"} + * {include file="index.tpl"} {* will use default resource type *} + * + * @var array + */ + var $default_resource_type = 'file'; + + /** + * The function used for cache file handling. If not set, built-in caching is used. + * + * @var null|string function name + */ + var $cache_handler_func = null; + + /** + * These are the variables from the globals array that are + * assigned to all templates automatically. This isn't really + * necessary any more, you can use the $smarty var to access them + * directly. + * + * @var array + */ + var $global_assign = array('HTTP_SERVER_VARS' => array('SCRIPT_NAME')); + + /** + * The value of "undefined". Leave it alone :-) + * + * @var null + */ + var $undefined = null; + + /** + * This indicates which filters are automatically loaded into Smarty. + * + * @var array array of filter names + */ + var $autoload_filters = array(); + + /**#@+ + * @var boolean + */ + /** + * This tells if config file vars of the same name overwrite each other or not. + * if disabled, same name variables are accumulated in an array. + */ + var $config_overwrite = true; + + /** + * This tells whether or not to automatically booleanize config file variables. + * If enabled, then the strings "on", "true", and "yes" are treated as boolean + * true, and "off", "false" and "no" are treated as boolean false. + */ + var $config_booleanize = true; + + /** + * This tells whether hidden sections [.foobar] are readable from the + * tempalates or not. Normally you would never allow this since that is + * the point behind hidden sections: the application can access them, but + * the templates cannot. + */ + var $config_read_hidden = false; + + /** + * This tells whether or not automatically fix newlines in config files. + * It basically converts \r (mac) or \r\n (dos) to \n + */ + var $config_fix_newlines = true; + /**#@-*/ + + /** + * If a template cannot be found, this PHP function will be executed. + * Useful for creating templates on-the-fly or other special action. + * + * @var string function name + */ + var $default_template_handler_func = ''; + + /** + * The file that contains the compiler class. This can a full + * pathname, or relative to the php_include path. + * + * @var string + */ + var $compiler_file = 'Smarty_Compiler.class.php'; + + /** + * The class used for compiling templates. + * + * @var string + */ + var $compiler_class = 'Smarty_Compiler'; + + /** + * The class used to load config vars. + * + * @var string + */ + var $config_class = 'Config_File'; + +/**#@+ + * END Smarty Configuration Section + * There should be no need to touch anything below this line. + * @access private + */ + /** + * error messages. true/false + * + * @var boolean + */ + var $_error_msg = false; + + /** + * where assigned template vars are kept + * + * @var array + */ + var $_tpl_vars = array(); + + /** + * stores run-time $smarty.* vars + * + * @var null|array + */ + var $_smarty_vars = null; + + /** + * keeps track of sections + * + * @var array + */ + var $_sections = array(); + + /** + * keeps track of foreach blocks + * + * @var array + */ + var $_foreach = array(); + + /** + * keeps track of tag hierarchy + * + * @var array + */ + var $_tag_stack = array(); + + /** + * configuration object + * + * @var Config_file + */ + var $_conf_obj = null; + + /** + * loaded configuration settings + * + * @var array + */ + var $_config = array(array('vars' => array(), 'files' => array())); + + /** + * md5 checksum of the string 'Smarty' + * + * @var string + */ + var $_smarty_md5 = 'f8d698aea36fcbead2b9d5359ffca76f'; + + /** + * Smarty version number + * + * @var string + */ + var $_version = '2.6.0'; + + /** + * current template inclusion depth + * + * @var integer + */ + var $_inclusion_depth = 0; + + /** + * for different compiled templates + * + * @var string + */ + var $_compile_id = null; + + /** + * text in URL to enable debug mode + * + * @var string + */ + var $_smarty_debug_id = 'SMARTY_DEBUG'; + + /** + * debugging information for debug console + * + * @var array + */ + var $_smarty_debug_info = array(); + + /** + * info that makes up a cache file + * + * @var array + */ + var $_cache_info = array(); + + /** + * default file permissions + * + * @var integer + */ + var $_file_perms = 0644; + + /** + * default dir permissions + * + * @var integer + */ + var $_dir_perms = 0771; + + /** + * registered objects + * + * @var array + */ + var $_reg_objects = array(); + + /** + * table keeping track of plugins + * + * @var array + */ + var $_plugins = array( + 'modifier' => array(), + 'function' => array(), + 'block' => array(), + 'compiler' => array(), + 'prefilter' => array(), + 'postfilter' => array(), + 'outputfilter' => array(), + 'resource' => array(), + 'insert' => array()); + + + /** + * cache serials + * + * @var array + */ + var $_cache_serials = array(); + + /** + * name of optional cache include file + * + * @var string + */ + var $_cache_include = null; + + /** + * indicate if the current code is used in a compiled + * include + * + * @var string + */ + var $_cache_including = false; + + /**#@-*/ + /** + * The class constructor. + * + * @uses $global_assign uses {@link assign()} to assign each corresponding + * value from $GLOBALS to the template vars + */ + function Smarty() + { + foreach ($this->global_assign as $key => $var_name) { + if (is_array($var_name)) { + foreach ($var_name as $var) { + if (isset($GLOBALS[$key][$var])) { + $this->assign($var, $GLOBALS[$key][$var]); + } else { + $this->assign($var, $this->undefined); + } + } + } else { + if (isset($GLOBALS[$var_name])) { + $this->assign($var_name, $GLOBALS[$var_name]); + } else { + $this->assign($var_name, $this->undefined); + } + } + } + } + + + /** + * assigns values to template variables + * + * @param array|string $tpl_var the template variable name(s) + * @param mixed $value the value to assign + */ + function assign($tpl_var, $value = null) + { + if (is_array($tpl_var)){ + foreach ($tpl_var as $key => $val) { + if ($key != '') { + $this->_tpl_vars[$key] = $val; + } + } + } else { + if ($tpl_var != '') + $this->_tpl_vars[$tpl_var] = $value; + } + } + + /** + * assigns values to template variables by reference + * + * @param string $tpl_var the template variable name + * @param mixed $value the referenced value to assign + */ + function assign_by_ref($tpl_var, &$value) + { + if ($tpl_var != '') + $this->_tpl_vars[$tpl_var] = &$value; + } + + /** + * appends values to template variables + * + * @param array|string $tpl_var the template variable name(s) + * @param mixed $value the value to append + */ + function append($tpl_var, $value=null, $merge=false) + { + if (is_array($tpl_var)) { + // $tpl_var is an array, ignore $value + foreach ($tpl_var as $_key => $_val) { + if ($_key != '') { + if(!@is_array($this->_tpl_vars[$_key])) { + settype($this->_tpl_vars[$_key],'array'); + } + if($merge && is_array($_val)) { + foreach($_val as $_mkey => $_mval) { + $this->_tpl_vars[$_key][$_mkey] = $_mval; + } + } else { + $this->_tpl_vars[$_key][] = $_val; + } + } + } + } else { + if ($tpl_var != '' && isset($value)) { + if(!@is_array($this->_tpl_vars[$tpl_var])) { + settype($this->_tpl_vars[$tpl_var],'array'); + } + if($merge && is_array($value)) { + foreach($value as $_mkey => $_mval) { + $this->_tpl_vars[$tpl_var][$_mkey] = $_mval; + } + } else { + $this->_tpl_vars[$tpl_var][] = $value; + } + } + } + } + + /** + * appends values to template variables by reference + * + * @param string $tpl_var the template variable name + * @param mixed $value the referenced value to append + */ + function append_by_ref($tpl_var, &$value, $merge=false) + { + if ($tpl_var != '' && isset($value)) { + if(!@is_array($this->_tpl_vars[$tpl_var])) { + settype($this->_tpl_vars[$tpl_var],'array'); + } + if ($merge && is_array($value)) { + foreach($value as $_key => $_val) { + $this->_tpl_vars[$tpl_var][$_key] = &$value[$_key]; + } + } else { + $this->_tpl_vars[$tpl_var][] = &$value; + } + } + } + + + /** + * clear the given assigned template variable. + * + * @param string $tpl_var the template variable to clear + */ + function clear_assign($tpl_var) + { + if (is_array($tpl_var)) + foreach ($tpl_var as $curr_var) + unset($this->_tpl_vars[$curr_var]); + else + unset($this->_tpl_vars[$tpl_var]); + } + + + /** + * Registers custom function to be used in templates + * + * @param string $function the name of the template function + * @param string $function_impl the name of the PHP function to register + */ + function register_function($function, $function_impl, $cacheable=true, $cache_attrs=null) + { + $this->_plugins['function'][$function] = + array($function_impl, null, null, false, $cacheable, $cache_attrs); + + } + + /** + * Unregisters custom function + * + * @param string $function name of template function + */ + function unregister_function($function) + { + unset($this->_plugins['function'][$function]); + } + + /** + * Registers object to be used in templates + * + * @param string $object name of template object + * @param object &$object_impl the referenced PHP object to register + * @param null|array $allowed list of allowed methods (empty = all) + * @param boolean $smarty_args smarty argument format, else traditional + * @param null|array $block_functs list of methods that are block format + */ + function register_object($object, &$object_impl, $allowed = array(), $smarty_args = true, $block_methods = array()) + { + settype($allowed, 'array'); + settype($smarty_args, 'boolean'); + $this->_reg_objects[$object] = + array(&$object_impl, $allowed, $smarty_args, $block_methods); + } + + /** + * Unregisters object + * + * @param string $object name of template object + */ + function unregister_object($object) + { + unset($this->_reg_objects[$object]); + } + + + /** + * Registers block function to be used in templates + * + * @param string $block name of template block + * @param string $block_impl PHP function to register + */ + function register_block($block, $block_impl, $cacheable=true, $cache_attrs=null) + { + $this->_plugins['block'][$block] = + array($block_impl, null, null, false, $cacheable, $cache_attrs); + } + + /** + * Unregisters block function + * + * @param string $block name of template function + */ + function unregister_block($block) + { + unset($this->_plugins['block'][$block]); + } + + /** + * Registers compiler function + * + * @param string $function name of template function + * @param string $function_impl name of PHP function to register + */ + function register_compiler_function($function, $function_impl, $cacheable=true) + { + $this->_plugins['compiler'][$function] = + array($function_impl, null, null, false, $cacheable); + } + + /** + * Unregisters compiler function + * + * @param string $function name of template function + */ + function unregister_compiler_function($function) + { + unset($this->_plugins['compiler'][$function]); + } + + /** + * Registers modifier to be used in templates + * + * @param string $modifier name of template modifier + * @param string $modifier_impl name of PHP function to register + */ + function register_modifier($modifier, $modifier_impl) + { + $this->_plugins['modifier'][$modifier] = + array($modifier_impl, null, null, false); + } + + /** + * Unregisters modifier + * + * @param string $modifier name of template modifier + */ + function unregister_modifier($modifier) + { + unset($this->_plugins['modifier'][$modifier]); + } + + /** + * Registers a resource to fetch a template + * + * @param string $type name of resource + * @param array $functions array of functions to handle resource + */ + function register_resource($type, $functions) + { + if (count($functions)==4) { + $this->_plugins['resource'][$type] = + array($functions, false); + + } elseif (count($functions)==5) { + $this->_plugins['resource'][$type] = + array(array(array(&$functions[0], $functions[1]) + ,array(&$functions[0], $functions[2]) + ,array(&$functions[0], $functions[3]) + ,array(&$functions[0], $functions[4])) + ,false); + + } else { + $this->trigger_error("malformed function-list for '$type' in register_resource"); + + } + } + + /** + * Unregisters a resource + * + * @param string $type name of resource + */ + function unregister_resource($type) + { + unset($this->_plugins['resource'][$type]); + } + + /** + * Registers a prefilter function to apply + * to a template before compiling + * + * @param string $function name of PHP function to register + */ + function register_prefilter($function) + { + $_name = (is_array($function)) ? $function[1] : $function; + $this->_plugins['prefilter'][$_name] + = array($function, null, null, false); + } + + /** + * Unregisters a prefilter function + * + * @param string $function name of PHP function + */ + function unregister_prefilter($function) + { + unset($this->_plugins['prefilter'][$function]); + } + + /** + * Registers a postfilter function to apply + * to a compiled template after compilation + * + * @param string $function name of PHP function to register + */ + function register_postfilter($function) + { + $_name = (is_array($function)) ? $function[1] : $function; + $this->_plugins['postfilter'][$_name] + = array($function, null, null, false); + } + + /** + * Unregisters a postfilter function + * + * @param string $function name of PHP function + */ + function unregister_postfilter($function) + { + unset($this->_plugins['postfilter'][$function]); + } + + /** + * Registers an output filter function to apply + * to a template output + * + * @param string $function name of PHP function + */ + function register_outputfilter($function) + { + $_name = (is_array($function)) ? $function[1] : $function; + $this->_plugins['outputfilter'][$_name] + = array($function, null, null, false); + } + + /** + * Unregisters an outputfilter function + * + * @param string $function name of PHP function + */ + function unregister_outputfilter($function) + { + unset($this->_plugins['outputfilter'][$function]); + } + + /** + * load a filter of specified type and name + * + * @param string $type filter type + * @param string $name filter name + */ + function load_filter($type, $name) + { + switch ($type) { + case 'output': + $_params = array('plugins' => array(array($type . 'filter', $name, null, null, false))); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + break; + + case 'pre': + case 'post': + if (!isset($this->_plugins[$type . 'filter'][$name])) + $this->_plugins[$type . 'filter'][$name] = false; + break; + } + } + + /** + * clear cached content for the given template and cache id + * + * @param string $tpl_file name of template file + * @param string $cache_id name of cache_id + * @param string $compile_id name of compile_id + * @param string $exp_time expiration time + * @return boolean + */ + function clear_cache($tpl_file = null, $cache_id = null, $compile_id = null, $exp_time = null) + { + + if (!isset($compile_id)) + $compile_id = $this->compile_id; + + if (!isset($tpl_file)) + $compile_id = null; + + $_auto_id = $this->_get_auto_id($cache_id, $compile_id); + + if (!empty($this->cache_handler_func)) { + return call_user_func_array($this->cache_handler_func, + array('clear', &$this, &$dummy, $tpl_file, $cache_id, $compile_id, $exp_time)); + } else { + $_params = array('auto_base' => $this->cache_dir, + 'auto_source' => $tpl_file, + 'auto_id' => $_auto_id, + 'exp_time' => $exp_time); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.rm_auto.php'); + return smarty_core_rm_auto($_params, $this); + } + + } + + + /** + * clear the entire contents of cache (all templates) + * + * @param string $exp_time expire time + * @return boolean results of {@link smarty_core_rm_auto()} + */ + function clear_all_cache($exp_time = null) + { + if (!empty($this->cache_handler_func)) { + $dummy = null; + call_user_func_array($this->cache_handler_func, + array('clear', &$this, &$dummy, null, null, null, $exp_time)); + } else { + $_params = array('auto_base' => $this->cache_dir, + 'auto_source' => null, + 'auto_id' => null, + 'exp_time' => $exp_time); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.rm_auto.php'); + return smarty_core_rm_auto($_params, $this); + } + } + + + /** + * test to see if valid cache exists for this template + * + * @param string $tpl_file name of template file + * @param string $cache_id + * @param string $compile_id + * @return string|false results of {@link _read_cache_file()} + */ + function is_cached($tpl_file, $cache_id = null, $compile_id = null) + { + if (!$this->caching) + return false; + + if (!isset($compile_id)) + $compile_id = $this->compile_id; + + $_params = array( + 'tpl_file' => $tpl_file, + 'cache_id' => $cache_id, + 'compile_id' => $compile_id + ); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.read_cache_file.php'); + return smarty_core_read_cache_file($_params, $this); + } + + + /** + * clear all the assigned template variables. + * + */ + function clear_all_assign() + { + $this->_tpl_vars = array(); + } + + /** + * clears compiled version of specified template resource, + * or all compiled template files if one is not specified. + * This function is for advanced use only, not normally needed. + * + * @param string $tpl_file + * @param string $compile_id + * @param string $exp_time + * @return boolean results of {@link smarty_core_rm_auto()} + */ + function clear_compiled_tpl($tpl_file = null, $compile_id = null, $exp_time = null) + { + if (!isset($compile_id)) { + $compile_id = $this->compile_id; + } + $_params = array('auto_base' => $this->compile_dir, + 'auto_source' => $tpl_file, + 'auto_id' => $compile_id, + 'exp_time' => $exp_time, + 'extensions' => array('.inc', '.php')); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.rm_auto.php'); + return smarty_core_rm_auto($_params, $this); + } + + /** + * Checks whether requested template exists. + * + * @param string $tpl_file + * @return boolean + */ + function template_exists($tpl_file) + { + $_params = array('resource_name' => $tpl_file, 'quiet'=>true, 'get_source'=>false); + return $this->_fetch_resource_info($_params); + } + + /** + * Returns an array containing template variables + * + * @param string $name + * @param string $type + * @return array + */ + function &get_template_vars($name=null) + { + if(!isset($name)) { + return $this->_tpl_vars; + } + if(isset($this->_tpl_vars[$name])) { + return $this->_tpl_vars[$name]; + } + } + + /** + * Returns an array containing config variables + * + * @param string $name + * @param string $type + * @return array + */ + function &get_config_vars($name=null) + { + if(!isset($name) && is_array($this->_config[0])) { + return $this->_config[0]['vars']; + } else if(isset($this->_config[0]['vars'][$name])) { + return $this->_config[0]['vars'][$name]; + } + } + + /** + * trigger Smarty error + * + * @param string $error_msg + * @param integer $error_type + */ + function trigger_error($error_msg, $error_type = E_USER_WARNING) + { + trigger_error("Smarty error: $error_msg", $error_type); + } + + + /** + * executes & displays the template results + * + * @param string $resource_name + * @param string $cache_id + * @param string $compile_id + */ + function display($resource_name, $cache_id = null, $compile_id = null) + { + $this->fetch($resource_name, $cache_id, $compile_id, true); + } + + /** + * executes & returns or displays the template results + * + * @param string $resource_name + * @param string $cache_id + * @param string $compile_id + * @param boolean $display + */ + function fetch($resource_name, $cache_id = null, $compile_id = null, $display = false) + { + static $_cache_info = array(); + + $_smarty_old_error_level = $this->debugging ? error_reporting() : error_reporting(error_reporting() & ~E_NOTICE); + + if (!$this->debugging && $this->debugging_ctrl == 'URL' + && @strstr($GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING'], $this->_smarty_debug_id)) { + // enable debugging from URL + $this->debugging = true; + } + + if ($this->debugging) { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.get_microtime.php'); + $_debug_start_time = smarty_core_get_microtime($_params, $this); + $this->_smarty_debug_info[] = array('type' => 'template', + 'filename' => $resource_name, + 'depth' => 0); + $_included_tpls_idx = count($this->_smarty_debug_info) - 1; + } + + if (!isset($compile_id)) { + $compile_id = $this->compile_id; + } + + $this->_compile_id = $compile_id; + $this->_inclusion_depth = 0; + + if ($this->caching) { + // save old cache_info, initialize cache_info + array_push($_cache_info, $this->_cache_info); + $this->_cache_info = array(); + $_params = array( + 'tpl_file' => $resource_name, + 'cache_id' => $cache_id, + 'compile_id' => $compile_id, + 'results' => null + ); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.read_cache_file.php'); + if (smarty_core_read_cache_file($_params, $this)) { + $_smarty_results = $_params['results']; + if (@count($this->_cache_info['insert_tags'])) { + $_params = array('plugins' => $this->_cache_info['insert_tags']); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + $_params = array('results' => $_smarty_results); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.process_cached_inserts.php'); + $_smarty_results = smarty_core_process_cached_inserts($_params, $this); + } + if (@count($this->_cache_info['cache_serials'])) { + $_params = array('results' => $_smarty_results); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.process_compiled_include.php'); + $_smarty_results = smarty_core_process_compiled_include($_params, $this); + } + + + if ($display) { + if ($this->debugging) + { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.get_microtime.php'); + $this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $_debug_start_time; + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.display_debug_console.php'); + $_smarty_results .= smarty_core_display_debug_console($_params, $this); + } + if ($this->cache_modified_check) { + $_last_modified_date = @substr($GLOBALS['HTTP_SERVER_VARS']['HTTP_IF_MODIFIED_SINCE'], 0, strpos($GLOBALS['HTTP_SERVER_VARS']['HTTP_IF_MODIFIED_SINCE'], 'GMT') + 3); + $_gmt_mtime = gmdate('D, d M Y H:i:s', $this->_cache_info['timestamp']).' GMT'; + if (@count($this->_cache_info['insert_tags']) == 0 + && !$this->_cache_serials + && $_gmt_mtime == $_last_modified_date) { + if (php_sapi_name()=='cgi') + header("Status: 304 Not Modified"); + else + header("HTTP/1.1 304 Not Modified"); + + } else { + header("Last-Modified: ".$_gmt_mtime); + echo $_smarty_results; + } + } else { + echo $_smarty_results; + } + error_reporting($_smarty_old_error_level); + // restore initial cache_info + $this->_cache_info = array_pop($_cache_info); + return true; + } else { + error_reporting($_smarty_old_error_level); + // restore initial cache_info + $this->_cache_info = array_pop($_cache_info); + return $_smarty_results; + } + } else { + $this->_cache_info['template'][$resource_name] = true; + if ($this->cache_modified_check) { + header("Last-Modified: ".gmdate('D, d M Y H:i:s', time()).' GMT'); + } + } + } + + // load filters that are marked as autoload + if (count($this->autoload_filters)) { + foreach ($this->autoload_filters as $_filter_type => $_filters) { + foreach ($_filters as $_filter) { + $this->load_filter($_filter_type, $_filter); + } + } + } + + $_smarty_compile_path = $this->_get_compile_path($resource_name); + + // if we just need to display the results, don't perform output + // buffering - for speed + $_cache_including = $this->_cache_including; + $this->_cache_including = false; + if ($display && !$this->caching && count($this->_plugins['outputfilter']) == 0) { + if ($this->_is_compiled($resource_name, $_smarty_compile_path) + || $this->_compile_resource($resource_name, $_smarty_compile_path)) + { + include($_smarty_compile_path); + } + } else { + ob_start(); + if ($this->_is_compiled($resource_name, $_smarty_compile_path) + || $this->_compile_resource($resource_name, $_smarty_compile_path)) + { + include($_smarty_compile_path); + } + $_smarty_results = ob_get_contents(); + ob_end_clean(); + + foreach ((array)$this->_plugins['outputfilter'] as $_output_filter) { + $_smarty_results = call_user_func_array($_output_filter[0], array($_smarty_results, &$this)); + } + } + + if ($this->caching) { + $_params = array('tpl_file' => $resource_name, + 'cache_id' => $cache_id, + 'compile_id' => $compile_id, + 'results' => $_smarty_results); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.write_cache_file.php'); + smarty_core_write_cache_file($_params, $this); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.process_cached_inserts.php'); + $_smarty_results = smarty_core_process_cached_inserts($_params, $this); + + if ($this->_cache_serials) { + // strip nocache-tags from output + $_smarty_results = preg_replace('!(\{/?nocache\:[0-9a-f]{32}#\d+\})!s' + ,'' + ,$_smarty_results); + } + // restore initial cache_info + $this->_cache_info = array_pop($_cache_info); + } + $this->_cache_including = $_cache_including; + + if ($display) { + if (isset($_smarty_results)) { echo $_smarty_results; } + if ($this->debugging) { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.get_microtime.php'); + $this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = (smarty_core_get_microtime($_params, $this) - $_debug_start_time); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.display_debug_console.php'); + echo smarty_core_display_debug_console($_params, $this); + } + error_reporting($_smarty_old_error_level); + return; + } else { + error_reporting($_smarty_old_error_level); + if (isset($_smarty_results)) { return $_smarty_results; } + } + } + + /** + * load configuration values + * + * @param string $file + * @param string $section + * @param string $scope + */ + function config_load($file, $section = null, $scope = 'global') + { + require_once($this->_get_plugin_filepath('function', 'config_load')); + smarty_function_config_load(array('file' => $file, 'section' => $section, 'scope' => $scope), $this); + } + + /** + * return a reference to a registered object + * + * @param string $name + * @return object + */ + function &get_registered_object($name) { + if (!isset($this->_reg_objects[$name])) + $this->_trigger_fatal_error("'$name' is not a registered object"); + + if (!is_object($this->_reg_objects[$name][0])) + $this->_trigger_fatal_error("registered '$name' is not an object"); + + return $this->_reg_objects[$name][0]; + } + + /** + * clear configuration values + * + * @param string $var + */ + function clear_config($var = null) + { + if(!isset($var)) { + // clear all values + $this->_config = array(array('vars' => array(), + 'files' => array())); + } else { + unset($this->_config[0]['vars'][$var]); + } + } + + /** + * get filepath of requested plugin + * + * @param string $type + * @param string $name + * @return string|false + */ + function _get_plugin_filepath($type, $name) + { + $_params = array('type' => $type, 'name' => $name); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.assemble_plugin_filepath.php'); + return smarty_core_assemble_plugin_filepath($_params, $this); + } + + /** + * test if resource needs compiling + * + * @param string $resource_name + * @param string $compile_path + * @return boolean + */ + function _is_compiled($resource_name, $compile_path) + { + if (!$this->force_compile && file_exists($compile_path)) { + if (!$this->compile_check) { + // no need to check compiled file + return true; + } else { + // get file source and timestamp + $_params = array('resource_name' => $resource_name, 'get_source'=>false); + if (!$this->_fetch_resource_info($_params, $this)) { + return false; + } + if ($_params['resource_timestamp'] <= filemtime($compile_path)) { + // template not expired, no recompile + return true; + } else { + // compile template + return false; + } + } + } else { + // compiled template does not exist, or forced compile + return false; + } + } + + /** + * compile the template + * + * @param string $resource_name + * @param string $compile_path + * @return boolean + */ + function _compile_resource($resource_name, $compile_path) + { + + $_params = array('resource_name' => $resource_name); + if (!$this->_fetch_resource_info($_params)) { + return false; + } + + $_source_content = $_params['source_content']; + $_resource_timestamp = $_params['resource_timestamp']; + $_cache_include = substr($compile_path, 0, -4).'.inc'; + + if ($this->_compile_source($resource_name, $_source_content, $_compiled_content, $_cache_include)) { + // if a _cache_serial was set, we also have to write an include-file: + if ($this->_cache_include_info) { + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.write_compiled_include.php'); + smarty_core_write_compiled_include(array_merge($this->_cache_include_info, array('compiled_content'=>$_compiled_content)), $this); + } + + $_params = array('compile_path'=>$compile_path, 'compiled_content' => $_compiled_content, 'resource_timestamp' => $_resource_timestamp); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.write_compiled_resource.php'); + smarty_core_write_compiled_resource($_params, $this); + + return true; + } else { + $this->trigger_error($smarty_compiler->_error_msg); + return false; + } + + } + + /** + * compile the given source + * + * @param string $resource_name + * @param string $source_content + * @param string $compiled_content + * @return boolean + */ + function _compile_source($resource_name, &$source_content, &$compiled_content, $cache_include_path=null) + { + if (file_exists(SMARTY_DIR . $this->compiler_file)) { + require_once(SMARTY_DIR . $this->compiler_file); + } else { + // use include_path + require_once($this->compiler_file); + } + + + $smarty_compiler = new $this->compiler_class; + + $smarty_compiler->template_dir = $this->template_dir; + $smarty_compiler->compile_dir = $this->compile_dir; + $smarty_compiler->plugins_dir = $this->plugins_dir; + $smarty_compiler->config_dir = $this->config_dir; + $smarty_compiler->force_compile = $this->force_compile; + $smarty_compiler->caching = $this->caching; + $smarty_compiler->php_handling = $this->php_handling; + $smarty_compiler->left_delimiter = $this->left_delimiter; + $smarty_compiler->right_delimiter = $this->right_delimiter; + $smarty_compiler->_version = $this->_version; + $smarty_compiler->security = $this->security; + $smarty_compiler->secure_dir = $this->secure_dir; + $smarty_compiler->security_settings = $this->security_settings; + $smarty_compiler->trusted_dir = $this->trusted_dir; + $smarty_compiler->_reg_objects = &$this->_reg_objects; + $smarty_compiler->_plugins = &$this->_plugins; + $smarty_compiler->_tpl_vars = &$this->_tpl_vars; + $smarty_compiler->default_modifiers = $this->default_modifiers; + $smarty_compiler->compile_id = $this->_compile_id; + $smarty_compiler->_config = $this->_config; + $smarty_compiler->request_use_auto_globals = $this->request_use_auto_globals; + + $smarty_compiler->_cache_serial = null; + $smarty_compiler->_cache_include = $cache_include_path; + + + $_results = $smarty_compiler->_compile_file($resource_name, $source_content, $compiled_content); + + if ($smarty_compiler->_cache_serial) { + $this->_cache_include_info = array( + 'cache_serial'=>$smarty_compiler->_cache_serial + ,'plugins_code'=>$smarty_compiler->_plugins_code + ,'include_file_path' => $cache_include_path); + + } else { + $this->_cache_include_info = null; + + } + + return $_results; + } + + /** + * Get the compile path for this resource + * + * @param string $resource_name + * @return string results of {@link _get_auto_filename()} + */ + function _get_compile_path($resource_name) + { + return $this->_get_auto_filename($this->compile_dir, $resource_name, + $this->_compile_id) . '.php'; + } + + /** + * fetch the template info. Gets timestamp, and source + * if get_source is true + * + * sets $source_content to the source of the template, and + * $resource_timestamp to its time stamp + * @param string $resource_name + * @param string $source_content + * @param integer $resource_timestamp + * @param boolean $get_source + * @param boolean $quiet + * @return boolean + */ + + function _fetch_resource_info(&$params) + { + if(!isset($params['get_source'])) { $params['get_source'] = true; } + if(!isset($params['quiet'])) { $params['quiet'] = false; } + + $_return = false; + $_params = array('resource_name' => $params['resource_name']) ; + if (isset($params['resource_base_path'])) + $_params['resource_base_path'] = $params['resource_base_path']; + + if ($this->_parse_resource_name($_params)) { + $_resource_type = $_params['resource_type']; + $_resource_name = $_params['resource_name']; + switch ($_resource_type) { + case 'file': + if ($params['get_source']) { + $params['source_content'] = $this->_read_file($_resource_name); + } + $params['resource_timestamp'] = filemtime($_resource_name); + $_return = is_file($_resource_name); + break; + + default: + // call resource functions to fetch the template source and timestamp + if ($params['get_source']) { + $_source_return = isset($this->_plugins['resource'][$_resource_type]) && + call_user_func_array($this->_plugins['resource'][$_resource_type][0][0], + array($_resource_name, &$params['source_content'], &$this)); + } else { + $_source_return = true; + } + + $_timestamp_return = isset($this->_plugins['resource'][$_resource_type]) && + call_user_func_array($this->_plugins['resource'][$_resource_type][0][1], + array($_resource_name, &$params['resource_timestamp'], &$this)); + + $_return = $_source_return && $_timestamp_return; + break; + } + } + + if (!$_return) { + // see if we can get a template with the default template handler + if (!empty($this->default_template_handler_func)) { + if (!is_callable($this->default_template_handler_func)) { + $this->trigger_error("default template handler function \"$this->default_template_handler_func\" doesn't exist."); + } else { + $_return = call_user_func_array( + $this->default_template_handler_func, + array($_params['resource_type'], $_params['resource_name'], &$params['source_content'], &$params['resource_timestamp'], &$this)); + } + } + } + + if (!$_return) { + if (!$params['quiet']) { + $this->trigger_error('unable to read resource: "' . $params['resource_name'] . '"'); + } + } else if ($_return && $this->security) { + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.is_secure.php'); + if (!smarty_core_is_secure($_params, $this)) { + if (!$params['quiet']) + $this->trigger_error('(secure mode) accessing "' . $params['resource_name'] . '" is not allowed'); + $params['source_content'] = null; + $params['resource_timestamp'] = null; + return false; + } + } + return $_return; + } + + + /** + * parse out the type and name from the resource + * + * @param string $resource_base_path + * @param string $resource_name + * @param string $resource_type + * @param string $resource_name + * @return boolean + */ + + function _parse_resource_name(&$params) + { + + // split tpl_path by the first colon + $_resource_name_parts = explode(':', $params['resource_name'], 2); + + if (count($_resource_name_parts) == 1) { + // no resource type given + $params['resource_type'] = $this->default_resource_type; + $params['resource_name'] = $_resource_name_parts[0]; + } else { + if(strlen($_resource_name_parts[0]) == 1) { + // 1 char is not resource type, but part of filepath + $params['resource_type'] = $this->default_resource_type; + $params['resource_name'] = $params['resource_name']; + } else { + $params['resource_type'] = $_resource_name_parts[0]; + $params['resource_name'] = $_resource_name_parts[1]; + } + } + + if ($params['resource_type'] == 'file') { + if (!preg_match("/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/", $params['resource_name'])) { + // relative pathname to $params['resource_base_path'] + // use the first directory where the file is found + if (isset($params['resource_base_path'])) { + $_resource_base_path = (array)$params['resource_base_path']; + } else { + $_resource_base_path = (array)$this->template_dir; + $_resource_base_path[] = '.'; + } + foreach ($_resource_base_path as $_curr_path) { + $_fullpath = $_curr_path . DIRECTORY_SEPARATOR . $params['resource_name']; + if (file_exists($_fullpath) && is_file($_fullpath)) { + $params['resource_name'] = $_fullpath; + return true; + } + // didn't find the file, try include_path + $_params = array('file_path' => $_fullpath); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.get_include_path.php'); + if(smarty_core_get_include_path($_params, $this)) { + $params['resource_name'] = $_params['new_file_path']; + return true; + } + } + return false; + } + } elseif (empty($this->_plugins['resource'][$params['resource_type']])) { + $_params = array('type' => $params['resource_type']); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.load_resource_plugin.php'); + smarty_core_load_resource_plugin($_params, $this); + } + + return true; + } + + + /** + * Handle modifiers + * + * @param string|null $modifier_name + * @param array|null $map_array + * @return string result of modifiers + */ + function _run_mod_handler() + { + $_args = func_get_args(); + list($_modifier_name, $_map_array) = array_splice($_args, 0, 2); + list($_func_name, $_tpl_file, $_tpl_line) = + $this->_plugins['modifier'][$_modifier_name]; + + $_var = $_args[0]; + foreach ($_var as $_key => $_val) { + $_args[0] = $_val; + $_var[$_key] = call_user_func_array($_func_name, $_args); + } + return $_var; + } + + /** + * Remove starting and ending quotes from the string + * + * @param string $string + * @return string + */ + function _dequote($string) + { + if (($string{0} == "'" || $string{0} == '"') && + $string{strlen($string)-1} == $string{0}) + return substr($string, 1, -1); + else + return $string; + } + + + /** + * read in a file from line $start for $lines. + * read the entire file if $start and $lines are null. + * + * @param string $filename + * @param integer $start + * @param integer $lines + * @return string + */ + function _read_file($filename, $start=null, $lines=null) + { + if (!($fd = @fopen($filename, 'r'))) { + return false; + } + flock($fd, LOCK_SH); + if ($start == null && $lines == null) { + // read the entire file + $contents = fread($fd, filesize($filename)); + } else { + if ( $start > 1 ) { + // skip the first lines before $start + for ($loop=1; $loop < $start; $loop++) { + fgets($fd, 65536); + } + } + if ( $lines == null ) { + // read the rest of the file + while (!feof($fd)) { + $contents .= fgets($fd, 65536); + } + } else { + // read up to $lines lines + for ($loop=0; $loop < $lines; $loop++) { + $contents .= fgets($fd, 65536); + if (feof($fd)) { + break; + } + } + } + } + fclose($fd); + return $contents; + } + + /** + * get a concrete filename for automagically created content + * + * @param string $auto_base + * @param string $auto_source + * @param string $auto_id + * @return string + * @staticvar string|null + * @staticvar string|null + */ + function _get_auto_filename($auto_base, $auto_source = null, $auto_id = null) + { + $_compile_dir_sep = $this->use_sub_dirs ? DIRECTORY_SEPARATOR : '^'; + + if(@is_dir($auto_base)) { + $_return = $auto_base . DIRECTORY_SEPARATOR; + } else { + // auto_base not found, try include_path + $_params = array('file_path' => $auto_base); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.get_include_path.php'); + smarty_core_get_include_path($_params, $this); + $_return = isset($_params['new_file_path']) ? $_params['new_file_path'] . DIRECTORY_SEPARATOR : null; + } + + if(isset($auto_id)) { + // make auto_id safe for directory names + $auto_id = str_replace('%7C',$_compile_dir_sep,(urlencode($auto_id))); + // split into separate directories + $_return .= $auto_id . $_compile_dir_sep; + } + + if(isset($auto_source)) { + // make source name safe for filename + $_filename = urlencode(basename($auto_source)); + $_crc32 = crc32($auto_source) . $_compile_dir_sep; + // prepend %% to avoid name conflicts with + // with $params['auto_id'] names + $_crc32 = '%%' . substr($_crc32,0,3) . $_compile_dir_sep . '%%' . $_crc32; + $_return .= $_crc32 . $_filename; + } + + return $_return; + } + + /** + * unlink a file, possibly using expiration time + * + * @param string $resource + * @param integer $exp_time + */ + function _unlink($resource, $exp_time = null) + { + if(isset($exp_time)) { + if(time() - @filemtime($resource) >= $exp_time) { + return @unlink($resource); + } + } else { + return @unlink($resource); + } + } + + /** + * returns an auto_id for auto-file-functions + * + * @param string $cache_id + * @param string $compile_id + * @return string|null + */ + function _get_auto_id($cache_id=null, $compile_id=null) { + if (isset($cache_id)) + return (isset($compile_id)) ? $cache_id . '|' . $compile_id : $cache_id; + elseif(isset($compile_id)) + return $compile_id; + else + return null; + } + + /** + * trigger Smarty plugin error + * + * @param string $error_msg + * @param string $tpl_file + * @param integer $tpl_line + * @param string $file + * @param integer $line + * @param integer $error_type + */ + function _trigger_fatal_error($error_msg, $tpl_file = null, $tpl_line = null, + $file = null, $line = null, $error_type = E_USER_ERROR) + { + if(isset($file) && isset($line)) { + $info = ' ('.basename($file).", line $line)"; + } else { + $info = null; + } + if (isset($tpl_line) && isset($tpl_file)) { + trigger_error("Smarty error: [in " . $tpl_file . " line " . + $tpl_line . "]: $error_msg$info", $error_type); + } else { + trigger_error("Smarty error: $error_msg$info", $error_type); + } + } + + + /** + * callback function for preg_replace, to call a non-cacheable block + * @return string + */ + function _process_compiled_include_callback($match) { + $_func = '_smarty_tplfunc_'.$match[2].'_'.$match[3]; + ob_start(); + $_func($this); + $_ret = ob_get_contents(); + ob_end_clean(); + return $_ret; + } + + + /** + * called for included templates + * + * @param string $_smarty_include_tpl_file + * @param string $_smarty_include_vars + */ + + // $_smarty_include_tpl_file, $_smarty_include_vars + + function _smarty_include($params) + { + if ($this->debugging) { + $_params = array(); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.get_microtime.php'); + $debug_start_time = smarty_core_get_microtime($_params, $this); + $this->_smarty_debug_info[] = array('type' => 'template', + 'filename' => $params['smarty_include_tpl_file'], + 'depth' => ++$this->_inclusion_depth); + $included_tpls_idx = count($this->_smarty_debug_info) - 1; + } + + $this->_tpl_vars = array_merge($this->_tpl_vars, $params['smarty_include_vars']); + + // config vars are treated as local, so push a copy of the + // current ones onto the front of the stack + array_unshift($this->_config, $this->_config[0]); + + $_smarty_compile_path = $this->_get_compile_path($params['smarty_include_tpl_file']); + + + if ($this->_is_compiled($params['smarty_include_tpl_file'], $_smarty_compile_path) + || $this->_compile_resource($params['smarty_include_tpl_file'], $_smarty_compile_path)) + { + include($_smarty_compile_path); + } + + // pop the local vars off the front of the stack + array_shift($this->_config); + + $this->_inclusion_depth--; + + if ($this->debugging) { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.get_microtime.php'); + $this->_smarty_debug_info[$included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $debug_start_time; + } + + if ($this->caching) { + $this->_cache_info['template'][$params['smarty_include_tpl_file']] = true; + } + } + + + /** + * get or set an array of cached attributes for function that is + * not cacheable + * @return array + */ + function &_smarty_cache_attrs($cache_serial, $count) { + $_cache_attrs =& $this->_cache_info['cache_attrs'][$cache_serial][$count]; + + if ($this->_cache_including) { + /* return next set of cache_attrs */ + $_return =& current($_cache_attrs); + next($_cache_attrs); + return $_return; + + } else { + /* add a reference to a new set of cache_attrs */ + $_cache_attrs[] = array(); + return $_cache_attrs[count($_cache_attrs)-1]; + + } + + } + + + /** + * wrapper for include() retaining $this + * @return mixed + */ + function _include($filename, $once=false, $params=null) + { + if ($once) { + return include_once($filename); + } else { + return include($filename); + } + } + + + /** + * wrapper for eval() retaining $this + * @return mixed + */ + function _eval($code, $params=null) + { + return eval($code); + } + /**#@-*/ + +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/Smarty_Compiler.class.php b/smarty/Smarty_Compiler.class.php new file mode 100644 index 0000000..e7ee4a8 --- /dev/null +++ b/smarty/Smarty_Compiler.class.php @@ -0,0 +1,2123 @@ + + * @author Andrei Zmievski + * @version 2.6.0 + * @copyright 2001-2003 ispi of Lincoln, Inc. + * @package Smarty + */ + +/* $Id: Smarty_Compiler.class.php,v 1.1.1.1 2004/01/13 16:02:46 gohr Exp $ */ + +/** + * Template compiling class + * @package Smarty + */ +class Smarty_Compiler extends Smarty { + + // internal vars + /**#@+ + * @access private + */ + var $_sectionelse_stack = array(); // keeps track of whether section had 'else' part + var $_foreachelse_stack = array(); // keeps track of whether foreach had 'else' part + var $_literal_blocks = array(); // keeps literal template blocks + var $_php_blocks = array(); // keeps php code blocks + var $_current_file = null; // the current template being compiled + var $_current_line_no = 1; // line number for error messages + var $_capture_stack = array(); // keeps track of nested capture buffers + var $_plugin_info = array(); // keeps track of plugins to load + var $_init_smarty_vars = false; + var $_permitted_tokens = array('true','false','yes','no','on','off','null'); + var $_db_qstr_regexp = null; // regexps are setup in the constructor + var $_si_qstr_regexp = null; + var $_qstr_regexp = null; + var $_func_regexp = null; + var $_var_bracket_regexp = null; + var $_dvar_guts_regexp = null; + var $_dvar_regexp = null; + var $_cvar_regexp = null; + var $_svar_regexp = null; + var $_avar_regexp = null; + var $_mod_regexp = null; + var $_var_regexp = null; + var $_parenth_param_regexp = null; + var $_func_call_regexp = null; + var $_obj_ext_regexp = null; + var $_obj_start_regexp = null; + var $_obj_params_regexp = null; + var $_obj_call_regexp = null; + var $_cacheable_state = 0; + var $_cache_attrs_count = 0; + var $_nocache_count = 0; + var $_cache_serial = null; + var $_cache_include = null; + + var $_strip_depth = 0; + var $_additional_newline = "\n"; + + /**#@-*/ + /** + * The class constructor. + */ + function Smarty_Compiler() + { + // matches double quoted strings: + // "foobar" + // "foo\"bar" + $this->_db_qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"'; + + // matches single quoted strings: + // 'foobar' + // 'foo\'bar' + $this->_si_qstr_regexp = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\''; + + // matches single or double quoted strings + $this->_qstr_regexp = '(?:' . $this->_db_qstr_regexp . '|' . $this->_si_qstr_regexp . ')'; + + // matches bracket portion of vars + // [0] + // [foo] + // [$bar] + $this->_var_bracket_regexp = '\[\$?[\w\.]+\]'; + + // matches $ vars (not objects): + // $foo + // $foo.bar + // $foo.bar.foobar + // $foo[0] + // $foo[$bar] + // $foo[5][blah] + // $foo[5].bar[$foobar][4] + $this->_dvar_math_regexp = '[\+\-\*\/\%]'; + $this->_dvar_math_var_regexp = '[\$\w\.\+\-\*\/\%\d\>\[\]]'; + $this->_dvar_num_var_regexp = '\-?\d+(?:\.\d+)?' . $this->_dvar_math_var_regexp; + $this->_dvar_guts_regexp = '\w+(?:' . $this->_var_bracket_regexp + . ')*(?:\.\$?\w+(?:' . $this->_var_bracket_regexp . ')*)*(?:' . $this->_dvar_math_regexp . '(?:\-?\d+(?:\.\d+)?|' . $this->_dvar_math_var_regexp . ')*)?'; + $this->_dvar_regexp = '\$' . $this->_dvar_guts_regexp; + + // matches config vars: + // #foo# + // #foobar123_foo# + $this->_cvar_regexp = '\#\w+\#'; + + // matches section vars: + // %foo.bar% + $this->_svar_regexp = '\%\w+\.\w+\%'; + + // matches all valid variables (no quotes, no modifiers) + $this->_avar_regexp = '(?:' . $this->_dvar_regexp . '|' + . $this->_cvar_regexp . '|' . $this->_svar_regexp . ')'; + + // matches valid variable syntax: + // $foo + // $foo + // #foo# + // #foo# + // "text" + // "text" + $this->_var_regexp = '(?:' . $this->_avar_regexp . '|' . $this->_qstr_regexp . ')'; + + // matches valid object call (no objects allowed in parameters): + // $foo->bar + // $foo->bar() + // $foo->bar("text") + // $foo->bar($foo, $bar, "text") + // $foo->bar($foo, "foo") + // $foo->bar->foo() + // $foo->bar->foo->bar() + $this->_obj_ext_regexp = '\->(?:\$?' . $this->_dvar_guts_regexp . ')'; + $this->_obj_params_regexp = '\((?:\w+|' + . $this->_var_regexp . '(?:\s*,\s*(?:(?:\w+|' + . $this->_var_regexp . ')))*)?\)'; + $this->_obj_start_regexp = '(?:' . $this->_dvar_regexp . '(?:' . $this->_obj_ext_regexp . ')+)'; + $this->_obj_call_regexp = '(?:' . $this->_obj_start_regexp . '(?:' . $this->_obj_params_regexp . ')?)'; + + // matches valid modifier syntax: + // |foo + // |@foo + // |foo:"bar" + // |foo:$bar + // |foo:"bar":$foobar + // |foo|bar + // |foo:$foo->bar + $this->_mod_regexp = '(?:\|@?\w+(?::(?>-?\w+|' + . $this->_obj_call_regexp . '|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)'; + + // matches valid function name: + // foo123 + // _foo_bar + $this->_func_regexp = '[a-zA-Z_]\w*'; + + // matches valid registered object: + // foo->bar + $this->_reg_obj_regexp = '[a-zA-Z_]\w*->[a-zA-Z_]\w*'; + + // matches valid parameter values: + // true + // $foo + // $foo|bar + // #foo# + // #foo#|bar + // "text" + // "text"|bar + // $foo->bar + $this->_param_regexp = '(?:\s*(?:' . $this->_obj_call_regexp . '|' + . $this->_var_regexp . '|\w+)(?>' . $this->_mod_regexp . '*)\s*)'; + + // matches valid parenthesised function parameters: + // + // "text" + // $foo, $bar, "text" + // $foo|bar, "foo"|bar, $foo->bar($foo)|bar + $this->_parenth_param_regexp = '(?:\((?:\w+|' + . $this->_param_regexp . '(?:\s*,\s*(?:(?:\w+|' + . $this->_param_regexp . ')))*)?\))'; + + // matches valid function call: + // foo() + // foo_bar($foo) + // _foo_bar($foo,"bar") + // foo123($foo,$foo->bar(),"foo") + $this->_func_call_regexp = '(?:' . $this->_func_regexp . '\s*(?:' + . $this->_parenth_param_regexp . '))'; + } + + /** + * compile a resource + * + * sets $compiled_content to the compiled source + * @param string $resource_name + * @param string $source_content + * @param string $compiled_content + * @return true + */ + function _compile_file($resource_name, $source_content, &$compiled_content) + { + + if ($this->security) { + // do not allow php syntax to be executed unless specified + if ($this->php_handling == SMARTY_PHP_ALLOW && + !$this->security_settings['PHP_HANDLING']) { + $this->php_handling = SMARTY_PHP_PASSTHRU; + } + } + + $this->_load_filters(); + + $this->_current_file = $resource_name; + $this->_current_line_no = 1; + $ldq = preg_quote($this->left_delimiter, '!'); + $rdq = preg_quote($this->right_delimiter, '!'); + + // run template source through prefilter functions + if (count($this->_plugins['prefilter']) > 0) { + foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) { + if ($prefilter === false) continue; + if ($prefilter[3] || is_callable($prefilter[0])) { + $source_content = call_user_func_array($prefilter[0], + array($source_content, &$this)); + $this->_plugins['prefilter'][$filter_name][3] = true; + } else { + $this->_trigger_fatal_error("[plugin] prefilter '$filter_name' is not implemented"); + } + } + } + + /* Annihilate the comments. */ + $source_content = preg_replace("!({$ldq})\*(.*?)\*({$rdq})!se", + "'\\1*'.str_repeat(\"\n\", substr_count('\\2', \"\n\")) .'*\\3'", + $source_content); + + /* Pull out the literal blocks. */ + preg_match_all("!{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}!s", $source_content, $_match); + $this->_literal_blocks = $_match[1]; + $source_content = preg_replace("!{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}!s", + $this->_quote_replace($this->left_delimiter.'literal'.$this->right_delimiter), $source_content); + + /* Pull out the php code blocks. */ + preg_match_all("!{$ldq}php{$rdq}(.*?){$ldq}/php{$rdq}!s", $source_content, $_match); + $this->_php_blocks = $_match[1]; + $source_content = preg_replace("!{$ldq}php{$rdq}(.*?){$ldq}/php{$rdq}!s", + $this->_quote_replace($this->left_delimiter.'php'.$this->right_delimiter), $source_content); + + /* Gather all template tags. */ + preg_match_all("!{$ldq}\s*(.*?)\s*{$rdq}!s", $source_content, $_match); + $template_tags = $_match[1]; + /* Split content by template tags to obtain non-template content. */ + $text_blocks = preg_split("!{$ldq}.*?{$rdq}!s", $source_content); + + /* loop through text blocks */ + for ($curr_tb = 0, $for_max = count($text_blocks); $curr_tb < $for_max; $curr_tb++) { + /* match anything resembling php tags */ + if (preg_match_all('!(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?php[\"\']?)!is', $text_blocks[$curr_tb], $sp_match)) { + /* replace tags with placeholders to prevent recursive replacements */ + $sp_match[1] = array_unique($sp_match[1]); + usort($sp_match[1], '_smarty_sort_length'); + for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { + $text_blocks[$curr_tb] = str_replace($sp_match[1][$curr_sp],'%%%SMARTYSP'.$curr_sp.'%%%',$text_blocks[$curr_tb]); + } + /* process each one */ + for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { + if ($this->php_handling == SMARTY_PHP_PASSTHRU) { + /* echo php contents */ + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', ''."\n", $text_blocks[$curr_tb]); + } else if ($this->php_handling == SMARTY_PHP_QUOTE) { + /* quote php tags */ + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', htmlspecialchars($sp_match[1][$curr_sp]), $text_blocks[$curr_tb]); + } else if ($this->php_handling == SMARTY_PHP_REMOVE) { + /* remove php tags */ + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '', $text_blocks[$curr_tb]); + } else { + /* SMARTY_PHP_ALLOW, but echo non php starting tags */ + $sp_match[1][$curr_sp] = preg_replace('%(<\?(?!php|=|$))%i', ''."\n", $sp_match[1][$curr_sp]); + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', $sp_match[1][$curr_sp], $text_blocks[$curr_tb]); + } + } + } + } + + /* Compile the template tags into PHP code. */ + $compiled_tags = array(); + for ($i = 0, $for_max = count($template_tags); $i < $for_max; $i++) { + $this->_current_line_no += substr_count($text_blocks[$i], "\n"); + $compiled_tags[] = $this->_compile_tag($template_tags[$i]); + $this->_current_line_no += substr_count($template_tags[$i], "\n"); + } + + $compiled_content = ''; + + /* Interleave the compiled contents and text blocks to get the final result. */ + for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) { + if ($compiled_tags[$i] == '') { + // tag result empty, remove first newline from following text block + $text_blocks[$i+1] = preg_replace('!^(\r\n|\r|\n)!', '', $text_blocks[$i+1]); + } + $compiled_content .= $text_blocks[$i].$compiled_tags[$i]; + } + $compiled_content .= $text_blocks[$i]; + + /* Reformat data between 'strip' and '/strip' tags, removing spaces, tabs and newlines. */ + if (preg_match_all("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s", $compiled_content, $_match)) { + $strip_tags = $_match[0]; + $strip_tags_modified = preg_replace("!{$ldq}/?strip{$rdq}|[\t ]+$|^[\t ]+!m", '', $strip_tags); + $strip_tags_modified = preg_replace('![\r\n]+!m', '', $strip_tags_modified); + for ($i = 0, $for_max = count($strip_tags); $i < $for_max; $i++) + $compiled_content = preg_replace("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s", + $this->_quote_replace($strip_tags_modified[$i]), + $compiled_content, 1); + } + + // remove \n from the end of the file, if any + if (($_len=strlen($compiled_content)) && ($compiled_content{$_len - 1} == "\n" )) { + $compiled_content = substr($compiled_content, 0, -1); + } + + if (!empty($this->_cache_serial)) { + $compiled_content = "_cache_serials['".$this->_cache_include."'] = '".$this->_cache_serial."'; ?>" . $compiled_content; + } + + // remove unnecessary close/open tags + $compiled_content = preg_replace('!\?>\n?<\?php!', '', $compiled_content); + + // run compiled template through postfilter functions + if (count($this->_plugins['postfilter']) > 0) { + foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) { + if ($postfilter === false) continue; + if ($postfilter[3] || is_callable($postfilter[0])) { + $compiled_content = call_user_func_array($postfilter[0], + array($compiled_content, &$this)); + $this->_plugins['postfilter'][$filter_name][3] = true; + } else { + $this->_trigger_fatal_error("Smarty plugin error: postfilter '$filter_name' is not implemented"); + } + } + } + + // put header at the top of the compiled template + $template_header = "_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n"; + $template_header .= " compiled from ".strtr(urlencode($resource_name), array('%2F'=>'/', '%3A'=>':'))." */ ?>\n"; + + /* Emit code to load needed plugins. */ + $this->_plugins_code = ''; + if (count($this->_plugin_info)) { + $_plugins_params = "array('plugins' => array("; + foreach ($this->_plugin_info as $plugin_type => $plugins) { + foreach ($plugins as $plugin_name => $plugin_info) { + $_plugins_params .= "array('$plugin_type', '$plugin_name', '$plugin_info[0]', $plugin_info[1], "; + $_plugins_params .= $plugin_info[2] ? 'true),' : 'false),'; + } + } + $_plugins_params .= '))'; + $plugins_code = "\n"; + $template_header .= $plugins_code; + $this->_plugin_info = array(); + $this->_plugins_code = $plugins_code; + } + + if ($this->_init_smarty_vars) { + $template_header .= "\n"; + $this->_init_smarty_vars = false; + } + + $compiled_content = $template_header . $compiled_content; + + return true; + } + + /** + * Compile a template tag + * + * @param string $template_tag + * @return string + */ + function _compile_tag($template_tag) + { + /* Matched comment. */ + if ($template_tag{0} == '*' && $template_tag{strlen($template_tag) - 1} == '*') + return ''; + + /* Split tag into two three parts: command, command modifiers and the arguments. */ + if(! preg_match('/^(?:(' . $this->_obj_call_regexp . '|' . $this->_var_regexp + . '|\/?' . $this->_reg_obj_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*)) + (?:\s+(.*))?$ + /xs', $template_tag, $match)) { + $this->_syntax_error("unrecognized tag: $template_tag", E_USER_ERROR, __FILE__, __LINE__); + } + + $tag_command = $match[1]; + $tag_modifier = isset($match[2]) ? $match[2] : null; + $tag_args = isset($match[3]) ? $match[3] : null; + + if (preg_match('!^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '$!', $tag_command)) { + /* tag name is a variable or object */ + $_return = $this->_parse_var_props($tag_command . $tag_modifier, $this->_parse_attrs($tag_args)); + if(isset($_tag_attrs['assign'])) { + return "assign('" . $this->_dequote($_tag_attrs['assign']) . "', $_return ); ?>\n"; + } else { + return "" . $this->_additional_newline; + } + } + + /* If the tag name is a registered object, we process it. */ + if (preg_match('!^\/?' . $this->_reg_obj_regexp . '$!', $tag_command)) { + return $this->_compile_registered_object_tag($tag_command, $this->_parse_attrs($tag_args), $tag_modifier); + } + + switch ($tag_command) { + case 'include': + return $this->_compile_include_tag($tag_args); + + case 'include_php': + return $this->_compile_include_php_tag($tag_args); + + case 'if': + return $this->_compile_if_tag($tag_args); + + case 'else': + return ''; + + case 'elseif': + return $this->_compile_if_tag($tag_args, true); + + case '/if': + return ''; + + case 'capture': + return $this->_compile_capture_tag(true, $tag_args); + + case '/capture': + return $this->_compile_capture_tag(false); + + case 'ldelim': + return $this->left_delimiter; + + case 'rdelim': + return $this->right_delimiter; + + case 'section': + array_push($this->_sectionelse_stack, false); + return $this->_compile_section_start($tag_args); + + case 'sectionelse': + $this->_sectionelse_stack[count($this->_sectionelse_stack)-1] = true; + return ""; + + case '/section': + if (array_pop($this->_sectionelse_stack)) + return ""; + else + return ""; + + case 'foreach': + array_push($this->_foreachelse_stack, false); + return $this->_compile_foreach_start($tag_args); + break; + + case 'foreachelse': + $this->_foreachelse_stack[count($this->_foreachelse_stack)-1] = true; + return ""; + + case '/foreach': + if (array_pop($this->_foreachelse_stack)) + return ""; + else + return ""; + + case 'strip': + case '/strip': + if ($tag_command{0}=='/') { + if (--$this->_strip_depth==0) { /* outermost closing {/strip} */ + $this->_additional_newline = "\n"; + return $this->left_delimiter.$tag_command.$this->right_delimiter; + } + } else { + if ($this->_strip_depth++==0) { /* outermost opening {strip} */ + $this->_additional_newline = ""; + return $this->left_delimiter.$tag_command.$this->right_delimiter; + } + } + return ''; + + case 'literal': + list (,$literal_block) = each($this->_literal_blocks); + $this->_current_line_no += substr_count($literal_block, "\n"); + return "" . $this->_additional_newline; + + case 'php': + if ($this->security && !$this->security_settings['PHP_TAGS']) { + $this->_syntax_error("(secure mode) php tags not permitted", E_USER_WARNING, __FILE__, __LINE__); + return; + } + list (,$php_block) = each($this->_php_blocks); + $this->_current_line_no += substr_count($php_block, "\n"); + return ''; + + case 'insert': + return $this->_compile_insert_tag($tag_args); + + default: + if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) { + return $output; + } else if ($this->_compile_block_tag($tag_command, $tag_args, $tag_modifier, $output)) { + return $output; + } else { + return $this->_compile_custom_tag($tag_command, $tag_args, $tag_modifier); + } + } + } + + + /** + * compile the custom compiler tag + * + * sets $output to the compiled custom compiler tag + * @param string $tag_command + * @param string $tag_args + * @param string $output + * @return boolean + */ + function _compile_compiler_tag($tag_command, $tag_args, &$output) + { + $found = false; + $have_function = true; + + /* + * First we check if the compiler function has already been registered + * or loaded from a plugin file. + */ + if (isset($this->_plugins['compiler'][$tag_command])) { + $found = true; + $plugin_func = $this->_plugins['compiler'][$tag_command][0]; + if (!is_callable($plugin_func)) { + $message = "compiler function '$tag_command' is not implemented"; + $have_function = false; + } + } + /* + * Otherwise we need to load plugin file and look for the function + * inside it. + */ + else if ($plugin_file = $this->_get_plugin_filepath('compiler', $tag_command)) { + $found = true; + + include_once $plugin_file; + + $plugin_func = 'smarty_compiler_' . $tag_command; + if (!is_callable($plugin_func)) { + $message = "plugin function $plugin_func() not found in $plugin_file\n"; + $have_function = false; + } else { + $this->_plugins['compiler'][$tag_command] = array($plugin_func, null, null, null, true); + } + } + + /* + * True return value means that we either found a plugin or a + * dynamically registered function. False means that we didn't and the + * compiler should now emit code to load custom function plugin for this + * tag. + */ + if ($found) { + if ($have_function) { + $output = call_user_func_array($plugin_func, array($tag_args, &$this)); + if($output != '') { + $output = '_push_cacheable_state('compiler', $tag_command) + . $output + . $this->_pop_cacheable_state('compiler', $tag_command) . ' ?>'; + } + } else { + $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); + } + return true; + } else { + return false; + } + } + + + /** + * compile block function tag + * + * sets $output to compiled block function tag + * @param string $tag_command + * @param string $tag_args + * @param string $tag_modifier + * @param string $output + * @return boolean + */ + function _compile_block_tag($tag_command, $tag_args, $tag_modifier, &$output) + { + if ($tag_command{0} == '/') { + $start_tag = false; + $tag_command = substr($tag_command, 1); + } else + $start_tag = true; + + $found = false; + $have_function = true; + + /* + * First we check if the block function has already been registered + * or loaded from a plugin file. + */ + if (isset($this->_plugins['block'][$tag_command])) { + $found = true; + $plugin_func = $this->_plugins['block'][$tag_command][0]; + if (!is_callable($plugin_func)) { + $message = "block function '$tag_command' is not implemented"; + $have_function = false; + } + } + /* + * Otherwise we need to load plugin file and look for the function + * inside it. + */ + else if ($plugin_file = $this->_get_plugin_filepath('block', $tag_command)) { + $found = true; + + include_once $plugin_file; + + $plugin_func = 'smarty_block_' . $tag_command; + if (!function_exists($plugin_func)) { + $message = "plugin function $plugin_func() not found in $plugin_file\n"; + $have_function = false; + } else { + $this->_plugins['block'][$tag_command] = array($plugin_func, null, null, null, true); + + } + } + + if (!$found) { + return false; + } else if (!$have_function) { + $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); + return true; + } + + /* + * Even though we've located the plugin function, compilation + * happens only once, so the plugin will still need to be loaded + * at runtime for future requests. + */ + $this->_add_plugin('block', $tag_command); + + if ($start_tag) { + $output = '_push_cacheable_state('block', $tag_command); + $attrs = $this->_parse_attrs($tag_args); + $arg_list = $this->_compile_arg_list('block', $tag_command, $attrs, $_cache_attrs=''); + $output .= "$_cache_attrs\$_params = \$this->_tag_stack[] = array('$tag_command', array(".implode(',', $arg_list).')); '; + $output .= $this->_compile_plugin_call('block', $tag_command).'($_params[1], null, $this, $_block_repeat=true); unset($_params);'; + $output .= 'while ($_block_repeat) { ob_start(); ?>'; + } else { + $output = '_block_content = ob_get_contents(); ob_end_clean(); '; + $_out_tag_text = $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], $this->_block_content, $this, $_block_repeat=false)'; + if ($tag_modifier != '') { + $this->_parse_modifiers($_out_tag_text, $tag_modifier); + } + $output .= 'echo '.$_out_tag_text.'; } '; + $output .= " array_pop(\$this->_tag_stack); " . $this->_pop_cacheable_state('block', $tag_command) . '?>'; + } + + return true; + } + + + /** + * compile custom function tag + * + * @param string $tag_command + * @param string $tag_args + * @param string $tag_modifier + * @return string + */ + function _compile_custom_tag($tag_command, $tag_args, $tag_modifier) + { + $this->_add_plugin('function', $tag_command); + + $_cacheable_state = $this->_push_cacheable_state('function', $tag_command); + $attrs = $this->_parse_attrs($tag_args); + $arg_list = $this->_compile_arg_list('function', $tag_command, $attrs, $_cache_attrs=''); + + $_return = $this->_compile_plugin_call('function', $tag_command).'(array('.implode(',', $arg_list)."), \$this)"; + if($tag_modifier != '') { + $this->_parse_modifiers($_return, $tag_modifier); + } + + if($_return != '') { + $_return = '_pop_cacheable_state('function', $tag_command) . "?>" . $this->_additional_newline; + } + + return $_return; + } + + /** + * compile a registered object tag + * + * @param string $tag_command + * @param array $attrs + * @param string $tag_modifier + * @return string + */ + function _compile_registered_object_tag($tag_command, $attrs, $tag_modifier) + { + if ($tag_command{0} == '/') { + $start_tag = false; + $tag_command = substr($tag_command, 1); + } else { + $start_tag = true; + } + + list($object, $obj_comp) = explode('->', $tag_command); + + $arg_list = array(); + if(count($attrs)) { + $_assign_var = false; + foreach ($attrs as $arg_name => $arg_value) { + if($arg_name == 'assign') { + $_assign_var = $arg_value; + unset($attrs['assign']); + continue; + } + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + } + + if($this->_reg_objects[$object][2]) { + // smarty object argument format + $args = "array(".implode(',', (array)$arg_list)."), \$this"; + } else { + // traditional argument format + $args = implode(',', array_values($attrs)); + if (empty($args)) { + $args = 'null'; + } + } + + $prefix = ''; + $postfix = ''; + $newline = ''; + if(!is_object($this->_reg_objects[$object][0])) { + $this->_trigger_fatal_error("registered '$object' is not an object"); + } elseif(!empty($this->_reg_objects[$object][1]) && !in_array($obj_comp, $this->_reg_objects[$object][1])) { + $this->_trigger_fatal_error("'$obj_comp' is not a registered component of object '$object'"); + } elseif(method_exists($this->_reg_objects[$object][0], $obj_comp)) { + // method + if(in_array($obj_comp, $this->_reg_objects[$object][3])) { + // block method + if ($start_tag) { + $prefix = "\$this->_tag_stack[] = array('$obj_comp', $args); "; + $prefix .= "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], null, \$this, \$_block_repeat=true); "; + $prefix .= "while (\$_block_repeat) { ob_start();"; + $return = null; + $postfix = ''; + } else { + $prefix = "\$this->_obj_block_content = ob_get_contents(); ob_end_clean(); "; + $return = "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], \$this->_obj_block_content, \$this, \$_block_repeat=false)"; + $postfix = "} array_pop(\$this->_tag_stack);"; + } + } else { + // non-block method + $return = "\$this->_reg_objects['$object'][0]->$obj_comp($args)"; + } + } else { + // property + $return = "\$this->_reg_objects['$object'][0]->$obj_comp"; + } + + if($return != null) { + if($tag_modifier != '') { + $this->_parse_modifiers($return, $tag_modifier); + } + + if(!empty($_assign_var)) { + $output = "\$this->assign('" . $this->_dequote($_assign_var) ."', $return);"; + } else { + $output = 'echo ' . $return . ';'; + $newline = $this->_additional_newline; + } + } else { + $output = ''; + } + + return '" . $newline; + } + + /** + * Compile {insert ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_insert_tag($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $name = $this->_dequote($attrs['name']); + + if (empty($name)) { + $this->_syntax_error("missing insert name", E_USER_ERROR, __FILE__, __LINE__); + } + + if (!empty($attrs['script'])) { + $delayed_loading = true; + } else { + $delayed_loading = false; + } + + foreach ($attrs as $arg_name => $arg_value) { + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + + $this->_add_plugin('insert', $name, $delayed_loading); + + $_params = "array('args' => array(".implode(', ', (array)$arg_list)."))"; + + return "" . $this->_additional_newline; + } + + /** + * Compile {include ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_include_tag($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $arg_list = array(); + + if (empty($attrs['file'])) { + $this->_syntax_error("missing 'file' attribute in include tag", E_USER_ERROR, __FILE__, __LINE__); + } + + foreach ($attrs as $arg_name => $arg_value) { + if ($arg_name == 'file') { + $include_file = $arg_value; + continue; + } else if ($arg_name == 'assign') { + $assign_var = $arg_value; + continue; + } + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + + $output = '_tpl_vars;\n"; + + + $_params = "array('smarty_include_tpl_file' => " . $include_file . ", 'smarty_include_vars' => array(".implode(',', (array)$arg_list)."))"; + $output .= "\$this->_smarty_include($_params);\n" . + "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" . + "unset(\$_smarty_tpl_vars);\n"; + + if (isset($assign_var)) { + $output .= "\$this->assign(" . $assign_var . ", ob_get_contents()); ob_end_clean();\n"; + } + + $output .= ' ?>'; + + return $output; + + } + + /** + * Compile {include ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_include_php_tag($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + + if (empty($attrs['file'])) { + $this->_syntax_error("missing 'file' attribute in include_php tag", E_USER_ERROR, __FILE__, __LINE__); + } + + $assign_var = (empty($attrs['assign'])) ? '' : $this->_dequote($attrs['assign']); + $once_var = (empty($attrs['once']) || $attrs['once']=='false') ? 'false' : 'true'; + + foreach($attrs as $arg_name => $arg_value) { + if($arg_name != 'file' AND $arg_name != 'once' AND $arg_name != 'assign') { + if(is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + } + + $_params = "array('smarty_file' => " . $attrs['file'] . ", 'smarty_assign' => '$assign_var', 'smarty_once' => $once_var, 'smarty_include_vars' => array(".implode(',', (array)$arg_list)."))"; + + return "" . $this->_additional_newline; + } + + + /** + * Compile {section ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_section_start($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $arg_list = array(); + + $output = '_syntax_error("missing section name", E_USER_ERROR, __FILE__, __LINE__); + } + + $output .= "if (isset(\$this->_sections[$section_name])) unset(\$this->_sections[$section_name]);\n"; + $section_props = "\$this->_sections[$section_name]"; + + foreach ($attrs as $attr_name => $attr_value) { + switch ($attr_name) { + case 'loop': + $output .= "{$section_props}['loop'] = is_array(\$_loop=$attr_value) ? count(\$_loop) : max(0, (int)\$_loop); unset(\$_loop);\n"; + break; + + case 'show': + if (is_bool($attr_value)) + $show_attr_value = $attr_value ? 'true' : 'false'; + else + $show_attr_value = "(bool)$attr_value"; + $output .= "{$section_props}['show'] = $show_attr_value;\n"; + break; + + case 'name': + $output .= "{$section_props}['$attr_name'] = $attr_value;\n"; + break; + + case 'max': + case 'start': + $output .= "{$section_props}['$attr_name'] = (int)$attr_value;\n"; + break; + + case 'step': + $output .= "{$section_props}['$attr_name'] = ((int)$attr_value) == 0 ? 1 : (int)$attr_value;\n"; + break; + + default: + $this->_syntax_error("unknown section attribute - '$attr_name'", E_USER_ERROR, __FILE__, __LINE__); + break; + } + } + + if (!isset($attrs['show'])) + $output .= "{$section_props}['show'] = true;\n"; + + if (!isset($attrs['loop'])) + $output .= "{$section_props}['loop'] = 1;\n"; + + if (!isset($attrs['max'])) + $output .= "{$section_props}['max'] = {$section_props}['loop'];\n"; + else + $output .= "if ({$section_props}['max'] < 0)\n" . + " {$section_props}['max'] = {$section_props}['loop'];\n"; + + if (!isset($attrs['step'])) + $output .= "{$section_props}['step'] = 1;\n"; + + if (!isset($attrs['start'])) + $output .= "{$section_props}['start'] = {$section_props}['step'] > 0 ? 0 : {$section_props}['loop']-1;\n"; + else { + $output .= "if ({$section_props}['start'] < 0)\n" . + " {$section_props}['start'] = max({$section_props}['step'] > 0 ? 0 : -1, {$section_props}['loop'] + {$section_props}['start']);\n" . + "else\n" . + " {$section_props}['start'] = min({$section_props}['start'], {$section_props}['step'] > 0 ? {$section_props}['loop'] : {$section_props}['loop']-1);\n"; + } + + $output .= "if ({$section_props}['show']) {\n"; + if (!isset($attrs['start']) && !isset($attrs['step']) && !isset($attrs['max'])) { + $output .= " {$section_props}['total'] = {$section_props}['loop'];\n"; + } else { + $output .= " {$section_props}['total'] = min(ceil(({$section_props}['step'] > 0 ? {$section_props}['loop'] - {$section_props}['start'] : {$section_props}['start']+1)/abs({$section_props}['step'])), {$section_props}['max']);\n"; + } + $output .= " if ({$section_props}['total'] == 0)\n" . + " {$section_props}['show'] = false;\n" . + "} else\n" . + " {$section_props}['total'] = 0;\n"; + + $output .= "if ({$section_props}['show']):\n"; + $output .= " + for ({$section_props}['index'] = {$section_props}['start'], {$section_props}['iteration'] = 1; + {$section_props}['iteration'] <= {$section_props}['total']; + {$section_props}['index'] += {$section_props}['step'], {$section_props}['iteration']++):\n"; + $output .= "{$section_props}['rownum'] = {$section_props}['iteration'];\n"; + $output .= "{$section_props}['index_prev'] = {$section_props}['index'] - {$section_props}['step'];\n"; + $output .= "{$section_props}['index_next'] = {$section_props}['index'] + {$section_props}['step'];\n"; + $output .= "{$section_props}['first'] = ({$section_props}['iteration'] == 1);\n"; + $output .= "{$section_props}['last'] = ({$section_props}['iteration'] == {$section_props}['total']);\n"; + + $output .= "?>"; + + return $output; + } + + + /** + * Compile {foreach ...} tag. + * + * @param string $tag_args + * @return string + */ + function _compile_foreach_start($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $arg_list = array(); + + if (empty($attrs['from'])) { + $this->_syntax_error("missing 'from' attribute", E_USER_ERROR, __FILE__, __LINE__); + } + + if (empty($attrs['item'])) { + $this->_syntax_error("missing 'item' attribute", E_USER_ERROR, __FILE__, __LINE__); + } + + $from = $attrs['from']; + $item = $this->_dequote($attrs['item']); + if (isset($attrs['name'])) + $name = $attrs['name']; + + $output = '_foreach[$name])) unset(\$this->_foreach[$name]);\n"; + $foreach_props = "\$this->_foreach[$name]"; + } + + $key_part = ''; + + foreach ($attrs as $attr_name => $attr_value) { + switch ($attr_name) { + case 'key': + $key = $this->_dequote($attrs['key']); + $key_part = "\$this->_tpl_vars['$key'] => "; + break; + + case 'name': + $output .= "{$foreach_props}['$attr_name'] = $attr_value;\n"; + break; + } + } + + if (isset($name)) { + $output .= "{$foreach_props}['total'] = count(\$_from = (array)$from);\n"; + $output .= "{$foreach_props}['show'] = {$foreach_props}['total'] > 0;\n"; + $output .= "if ({$foreach_props}['show']):\n"; + $output .= "{$foreach_props}['iteration'] = 0;\n"; + $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n"; + $output .= " {$foreach_props}['iteration']++;\n"; + $output .= " {$foreach_props}['first'] = ({$foreach_props}['iteration'] == 1);\n"; + $output .= " {$foreach_props}['last'] = ({$foreach_props}['iteration'] == {$foreach_props}['total']);\n"; + } else { + $output .= "if (count(\$_from = (array)$from)):\n"; + $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n"; + } + $output .= '?>'; + + return $output; + } + + + /** + * Compile {capture} .. {/capture} tags + * + * @param boolean $start true if this is the {capture} tag + * @param string $tag_args + * @return string + */ + + function _compile_capture_tag($start, $tag_args = '') + { + $attrs = $this->_parse_attrs($tag_args); + + if ($start) { + if (isset($attrs['name'])) + $buffer = $attrs['name']; + else + $buffer = "'default'"; + + if (isset($attrs['assign'])) + $assign = $attrs['assign']; + else + $assign = null; + $output = ""; + $this->_capture_stack[] = array($buffer, $assign); + } else { + list($buffer, $assign) = array_pop($this->_capture_stack); + $output = "_smarty_vars['capture'][$buffer] = ob_get_contents(); "; + if (isset($assign)) { + $output .= " \$this->assign($assign, ob_get_contents());"; + } + $output .= "ob_end_clean(); ?>"; + } + + return $output; + } + + /** + * Compile {if ...} tag + * + * @param string $tag_args + * @param boolean $elseif if true, uses elseif instead of if + * @return string + */ + function _compile_if_tag($tag_args, $elseif = false) + { + + /* Tokenize args for 'if' tag. */ + preg_match_all('/(?> + ' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . '*)? | # valid object call + ' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)? | # var or quoted string + \-?0[xX][0-9a-fA-F]+|\-?\d+(?:\.\d+)?|\.\d+|!==|===|==|!=|<>|<<|>>|<=|>=|\&\&|\|\||\(|\)|,|\!|\^|=|\&|\~|<|>|\||\%|\+|\-|\/|\*|\@ | # valid non-word token + \b\w+\b | # valid word token + \S+ # anything else + )/x', $tag_args, $match); + + $tokens = $match[0]; + + // make sure we have balanced parenthesis + $token_count = array_count_values($tokens); + if(isset($token_count['(']) && $token_count['('] != $token_count[')']) { + $this->_syntax_error("unbalanced parenthesis in if statement", E_USER_ERROR, __FILE__, __LINE__); + } + + $is_arg_stack = array(); + + for ($i = 0; $i < count($tokens); $i++) { + + $token = &$tokens[$i]; + + switch (strtolower($token)) { + case '!': + case '%': + case '!==': + case '==': + case '===': + case '>': + case '<': + case '!=': + case '<>': + case '<<': + case '>>': + case '<=': + case '>=': + case '&&': + case '||': + case '|': + case '^': + case '&': + case '~': + case ')': + case ',': + case '+': + case '-': + case '*': + case '/': + case '@': + break; + + case 'eq': + $token = '=='; + break; + + case 'ne': + case 'neq': + $token = '!='; + break; + + case 'lt': + $token = '<'; + break; + + case 'le': + case 'lte': + $token = '<='; + break; + + case 'gt': + $token = '>'; + break; + + case 'ge': + case 'gte': + $token = '>='; + break; + + case 'and': + $token = '&&'; + break; + + case 'or': + $token = '||'; + break; + + case 'not': + $token = '!'; + break; + + case 'mod': + $token = '%'; + break; + + case '(': + array_push($is_arg_stack, $i); + break; + + case 'is': + /* If last token was a ')', we operate on the parenthesized + expression. The start of the expression is on the stack. + Otherwise, we operate on the last encountered token. */ + if ($tokens[$i-1] == ')') + $is_arg_start = array_pop($is_arg_stack); + else + $is_arg_start = $i-1; + /* Construct the argument for 'is' expression, so it knows + what to operate on. */ + $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start)); + + /* Pass all tokens from next one until the end to the + 'is' expression parsing function. The function will + return modified tokens, where the first one is the result + of the 'is' expression and the rest are the tokens it + didn't touch. */ + $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1)); + + /* Replace the old tokens with the new ones. */ + array_splice($tokens, $is_arg_start, count($tokens), $new_tokens); + + /* Adjust argument start so that it won't change from the + current position for the next iteration. */ + $i = $is_arg_start; + break; + + default: + if(preg_match('!^' . $this->_func_regexp . '$!', $token) ) { + // function call + if($this->security && + !in_array($token, $this->security_settings['IF_FUNCS'])) { + $this->_syntax_error("(secure mode) '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__); + } + } elseif(preg_match('!^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)$!', $token)) { + // object or variable + $token = $this->_parse_var_props($token); + } elseif(is_numeric($token)) { + // number, skip it + } else { + $this->_syntax_error("unidentified token '$token'", E_USER_ERROR, __FILE__, __LINE__); + } + break; + } + } + + if ($elseif) + return ''; + else + return ''; + } + + + function _compile_arg_list($type, $name, $attrs, &$cache_code) { + $arg_list = array(); + + if (isset($type) && isset($name) + && isset($this->_plugins[$type]) + && isset($this->_plugins[$type][$name]) + && empty($this->_plugins[$type][$name][4]) + && is_array($this->_plugins[$type][$name][5]) + ) { + /* we have a list of parameters that should be cached */ + $_cache_attrs = $this->_plugins[$type][$name][5]; + $_count = $this->_cache_attrs_count++; + $cache_code = "\$_cache_attrs =& \$this->_smarty_cache_attrs('$this->_cache_serial','$_count');"; + + } else { + /* no parameters are cached */ + $_cache_attrs = null; + } + + foreach ($attrs as $arg_name => $arg_value) { + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + if (is_null($arg_value)) + $arg_value = 'null'; + if ($_cache_attrs && in_array($arg_name, $_cache_attrs)) { + $arg_list[] = "'$arg_name' => (\$this->_cache_including) ? \$_cache_attrs['$arg_name'] : (\$_cache_attrs['$arg_name']=$arg_value)"; + } else { + $arg_list[] = "'$arg_name' => $arg_value"; + } + } + return $arg_list; + } + + /** + * Parse is expression + * + * @param string $is_arg + * @param array $tokens + * @return array + */ + function _parse_is_expr($is_arg, $tokens) + { + $expr_end = 0; + $negate_expr = false; + + if (($first_token = array_shift($tokens)) == 'not') { + $negate_expr = true; + $expr_type = array_shift($tokens); + } else + $expr_type = $first_token; + + switch ($expr_type) { + case 'even': + if (@$tokens[$expr_end] == 'by') { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "!(($is_arg / $expr_arg) % " . $this->_parse_var_props($expr_arg) . ")"; + } else + $expr = "!($is_arg % 2)"; + break; + + case 'odd': + if (@$tokens[$expr_end] == 'by') { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "(($is_arg / $expr_arg) % ". $this->_parse_var_props($expr_arg) . ")"; + } else + $expr = "($is_arg % 2)"; + break; + + case 'div': + if (@$tokens[$expr_end] == 'by') { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "!($is_arg % " . $this->_parse_var_props($expr_arg) . ")"; + } else { + $this->_syntax_error("expecting 'by' after 'div'", E_USER_ERROR, __FILE__, __LINE__); + } + break; + + default: + $this->_syntax_error("unknown 'is' expression - '$expr_type'", E_USER_ERROR, __FILE__, __LINE__); + break; + } + + if ($negate_expr) { + $expr = "!($expr)"; + } + + array_splice($tokens, 0, $expr_end, $expr); + + return $tokens; + } + + + /** + * Parse attribute string + * + * @param string $tag_args + * @return array + */ + function _parse_attrs($tag_args) + { + + /* Tokenize tag attributes. */ + preg_match_all('/(?:' . $this->_obj_call_regexp . '|' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+) + )+ | + [=] + /x', $tag_args, $match); + $tokens = $match[0]; + + $attrs = array(); + /* Parse state: + 0 - expecting attribute name + 1 - expecting '=' + 2 - expecting attribute value (not '=') */ + $state = 0; + + foreach ($tokens as $token) { + switch ($state) { + case 0: + /* If the token is a valid identifier, we set attribute name + and go to state 1. */ + if (preg_match('!^\w+$!', $token)) { + $attr_name = $token; + $state = 1; + } else + $this->_syntax_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__); + break; + + case 1: + /* If the token is '=', then we go to state 2. */ + if ($token == '=') { + $state = 2; + } else + $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); + break; + + case 2: + /* If token is not '=', we set the attribute value and go to + state 0. */ + if ($token != '=') { + /* We booleanize the token if it's a non-quoted possible + boolean value. */ + if (preg_match('!^(on|yes|true)$!', $token)) { + $token = 'true'; + } else if (preg_match('!^(off|no|false)$!', $token)) { + $token = 'false'; + } else if ($token == 'null') { + $token = 'null'; + } else if (preg_match('!^-?([0-9]+|0[xX][0-9a-fA-F]+)$!', $token)) { + /* treat integer literally */ + } else if (!preg_match('!^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$!', $token)) { + /* treat as a string, double-quote it escaping quotes */ + $token = '"'.addslashes($token).'"'; + } + + $attrs[$attr_name] = $token; + $state = 0; + } else + $this->_syntax_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__); + break; + } + $last_token = $token; + } + + if($state != 0) { + if($state == 1) { + $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); + } else { + $this->_syntax_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__); + } + } + + $this->_parse_vars_props($attrs); + + return $attrs; + } + + /** + * compile multiple variables and section properties tokens into + * PHP code + * + * @param array $tokens + */ + function _parse_vars_props(&$tokens) + { + foreach($tokens as $key => $val) { + $tokens[$key] = $this->_parse_var_props($val); + } + } + + /** + * compile single variable and section properties token into + * PHP code + * + * @param string $val + * @param string $tag_attrs + * @return string + */ + function _parse_var_props($val) + { + $val = trim($val); + + if(preg_match('!^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(' . $this->_mod_regexp . '*)$!', $val, $match)) { + // $ variable or object + $return = $this->_parse_var($match[1]); + if($match[2] != '') { + $this->_parse_modifiers($return, $match[2]); + } + return $return; + } + elseif(preg_match('!^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) { + // double quoted text + preg_match('!^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . '*)$!', $val, $match); + $return = $this->_expand_quoted_text($match[1]); + if($match[2] != '') { + $this->_parse_modifiers($return, $match[2]); + } + return $return; + } + elseif(preg_match('!^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) { + // single quoted text + preg_match('!^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . '*)$!', $val, $match); + if($match[2] != '') { + $this->_parse_modifiers($match[1], $match[2]); + return $match[1]; + } + } + elseif(preg_match('!^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) { + // config var + return $this->_parse_conf_var($val); + } + elseif(preg_match('!^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) { + // section var + return $this->_parse_section_prop($val); + } + elseif(!in_array($val, $this->_permitted_tokens) && !is_numeric($val)) { + // literal string + return $this->_expand_quoted_text('"' . $val .'"'); + } + return $val; + } + + /** + * expand quoted text with embedded variables + * + * @param string $var_expr + * @return string + */ + function _expand_quoted_text($var_expr) + { + // if contains unescaped $, expand it + if(preg_match_all('%(?:\`(?_dvar_guts_regexp . '\`)|(?:(?_parse_var(str_replace('`','',$_var)) . ')."', $var_expr); + } + $_return = preg_replace('%\.""|(?_dvar_math_regexp.'|'.$this->_qstr_regexp.')!', $var_expr, -1, PREG_SPLIT_DELIM_CAPTURE); + + if(count($_math_vars) > 1) { + $_first_var = ""; + $_complete_var = ""; + // simple check if there is any math, to stop recursion (due to modifiers with "xx % yy" as parameter) + foreach($_math_vars as $_k => $_math_var) { + $_math_var = $_math_vars[$_k]; + + if(!empty($_math_var) || is_numeric($_math_var)) { + // hit a math operator, so process the stuff which came before it + if(preg_match('!^' . $this->_dvar_math_regexp . '$!', $_math_var)) { + $_has_math = true; + if(!empty($_complete_var) || is_numeric($_complete_var)) { + $_output .= $this->_parse_var($_complete_var); + } + + // just output the math operator to php + $_output .= $_math_var; + + if(empty($_first_var)) + $_first_var = $_complete_var; + + $_complete_var = ""; + } else { + // fetch multiple -> (like $foo->bar->baz ) which wouldn't get fetched else, because it would only get $foo->bar and treat the ->baz as "-" ">baz" then + for($_i = $_k + 1; $_i <= count($_math_vars); $_i += 2) { + // fetch -> because it gets splitted at - and move it back together + if( /* prevent notice */ (isset($_math_vars[$_i]) && isset($_math_vars[$_i+1])) && ($_math_vars[$_i] === '-' && $_math_vars[$_i+1]{0} === '>')) { + $_math_var .= $_math_vars[$_i].$_math_vars[$_i+1]; + $_math_vars[$_i] = $_math_vars[$_i+1] = ''; + } else { + break; + } + } + $_complete_var .= $_math_var; + } + } + } + if($_has_math) { + if(!empty($_complete_var) || is_numeric($_complete_var)) + $_output .= $this->_parse_var($_complete_var, true); + + // get the modifiers working (only the last var from math + modifier is left) + $var_expr = $_complete_var; + } + } + + // prevent cutting of first digit in the number (we _definitly_ got a number if the first char is a digit) + if(is_numeric($var_expr{0})) + $_var_ref = $var_expr; + else + $_var_ref = substr($var_expr, 1); + + if(!$_has_math) { + // get [foo] and .foo and ->foo and (...) pieces + preg_match_all('!(?:^\w+)|' . $this->_obj_params_regexp . '|(?:' . $this->_var_bracket_regexp . ')|->\$?\w+|\.\$?\w+|\S+!', $_var_ref, $match); + + $_indexes = $match[0]; + $_var_name = array_shift($_indexes); + + /* Handle $smarty.* variable references as a special case. */ + if ($_var_name == 'smarty') { + /* + * If the reference could be compiled, use the compiled output; + * otherwise, fall back on the $smarty variable generated at + * run-time. + */ + if (($smarty_ref = $this->_compile_smarty_ref($_indexes)) !== null) { + $_output = $smarty_ref; + } else { + $_var_name = substr(array_shift($_indexes), 1); + $_output = "\$this->_smarty_vars['$_var_name']"; + } + } elseif(is_numeric($_var_name) && is_numeric($var_expr{0})) { + // because . is the operator for accessing arrays thru inidizes we need to put it together again for floating point numbers + if(count($_indexes) > 0) + { + $_var_name .= implode("", $_indexes); + $_indexes = array(); + } + $_output = $_var_name; + } else { + $_output = "\$this->_tpl_vars['$_var_name']"; + } + + foreach ($_indexes as $_index) { + if ($_index{0} == '[') { + $_index = substr($_index, 1, -1); + if (is_numeric($_index)) { + $_output .= "[$_index]"; + } elseif ($_index{0} == '$') { + if (strpos($_index, '.') !== false) { + $_output .= '[' . $this->_parse_var($_index) . ']'; + } else { + $_output .= "[\$this->_tpl_vars['" . substr($_index, 1) . "']]"; + } + } else { + $_var_parts = explode('.', $_index); + $_var_section = $_var_parts[0]; + $_var_section_prop = isset($_var_parts[1]) ? $_var_parts[1] : 'index'; + $_output .= "[\$this->_sections['$_var_section']['$_var_section_prop']]"; + } + } else if ($_index{0} == '.') { + if ($_index{1} == '$') + $_output .= "[\$this->_tpl_vars['" . substr($_index, 2) . "']]"; + else + $_output .= "['" . substr($_index, 1) . "']"; + } else if (substr($_index,0,2) == '->') { + if(substr($_index,2,2) == '__') { + $this->_syntax_error('call to internal object members is not allowed', E_USER_ERROR, __FILE__, __LINE__); + } elseif($this->security && substr($_index, 2, 1) == '_') { + $this->_syntax_error('(secure) call to private object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); + } elseif ($_index{2} == '$') { + if ($this->security) { + $this->_syntax_error('(secure) call to dynamic object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); + } else { + $_output .= '->{(($_var=$this->_tpl_vars[\''.substr($_index,3).'\']) && substr($_var,0,2)!=\'__\') ? $_var : $this->trigger_error("cannot access property \\"$_var\\"")}'; + } + } else { + $_output .= $_index; + } + } elseif ($_index{0} == '(') { + $_index = $this->_parse_parenth_args($_index); + $_output .= $_index; + } else { + $_output .= $_index; + } + } + } + + return $_output; + } + + /** + * parse arguments in function call parenthesis + * + * @param string $parenth_args + * @return string + */ + function _parse_parenth_args($parenth_args) + { + preg_match_all('!' . $this->_param_regexp . '!',$parenth_args, $match); + $match = $match[0]; + rsort($match); + reset($match); + $orig_vals = $match; + $this->_parse_vars_props($match); + return str_replace($orig_vals, $match, $parenth_args); + } + + /** + * parse configuration variable expression into PHP code + * + * @param string $conf_var_expr + */ + function _parse_conf_var($conf_var_expr) + { + $parts = explode('|', $conf_var_expr, 2); + $var_ref = $parts[0]; + $modifiers = isset($parts[1]) ? $parts[1] : ''; + + $var_name = substr($var_ref, 1, -1); + + $output = "\$this->_config[0]['vars']['$var_name']"; + + $this->_parse_modifiers($output, $modifiers); + + return $output; + } + + /** + * parse section property expression into PHP code + * + * @param string $section_prop_expr + * @return string + */ + function _parse_section_prop($section_prop_expr) + { + $parts = explode('|', $section_prop_expr, 2); + $var_ref = $parts[0]; + $modifiers = isset($parts[1]) ? $parts[1] : ''; + + preg_match('!%(\w+)\.(\w+)%!', $var_ref, $match); + $section_name = $match[1]; + $prop_name = $match[2]; + + $output = "\$this->_sections['$section_name']['$prop_name']"; + + $this->_parse_modifiers($output, $modifiers); + + return $output; + } + + + /** + * parse modifier chain into PHP code + * + * sets $output to parsed modified chain + * @param string $output + * @param string $modifier_string + */ + function _parse_modifiers(&$output, $modifier_string) + { + preg_match_all('!\|(@?\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)!', '|' . $modifier_string, $_match); + list(, $_modifiers, $modifier_arg_strings) = $_match; + + for ($_i = 0, $_for_max = count($_modifiers); $_i < $_for_max; $_i++) { + $_modifier_name = $_modifiers[$_i]; + + if($_modifier_name == 'smarty') { + // skip smarty modifier + continue; + } + + preg_match_all('!:(' . $this->_qstr_regexp . '|[^:]+)!', $modifier_arg_strings[$_i], $_match); + $_modifier_args = $_match[1]; + + if ($_modifier_name{0} == '@') { + $_map_array = false; + $_modifier_name = substr($_modifier_name, 1); + } else { + $_map_array = true; + } + + $this->_add_plugin('modifier', $_modifier_name); + if (empty($this->_plugins['modifier'][$_modifier_name]) + && !$this->_get_plugin_filepath('modifier', $_modifier_name) + && function_exists($_modifier_name)) { + if ($this->security && !in_array($_modifier_name, $this->security_settings['MODIFIER_FUNCS'])) { + $this->_trigger_fatal_error("[plugin] (secure mode) modifier '$_modifier_name' is not allowed" , $_tpl_file, $_tpl_line, __FILE__, __LINE__); + } else { + $this->_plugins['modifier'][$_modifier_name] = array($_modifier_name, null, null, false); + } + } + + $this->_parse_vars_props($_modifier_args); + + if($_modifier_name == 'default') { + // supress notifications of default modifier vars and args + if($output{0} == '$') { + $output = '@' . $output; + } + if(isset($_modifier_args[0]) && $_modifier_args[0]{0} == '$') { + $_modifier_args[0] = '@' . $_modifier_args[0]; + } + } + if (count($_modifier_args) > 0) + $_modifier_args = ', '.implode(', ', $_modifier_args); + else + $_modifier_args = ''; + + if ($_map_array) { + $output = "((is_array(\$_tmp=$output)) ? \$this->_run_mod_handler('$_modifier_name', true, \$_tmp$_modifier_args) : " . $this->_compile_plugin_call('modifier', $_modifier_name) . "(\$_tmp$_modifier_args))"; + + } else { + + $output = $this->_compile_plugin_call('modifier', $_modifier_name)."($output$_modifier_args)"; + + } + } + } + + + /** + * add plugin + * + * @param string $type + * @param string $name + * @param boolean? $delayed_loading + */ + function _add_plugin($type, $name, $delayed_loading = null) + { + if (!isset($this->_plugin_info[$type])) { + $this->_plugin_info[$type] = array(); + } + if (!isset($this->_plugin_info[$type][$name])) { + $this->_plugin_info[$type][$name] = array($this->_current_file, + $this->_current_line_no, + $delayed_loading); + } + } + + + /** + * Compiles references of type $smarty.foo + * + * @param string $indexes + * @return string + */ + function _compile_smarty_ref(&$indexes) + { + /* Extract the reference name. */ + $_ref = substr($indexes[0], 1); + foreach($indexes as $_index_no=>$_index) { + if ($_index{0} != '.' && $_index_no<2 || !preg_match('!^(\.|\[|->)!', $_index)) { + $this->_syntax_error('$smarty' . implode('', array_slice($indexes, 0, 2)) . ' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__); + } + } + + switch ($_ref) { + case 'now': + $compiled_ref = 'time()'; + $_max_index = 1; + break; + + case 'foreach': + case 'section': + array_shift($indexes); + $_var = $this->_parse_var_props(substr($indexes[0], 1)); + if ($_ref == 'foreach') + $compiled_ref = "\$this->_foreach[$_var]"; + else + $compiled_ref = "\$this->_sections[$_var]"; + break; + + case 'get': + $compiled_ref = ($this->request_use_auto_globals) ? '$_GET' : "\$GLOBALS['HTTP_GET_VARS']"; + break; + + case 'post': + $compiled_ref = ($this->request_use_auto_globals) ? '$_POST' : "\$GLOBALS['HTTP_POST_VARS']"; + break; + + case 'cookies': + $compiled_ref = ($this->request_use_auto_globals) ? '$_COOKIE' : "\$GLOBALS['HTTP_COOKIE_VARS']"; + break; + + case 'env': + $compiled_ref = ($this->request_use_auto_globals) ? '$_ENV' : "\$GLOBALS['HTTP_ENV_VARS']"; + break; + + case 'server': + $compiled_ref = ($this->request_use_auto_globals) ? '$_SERVER' : "\$GLOBALS['HTTP_SERVER_VARS']"; + break; + + case 'session': + $compiled_ref = ($this->request_use_auto_globals) ? '$_SESSION' : "\$GLOBALS['HTTP_SESSION_VARS']"; + break; + + /* + * These cases are handled either at run-time or elsewhere in the + * compiler. + */ + case 'request': + if ($this->request_use_auto_globals) { + $compiled_ref = '$_REQUEST'; + break; + } else { + $this->_init_smarty_vars = true; + } + return null; + + case 'capture': + return null; + + case 'template': + $compiled_ref = "'$this->_current_file'"; + $_max_index = 1; + break; + + case 'version': + $compiled_ref = "'$this->_version'"; + $_max_index = 1; + break; + + case 'const': + array_shift($indexes); + $_val = $this->_parse_var_props(substr($indexes[0],1)); + $compiled_ref = '@constant(' . $_val . ')'; + $_max_index = 1; + break; + + case 'config': + $compiled_ref = "\$this->_config[0]['vars']"; + $_max_index = 2; + break; + + default: + $this->_syntax_error('$smarty.' . $_ref . ' is an unknown reference', E_USER_ERROR, __FILE__, __LINE__); + break; + } + + if (isset($_max_index) && count($indexes) > $_max_index) { + $this->_syntax_error('$smarty' . implode('', $indexes) .' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__); + } + + array_shift($indexes); + return $compiled_ref; + } + + /** + * compiles call to plugin of type $type with name $name + * returns a string containing the function-name or method call + * without the paramter-list that would have follow to make the + * call valid php-syntax + * + * @param string $type + * @param string $name + * @return string + */ + function _compile_plugin_call($type, $name) { + if (isset($this->_plugins[$type][$name])) { + /* plugin loaded */ + if (is_array($this->_plugins[$type][$name][0])) { + return ((is_object($this->_plugins[$type][$name][0][0])) ? + "\$this->_plugins['$type']['$name'][0][0]->" /* method callback */ + : (string)($this->_plugins[$type][$name][0][0]).'::' /* class callback */ + ). $this->_plugins[$type][$name][0][1]; + + } else { + /* function callback */ + return $this->_plugins[$type][$name][0]; + + } + } else { + /* plugin not loaded -> auto-loadable-plugin */ + return 'smarty_'.$type.'_'.$name; + + } + } + + /** + * load pre- and post-filters + */ + function _load_filters() + { + if (count($this->_plugins['prefilter']) > 0) { + foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) { + if ($prefilter === false) { + unset($this->_plugins['prefilter'][$filter_name]); + $_params = array('plugins' => array(array('prefilter', $filter_name, null, null, false))); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + } + } + } + if (count($this->_plugins['postfilter']) > 0) { + foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) { + if ($postfilter === false) { + unset($this->_plugins['postfilter'][$filter_name]); + $_params = array('plugins' => array(array('postfilter', $filter_name, null, null, false))); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + } + } + } + } + + + /** + * Quote subpattern references + * + * @param string $string + * @return string + */ + function _quote_replace($string) + { + return preg_replace('![\\$]\d!', '\\\\\\0', $string); + } + + /** + * display Smarty syntax error + * + * @param string $error_msg + * @param integer $error_type + * @param string $file + * @param integer $line + */ + function _syntax_error($error_msg, $error_type = E_USER_ERROR, $file=null, $line=null) + { + if(isset($file) && isset($line)) { + $info = ' ('.basename($file).", line $line)"; + } else { + $info = null; + } + trigger_error('Smarty: [in ' . $this->_current_file . ' line ' . + $this->_current_line_no . "]: syntax error: $error_msg$info", $error_type); + } + + + /** + * check if the compilation changes from cacheable to + * non-cacheable state with the beginning of the current + * plugin. return php-code to reflect the transition. + * @return string + */ + function _push_cacheable_state($type, $name) { + $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4]; + if ($_cacheable + || 0<$this->_cacheable_state++) return ''; + if (!isset($this->_cache_serial)) $this->_cache_serial = md5(uniqid('Smarty')); + $_ret = 'if ($this->caching) { echo \'{nocache:' + . $this->_cache_serial . '#' . $this->_nocache_count + . '}\';}'; + return $_ret; + } + + + /** + * check if the compilation changes from non-cacheable to + * cacheable state with the end of the current plugin return + * php-code to reflect the transition. + * @return string + */ + function _pop_cacheable_state($type, $name) { + $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4]; + if ($_cacheable + || --$this->_cacheable_state>0) return ''; + return 'if ($this->caching) { echo \'{/nocache:' + . $this->_cache_serial . '#' . ($this->_nocache_count++) + . '}\';}'; + } + +} + +/** + * compare to values by their string length + * + * @access private + * @param string $a + * @param string $b + * @return 0|-1|1 + */ +function _smarty_sort_length($a, $b) +{ + if($a == $b) + return 0; + + if(strlen($a) == strlen($b)) + return ($a > $b) ? -1 : 1; + + return (strlen($a) > strlen($b)) ? -1 : 1; +} + + +/* vim: set et: */ + +?> diff --git a/smarty/core/core.assemble_plugin_filepath.php b/smarty/core/core.assemble_plugin_filepath.php new file mode 100644 index 0000000..ec44f8e --- /dev/null +++ b/smarty/core/core.assemble_plugin_filepath.php @@ -0,0 +1,62 @@ +plugins_dir as $_plugin_dir) { + + $_plugin_filepath = $_plugin_dir . DIRECTORY_SEPARATOR . $_plugin_filename; + + // see if path is relative + if (!preg_match("/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/", $_plugin_dir)) { + $_relative_paths[] = $_plugin_dir; + // relative path, see if it is in the SMARTY_DIR + if (@is_readable(SMARTY_DIR . $_plugin_filepath)) { + $_return = SMARTY_DIR . $_plugin_filepath; + break; + } + } + // try relative to cwd (or absolute) + if (@is_readable($_plugin_filepath)) { + $_return = $_plugin_filepath; + break; + } + } + + if($_return === false) { + // still not found, try PHP include_path + if(isset($_relative_paths)) { + foreach ((array)$_relative_paths as $_plugin_dir) { + + $_plugin_filepath = $_plugin_dir . DIRECTORY_SEPARATOR . $_plugin_filename; + + $_params = array('file_path' => $_plugin_filepath); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.get_include_path.php'); + if(smarty_core_get_include_path($_params, $smarty)) { + return $_params['new_file_path']; + } + } + } + } + + return $_return; +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/core/core.assign_smarty_interface.php b/smarty/core/core.assign_smarty_interface.php new file mode 100644 index 0000000..7e65a73 --- /dev/null +++ b/smarty/core/core.assign_smarty_interface.php @@ -0,0 +1,43 @@ + + * Name: assign_smarty_interface
+ * Purpose: assign the $smarty interface variable + * @param array Format: null + * @param Smarty + */ +function smarty_core_assign_smarty_interface($params, &$smarty) +{ + if (isset($smarty->_smarty_vars) && isset($smarty->_smarty_vars['request'])) { + return; + } + + $_globals_map = array('g' => 'HTTP_GET_VARS', + 'p' => 'HTTP_POST_VARS', + 'c' => 'HTTP_COOKIE_VARS', + 's' => 'HTTP_SERVER_VARS', + 'e' => 'HTTP_ENV_VARS'); + + $_smarty_vars_request = array(); + + foreach (preg_split('!!', strtolower($smarty->request_vars_order)) as $_c) { + if (isset($_globals_map[$_c])) { + $_smarty_vars_request = array_merge($_smarty_vars_request, $GLOBALS[$_globals_map[$_c]]); + } + } + $_smarty_vars_request = @array_merge($_smarty_vars_request, $GLOBALS['HTTP_SESSION_VARS']); + + $smarty->_smarty_vars['request'] = $_smarty_vars_request; +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/core/core.create_dir_structure.php b/smarty/core/core.create_dir_structure.php new file mode 100644 index 0000000..999cf59 --- /dev/null +++ b/smarty/core/core.create_dir_structure.php @@ -0,0 +1,79 @@ +_dir_perms) && !is_dir($_new_dir)) { + $smarty->trigger_error("problem creating directory '" . $_new_dir . "'"); + return false; + } + $_new_dir .= '/'; + } + } +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/core/core.display_debug_console.php b/smarty/core/core.display_debug_console.php new file mode 100644 index 0000000..c509ff7 --- /dev/null +++ b/smarty/core/core.display_debug_console.php @@ -0,0 +1,60 @@ + + * Name: display_debug_console
+ * Purpose: display the javascript debug console window + * @param array Format: null + * @param Smarty + */ +function smarty_core_display_debug_console($params, &$smarty) +{ + // we must force compile the debug template in case the environment + // changed between separate applications. + + if(empty($smarty->debug_tpl)) { + // set path to debug template from SMARTY_DIR + $smarty->debug_tpl = SMARTY_DIR . 'debug.tpl'; + if($smarty->security && is_file($smarty->debug_tpl)) { + $smarty->secure_dir[] = dirname(realpath($smarty->debug_tpl)); + } + } + + $_ldelim_orig = $smarty->left_delimiter; + $_rdelim_orig = $smarty->right_delimiter; + + $smarty->left_delimiter = '{'; + $smarty->right_delimiter = '}'; + + $_compile_id_orig = $smarty->_compile_id; + $smarty->_compile_id = null; + + $_compile_path = $smarty->_get_compile_path($smarty->debug_tpl); + if ($smarty->_compile_resource($smarty->debug_tpl, $_compile_path)) + { + ob_start(); + $smarty->_include($_compile_path); + $_results = ob_get_contents(); + ob_end_clean(); + } else { + $_results = ''; + } + + $smarty->_compile_id = $_compile_id_orig; + + $smarty->left_delimiter = $_ldelim_orig; + $smarty->right_delimiter = $_rdelim_orig; + + return $_results; +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/core/core.get_include_path.php b/smarty/core/core.get_include_path.php new file mode 100644 index 0000000..eb7188c --- /dev/null +++ b/smarty/core/core.get_include_path.php @@ -0,0 +1,44 @@ + diff --git a/smarty/core/core.get_microtime.php b/smarty/core/core.get_microtime.php new file mode 100644 index 0000000..f1a28e0 --- /dev/null +++ b/smarty/core/core.get_microtime.php @@ -0,0 +1,23 @@ + diff --git a/smarty/core/core.get_php_resource.php b/smarty/core/core.get_php_resource.php new file mode 100644 index 0000000..8121acf --- /dev/null +++ b/smarty/core/core.get_php_resource.php @@ -0,0 +1,80 @@ +trusted_dir; + $smarty->_parse_resource_name($params, $smarty); + + /* + * Find out if the resource exists. + */ + + if ($params['resource_type'] == 'file') { + $_readable = false; + if(file_exists($params['resource_name']) && is_readable($params['resource_name'])) { + $_readable = true; + } else { + // test for file in include_path + $_params = array('file_path' => $params['resource_name']); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.get_include_path.php'); + if(smarty_core_get_include_path($_params, $smarty)) { + $_include_path = $_params['new_file_path']; + $_readable = true; + } + } + } else if ($params['resource_type'] != 'file') { + $_template_source = null; + $_readable = is_callable($smarty->_plugins['resource'][$params['resource_type']][0][0]) + && call_user_func_array($smarty->_plugins['resource'][$params['resource_type']][0][0], + array($params['resource_name'], &$_template_source, &$smarty)); + } + + /* + * Set the error function, depending on which class calls us. + */ + if (method_exists($smarty, '_syntax_error')) { + $_error_funcc = '_syntax_error'; + } else { + $_error_funcc = 'trigger_error'; + } + + if ($_readable) { + if ($smarty->security) { + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.is_trusted.php'); + if (!smarty_core_is_trusted($params, $smarty)) { + $smarty->$_error_funcc('(secure mode) ' . $params['resource_type'] . ':' . $params['resource_name'] . ' is not trusted'); + return false; + } + } + } else { + $smarty->$_error_funcc($params['resource_type'] . ':' . $params['resource_name'] . ' is not readable'); + return false; + } + + if ($params['resource_type'] == 'file') { + $params['php_resource'] = $params['resource_name']; + } else { + $params['php_resource'] = $_template_source; + } + return true; +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/core/core.is_secure.php b/smarty/core/core.is_secure.php new file mode 100644 index 0000000..877886b --- /dev/null +++ b/smarty/core/core.is_secure.php @@ -0,0 +1,59 @@ +security || $smarty->security_settings['INCLUDE_ANY']) { + return true; + } + + $_smarty_secure = false; + if ($params['resource_type'] == 'file') { + if($check_template_dir) { + if (!in_array($smarty->template_dir, $smarty->secure_dir)) + // add template_dir to secure_dir array + array_unshift($smarty->secure_dir, $smarty->template_dir); + $check_template_dir = false; + } + if (!empty($smarty->secure_dir)) { + $_rp = realpath($params['resource_name']); + foreach ((array)$smarty->secure_dir as $curr_dir) { + if ( !empty($curr_dir) && is_readable ($curr_dir)) { + $_cd = realpath($curr_dir); + if (strncmp($_rp, $_cd, strlen($_cd)) == 0 + && $_rp{strlen($_cd)} == DIRECTORY_SEPARATOR ) { + $_smarty_secure = true; + break; + } + } + } + } + } else { + // resource is not on local file system + $_smarty_secure = call_user_func_array( + $smarty->_plugins['resource'][$params['resource_type']][0][2], + array($params['resource_name'], &$_smarty_secure, &$smarty)); + } + + return $_smarty_secure; +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/core/core.is_trusted.php b/smarty/core/core.is_trusted.php new file mode 100644 index 0000000..c90e3ef --- /dev/null +++ b/smarty/core/core.is_trusted.php @@ -0,0 +1,50 @@ +trusted_dir)) { + $_rp = realpath($params['resource_name']); + foreach ((array)$smarty->trusted_dir as $curr_dir) { + if (!empty($curr_dir) && is_readable ($curr_dir)) { + $_cd = realpath($curr_dir); + if (strncmp($_rp, $_cd, strlen($_cd)) == 0 + && $_rp{strlen($_cd)} == DIRECTORY_SEPARATOR ) { + $_smarty_trusted = true; + break; + } + } + } + } + + } else { + // resource is not on local file system + $_smarty_trusted = call_user_func_array($smarty->_plugins['resource'][$params['resource_type']][0][3], + array($params['resource_name'], $smarty)); + } + + return $_smarty_trusted; +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/core/core.load_plugins.php b/smarty/core/core.load_plugins.php new file mode 100644 index 0000000..6db1dc5 --- /dev/null +++ b/smarty/core/core.load_plugins.php @@ -0,0 +1,125 @@ +_plugins[$_type][$_name]; + + /* + * We do not load plugin more than once for each instance of Smarty. + * The following code checks for that. The plugin can also be + * registered dynamically at runtime, in which case template file + * and line number will be unknown, so we fill them in. + * + * The final element of the info array is a flag that indicates + * whether the dynamically registered plugin function has been + * checked for existence yet or not. + */ + if (isset($_plugin)) { + if (empty($_plugin[3])) { + if (!is_callable($_plugin[0])) { + $smarty->_trigger_fatal_error("[plugin] $_type '$_name' is not implemented", $_tpl_file, $_tpl_line, __FILE__, __LINE__); + } else { + $_plugin[1] = $_tpl_file; + $_plugin[2] = $_tpl_line; + $_plugin[3] = true; + if (!isset($_plugin[4])) $_plugin[4] = true; /* cacheable */ + } + } + continue; + } else if ($_type == 'insert') { + /* + * For backwards compatibility, we check for insert functions in + * the symbol table before trying to load them as a plugin. + */ + $_plugin_func = 'insert_' . $_name; + if (function_exists($_plugin_func)) { + $_plugin = array($_plugin_func, $_tpl_file, $_tpl_line, true, false); + continue; + } + } + + $_plugin_file = $smarty->_get_plugin_filepath($_type, $_name); + + if (! $_found = ($_plugin_file != false)) { + $_message = "could not load plugin file '$_type.$_name.php'\n"; + } + + /* + * If plugin file is found, it -must- provide the properly named + * plugin function. In case it doesn't, simply output the error and + * do not fall back on any other method. + */ + if ($_found) { + include_once $_plugin_file; + + $_plugin_func = 'smarty_' . $_type . '_' . $_name; + if (!function_exists($_plugin_func)) { + $smarty->_trigger_fatal_error("[plugin] function $_plugin_func() not found in $_plugin_file", $_tpl_file, $_tpl_line, __FILE__, __LINE__); + continue; + } + } + /* + * In case of insert plugins, their code may be loaded later via + * 'script' attribute. + */ + else if ($_type == 'insert' && $_delayed_loading) { + $_plugin_func = 'smarty_' . $_type . '_' . $_name; + $_found = true; + } + + /* + * Plugin specific processing and error checking. + */ + if (!$_found) { + if ($_type == 'modifier') { + /* + * In case modifier falls back on using PHP functions + * directly, we only allow those specified in the security + * context. + */ + if ($smarty->security && !in_array($_name, $smarty->security_settings['MODIFIER_FUNCS'])) { + $_message = "(secure mode) modifier '$_name' is not allowed"; + } else { + if (!function_exists($_name)) { + $_message = "modifier '$_name' is not implemented"; + } else { + $_plugin_func = $_name; + $_found = true; + } + } + } else if ($_type == 'function') { + /* + * This is a catch-all situation. + */ + $_message = "unknown tag - '$_name'"; + } + } + + if ($_found) { + $smarty->_plugins[$_type][$_name] = array($_plugin_func, $_tpl_file, $_tpl_line, true, true); + } else { + // output error + $smarty->_trigger_fatal_error('[plugin] ' . $_message, $_tpl_file, $_tpl_line, __FILE__, __LINE__); + } + } +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/core/core.load_resource_plugin.php b/smarty/core/core.load_resource_plugin.php new file mode 100644 index 0000000..a7d37d1 --- /dev/null +++ b/smarty/core/core.load_resource_plugin.php @@ -0,0 +1,74 @@ +_plugins['resource'][$params['type']]; + if (isset($_plugin)) { + if (!$_plugin[1] && count($_plugin[0])) { + $_plugin[1] = true; + foreach ($_plugin[0] as $_plugin_func) { + if (!is_callable($_plugin_func)) { + $_plugin[1] = false; + break; + } + } + } + + if (!$_plugin[1]) { + $smarty->_trigger_fatal_error("[plugin] resource '" . $params['type'] . "' is not implemented", null, null, __FILE__, __LINE__); + } + + return; + } + + $_plugin_file = $smarty->_get_plugin_filepath('resource', $params['type']); + $_found = ($_plugin_file != false); + + if ($_found) { /* + * If the plugin file is found, it -must- provide the properly named + * plugin functions. + */ + include_once($_plugin_file); + + /* + * Locate functions that we require the plugin to provide. + */ + $_resource_ops = array('source', 'timestamp', 'secure', 'trusted'); + $_resource_funcs = array(); + foreach ($_resource_ops as $_op) { + $_plugin_func = 'smarty_resource_' . $params['type'] . '_' . $_op; + if (!function_exists($_plugin_func)) { + $smarty->_trigger_fatal_error("[plugin] function $_plugin_func() not found in $_plugin_file", null, null, __FILE__, __LINE__); + return; + } else { + $_resource_funcs[] = $_plugin_func; + } + } + + $smarty->_plugins['resource'][$params['type']] = array($_resource_funcs, true); + } +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/core/core.process_cached_inserts.php b/smarty/core/core.process_cached_inserts.php new file mode 100644 index 0000000..0e368fd --- /dev/null +++ b/smarty/core/core.process_cached_inserts.php @@ -0,0 +1,71 @@ +_smarty_md5.'{insert_cache (.*)}'.$smarty->_smarty_md5.'!Uis', + $params['results'], $match); + list($cached_inserts, $insert_args) = $match; + + for ($i = 0, $for_max = count($cached_inserts); $i < $for_max; $i++) { + if ($smarty->debugging) { + $_params = array(); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.get_microtime.php'); + $debug_start_time = smarty_core_get_microtime($_params, $smarty); + } + + $args = unserialize($insert_args[$i]); + $name = $args['name']; + + if (isset($args['script'])) { + $_params = array('resource_name' => $smarty->_dequote($args['script'])); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.get_php_resource.php'); + if(!smarty_core_get_php_resource($_params, $smarty)) { + return false; + } + $resource_type = $_params['resource_type']; + $php_resource = $_params['php_resource']; + + + if ($resource_type == 'file') { + $smarty->_include($php_resource, true); + } else { + $smarty->_eval($php_resource); + } + } + + $function_name = $smarty->_plugins['insert'][$name][0]; + if (empty($args['assign'])) { + $replace = $function_name($args, $smarty); + } else { + $smarty->assign($args['assign'], $function_name($args, $smarty)); + $replace = ''; + } + + $params['results'] = str_replace($cached_inserts[$i], $replace, $params['results']); + if ($smarty->debugging) { + $_params = array(); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.get_microtime.php'); + $smarty->_smarty_debug_info[] = array('type' => 'insert', + 'filename' => 'insert_'.$name, + 'depth' => $smarty->_inclusion_depth, + 'exec_time' => smarty_core_get_microtime($_params, $smarty) - $debug_start_time); + } + } + + return $params['results']; +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/core/core.process_compiled_include.php b/smarty/core/core.process_compiled_include.php new file mode 100644 index 0000000..3e1d4c1 --- /dev/null +++ b/smarty/core/core.process_compiled_include.php @@ -0,0 +1,32 @@ +_cache_including; + $smarty->_cache_including = true; + + $_return = $params['results']; + foreach ($smarty->_cache_serials as $_include_file_path=>$_cache_serial) { + $_return = preg_replace_callback('!(\{nocache\:('.$_cache_serial.')#(\d+)\})!s', + array(&$smarty, '_process_compiled_include_callback'), + $_return); + } + $smarty->_cache_including = $_cache_including; + return $_return; +} + +?> diff --git a/smarty/core/core.read_cache_file.php b/smarty/core/core.read_cache_file.php new file mode 100644 index 0000000..2ab4281 --- /dev/null +++ b/smarty/core/core.read_cache_file.php @@ -0,0 +1,111 @@ +force_compile) { + // force compile enabled, always regenerate + return false; + } + + if (isset($content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']])) { + list($params['results'], $smarty->_cache_info) = $content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']]; + return true; + } + + if (!empty($smarty->cache_handler_func)) { + // use cache_handler function + call_user_func_array($smarty->cache_handler_func, + array('read', &$smarty, &$params['results'], $params['tpl_file'], $params['cache_id'], $params['compile_id'], null)); + } else { + // use local cache file + $_auto_id = $smarty->_get_auto_id($params['cache_id'], $params['compile_id']); + $_cache_file = $smarty->_get_auto_filename($smarty->cache_dir, $params['tpl_file'], $_auto_id); + $params['results'] = $smarty->_read_file($_cache_file); + } + + if (empty($params['results'])) { + // nothing to parse (error?), regenerate cache + return false; + } + + $cache_split = explode("\n", $params['results'], 2); + $cache_header = $cache_split[0]; + + $_cache_info = unserialize($cache_header); + + if ($smarty->caching == 2 && isset ($_cache_info['expires'])){ + // caching by expiration time + if ($_cache_info['expires'] > -1 && (time() > $_cache_info['expires'])) { + // cache expired, regenerate + return false; + } + } else { + // caching by lifetime + if ($smarty->cache_lifetime > -1 && (time() - $_cache_info['timestamp'] > $smarty->cache_lifetime)) { + // cache expired, regenerate + return false; + } + } + + if ($smarty->compile_check) { + $_params = array('get_source' => false, 'quiet'=>true); + foreach (array_keys($_cache_info['template']) as $_template_dep) { + $_params['resource_name'] = $_template_dep; + if (!$smarty->_fetch_resource_info($_params) || $_cache_info['timestamp'] < $_params['resource_timestamp']) { + // template file has changed, regenerate cache + return false; + } + } + + if (isset($_cache_info['config'])) { + $_params = array('resource_base_path' => $smarty->config_dir, 'get_source' => false, 'quiet'=>true); + foreach (array_keys($_cache_info['config']) as $_config_dep) { + $_params['resource_name'] = $_config_dep; + if (!$smarty->_fetch_resource_info($_params) || $_cache_info['timestamp'] < $_params['resource_timestamp']) { + // config file has changed, regenerate cache + return false; + } + } + } + } + + foreach ($_cache_info['cache_serials'] as $_include_file_path=>$_cache_serial) { + if (empty($smarty->_cache_serials[$_include_file_path])) { + $smarty->_include($_include_file_path, true); + } + + if ($smarty->_cache_serials[$_include_file_path] != $_cache_serial) { + /* regenerate */ + return false; + } + } + $params['results'] = $cache_split[1]; + $content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']] = array($params['results'], $_cache_info); + + $smarty->_cache_info = $_cache_info; + return true; +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/core/core.rm_auto.php b/smarty/core/core.rm_auto.php new file mode 100644 index 0000000..b7cdaf8 --- /dev/null +++ b/smarty/core/core.rm_auto.php @@ -0,0 +1,71 @@ + $params['auto_base'], + 'level' => 0, + 'exp_time' => $params['exp_time'] + ); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.rmdir.php'); + $_res = smarty_core_rmdir($_params, $smarty); + } else { + $_tname = $smarty->_get_auto_filename($params['auto_base'], $params['auto_source'], $params['auto_id']); + + if(isset($params['auto_source'])) { + if (isset($params['extensions'])) { + $_res = false; + foreach ((array)$params['extensions'] as $_extension) + $_res |= $smarty->_unlink($_tname.$_extension, $params['exp_time']); + } else { + $_res = $smarty->_unlink($_tname, $params['exp_time']); + } + } elseif ($smarty->use_sub_dirs) { + $_params = array( + 'dirname' => $_tname, + 'level' => 1, + 'exp_time' => $params['exp_time'] + ); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.rmdir.php'); + $_res = smarty_core_rmdir($_params, $smarty); + } else { + // remove matching file names + $_handle = opendir($params['auto_base']); + $_res = true; + while (false !== ($_filename = readdir($_handle))) { + if($_filename == '.' || $_filename == '..') { + continue; + } elseif (substr($params['auto_base'] . DIRECTORY_SEPARATOR . $_filename, 0, strlen($_tname)) == $_tname) { + $_res &= (bool)$smarty->_unlink($params['auto_base'] . DIRECTORY_SEPARATOR . $_filename, $params['exp_time']); + } + } + } + } + + return $_res; +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/core/core.rmdir.php b/smarty/core/core.rmdir.php new file mode 100644 index 0000000..38df822 --- /dev/null +++ b/smarty/core/core.rmdir.php @@ -0,0 +1,55 @@ + keep root) + * WARNING: no tests, it will try to remove what you tell it! + * + * @param string $dirname + * @param integer $level + * @param integer $exp_time + * @return boolean + */ + +// $dirname, $level = 1, $exp_time = null + +function smarty_core_rmdir($params, &$smarty) +{ + if(!isset($params['level'])) { $params['level'] = 1; } + if(!isset($params['exp_time'])) { $params['exp_time'] = null; } + + if($_handle = @opendir($params['dirname'])) { + + while (false !== ($_entry = readdir($_handle))) { + if ($_entry != '.' && $_entry != '..') { + if (@is_dir($params['dirname'] . DIRECTORY_SEPARATOR . $_entry)) { + $_params = array( + 'dirname' => $params['dirname'] . DIRECTORY_SEPARATOR . $_entry, + 'level' => $params['level'] + 1, + 'exp_time' => $params['exp_time'] + ); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.rmdir.php'); + smarty_core_rmdir($_params, $smarty); + } + else { + $smarty->_unlink($params['dirname'] . DIRECTORY_SEPARATOR . $_entry, $params['exp_time']); + } + } + } + closedir($_handle); + } + + if ($params['level']) { + return @rmdir($params['dirname']); + } + return (bool)$_handle; + +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/core/core.run_insert_handler.php b/smarty/core/core.run_insert_handler.php new file mode 100644 index 0000000..aa391ab --- /dev/null +++ b/smarty/core/core.run_insert_handler.php @@ -0,0 +1,71 @@ +debugging) { + $_params = array(); + $_debug_start_time = smarty_core_get_microtime($_params, $smarty); + } + + if ($smarty->caching) { + $_arg_string = serialize($params['args']); + $_name = $params['args']['name']; + if (!isset($smarty->_cache_info['insert_tags'][$_name])) { + $smarty->_cache_info['insert_tags'][$_name] = array('insert', + $_name, + $smarty->_plugins['insert'][$_name][1], + $smarty->_plugins['insert'][$_name][2], + !empty($params['args']['script']) ? true : false); + } + return $smarty->_smarty_md5."{insert_cache $_arg_string}".$smarty->_smarty_md5; + } else { + if (isset($params['args']['script'])) { + $_params = array('resource_name' => $smarty->_dequote($params['args']['script'])); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.get_php_resource.php'); + if(!smarty_core_get_php_resource($_params, $smarty)) { + return false; + } + + if ($_params['resource_type'] == 'file') { + $smarty->_include($_params['php_resource'], true); + } else { + $smarty->_eval($_params['php_resource']); + } + unset($params['args']['script']); + } + + $_funcname = $smarty->_plugins['insert'][$params['args']['name']][0]; + $_content = $_funcname($params['args'], $smarty); + if ($smarty->debugging) { + $_params = array(); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.get_microtime.php'); + $smarty->_smarty_debug_info[] = array('type' => 'insert', + 'filename' => 'insert_'.$params['args']['name'], + 'depth' => $smarty->_inclusion_depth, + 'exec_time' => smarty_core_get_microtime($_params, $smarty) - $_debug_start_time); + } + + if (!empty($params['args']["assign"])) { + $smarty->assign($params['args']["assign"], $_content); + } else { + return $_content; + } + } +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/core/core.smarty_include_php.php b/smarty/core/core.smarty_include_php.php new file mode 100644 index 0000000..4b31648 --- /dev/null +++ b/smarty/core/core.smarty_include_php.php @@ -0,0 +1,50 @@ + $params['smarty_file']); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.get_php_resource.php'); + smarty_core_get_php_resource($_params, $smarty); + $_smarty_resource_type = $_params['resource_type']; + $_smarty_php_resource = $_params['php_resource']; + + if (!empty($params['smarty_assign'])) { + ob_start(); + if ($_smarty_resource_type == 'file') { + $smarty->_include($_smarty_php_resource, $params['smarty_once'], $params['smarty_include_vars']); + } else { + $smarty->_eval($_smarty_php_resource, $params['smarty_include_vars']); + } + $smarty->assign($params['smarty_assign'], ob_get_contents()); + ob_end_clean(); + } else { + if ($_smarty_resource_type == 'file') { + $smarty->_include($_smarty_php_resource, $params['smarty_once'], $params['smarty_include_vars']); + } else { + $smarty->_eval($_smarty_php_resource, $params['smarty_include_vars']); + } + } +} + + +/* vim: set expandtab: */ + +?> diff --git a/smarty/core/core.write_cache_file.php b/smarty/core/core.write_cache_file.php new file mode 100644 index 0000000..7429ad9 --- /dev/null +++ b/smarty/core/core.write_cache_file.php @@ -0,0 +1,73 @@ +_cache_info['timestamp'] = time(); + if ($smarty->cache_lifetime > -1){ + // expiration set + $smarty->_cache_info['expires'] = $smarty->_cache_info['timestamp'] + $smarty->cache_lifetime; + } else { + // cache will never expire + $smarty->_cache_info['expires'] = -1; + } + + // collapse {nocache...}-tags + $params['results'] = preg_replace('!((\{nocache\:([0-9a-f]{32})#(\d+)\})' + .'.*' + .'{/nocache\:\\3#\\4\})!Us' + ,'\\2' + ,$params['results']); + $smarty->_cache_info['cache_serials'] = $smarty->_cache_serials; + + // prepend the cache header info into cache file + $params['results'] = serialize($smarty->_cache_info)."\n".$params['results']; + + if (!empty($smarty->cache_handler_func)) { + // use cache_handler function + call_user_func_array($smarty->cache_handler_func, + array('write', &$smarty, &$params['results'], $params['tpl_file'], $params['cache_id'], $params['compile_id'], null)); + } else { + // use local cache file + + if(!@is_writable($smarty->cache_dir)) { + // cache_dir not writable, see if it exists + if(!@is_dir($smarty->cache_dir)) { + $smarty->trigger_error('the $cache_dir \'' . $smarty->cache_dir . '\' does not exist, or is not a directory.', E_USER_ERROR); + return false; + } + $smarty->trigger_error('unable to write to $cache_dir \'' . realpath($smarty->cache_dir) . '\'. Be sure $cache_dir is writable by the web server user.', E_USER_ERROR); + return false; + } + + $_auto_id = $smarty->_get_auto_id($params['cache_id'], $params['compile_id']); + $_cache_file = $smarty->_get_auto_filename($smarty->cache_dir, $params['tpl_file'], $_auto_id); + $_params = array('filename' => $_cache_file, 'contents' => $params['results'], 'create_dirs' => true); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.write_file.php'); + smarty_core_write_file($_params, $smarty); + return true; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/core/core.write_compiled_include.php b/smarty/core/core.write_compiled_include.php new file mode 100644 index 0000000..9c6a491 --- /dev/null +++ b/smarty/core/core.write_compiled_include.php @@ -0,0 +1,59 @@ +caching\) \{ echo \'\{nocache\:('.$params['cache_serial'].')#(\d+)\}\';\}'; + $_tag_end = 'if \(\$this->caching\) \{ echo \'\{/nocache\:(\\2)#(\\3)\}\';\}'; + + preg_match_all('!('.$_tag_start.'(.*)'.$_tag_end.')!Us', + $params['compiled_content'], $_match_source, PREG_SET_ORDER); + + // no nocache-parts found: done + if (count($_match_source)==0) return; + + // convert the matched php-code to functions + $_include_compiled = "_cache_serials[$_compile_path] = $params['cache_serial']; + $_include_compiled .= "\$this->_cache_serials['".$_compile_path."'] = '".$params['cache_serial']."';\n\n?>"; + + $_include_compiled .= $params['plugins_code']; + $_include_compiled .= "\n"; + + $_params = array('filename' => $_compile_path, + 'contents' => $_include_compiled, 'create_dirs' => true); + + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.write_file.php'); + smarty_core_write_file($_params, $smarty); + return true; +} + + +?> diff --git a/smarty/core/core.write_compiled_resource.php b/smarty/core/core.write_compiled_resource.php new file mode 100644 index 0000000..09b50d3 --- /dev/null +++ b/smarty/core/core.write_compiled_resource.php @@ -0,0 +1,37 @@ +compile_dir)) { + // compile_dir not writable, see if it exists + if(!@is_dir($smarty->compile_dir)) { + $smarty->trigger_error('the $compile_dir \'' . $smarty->compile_dir . '\' does not exist, or is not a directory.', E_USER_ERROR); + return false; + } + $smarty->trigger_error('unable to write to $compile_dir \'' . realpath($smarty->compile_dir) . '\'. Be sure $compile_dir is writable by the web server user.', E_USER_ERROR); + return false; + } + + $_params = array('filename' => $params['compile_path'], 'contents' => $params['compiled_content'], 'create_dirs' => true); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.write_file.php'); + smarty_core_write_file($_params, $smarty); + touch($params['compile_path'], $params['resource_timestamp']); + return true; +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/core/core.write_file.php b/smarty/core/core.write_file.php new file mode 100644 index 0000000..c92454d --- /dev/null +++ b/smarty/core/core.write_file.php @@ -0,0 +1,48 @@ + $_dirname); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.create_dir_structure.php'); + smarty_core_create_dir_structure($_params, $smarty); + } + + // write to tmp file, then rename it to avoid + // file locking race condition + $_tmp_file = $_dirname . DIRECTORY_SEPARATOR . uniqid(''); + + if (!($fd = @fopen($_tmp_file, 'w'))) { + $smarty->trigger_error("problem writing temporary file '$_tmp_file'"); + return false; + } + + fwrite($fd, $params['contents']); + fclose($fd); + if(file_exists($params['filename'])) { + @unlink($params['filename']); + } + @rename($_tmp_file, $params['filename']); + @chmod($params['filename'], $smarty->_file_perms); + + return true; +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/debug.tpl b/smarty/debug.tpl new file mode 100644 index 0000000..01265fb --- /dev/null +++ b/smarty/debug.tpl @@ -0,0 +1,64 @@ +{* Smarty *} + +{* debug.tpl, last updated version 2.0.1 *} + +{assign_debug_info} + +{if isset($_smarty_debug_output) and $_smarty_debug_output eq "html"} + + + + {section name=templates loop=$_debug_tpls} + + {sectionelse} + + {/section} + + {section name=vars loop=$_debug_keys} + + {sectionelse} + + {/section} + + {section name=config_vars loop=$_debug_config_keys} + + {sectionelse} + + {/section} +
Smarty Debug Console
included templates & config files (load time in seconds):
{section name=indent loop=$_debug_tpls[templates].depth}   {/section}{$_debug_tpls[templates].filename|escape:html}{if isset($_debug_tpls[templates].exec_time)} ({$_debug_tpls[templates].exec_time|string_format:"%.5f"}){if %templates.index% eq 0} (total){/if}{/if}
no templates included
assigned template variables:
{ldelim}${$_debug_keys[vars]}{rdelim}{$_debug_vals[vars]|@debug_print_var}
no template variables assigned
assigned config file variables (outer template scope):
{ldelim}#{$_debug_config_keys[config_vars]}#{rdelim}{$_debug_config_vals[config_vars]|@debug_print_var}
no config vars assigned
+ +{else} + +{/if} diff --git a/smarty/plugins/block.textformat.php b/smarty/plugins/block.textformat.php new file mode 100644 index 0000000..7ddccc7 --- /dev/null +++ b/smarty/plugins/block.textformat.php @@ -0,0 +1,83 @@ + + * Name: textformat
+ * Purpose: format text a certain way with preset styles + * or custom wrap/indent settings
+ * @link http://smarty.php.net/manual/en/language.function.textformat.php {textformat} + * (Smarty online manual) + * @param array + *
+ * Params:   style: string (email)
+ *           indent: integer (0)
+ *           wrap: integer (80)
+ *           wrap_char string ("\n")
+ *           indent_char: string (" ")
+ *           wrap_boundary: boolean (true)
+ * 
+ * @param string contents of the block + * @param Smarty clever simulation of a method + * @return string string $content re-formatted + */ +function smarty_block_textformat($params, $content, &$smarty) +{ + $style = null; + $indent = 0; + $indent_first = 0; + $indent_char = ' '; + $wrap = 80; + $wrap_char = "\n"; + $wrap_cut = false; + $assign = null; + + if($content == null) { + return true; + } + + extract($params); + + if($style == 'email') { + $wrap = 72; + } + + // split into paragraphs + $paragraphs = preg_split('![\r\n][\r\n]!',$content); + $output = ''; + + foreach($paragraphs as $paragraph) { + if($paragraph == '') { + continue; + } + // convert mult. spaces & special chars to single space + $paragraph = preg_replace(array('!\s+!','!(^\s+)|(\s+$)!'),array(' ',''),$paragraph); + // indent first line + if($indent_first > 0) { + $paragraph = str_repeat($indent_char,$indent_first) . $paragraph; + } + // wordwrap sentences + $paragraph = wordwrap($paragraph, $wrap - $indent, $wrap_char, $wrap_cut); + // indent lines + if($indent > 0) { + $paragraph = preg_replace('!^!m',str_repeat($indent_char,$indent),$paragraph); + } + $output .= $paragraph . $wrap_char . $wrap_char; + } + + if($assign != null) { + $smarty->assign($assign,$output); + } else { + return $output; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/function.assign.php b/smarty/plugins/function.assign.php new file mode 100644 index 0000000..ad23f04 --- /dev/null +++ b/smarty/plugins/function.assign.php @@ -0,0 +1,38 @@ + + * Name: assign
+ * Purpose: assign a value to a template variable + * @link http://smarty.php.net/manual/en/language.custom.functions.php#LANGUAGE.FUNCTION.ASSIGN {assign} + * (Smarty online manual) + * @param array Format: array('var' => variable name, 'value' => value to assign) + * @param Smarty + */ +function smarty_function_assign($params, &$smarty) +{ + extract($params); + + if (empty($var)) { + $smarty->trigger_error("assign: missing 'var' parameter"); + return; + } + + if (!in_array('value', array_keys($params))) { + $smarty->trigger_error("assign: missing 'value' parameter"); + return; + } + + $smarty->assign($var, $value); +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/function.assign_debug_info.php b/smarty/plugins/function.assign_debug_info.php new file mode 100644 index 0000000..c281ce8 --- /dev/null +++ b/smarty/plugins/function.assign_debug_info.php @@ -0,0 +1,39 @@ + + * Name: assign_debug_info
+ * Purpose: assign debug info to the template
+ * @param array unused in this plugin, this plugin uses {@link Smarty::$_config}, + * {@link Smarty::$_tpl_vars} and {@link Smarty::$_smarty_debug_info} + * @param Smarty + */ +function smarty_function_assign_debug_info($params, &$smarty) +{ + $assigned_vars = $smarty->_tpl_vars; + ksort($assigned_vars); + if (@is_array($smarty->_config[0])) { + $config_vars = $smarty->_config[0]; + ksort($config_vars); + $smarty->assign("_debug_config_keys", array_keys($config_vars)); + $smarty->assign("_debug_config_vals", array_values($config_vars)); + } + + $included_templates = $smarty->_smarty_debug_info; + + $smarty->assign("_debug_keys", array_keys($assigned_vars)); + $smarty->assign("_debug_vals", array_values($assigned_vars)); + + $smarty->assign("_debug_tpls", $included_templates); +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/function.config_load.php b/smarty/plugins/function.config_load.php new file mode 100644 index 0000000..12b7462 --- /dev/null +++ b/smarty/plugins/function.config_load.php @@ -0,0 +1,130 @@ + + * Name: config_load
+ * Purpose: load config file vars + * @link http://smarty.php.net/manual/en/language.function.config.load.php {config_load} + * (Smarty online manual) + * @param array Format: + *
+ * array('file' => required config file name,
+ *       'section' => optional config file section to load
+ *       'scope' => local/parent/global
+ *       'global' => overrides scope, setting to parent if true)
+ * 
+ * @param Smarty + */ +function smarty_function_config_load($params, &$smarty) +{ + if ($smarty->debugging) { + $_params = array(); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.get_microtime.php'); + $_debug_start_time = smarty_core_get_microtime($_params, $smarty); + } + + $_file = isset($params['file']) ? $smarty->_dequote($params['file']) : null; + $_section = isset($params['section']) ? $smarty->_dequote($params['section']) : null; + $_scope = isset($params['scope']) ? $smarty->_dequote($params['scope']) : 'global'; + $_global = isset($params['global']) ? $smarty->_dequote($params['global']) : false; + + if (!isset($_file) || strlen($_file) == 0) { + $smarty->_syntax_error("missing 'file' attribute in config_load tag", E_USER_ERROR, __FILE__, __LINE__); + } + + if (isset($_scope)) { + if ($_scope != 'local' && + $_scope != 'parent' && + $_scope != 'global') { + $smarty->_syntax_error("invalid 'scope' attribute value", E_USER_ERROR, __FILE__, __LINE__); + } + } else { + if ($_global) { + $_scope = 'parent'; + } else { + $_scope = 'local'; + } + } + + if(@is_dir($smarty->config_dir)) { + $_config_dir = $smarty->config_dir; + } else { + // config_dir not found, try include_path + $_params = array('file_path' => $smarty->config_dir); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.get_include_path.php'); + smarty_core_get_include_path($_params, $smarty); + $_config_dir = $_params['new_file_path']; + } + + $_file_path = $_config_dir . DIRECTORY_SEPARATOR . $_file; + if (isset($_section)) + $_compile_file = $smarty->_get_compile_path($_file_path.'|'.$_section); + else + $_compile_file = $smarty->_get_compile_path($_file_path); + + if($smarty->force_compile + || !file_exists($_compile_file) + || ($smarty->compile_check + && !$smarty->_is_compiled($_file_path, $_compile_file))) { + // compile config file + if(!is_object($smarty->_conf_obj)) { + require_once SMARTY_DIR . $smarty->config_class . '.class.php'; + $smarty->_conf_obj = new $smarty->config_class($_config_dir); + $smarty->_conf_obj->overwrite = $smarty->config_overwrite; + $smarty->_conf_obj->booleanize = $smarty->config_booleanize; + $smarty->_conf_obj->read_hidden = $smarty->config_read_hidden; + $smarty->_conf_obj->fix_newlines = $smarty->config_fix_newlines; + $smarty->_conf_obj->set_path = $_config_dir; + } + $_config_vars = array_merge($smarty->_conf_obj->get($_file), + $smarty->_conf_obj->get($_file, $_section)); + if(function_exists('var_export')) { + $_output = ''; + } else { + $_output = ''\\\'', '\\'=>'\\\\')) . '\'); ?>'; + } + $_params = (array('compile_path' => $_compile_file, 'compiled_content' => $_output, 'resource_timestamp' => filemtime($_file_path))); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.write_compiled_resource.php'); + smarty_core_write_compiled_resource($_params, $smarty); + } else { + include($_compile_file); + } + + if ($smarty->caching) { + $smarty->_cache_info['config'][$_file] = true; + } + + $smarty->_config[0]['vars'] = @array_merge($smarty->_config[0]['vars'], $_config_vars); + $smarty->_config[0]['files'][$_file] = true; + + if ($_scope == 'parent') { + $smarty->_config[1]['vars'] = @array_merge($smarty->_config[1]['vars'], $_config_vars); + $smarty->_config[1]['files'][$_file] = true; + } else if ($_scope == 'global') { + for ($i = 1, $for_max = count($smarty->_config); $i < $for_max; $i++) { + $smarty->_config[$i]['vars'] = @array_merge($smarty->_config[$i]['vars'], $_config_vars); + $smarty->_config[$i]['files'][$_file] = true; + } + } + + if ($smarty->debugging) { + $_params = array(); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.get_microtime.php'); + $smarty->_smarty_debug_info[] = array('type' => 'config', + 'filename' => $_file.' ['.$_section.'] '.$_scope, + 'depth' => $smarty->_inclusion_depth, + 'exec_time' => smarty_core_get_microtime($_params, $smarty) - $_debug_start_time); + } + +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/function.counter.php b/smarty/plugins/function.counter.php new file mode 100644 index 0000000..2536c14 --- /dev/null +++ b/smarty/plugins/function.counter.php @@ -0,0 +1,88 @@ + + * Name: counter
+ * Purpose: print out a counter value + * @link http://smarty.php.net/manual/en/language.function.counter.php {counter} + * (Smarty online manual) + * @param array parameters + * @param Smarty + * @return string|null + */ +function smarty_function_counter($params, &$smarty) +{ + static $counters = array(); + + extract($params); + + if (!isset($name)) { + if(isset($id)) { + $name = $id; + } else { + $name = "default"; + } + } + + if (!isset($counters[$name])) { + $counters[$name] = array( + 'start'=>1, + 'skip'=>1, + 'direction'=>'up', + 'count'=>1 + ); + } + $counter =& $counters[$name]; + + if (isset($start)) { + $counter['start'] = $counter['count'] = $start; + } + + if (!empty($assign)) { + $counter['assign'] = $assign; + } + + if (isset($counter['assign'])) { + $smarty->assign($counter['assign'], $counter['count']); + } + + if (isset($print)) { + $print = (bool)$print; + } else { + $print = empty($counter['assign']); + } + + if ($print) { + $retval = $counter['count']; + } else { + $retval = null; + } + + if (isset($skip)) { + $counter['skip'] = $skip; + } + + if (isset($direction)) { + $counter['direction'] = $direction; + } + + if ($counter['direction'] == "down") + $counter['count'] -= $counter['skip']; + else + $counter['count'] += $counter['skip']; + + return $retval; + +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/function.cycle.php b/smarty/plugins/function.cycle.php new file mode 100644 index 0000000..d5909a6 --- /dev/null +++ b/smarty/plugins/function.cycle.php @@ -0,0 +1,119 @@ + + * Name: cycle
+ * Date: May 3, 2002
+ * Purpose: cycle through given values
+ * Input: + * - name = name of cycle (optional) + * - values = comma separated list of values to cycle, + * or an array of values to cycle + * (this can be left out for subsequent calls) + * - reset = boolean - resets given var to true + * - print = boolean - print var or not. default is true + * - advance = boolean - whether or not to advance the cycle + * - delimiter = the value delimiter, default is "," + * - assign = boolean, assigns to template var instead of + * printed. + * + * Examples:
+ *
+ * {cycle values="#eeeeee,#d0d0d0d"}
+ * {cycle name=row values="one,two,three" reset=true}
+ * {cycle name=row}
+ * 
+ * @link http://smarty.php.net/manual/en/language.function.cycle.php {cycle} + * (Smarty online manual) + * @author Monte Ohrt + * @author credit to Mark Priatel + * @author credit to Gerard + * @author credit to Jason Sweat + * @version 1.3 + * @param array + * @param Smarty + * @return string|null + */ +function smarty_function_cycle($params, &$smarty) +{ + static $cycle_vars; + + extract($params); + + if (empty($name)) { + $name = 'default'; + } + + if (!isset($print)) { + $print = true; + } + + if (!isset($advance)) { + $advance = true; + } + + if (!isset($reset)) { + $reset = false; + } + + if (!in_array('values', array_keys($params))) { + if(!isset($cycle_vars[$name]['values'])) { + $smarty->trigger_error("cycle: missing 'values' parameter"); + return; + } + } else { + if(isset($cycle_vars[$name]['values']) + && $cycle_vars[$name]['values'] != $values ) { + $cycle_vars[$name]['index'] = 0; + } + $cycle_vars[$name]['values'] = $values; + } + + if (isset($delimiter)) { + $cycle_vars[$name]['delimiter'] = $delimiter; + } elseif (!isset($cycle_vars[$name]['delimiter'])) { + $cycle_vars[$name]['delimiter'] = ','; + } + + if(!is_array($cycle_vars[$name]['values'])) { + $cycle_array = explode($cycle_vars[$name]['delimiter'],$cycle_vars[$name]['values']); + } else { + $cycle_array = $cycle_vars[$name]['values']; + } + + if(!isset($cycle_vars[$name]['index']) || $reset ) { + $cycle_vars[$name]['index'] = 0; + } + + if (isset($assign)) { + $print = false; + $smarty->assign($assign, $cycle_array[$cycle_vars[$name]['index']]); + } + + if($print) { + $retval = $cycle_array[$cycle_vars[$name]['index']]; + } else { + $retval = null; + } + + if($advance) { + if ( $cycle_vars[$name]['index'] >= count($cycle_array) -1 ) { + $cycle_vars[$name]['index'] = 0; + } else { + $cycle_vars[$name]['index']++; + } + } + + return $retval; +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/function.debug.php b/smarty/plugins/function.debug.php new file mode 100644 index 0000000..2452d62 --- /dev/null +++ b/smarty/plugins/function.debug.php @@ -0,0 +1,35 @@ + + * Name: debug
+ * Date: July 1, 2002
+ * Purpose: popup debug window + * @link http://smarty.php.net/manual/en/language.function.debug.php {debug} + * (Smarty online manual) + * @author Monte Ohrt + * @version 1.0 + * @param array + * @param Smarty + * @return string output from {@link Smarty::_generate_debug_output()} + */ +function smarty_function_debug($params, &$smarty) +{ + if($params['output']) { + $smarty->assign('_smarty_debug_output',$params['output']); + } + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.display_debug_console.php'); + return smarty_core_display_debug_console(null, $smarty); +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/function.eval.php b/smarty/plugins/function.eval.php new file mode 100644 index 0000000..3a4b8b2 --- /dev/null +++ b/smarty/plugins/function.eval.php @@ -0,0 +1,48 @@ + + * Name: eval
+ * Purpose: evaluate a template variable as a template
+ * @link http://smarty.php.net/manual/en/language.function.eval.php {eval} + * (Smarty online manual) + * @param array + * @param Smarty + */ +function smarty_function_eval($params, &$smarty) +{ + + if (!isset($params['var'])) { + $smarty->trigger_error("eval: missing 'var' parameter"); + return; + } + + if($params['var'] == '') { + return; + } + + $smarty->_compile_source('evaluated template', $params['var'], $_var_compiled); + + ob_start(); + $smarty->_eval('?>' . $_var_compiled); + $_contents = ob_get_contents(); + ob_end_clean(); + + if (!empty($params['assign'])) { + $smarty->assign($params['assign'], $_contents); + } else { + return $_contents; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/function.fetch.php b/smarty/plugins/function.fetch.php new file mode 100644 index 0000000..b013b8c --- /dev/null +++ b/smarty/plugins/function.fetch.php @@ -0,0 +1,217 @@ + + * Name: fetch
+ * Purpose: fetch file, web or ftp data and display results + * @link http://smarty.php.net/manual/en/language.function.fetch.php {fetch} + * (Smarty online manual) + * @param array + * @param Smarty + * @return string|null if the assign parameter is passed, Smarty assigns the + * result to a template variable + */ +function smarty_function_fetch($params, &$smarty) +{ + if (empty($params['file'])) { + $smarty->_trigger_fatal_error("[plugin] parameter 'file' cannot be empty"); + return; + } + + if ($smarty->security && !preg_match('!^(http|ftp)://!i', $params['file'])) { + $_params = array('resource_type' => 'file', 'resource_name' => $params['file']); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.is_secure.php'); + if(!smarty_core_is_secure($_params, $smarty)) { + $smarty->_trigger_fatal_error('[plugin] (secure mode) fetch \'' . $params['file'] . '\' is not allowed'); + return; + } + + // fetch the file + if($fp = @fopen($params['file'],'r')) { + while(!feof($fp)) { + $content .= fgets ($fp,4096); + } + fclose($fp); + } else { + $smarty->_trigger_fatal_error('[plugin] fetch cannot read file \'' . $params['file'] . '\''); + return; + } + } else { + // not a local file + if(preg_match('!^http://!i',$params['file'])) { + // http fetch + if($uri_parts = parse_url($params['file'])) { + // set defaults + $host = $server_name = $uri_parts['host']; + $timeout = 30; + $accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*"; + $agent = "Smarty Template Engine ".$smarty->_version; + $referer = ""; + $uri = !empty($uri_parts['path']) ? $uri_parts['path'] : '/'; + $uri .= !empty($uri_parts['query']) ? '?' . $uri_parts['query'] : ''; + $_is_proxy = false; + if(empty($uri_parts['port'])) { + $port = 80; + } else { + $port = $uri_parts['port']; + } + if(empty($uri_parts['user'])) { + $user = ''; + } + // loop through parameters, setup headers + foreach($params as $param_key => $param_value) { + switch($param_key) { + case "file": + case "assign": + case "assign_headers": + break; + case "user": + if(!empty($param_value)) { + $user = $param_value; + } + break; + case "pass": + if(!empty($param_value)) { + $pass = $param_value; + } + break; + case "accept": + if(!empty($param_value)) { + $accept = $param_value; + } + break; + case "header": + if(!empty($param_value)) { + if(!preg_match('![\w\d-]+: .+!',$param_value)) { + $smarty->_trigger_fatal_error("[plugin] invalid header format '".$param_value."'"); + return; + } else { + $extra_headers[] = $param_value; + } + } + break; + case "proxy_host": + if(!empty($param_value)) { + $proxy_host = $param_value; + } + break; + case "proxy_port": + if(!preg_match('!\D!', $param_value)) { + $proxy_port = (int) $param_value; + } else { + $smarty->_trigger_fatal_error("[plugin] invalid value for attribute '".$param_key."'"); + return; + } + break; + case "agent": + if(!empty($param_value)) { + $agent = $param_value; + } + break; + case "referer": + if(!empty($param_value)) { + $referer = $param_value; + } + break; + case "timeout": + if(!preg_match('!\D!', $param_value)) { + $timeout = (int) $param_value; + } else { + $smarty->_trigger_fatal_error("[plugin] invalid value for attribute '".$param_key."'"); + return; + } + break; + default: + $smarty->_trigger_fatal_error("[plugin] unrecognized attribute '".$param_key."'"); + return; + } + } + if(!empty($proxy_host) && !empty($proxy_port)) { + $_is_proxy = true; + $fp = fsockopen($proxy_host,$proxy_port,$errno,$errstr,$timeout); + } else { + $fp = fsockopen($server_name,$port,$errno,$errstr,$timeout); + } + + if(!$fp) { + $smarty->_trigger_fatal_error("[plugin] unable to fetch: $errstr ($errno)"); + return; + } else { + if($_is_proxy) { + fputs($fp, 'GET ' . $params['file'] . " HTTP/1.0\r\n"); + } else { + fputs($fp, "GET $uri HTTP/1.0\r\n"); + } + if(!empty($host)) { + fputs($fp, "Host: $host\r\n"); + } + if(!empty($accept)) { + fputs($fp, "Accept: $accept\r\n"); + } + if(!empty($agent)) { + fputs($fp, "User-Agent: $agent\r\n"); + } + if(!empty($referer)) { + fputs($fp, "Referer: $referer\r\n"); + } + if(isset($extra_headers) && is_array($extra_headers)) { + foreach($extra_headers as $curr_header) { + fputs($fp, $curr_header."\r\n"); + } + } + if(!empty($user) && !empty($pass)) { + fputs($fp, "Authorization: BASIC ".base64_encode("$user:$pass")."\r\n"); + } + + $content = ''; + fputs($fp, "\r\n"); + while(!feof($fp)) { + $content .= fgets($fp,4096); + } + fclose($fp); + $csplit = split("\r\n\r\n",$content,2); + + $content = $csplit[1]; + + if(!empty($params['assign_headers'])) { + $smarty->assign($params['assign_headers'],split("\r\n",$csplit[0])); + } + } + } else { + $smarty->_trigger_fatal_error("[plugin] unable to parse URL, check syntax"); + return; + } + } else { + // ftp fetch + if($fp = @fopen($params['file'],'r')) { + while(!feof($fp)) { + $content .= fgets ($fp,4096); + } + fclose($fp); + } else { + $smarty->_trigger_fatal_error('[plugin] fetch cannot read file \'' . $params['file'] .'\''); + return; + } + } + + } + + + if (!empty($params['assign'])) { + $smarty->assign($params['assign'],$content); + } else { + return $content; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/function.html_checkboxes.php b/smarty/plugins/function.html_checkboxes.php new file mode 100644 index 0000000..c146fc1 --- /dev/null +++ b/smarty/plugins/function.html_checkboxes.php @@ -0,0 +1,135 @@ + + * Type: function
+ * Name: html_checkboxes
+ * Date: 24.Feb.2003
+ * Purpose: Prints out a list of checkbox input types
+ * Input:
+ * - name (optional) - string default "checkbox" + * - values (required) - array + * - options (optional) - associative array + * - checked (optional) - array default not set + * - separator (optional) - ie
or   + * - output (optional) - without this one the buttons don't have names + * Examples: + *
+ * {html_checkboxes values=$ids output=$names}
+ * {html_checkboxes values=$ids name='box' separator='
' output=$names} + * {html_checkboxes values=$ids checked=$checked separator='
' output=$names} + *
+ * @link http://smarty.php.net/manual/en/language.function.html.checkboxes.php {html_checkboxes} + * (Smarty online manual) + * @author Christopher Kvarme + * @author credits to Monte Ohrt + * @version 1.0 + * @param array + * @param Smarty + * @return string + * @uses smarty_function_escape_special_chars() + */ +function smarty_function_html_checkboxes($params, &$smarty) +{ + require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); + + $name = 'checkbox'; + $values = null; + $options = null; + $selected = null; + $separator = ''; + $labels = true; + $output = null; + + $extra = ''; + + foreach($params as $_key => $_val) { + switch($_key) { + case 'name': + case 'separator': + $$_key = $_val; + break; + + case 'labels': + $$_key = (bool)$_val; + break; + + case 'options': + $$_key = (array)$_val; + break; + + case 'values': + case 'output': + $$_key = array_values((array)$_val); + break; + + case 'checked': + case 'selected': + $selected = array_values((array)$_val); + break; + + case 'checkboxes': + $smarty->trigger_error('html_checkboxes: the use of the "checkboxes" attribute is deprecated, use "options" instead', E_USER_WARNING); + $options = (array)$_val; + break; + + default: + if(!is_array($_val)) { + $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; + } else { + $smarty->trigger_error("html_checkboxes: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + } + } + + if (!isset($options) && !isset($values)) + return ''; /* raise error here? */ + + settype($selected, 'array'); + $_html_result = ''; + + if (is_array($options)) { + + foreach ($options as $_key=>$_val) + $_html_result .= smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels); + + + } else { + foreach ($values as $_i=>$_key) { + $_val = isset($output[$_i]) ? $output[$_i] : ''; + $_html_result .= smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels); + } + + } + + return $_html_result; + +} + +function smarty_function_html_checkboxes_output($name, $value, $output, $selected, $extra, $separator, $labels) { + $_output = ''; + if ($labels) $_output .= ''; + $_output .= $separator . "\n"; + + return $_output; +} + +?> diff --git a/smarty/plugins/function.html_image.php b/smarty/plugins/function.html_image.php new file mode 100644 index 0000000..2fcdb4e --- /dev/null +++ b/smarty/plugins/function.html_image.php @@ -0,0 +1,143 @@ + + * Name: html_image
+ * Date: Feb 24, 2003
+ * Purpose: format HTML tags for the image
+ * Input:
+ * - file = file (and path) of image (required) + * - border = border width (optional, default 0) + * - height = image height (optional, default actual height) + * - image =image width (optional, default actual width) + * - basedir = base directory for absolute paths, default + * is environment variable DOCUMENT_ROOT + * + * Examples: {html_image file="images/masthead.gif"} + * Output: + * @link http://smarty.php.net/manual/en/language.function.html.image.php {html_image} + * (Smarty online manual) + * @author Monte Ohrt + * @author credits to Duda - wrote first image function + * in repository, helped with lots of functionality + * @version 1.0 + * @param array + * @param Smarty + * @return string + * @uses smarty_function_escape_special_chars() + */ +function smarty_function_html_image($params, &$smarty) +{ + require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); + + $alt = ''; + $file = ''; + $border = 0; + $height = ''; + $width = ''; + $extra = ''; + $prefix = ''; + $suffix = ''; + $basedir = isset($GLOBALS['HTTP_SERVER_VARS']['DOCUMENT_ROOT']) + ? $GLOBALS['HTTP_SERVER_VARS']['DOCUMENT_ROOT'] : ''; + if(strstr($GLOBALS['HTTP_SERVER_VARS']['HTTP_USER_AGENT'], 'Mac')) { + $dpi_default = 72; + } else { + $dpi_default = 96; + } + + foreach($params as $_key => $_val) { + switch($_key) { + case 'file': + case 'border': + case 'height': + case 'width': + case 'dpi': + case 'basedir': + $$_key = $_val; + break; + + case 'alt': + if(!is_array($_val)) { + $$_key = smarty_function_escape_special_chars($_val); + } else { + $smarty->trigger_error("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + + case 'link': + case 'href': + $prefix = ''; + $suffix = ''; + break; + + default: + if(!is_array($_val)) { + $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; + } else { + $smarty->trigger_error("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + } + } + + if (empty($file)) { + $smarty->trigger_error("html_image: missing 'file' parameter", E_USER_NOTICE); + return; + } + + if (substr($file,0,1) == '/') { + $_image_path = $basedir . $file; + } else { + $_image_path = $file; + } + + if(!isset($params['width']) || !isset($params['height'])) { + if(!$_image_data = @getimagesize($_image_path)) { + if(!file_exists($_image_path)) { + $smarty->trigger_error("html_image: unable to find '$_image_path'", E_USER_NOTICE); + return; + } else if(!is_readable($_image_path)) { + $smarty->trigger_error("html_image: unable to read '$_image_path'", E_USER_NOTICE); + return; + } else { + $smarty->trigger_error("html_image: '$_image_path' is not a valid image file", E_USER_NOTICE); + return; + } + } + $_params = array('resource_type' => 'file', 'resource_name' => $_image_path); + require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.is_secure.php'); + if(!$smarty->security && !smarty_core_is_secure($_params, $smarty)) { + $smarty->trigger_error("html_image: (secure) '$_image_path' not in secure directory", E_USER_NOTICE); + return; + } + + if(!isset($params['width'])) { + $width = $_image_data[0]; + } + if(!isset($params['height'])) { + $height = $_image_data[1]; + } + + } + + if(isset($params['dpi'])) { + $_resize = $dpi_default/$params['dpi']; + $width = round($width * $_resize); + $height = round($height * $_resize); + } + + return $prefix . ''.$alt.'' . $suffix; +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/function.html_options.php b/smarty/plugins/function.html_options.php new file mode 100644 index 0000000..1b10653 --- /dev/null +++ b/smarty/plugins/function.html_options.php @@ -0,0 +1,118 @@ + + * Name: html_options
+ * Input:
+ * - name (optional) - string default "select" + * - values (required if no options supplied) - array + * - options (required if no values supplied) - associative array + * - selected (optional) - string default not set + * - output (required if not options supplied) - array + * Purpose: Prints the list of ' . "\n"; + foreach ($values as $key => $value) { + $optgroup_html .= smarty_function_html_options_optoutput($key, $value, $selected); + } + $optgroup_html .= "\n"; + return $optgroup_html; +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/function.html_radios.php b/smarty/plugins/function.html_radios.php new file mode 100644 index 0000000..b80e9bc --- /dev/null +++ b/smarty/plugins/function.html_radios.php @@ -0,0 +1,138 @@ + + * Type: function
+ * Name: html_radios
+ * Date: 24.Feb.2003
+ * Purpose: Prints out a list of radio input types
+ * Input:
+ * - name (optional) - string default "radio" + * - values (required) - array + * - options (optional) - associative array + * - checked (optional) - array default not set + * - separator (optional) - ie
or   + * - output (optional) - without this one the buttons don't have names + * Examples: + *
+ * {html_radios values=$ids output=$names}
+ * {html_radios values=$ids name='box' separator='
' output=$names} + * {html_radios values=$ids checked=$checked separator='
' output=$names} + *
+ * @link http://smarty.php.net/manual/en/language.function.html.radios.php {html_radios} + * (Smarty online manual) + * @author Christopher Kvarme + * @author credits to Monte Ohrt + * @version 1.0 + * @param array + * @param Smarty + * @return string + * @uses smarty_function_escape_special_chars() + */ +function smarty_function_html_radios($params, &$smarty) +{ + require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); + + $name = 'radio'; + $values = null; + $options = null; + $selected = null; + $separator = ''; + $labels = true; + $output = null; + $extra = ''; + + foreach($params as $_key => $_val) { + switch($_key) { + case 'name': + case 'separator': + $$_key = (string)$_val; + break; + + case 'checked': + case 'selected': + if(is_array($_val)) { + $smarty->trigger_error('html_radios: the "' . $_key . '" attribute cannot be an array', E_USER_WARNING); + } else { + $selected = (string)$_val; + } + break; + + case 'labels': + $$_key = (bool)$_val; + break; + + case 'options': + $$_key = (array)$_val; + break; + + case 'values': + case 'output': + $$_key = array_values((array)$_val); + break; + + case 'radios': + $smarty->trigger_error('html_radios: the use of the "radios" attribute is deprecated, use "options" instead', E_USER_WARNING); + $options = (array)$_val; + break; + + + default: + if(!is_array($_val)) { + $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; + } else { + $smarty->trigger_error("html_radios: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + } + } + + if (!isset($options) && !isset($values)) + return ''; /* raise error here? */ + + $_html_result = ''; + + if (isset($options) && is_array($options)) { + + foreach ((array)$options as $_key=>$_val) + $_html_result .= smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels); + + } else { + + foreach ((array)$values as $_i=>$_key) { + $_val = isset($output[$_i]) ? $output[$_i] : ''; + $_html_result .= smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels); + } + + } + + return $_html_result; + +} + +function smarty_function_html_radios_output($name, $value, $output, $selected, $extra, $separator, $labels) { + $_output = ''; + if ($labels) $_output .= ''; + $_output .= $separator . "\n"; + + return $_output; +} + +?> diff --git a/smarty/plugins/function.html_select_date.php b/smarty/plugins/function.html_select_date.php new file mode 100644 index 0000000..dd90e92 --- /dev/null +++ b/smarty/plugins/function.html_select_date.php @@ -0,0 +1,243 @@ + + * Name: html_select_date
+ * Purpose: Prints the dropdowns for date selection. + * + * ChangeLog:
+ * - 1.0 initial release + * - 1.1 added support for +/- N syntax for begin + * and end year values. (Monte) + * - 1.2 added support for yyyy-mm-dd syntax for + * time value. (Jan Rosier) + * - 1.3 added support for choosing format for + * month values (Gary Loescher) + * - 1.3.1 added support for choosing format for + * day values (Marcus Bointon) + * @link http://smarty.php.net/manual/en/language.function.html.select.date.php {html_select_date} + * (Smarty online manual) + * @version 1.3 + * @author Andrei Zmievski + * @param array + * @param Smarty + * @return string + */ +function smarty_function_html_select_date($params, &$smarty) +{ + require_once $smarty->_get_plugin_filepath('shared','make_timestamp'); + require_once $smarty->_get_plugin_filepath('function','html_options'); + /* Default values. */ + $prefix = "Date_"; + $start_year = strftime("%Y"); + $end_year = $start_year; + $display_days = true; + $display_months = true; + $display_years = true; + $month_format = "%B"; + /* Write months as numbers by default GL */ + $month_value_format = "%m"; + $day_format = "%02d"; + /* Write day values using this format MB */ + $day_value_format = "%d"; + $year_as_text = false; + /* Display years in reverse order? Ie. 2000,1999,.... */ + $reverse_years = false; + /* Should the select boxes be part of an array when returned from PHP? + e.g. setting it to "birthday", would create "birthday[Day]", + "birthday[Month]" & "birthday[Year]". Can be combined with prefix */ + $field_array = null; + /* tags. + If not set, uses default dropdown. */ + $day_size = null; + $month_size = null; + $year_size = null; + /* Unparsed attributes common to *ALL* the tags. + An example might be in the template: all_extra ='class ="foo"'. */ + $all_extra = null; + /* Separate attributes for the tags. */ + $day_extra = null; + $month_extra = null; + $year_extra = null; + /* Order in which to display the fields. + "D" -> day, "M" -> month, "Y" -> year. */ + $field_order = 'MDY'; + /* String printed between the different fields. */ + $field_separator = "\n"; + $time = time(); + + + extract($params); + + // If $time is not in format yyyy-mm-dd + if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $time)) { + // then $time is empty or unix timestamp or mysql timestamp + // using smarty_make_timestamp to get an unix timestamp and + // strftime to make yyyy-mm-dd + $time = strftime('%Y-%m-%d', smarty_make_timestamp($time)); + } + // Now split this in pieces, which later can be used to set the select + $time = explode("-", $time); + + // make syntax "+N" or "-N" work with start_year and end_year + if (preg_match('!^(\+|\-)\s*(\d+)$!', $end_year, $match)) { + if ($match[1] == '+') { + $end_year = strftime('%Y') + $match[2]; + } else { + $end_year = strftime('%Y') - $match[2]; + } + } + if (preg_match('!^(\+|\-)\s*(\d+)$!', $start_year, $match)) { + if ($match[1] == '+') { + $start_year = strftime('%Y') + $match[2]; + } else { + $start_year = strftime('%Y') - $match[2]; + } + } + + $field_order = strtoupper($field_order); + + $html_result = $month_result = $day_result = $year_result = ""; + + if ($display_months) { + $month_names = array(); + $month_values = array(); + + for ($i = 1; $i <= 12; $i++) { + $month_names[] = strftime($month_format, mktime(0, 0, 0, $i, 1, 2000)); + $month_values[] = strftime($month_value_format, mktime(0, 0, 0, $i, 1, 2000)); + } + + $month_result .= ''; + } + + if ($display_days) { + $days = array(); + for ($i = 1; $i <= 31; $i++) { + $days[] = sprintf($day_format, $i); + $day_values[] = sprintf($day_value_format, $i); + } + + $day_result .= ''; + } + + if ($display_years) { + if (null !== $field_array){ + $year_name = $field_array . '[' . $prefix . 'Year]'; + } else { + $year_name = $prefix . 'Year'; + } + if ($year_as_text) { + $year_result .= ' $years, + 'values' => $years, + 'selected' => $time[0], + 'print_result' => false), + $smarty); + $year_result .= ''; + } + } + + // Loop thru the field_order field + for ($i = 0; $i <= 2; $i++){ + $c = substr($field_order, $i, 1); + switch ($c){ + case 'D': + $html_result .= $day_result; + break; + + case 'M': + $html_result .= $month_result; + break; + + case 'Y': + $html_result .= $year_result; + break; + } + // Add the field seperator + if($i != 2) { + $html_result .= $field_separator; + } + } + + return $html_result; +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/function.html_select_time.php b/smarty/plugins/function.html_select_time.php new file mode 100644 index 0000000..969c13e --- /dev/null +++ b/smarty/plugins/function.html_select_time.php @@ -0,0 +1,163 @@ + + * Name: html_select_time
+ * Purpose: Prints the dropdowns for time selection + * @link http://smarty.php.net/manual/en/language.function.html.select.time.php {html_select_time} + * (Smarty online manual) + * @param array + * @param Smarty + * @return string + * @uses smarty_make_timestamp() + */ +function smarty_function_html_select_time($params, &$smarty) +{ + require_once $smarty->_get_plugin_filepath('shared','make_timestamp'); + require_once $smarty->_get_plugin_filepath('function','html_options'); + /* Default values. */ + $prefix = "Time_"; + $time = time(); + $display_hours = true; + $display_minutes = true; + $display_seconds = true; + $display_meridian = true; + $use_24_hours = true; + $minute_interval = 1; + $second_interval = 1; + /* Should the select boxes be part of an array when returned from PHP? + e.g. setting it to "birthday", would create "birthday[Hour]", + "birthday[Minute]", "birthday[Seconds]" & "birthday[Meridian]". + Can be combined with prefix. */ + $field_array = null; + $all_extra = null; + $hour_extra = null; + $minute_extra = null; + $second_extra = null; + $meridian_extra = null; + + extract($params); + + $time = smarty_make_timestamp($time); + + $html_result = ''; + + if ($display_hours) { + $hours = $use_24_hours ? range(0, 23) : range(1, 12); + $hour_fmt = $use_24_hours ? '%H' : '%I'; + for ($i = 0, $for_max = count($hours); $i < $for_max; $i++) + $hours[$i] = sprintf('%02d', $hours[$i]); + $html_result .= '\n"; + } + + if ($display_minutes) { + $all_minutes = range(0, 59); + for ($i = 0, $for_max = count($all_minutes); $i < $for_max; $i+= $minute_interval) + $minutes[] = sprintf('%02d', $all_minutes[$i]); + $selected = intval(floor(strftime('%M', $time) / $minute_interval) * $minute_interval); + $html_result .= '\n"; + } + + if ($display_seconds) { + $all_seconds = range(0, 59); + for ($i = 0, $for_max = count($all_seconds); $i < $for_max; $i+= $second_interval) + $seconds[] = sprintf('%02d', $all_seconds[$i]); + $selected = intval(floor(strftime('%S', $time) / $second_interval) * $second_interval); + $html_result .= '\n"; + } + + if ($display_meridian && !$use_24_hours) { + $html_result .= '\n"; + } + + return $html_result; +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/function.html_table.php b/smarty/plugins/function.html_table.php new file mode 100644 index 0000000..33be01a --- /dev/null +++ b/smarty/plugins/function.html_table.php @@ -0,0 +1,113 @@ + + * Name: html_table
+ * Date: Feb 17, 2003
+ * Purpose: make an html table from an array of data
+ * Input:
+ * - loop = array to loop through + * - cols = number of columns + * - rows = number of rows + * - table_attr = table attributes + * - tr_attr = table row attributes (arrays are cycled) + * - td_attr = table cell attributes (arrays are cycled) + * - trailpad = value to pad trailing cells with + * - vdir = vertical direction (default: "down", means top-to-bottom) + * - hdir = horizontal direction (default: "right", means left-to-right) + * - inner = inner loop (default "cols": print $loop line by line, + * $loop will be printed column by column otherwise) + * + * + * Examples: + *
+ * {table loop=$data}
+ * {table loop=$data cols=4 tr_attr='"bgcolor=red"'}
+ * {table loop=$data cols=4 tr_attr=$colors}
+ * 
+ * @author Monte Ohrt + * @version 1.0 + * @link http://smarty.php.net/manual/en/language.function.html.table.php {html_table} + * (Smarty online manual) + * @param array + * @param Smarty + * @return string + */ +function smarty_function_html_table($params, &$smarty) +{ + $table_attr = 'border="1"'; + $tr_attr = ''; + $td_attr = ''; + $cols = 3; + $rows = 3; + $trailpad = ' '; + $vdir = 'down'; + $hdir = 'right'; + $inner = 'cols'; + + extract($params); + + if (!isset($loop)) { + $smarty->trigger_error("html_table: missing 'loop' parameter"); + return; + } + + $loop_count = count($loop); + if (empty($params['rows'])) { + /* no rows specified */ + $rows = ceil($loop_count/$cols); + } elseif (empty($params['cols'])) { + if (!empty($params['rows'])) { + /* no cols specified, but rows */ + $cols = ceil($loop_count/$rows); + } + } + + $output = "\n"; + + for ($r=0; $r<$rows; $r++) { + $output .= "\n"; + $rx = ($vdir == 'down') ? $r*$cols : ($rows-1-$r)*$cols; + + for ($c=0; $c<$cols; $c++) { + $x = ($hdir == 'right') ? $rx+$c : $rx+$cols-1-$c; + if ($inner!='cols') { + /* shuffle x to loop over rows*/ + $x = floor($x/$cols) + ($x%$cols)*$rows; + } + + if ($x<$loop_count) { + $output .= "" . $loop[$x] . "\n"; + } else { + $output .= "$trailpad\n"; + } + } + $output .= "\n"; + } + $output .= "
\n"; + + return $output; +} + +function smarty_function_html_table_cycle($name, $var, $no) { + if(!is_array($var)) { + $ret = $var; + } else { + $ret = $var[$no % count($var)]; + } + + return ($ret) ? ' '.$ret : ''; +} + + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/function.mailto.php b/smarty/plugins/function.mailto.php new file mode 100644 index 0000000..f6e3de0 --- /dev/null +++ b/smarty/plugins/function.mailto.php @@ -0,0 +1,140 @@ + + * Name: mailto
+ * Date: May 21, 2002 + * Purpose: automate mailto address link creation, and optionally + * encode them.
+ * Input:
+ * - address = e-mail address + * - text = (optional) text to display, default is address + * - encode = (optional) can be one of: + * * none : no encoding (default) + * * javascript : encode with javascript + * * hex : encode with hexidecimal (no javascript) + * - cc = (optional) address(es) to carbon copy + * - bcc = (optional) address(es) to blind carbon copy + * - subject = (optional) e-mail subject + * - newsgroups = (optional) newsgroup(s) to post to + * - followupto = (optional) address(es) to follow up to + * - extra = (optional) extra tags for the href link + * + * Examples: + *
+ * {mailto address="me@domain.com"}
+ * {mailto address="me@domain.com" encode="javascript"}
+ * {mailto address="me@domain.com" encode="hex"}
+ * {mailto address="me@domain.com" subject="Hello to you!"}
+ * {mailto address="me@domain.com" cc="you@domain.com,they@domain.com"}
+ * {mailto address="me@domain.com" extra='class="mailto"'}
+ * 
+ * @link http://smarty.php.net/manual/en/language.function.mailto.php {mailto} + * (Smarty online manual) + * @version 1.2 + * @author Monte Ohrt + * @author credits to Jason Sweat (added cc, bcc and subject functionality) + * @param array + * @param Smarty + * @return string + */ +function smarty_function_mailto($params, &$smarty) +{ + $extra = ''; + extract($params); + + if (empty($address)) { + $smarty->trigger_error("mailto: missing 'address' parameter"); + return; + } + + if (empty($text)) { + $text = $address; + } + + // netscape and mozilla do not decode %40 (@) in BCC field (bug?) + // so, don't encode it. + + $mail_parms = array(); + if (!empty($cc)) { + $mail_parms[] = 'cc='.str_replace('%40','@',rawurlencode($cc)); + } + + if (!empty($bcc)) { + $mail_parms[] = 'bcc='.str_replace('%40','@',rawurlencode($bcc)); + } + + if (!empty($subject)) { + $mail_parms[] = 'subject='.rawurlencode($subject); + } + + if (!empty($newsgroups)) { + $mail_parms[] = 'newsgroups='.rawurlencode($newsgroups); + } + + if (!empty($followupto)) { + $mail_parms[] = 'followupto='.str_replace('%40','@',rawurlencode($followupto)); + } + + $mail_parm_vals = ''; + for ($i=0; $itrigger_error("mailto: 'encode' parameter must be none, javascript or hex"); + return; + } + + if ($encode == 'javascript' ) { + $string = 'document.write(\''.$text.'\');'; + + for ($x=0; $x < strlen($string); $x++) { + $js_encode .= '%' . bin2hex($string[$x]); + } + + return ''; + + } elseif ($encode == 'hex') { + + preg_match('!^(.*)(\?.*)$!',$address,$match); + if(!empty($match[2])) { + $smarty->trigger_error("mailto: hex encoding does not work with extra attributes. Try javascript."); + return; + } + for ($x=0; $x < strlen($address); $x++) { + if(preg_match('!\w!',$address[$x])) { + $address_encode .= '%' . bin2hex($address[$x]); + } else { + $address_encode .= $address[$x]; + } + } + for ($x=0; $x < strlen($text); $x++) { + $text_encode .= '&#x' . bin2hex($text[$x]).';'; + } + + return ''.$text_encode.''; + + } else { + // no encoding + return ''.$text.''; + + } + +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/function.math.php b/smarty/plugins/function.math.php new file mode 100644 index 0000000..c080d4d --- /dev/null +++ b/smarty/plugins/function.math.php @@ -0,0 +1,82 @@ + + * Name: math
+ * Purpose: handle math computations in template
+ * @link http://smarty.php.net/manual/en/language.function.math.php {math} + * (Smarty online manual) + * @param array + * @param Smarty + * @return string + */ +function smarty_function_math($params, &$smarty) +{ + // be sure equation parameter is present + if (empty($params['equation'])) { + $smarty->trigger_error("math: missing equation parameter"); + return; + } + + $equation = $params['equation']; + + // make sure parenthesis are balanced + if (substr_count($equation,"(") != substr_count($equation,")")) { + $smarty->trigger_error("math: unbalanced parenthesis"); + return; + } + + // match all vars in equation, make sure all are passed + preg_match_all("!\!(0x)([a-zA-Z][a-zA-Z0-9_]*)!",$equation, $match); + $allowed_funcs = array('int','abs','ceil','cos','exp','floor','log','log10', + 'max','min','pi','pow','rand','round','sin','sqrt','srand','tan'); + foreach($match[2] as $curr_var) { + if (!in_array($curr_var,array_keys($params)) && !in_array($curr_var, $allowed_funcs)) { + $smarty->trigger_error("math: parameter $curr_var not passed as argument"); + return; + } + } + + foreach($params as $key => $val) { + if ($key != "equation" && $key != "format" && $key != "assign") { + // make sure value is not empty + if (strlen($val)==0) { + $smarty->trigger_error("math: parameter $key is empty"); + return; + } + if (!is_numeric($val)) { + $smarty->trigger_error("math: parameter $key: is not numeric"); + return; + } + $equation = preg_replace("/\b$key\b/",$val, $equation); + } + } + + eval("\$smarty_math_result = ".$equation.";"); + + if (empty($params['format'])) { + if (empty($params['assign'])) { + return $smarty_math_result; + } else { + $smarty->assign($params['assign'],$smarty_math_result); + } + } else { + if (empty($params['assign'])){ + printf($params['format'],$smarty_math_result); + } else { + $smarty->assign($params['assign'],sprintf($params['format'],$smarty_math_result)); + } + } +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/function.popup.php b/smarty/plugins/function.popup.php new file mode 100644 index 0000000..d1030a7 --- /dev/null +++ b/smarty/plugins/function.popup.php @@ -0,0 +1,87 @@ + + * Name: popup
+ * Purpose: make text pop up in windows via overlib + * @link http://smarty.php.net/manual/en/language.function.popup.php {popup} + * (Smarty online manual) + * @param array + * @param Smarty + * @return string + */ +function smarty_function_popup($params, &$smarty) +{ + extract($params); + + if (empty($text) && !isset($inarray) && empty($function)) { + $smarty->trigger_error("overlib: attribute 'text' or 'inarray' or 'function' required"); + return false; + } + + if (empty($trigger)) { $trigger = "onmouseover"; } + + $retval = $trigger . '="return overlib(\''.preg_replace(array("!'!","![\r\n]!"),array("\'",'\r'),$text).'\''; + if ($sticky) { $retval .= ",STICKY"; } + if (!empty($caption)) { $retval .= ",CAPTION,'".str_replace("'","\'",$caption)."'"; } + if (!empty($fgcolor)) { $retval .= ",FGCOLOR,'$fgcolor'"; } + if (!empty($bgcolor)) { $retval .= ",BGCOLOR,'$bgcolor'"; } + if (!empty($textcolor)) { $retval .= ",TEXTCOLOR,'$textcolor'"; } + if (!empty($capcolor)) { $retval .= ",CAPCOLOR,'$capcolor'"; } + if (!empty($closecolor)) { $retval .= ",CLOSECOLOR,'$closecolor'"; } + if (!empty($textfont)) { $retval .= ",TEXTFONT,'$textfont'"; } + if (!empty($captionfont)) { $retval .= ",CAPTIONFONT,'$captionfont'"; } + if (!empty($closefont)) { $retval .= ",CLOSEFONT,'$closefont'"; } + if (!empty($textsize)) { $retval .= ",TEXTSIZE,$textsize"; } + if (!empty($captionsize)) { $retval .= ",CAPTIONSIZE,$captionsize"; } + if (!empty($closesize)) { $retval .= ",CLOSESIZE,$closesize"; } + if (!empty($width)) { $retval .= ",WIDTH,$width"; } + if (!empty($height)) { $retval .= ",HEIGHT,$height"; } + if (!empty($left)) { $retval .= ",LEFT"; } + if (!empty($right)) { $retval .= ",RIGHT"; } + if (!empty($center)) { $retval .= ",CENTER"; } + if (!empty($above)) { $retval .= ",ABOVE"; } + if (!empty($below)) { $retval .= ",BELOW"; } + if (isset($border)) { $retval .= ",BORDER,$border"; } + if (isset($offsetx)) { $retval .= ",OFFSETX,$offsetx"; } + if (isset($offsety)) { $retval .= ",OFFSETY,$offsety"; } + if (!empty($fgbackground)) { $retval .= ",FGBACKGROUND,'$fgbackground'"; } + if (!empty($bgbackground)) { $retval .= ",BGBACKGROUND,'$bgbackground'"; } + if (!empty($closetext)) { $retval .= ",CLOSETEXT,'".str_replace("'","\'",$closetext)."'"; } + if (!empty($noclose)) { $retval .= ",NOCLOSE"; } + if (!empty($status)) { $retval .= ",STATUS,'".str_replace("'","\'",$status)."'"; } + if (!empty($autostatus)) { $retval .= ",AUTOSTATUS"; } + if (!empty($autostatuscap)) { $retval .= ",AUTOSTATUSCAP"; } + if (isset($inarray)) { $retval .= ",INARRAY,'$inarray'"; } + if (isset($caparray)) { $retval .= ",CAPARRAY,'$caparray'"; } + if (!empty($capicon)) { $retval .= ",CAPICON,'$capicon'"; } + if (!empty($snapx)) { $retval .= ",SNAPX,$snapx"; } + if (!empty($snapy)) { $retval .= ",SNAPY,$snapy"; } + if (isset($fixx)) { $retval .= ",FIXX,$fixx"; } + if (isset($fixy)) { $retval .= ",FIXY,$fixy"; } + if (!empty($background)) { $retval .= ",BACKGROUND,'$background'"; } + if (!empty($padx)) { $retval .= ",PADX,$padx"; } + if (!empty($pady)) { $retval .= ",PADY,$pady"; } + if (!empty($fullhtml)) { $retval .= ",FULLHTML"; } + if (!empty($frame)) { $retval .= ",FRAME,'$frame'"; } + if (isset($timeout)) { $retval .= ",TIMEOUT,$timeout"; } + if (!empty($function)) { $retval .= ",FUNCTION,'$function'"; } + if (isset($delay)) { $retval .= ",DELAY,$delay"; } + if (!empty($hauto)) { $retval .= ",HAUTO"; } + if (!empty($vauto)) { $retval .= ",VAUTO"; } + $retval .= ');" onmouseout="nd();"'; + + return $retval; +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/function.popup_init.php b/smarty/plugins/function.popup_init.php new file mode 100644 index 0000000..d9b42bd --- /dev/null +++ b/smarty/plugins/function.popup_init.php @@ -0,0 +1,39 @@ + + * Name: popup_init
+ * Purpose: initialize overlib + * @link http://smarty.php.net/manual/en/language.function.popup.init.php {popup_init} + * (Smarty online manual) + * @param array + * @param Smarty + * @return string + */ +function smarty_function_popup_init($params, &$smarty) +{ + $zindex = 1000; + + if (!empty($params['zindex'])) { + $zindex = $params['zindex']; + } + + if (!empty($params['src'])) { + return '' . "\n" + . '' . "\n"; + } else { + $smarty->trigger_error("popup_init: missing src parameter"); + } +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/modifier.capitalize.php b/smarty/plugins/modifier.capitalize.php new file mode 100644 index 0000000..41d63ed --- /dev/null +++ b/smarty/plugins/modifier.capitalize.php @@ -0,0 +1,25 @@ + + * Name: capitalize
+ * Purpose: capitalize words in the string + * @link http://smarty.php.net/manual/en/language.modifiers.php#LANGUAGE.MODIFIER.CAPITALIZE + * capitalize (Smarty online manual) + * @param string + * @return string + */ +function smarty_modifier_capitalize($string) +{ + return ucwords($string); +} + +?> diff --git a/smarty/plugins/modifier.cat.php b/smarty/plugins/modifier.cat.php new file mode 100644 index 0000000..8dc7324 --- /dev/null +++ b/smarty/plugins/modifier.cat.php @@ -0,0 +1,33 @@ + + * Name: cat
+ * Date: Feb 24, 2003 + * Purpose: catenate a value to a variable + * Input: string to catenate + * Example: {$var|cat:"foo"} + * @link http://smarty.php.net/manual/en/language.modifier.cat.php cat + * (Smarty online manual) + * @author Monte Ohrt + * @version 1.0 + * @param string + * @param string + * @return string + */ +function smarty_modifier_cat($string, $cat) +{ + return $string . $cat; +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/modifier.count_characters.php b/smarty/plugins/modifier.count_characters.php new file mode 100644 index 0000000..49ce655 --- /dev/null +++ b/smarty/plugins/modifier.count_characters.php @@ -0,0 +1,31 @@ + + * Name: count_characteres
+ * Purpose: count the number of characters in a text + * @link http://smarty.php.net/manual/en/language.modifier.count.characters.php + * count_characters (Smarty online manual) + * @param string + * @param boolean include whitespace in the character count + * @return integer + */ +function smarty_modifier_count_characters($string, $include_spaces = false) +{ + if ($include_spaces) + return(strlen($string)); + + return preg_match_all("/[^\s]/",$string, $match); +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/modifier.count_paragraphs.php b/smarty/plugins/modifier.count_paragraphs.php new file mode 100644 index 0000000..6a9833c --- /dev/null +++ b/smarty/plugins/modifier.count_paragraphs.php @@ -0,0 +1,28 @@ + + * Name: count_paragraphs
+ * Purpose: count the number of paragraphs in a text + * @link http://smarty.php.net/manual/en/language.modifier.count.paragraphs.php + * count_paragraphs (Smarty online manual) + * @param string + * @return integer + */ +function smarty_modifier_count_paragraphs($string) +{ + // count \r or \n characters + return count(preg_split('/[\r\n]+/', $string)); +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/modifier.count_sentences.php b/smarty/plugins/modifier.count_sentences.php new file mode 100644 index 0000000..0c210f0 --- /dev/null +++ b/smarty/plugins/modifier.count_sentences.php @@ -0,0 +1,28 @@ + + * Name: count_sentences + * Purpose: count the number of sentences in a text + * @link http://smarty.php.net/manual/en/language.modifier.count.paragraphs.php + * count_sentences (Smarty online manual) + * @param string + * @return integer + */ +function smarty_modifier_count_sentences($string) +{ + // find periods with a word before but not after. + return preg_match_all('/[^\s]\.(?!\w)/', $string, $match); +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/modifier.count_words.php b/smarty/plugins/modifier.count_words.php new file mode 100644 index 0000000..42c8a74 --- /dev/null +++ b/smarty/plugins/modifier.count_words.php @@ -0,0 +1,32 @@ + + * Name: count_words
+ * Purpose: count the number of words in a text + * @link http://smarty.php.net/manual/en/language.modifier.count.words.php + * count_words (Smarty online manual) + * @param string + * @return integer + */ +function smarty_modifier_count_words($string) +{ + // split text by ' ',\r,\n,\f,\t + $split_array = preg_split('/\s+/',$string); + // count matches that contain alphanumerics + $word_count = preg_grep('/[a-zA-Z0-9\\x80-\\xff]/', $split_array); + + return count($word_count); +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/modifier.date_format.php b/smarty/plugins/modifier.date_format.php new file mode 100644 index 0000000..dbe26a5 --- /dev/null +++ b/smarty/plugins/modifier.date_format.php @@ -0,0 +1,43 @@ +_get_plugin_filepath('shared','make_timestamp'); +/** + * Smarty date_format modifier plugin + * + * Type: modifier
+ * Name: date_format
+ * Purpose: format datestamps via strftime
+ * Input:
+ * - string: input date string + * - format: strftime format for output + * - default_date: default date if $string is empty + * @link http://smarty.php.net/manual/en/language.modifier.date.format.php + * date_format (Smarty online manual) + * @param string + * @param string + * @param string + * @return string|void + * @uses smarty_make_timestamp() + */ +function smarty_modifier_date_format($string, $format="%b %e, %Y", $default_date=null) +{ + if($string != '') { + return strftime($format, smarty_make_timestamp($string)); + } elseif (isset($default_date) && $default_date != '') { + return strftime($format, smarty_make_timestamp($default_date)); + } else { + return; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/modifier.debug_print_var.php b/smarty/plugins/modifier.debug_print_var.php new file mode 100644 index 0000000..3528311 --- /dev/null +++ b/smarty/plugins/modifier.debug_print_var.php @@ -0,0 +1,57 @@ + + * Name: debug_print_var
+ * Purpose: formats variable contents for display in the console + * @link http://smarty.php.net/manual/en/language.modifier.debug.print.var.php + * debug_print_var (Smarty online manual) + * @param array|object + * @param integer + * @param integer + * @return string + */ +function smarty_modifier_debug_print_var($var, $depth = 0, $length = 40) +{ + $_replace = array("\n"=>'\n', "\r"=>'\r', "\t"=>'\t'); + if (is_array($var)) { + $results = "Array (".count($var).")"; + foreach ($var as $curr_key => $curr_val) { + $return = smarty_modifier_debug_print_var($curr_val, $depth+1, $length); + $results .= "
".str_repeat(' ', $depth*2)."".strtr($curr_key, $_replace)." => $return"; + } + return $results; + } else if (is_object($var)) { + $object_vars = get_object_vars($var); + $results = "".get_class($var)." Object (".count($object_vars).")"; + foreach ($object_vars as $curr_key => $curr_val) { + $return = smarty_modifier_debug_print_var($curr_val, $depth+1, $length); + $results .= "
".str_repeat(' ', $depth*2)."$curr_key => $return"; + } + return $results; + } else { + if (empty($var) && $var != "0") { + return 'empty'; + } + if (strlen($var) > $length ) { + $results = substr($var, 0, $length-3).'...'; + } else { + $results = $var; + } + $results = htmlspecialchars($results); + $results = strtr($results, $_replace); + return $results; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/modifier.default.php b/smarty/plugins/modifier.default.php new file mode 100644 index 0000000..8268e39 --- /dev/null +++ b/smarty/plugins/modifier.default.php @@ -0,0 +1,31 @@ + + * Name: default
+ * Purpose: designate default value for empty variables + * @link http://smarty.php.net/manual/en/language.modifier.default.php + * default (Smarty online manual) + * @param string + * @param string + * @return string + */ +function smarty_modifier_default($string, $default = '') +{ + if (!isset($string) || $string === '') + return $default; + else + return $string; +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/modifier.escape.php b/smarty/plugins/modifier.escape.php new file mode 100644 index 0000000..dc7bae2 --- /dev/null +++ b/smarty/plugins/modifier.escape.php @@ -0,0 +1,84 @@ + + * Name: escape
+ * Purpose: Escape the string according to escapement type + * @link http://smarty.php.net/manual/en/language.modifier.escape.php + * escape (Smarty online manual) + * @param string + * @param html|htmlall|url|quotes|hex|hexentity|javascript + * @return string + */ +function smarty_modifier_escape($string, $esc_type = 'html') +{ + switch ($esc_type) { + case 'html': + return htmlspecialchars($string, ENT_QUOTES); + + case 'htmlall': + return htmlentities($string, ENT_QUOTES); + + case 'url': + return urlencode($string); + + case 'quotes': + // escape unescaped single quotes + return preg_replace("%(?'\\\\',"'"=>"\\'",'"'=>'\\"',"\r"=>'\\r',"\n"=>'\\n')); + + default: + return $string; + } +} + +function smarty_modifier_escape_qp_enc( $input = "") { + $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'); + $escape = "="; + $linlen = strlen($input); + $newline = ''; + for($i = 0; $i < $linlen; $i++) { + $c = substr( $input, $i, 1 ); + $dec = ord( $c ); + if( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ){ + $h2 = floor($dec/16); + $h1 = floor($dec%16); + $c = $escape.$hex["$h2"].$hex["$h1"]; + } + $newline .= $c; + } + return $newline; +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/modifier.indent.php b/smarty/plugins/modifier.indent.php new file mode 100644 index 0000000..552c3e1 --- /dev/null +++ b/smarty/plugins/modifier.indent.php @@ -0,0 +1,27 @@ + + * Name: indent
+ * Purpose: indent lines of text + * @link http://smarty.php.net/manual/en/language.modifier.indent.php + * indent (Smarty online manual) + * @param string + * @param integer + * @param string + * @return string + */ +function smarty_modifier_indent($string,$chars=4,$char=" ") +{ + return preg_replace('!^!m',str_repeat($char,$chars),$string); +} + +?> diff --git a/smarty/plugins/modifier.lower.php b/smarty/plugins/modifier.lower.php new file mode 100644 index 0000000..ee37423 --- /dev/null +++ b/smarty/plugins/modifier.lower.php @@ -0,0 +1,25 @@ + + * Name: lower
+ * Purpose: convert string to lowercase + * @link http://smarty.php.net/manual/en/language.modifier.lower.php + * lower (Smarty online manual) + * @param string + * @return string + */ +function smarty_modifier_lower($string) +{ + return strtolower($string); +} + +?> diff --git a/smarty/plugins/modifier.nl2br.php b/smarty/plugins/modifier.nl2br.php new file mode 100644 index 0000000..5a9b744 --- /dev/null +++ b/smarty/plugins/modifier.nl2br.php @@ -0,0 +1,35 @@ + + * Name: nl2br
+ * Date: Feb 26, 2003 + * Purpose: convert \r\n, \r or \n to <
> + * Input:
+ * - contents = contents to replace + * - preceed_test = if true, includes preceeding break tags + * in replacement + * Example: {$text|nl2br} + * @link http://smarty.php.net/manual/en/language.modifier.nl2br.php + * nl2br (Smarty online manual) + * @version 1.0 + * @author Monte Ohrt + * @param string + * @return string + */ +function smarty_modifier_nl2br($string) +{ + return nl2br($string); +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/modifier.regex_replace.php b/smarty/plugins/modifier.regex_replace.php new file mode 100644 index 0000000..b9cc865 --- /dev/null +++ b/smarty/plugins/modifier.regex_replace.php @@ -0,0 +1,29 @@ + + * Name: regex_replace
+ * Purpose: regular epxression search/replace + * @link http://smarty.php.net/manual/en/language.modifier.regex.replace.php + * regex_replace (Smarty online manual) + * @param string + * @param string|array + * @param string|array + * @return string + */ +function smarty_modifier_regex_replace($string, $search, $replace) +{ + return preg_replace($search, $replace, $string); +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/modifier.replace.php b/smarty/plugins/modifier.replace.php new file mode 100644 index 0000000..2a43515 --- /dev/null +++ b/smarty/plugins/modifier.replace.php @@ -0,0 +1,29 @@ + + * Name: replace
+ * Purpose: simple search/replace + * @link http://smarty.php.net/manual/en/language.modifier.replace.php + * replace (Smarty online manual) + * @param string + * @param string + * @param string + * @return string + */ +function smarty_modifier_replace($string, $search, $replace) +{ + return str_replace($search, $replace, $string); +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/modifier.spacify.php b/smarty/plugins/modifier.spacify.php new file mode 100644 index 0000000..dad057f --- /dev/null +++ b/smarty/plugins/modifier.spacify.php @@ -0,0 +1,29 @@ + + * Name: spacify
+ * Purpose: add spaces between characters in a string + * @link http://smarty.php.net/manual/en/language.modifier.spacify.php + * spacify (Smarty online manual) + * @param string + * @param string + * @return string + */ +function smarty_modifier_spacify($string, $spacify_char = ' ') +{ + return implode($spacify_char, + preg_split('//', $string, -1, PREG_SPLIT_NO_EMPTY)); +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/modifier.string_format.php b/smarty/plugins/modifier.string_format.php new file mode 100644 index 0000000..efd6215 --- /dev/null +++ b/smarty/plugins/modifier.string_format.php @@ -0,0 +1,28 @@ + + * Name: string_format
+ * Purpose: format strings via sprintf + * @link http://smarty.php.net/manual/en/language.modifier.string.format.php + * string_format (Smarty online manual) + * @param string + * @param string + * @return string + */ +function smarty_modifier_string_format($string, $format) +{ + return sprintf($format, $string); +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/modifier.strip.php b/smarty/plugins/modifier.strip.php new file mode 100644 index 0000000..0db2f8a --- /dev/null +++ b/smarty/plugins/modifier.strip.php @@ -0,0 +1,33 @@ + + * Name: strip
+ * Purpose: Replace all repeated spaces, newlines, tabs + * with a single space or supplied replacement string.
+ * Example: {$var|strip} {$var|strip:" "} + * Date: September 25th, 2002 + * @link http://smarty.php.net/manual/en/language.modifier.strip.php + * strip (Smarty online manual) + * @author Monte Ohrt + * @version 1.0 + * @param string + * @param string + * @return string + */ +function smarty_modifier_strip($text, $replace = ' ') +{ + return preg_replace('!\s+!', $replace, $text); +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/modifier.strip_tags.php b/smarty/plugins/modifier.strip_tags.php new file mode 100644 index 0000000..45f1ec1 --- /dev/null +++ b/smarty/plugins/modifier.strip_tags.php @@ -0,0 +1,31 @@ + + * Name: strip_tags
+ * Purpose: strip html tags from text + * @link http://smarty.php.net/manual/en/language.modifier.strip.tags.php + * strip_tags (Smarty online manual) + * @param string + * @param boolean + * @return string + */ +function smarty_modifier_strip_tags($string, $replace_with_space = true) +{ + if ($replace_with_space) + return preg_replace('!<[^>]*?>!', ' ', $string); + else + return strip_tags($string); +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/modifier.truncate.php b/smarty/plugins/modifier.truncate.php new file mode 100644 index 0000000..c82b14a --- /dev/null +++ b/smarty/plugins/modifier.truncate.php @@ -0,0 +1,43 @@ + + * Name: truncate
+ * Purpose: Truncate a string to a certain length if necessary, + * optionally splitting in the middle of a word, and + * appending the $etc string. + * @link http://smarty.php.net/manual/en/language.modifier.truncate.php + * truncate (Smarty online manual) + * @param string + * @param integer + * @param string + * @param boolean + * @return string + */ +function smarty_modifier_truncate($string, $length = 80, $etc = '...', + $break_words = false) +{ + if ($length == 0) + return ''; + + if (strlen($string) > $length) { + $length -= strlen($etc); + if (!$break_words) + $string = preg_replace('/\s+?(\S+)?$/', '', substr($string, 0, $length+1)); + + return substr($string, 0, $length).$etc; + } else + return $string; +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/modifier.upper.php b/smarty/plugins/modifier.upper.php new file mode 100644 index 0000000..9d9ef35 --- /dev/null +++ b/smarty/plugins/modifier.upper.php @@ -0,0 +1,25 @@ + + * Name: upper
+ * Purpose: convert string to uppercase + * @link http://smarty.php.net/manual/en/language.modifier.upper.php + * upper (Smarty online manual) + * @param string + * @return string + */ +function smarty_modifier_upper($string) +{ + return strtoupper($string); +} + +?> diff --git a/smarty/plugins/modifier.wordwrap.php b/smarty/plugins/modifier.wordwrap.php new file mode 100644 index 0000000..55b4a1d --- /dev/null +++ b/smarty/plugins/modifier.wordwrap.php @@ -0,0 +1,28 @@ + + * Name: wordwrap
+ * Purpose: wrap a string of text at a given length + * @link http://smarty.php.net/manual/en/language.modifier.wordwrap.php + * wordwrap (Smarty online manual) + * @param string + * @param integer + * @param string + * @param boolean + * @return string + */ +function smarty_modifier_wordwrap($string,$length=80,$break="\n",$cut=false) +{ + return wordwrap($string,$length,$break,$cut); +} + +?> diff --git a/smarty/plugins/outputfilter.trimwhitespace.php b/smarty/plugins/outputfilter.trimwhitespace.php new file mode 100644 index 0000000..e82acc1 --- /dev/null +++ b/smarty/plugins/outputfilter.trimwhitespace.php @@ -0,0 +1,75 @@ + + * Type: outputfilter
+ * Name: trimwhitespace
+ * Date: Jan 25, 2003
+ * Purpose: trim leading white space and blank lines from + * template source after it gets interpreted, cleaning + * up code and saving bandwidth. Does not affect + * <
>
and blocks.
+ * Install: Drop into the plugin directory, call + * $smarty->load_filter('output','trimwhitespace'); + * from application. + * @author Monte Ohrt + * @author Contributions from Lars Noschinski + * @version 1.3 + * @param string + * @param Smarty + */ + function smarty_outputfilter_trimwhitespace($source, &$smarty) + { + // Pull out the script blocks + preg_match_all("!]+>.*?!is", $source, $match); + $_script_blocks = $match[0]; + $source = preg_replace("!]+>.*?!is", + '@@@SMARTY:TRIM:SCRIPT@@@', $source); + + // Pull out the pre blocks + preg_match_all("!
.*?
!is", $source, $match); + $_pre_blocks = $match[0]; + $source = preg_replace("!
.*?
!is", + '@@@SMARTY:TRIM:PRE@@@', $source); + + // Pull out the textarea blocks + preg_match_all("!]+>.*?!is", $source, $match); + $_textarea_blocks = $match[0]; + $source = preg_replace("!]+>.*?!is", + '@@@SMARTY:TRIM:TEXTAREA@@@', $source); + + // remove all leading spaces, tabs and carriage returns NOT + // preceeded by a php close tag. + $source = trim(preg_replace('/((?)\n)[\s]+/m', '\1', $source)); + + // replace script blocks + smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:SCRIPT@@@",$_script_blocks, $source); + + // replace pre blocks + smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:PRE@@@",$_pre_blocks, $source); + + // replace textarea blocks + smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:TEXTAREA@@@",$_textarea_blocks, $source); + + return $source; + } + +function smarty_outputfilter_trimwhitespace_replace($search_str, $replace, &$subject) { + $_len = strlen($search_str); + $_pos = 0; + for ($_i=0, $_count=count($replace); $_i<$_count; $_i++) + if (($_pos=strpos($subject, $search_str, $_pos))!==false) + $subject = substr_replace($subject, $replace[$_i], $_pos, $_len); + else + break; + +} + +?> diff --git a/smarty/plugins/shared.escape_special_chars.php b/smarty/plugins/shared.escape_special_chars.php new file mode 100644 index 0000000..090ee9c --- /dev/null +++ b/smarty/plugins/shared.escape_special_chars.php @@ -0,0 +1,30 @@ + + * Purpose: used by other smarty functions to escape + * special chars except for already escaped ones + * @param string + * @return string + */ +function smarty_function_escape_special_chars($string) +{ + if(!is_array($string)) { + $string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string); + $string = htmlspecialchars($string); + $string = str_replace(array('%%%SMARTY_START%%%','%%%SMARTY_END%%%'), array('&',';'), $string); + } + return $string; +} + +/* vim: set expandtab: */ + +?> diff --git a/smarty/plugins/shared.make_timestamp.php b/smarty/plugins/shared.make_timestamp.php new file mode 100644 index 0000000..acdd777 --- /dev/null +++ b/smarty/plugins/shared.make_timestamp.php @@ -0,0 +1,43 @@ + + * Purpose: used by other smarty functions to make a timestamp + * from a string. + * @param string + * @return string + */ +function smarty_make_timestamp($string) +{ + if(empty($string)) { + $string = "now"; + } + $time = strtotime($string); + if (is_numeric($time) && $time != -1) + return $time; + + // is mysql timestamp format of YYYYMMDDHHMMSS? + if (preg_match('/^\d{14}$/', $string)) { + $time = mktime(substr($string,8,2),substr($string,10,2),substr($string,12,2), + substr($string,4,2),substr($string,6,2),substr($string,0,4)); + + return $time; + } + + // couldn't recognize it, try to return a time + $time = (int) $string; + if ($time > 0) + return $time; + else + return time(); +} + +/* vim: set expandtab: */ + +?> diff --git a/template.php b/template.php new file mode 100644 index 0000000..7448a24 --- /dev/null +++ b/template.php @@ -0,0 +1,163 @@ +assign('user',$_SESSION[ldapab][username]); + $smarty->assign('binddn',$_SESSION[ldapab][binddn]); + if(!empty($_SESSION[ldapab][lastlocation])){ + $smarty->assign('home',$_SESSION[ldapab][lastlocation]); + }else{ + $smarty->assign('home','index.php'); + } + $smarty->assign('conf',$conf); + $smarty->assign('lang',$lang); + $smarty->assign('dfexample',$dfexample); +} + +/** + * assigns all the interesting data from an ldap result to + * the smarty template + */ +function tpl_entry($in){ + global $smarty; + global $conf; + $entries = namedentries(); + + + //handle named entries + foreach(array_keys($entries) as $key){ + if($in[$key]){ + if(is_array($in[$key])){ + $out[$entries[$key]] = $in[$key][0]; + }else{ + $out[$entries[$key]] = $in[$key]; + } + } + } + + //set the type + $out['dn'] = normalize_dn($out['dn']); + $conf[publicbook] = normalize_dn($conf[publicbook]); + if($out['dn']){ + if(strstr($out['dn'],$conf[publicbook])){ + $out[type] = 'public'; + }else{ + $out[type] = 'private'; + } + } + + //mail entries are handled special + $out['mail'] = $in['mail']; + if ($conf[extended]){ + //handle marker special in extended mode + $out['marker'] = $in['marker']; + } + + //decode array + utf8_decode_array($out); + +/*print '
';
+print_r($out);
+print '
';*/ + + $smarty->assign('entry',$out); +} + +/** + * assigns the last LDAP error to the template + */ +function tpl_ldaperror($message=""){ + global $LDAP_CON; + global $__LDAPERROR__; + global $smarty; + $errno = ldap_errno($LDAP_CON); + if($errno){ + $__LDAPERROR__ .= ldap_err2str($errno); + if(!empty($message)){ + $__LDAPERROR__ .= "($message)"; + } + $__LDAPERROR__ .= '\n'; + } + $smarty->assign("LDAPERRORS",$__LDAPERROR__); +} + +/** + * assigns all markers to the template + */ +function tpl_markers(){ + global $conf; + global $LDAP_CON; + global $smarty; + + if(!$conf[extended]) return; + + $markers = array(); + + $sr = ldap_list($LDAP_CON,$conf[publicbook],"ObjectClass=inetOrgPerson",array("marker")); + $result1 = ldap_get_binentries($LDAP_CON, $sr); + //check users private addressbook + if(!empty($_SESSION[ldapab][binddn])){ + $sr = @ldap_list($LDAP_CON, + $conf[privatebook].','.$_SESSION[ldapab][binddn], + "ObjectClass=inetOrgPerson",array("marker")); + $result2 = ldap_get_binentries($LDAP_CON, $sr); + } + $result = array_merge($result1,$result2); + + if(count($result)){ + foreach ($result as $entry){ + if(count($entry['marker'])){ + foreach($entry['marker'] as $marker){ + array_push($markers, $marker); + } + } + } + } + $markers = array_unique($markers); + sort($markers,SORT_STRING); + + utf8_decode_array($markers); + $smarty->assign('markers',$markers); +} + +/** + * Assigns all distinct organization names to the template + */ +function tpl_orgs(){ + global $conf; + global $LDAP_CON; + global $smarty; + + $orgs = array(); + + $sr = ldap_list($LDAP_CON,$conf[publicbook],"ObjectClass=inetOrgPerson",array("o")); + $result1 = ldap_get_binentries($LDAP_CON, $sr); + //check users private addressbook + if(!empty($_SESSION[ldapab][binddn])){ + $sr = @ldap_list($LDAP_CON, + $conf[privatebook].','.$_SESSION[ldapab][binddn], + "ObjectClass=inetOrgPerson",array("o")); + $result2 = ldap_get_binentries($LDAP_CON, $sr); + } + $result = array_merge($result1,$result2); + + if(count($result)){ + foreach ($result as $entry){ + if(!empty($entry[o][0])){ + array_push($orgs, $entry[o][0]); + } + } + } + $orgs = array_unique($orgs); + sort($orgs,SORT_STRING); + utf8_decode_array($orgs); + $smarty->assign('orgs',$orgs); +} + +?> diff --git a/templates/blank.gif b/templates/blank.gif new file mode 100644 index 0000000000000000000000000000000000000000..9935f82104a336a22da8f8bac84db0749a4bd27b GIT binary patch literal 42 pcmZ?wbhEHbWMp7uXkY+=|Ns9h{$ycf01D`U_#hbuCPp6yYXG?z2LJ#7 literal 0 HcmV?d00001 diff --git a/templates/entry_edit.tpl b/templates/entry_edit.tpl new file mode 100644 index 0000000..de2283d --- /dev/null +++ b/templates/entry_edit.tpl @@ -0,0 +1,179 @@ +

+ {if $entry.type != ''} + + {/if} + {$entry.givenname} {$entry.name} +

+ +
+ + + + +{include file="ldaperror.tpl"} + + + + + + + + {if $entry.dn == ''} + + + + {/if} + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {if $conf.extended} + {include file="extended_edit.tpl"} + {/if} +
{$lang.business}
{$lang.name}:
{$lang.givenname}:
{$lang.title}:
{$lang.organization}: + +
+ +
{$lang.office}:
{$lang.street}:
{$lang.zip}:
{$lang.location}:
{$lang.phone}:
{$lang.fax}:
{$lang.pager}:
{$lang.manager}: + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {foreach from=$entry.mail item=mail} + + + + + {/foreach} + + + + + + + + + + + + + + + + + +
{$lang.private}
{$lang.homestreet}:
{$lang.homephone}:
{$lang.mobile}:
{$lang.url}:
{$lang.photo}:
({$lang.msg_jpegonly})
{if $entry.photo} + + +
+ {/if} + +
{$lang.mail}
{counter}:
{counter}:
{counter}:
{$lang.note}
+
+ {$lang.msg_addto}
+
+ +
+ + +
+

+ +
+ +
diff --git a/templates/entry_show.tpl b/templates/entry_show.tpl new file mode 100644 index 0000000..b87a69e --- /dev/null +++ b/templates/entry_show.tpl @@ -0,0 +1,120 @@ +

+ + {$entry.givenname} {$entry.name} +

+{if $entry.photo != ''} + +{/if} + +{include file="ldaperror.tpl"} + + + + + + + +
+ {$lang.business} +
+ + + + + {if $entry.phone} + + + + + {/if} + {if $entry.fax} + + + + + {/if} + {if $entry.pager} + + + + + {/if} + {if $entry.mail} + + + + + {/if} +
+ {$entry.title} {$entry.givenname} {$entry.name}
+ {if $entry.organization}{$entry.organization}
{/if} + {if $entry.office}{$entry.office}
{/if} + {if $entry.street}{$entry.street}
{/if} + {if $entry.location}{$entry.zip} {$entry.location}
{/if} +
+
{$lang.phone}:{$entry.phone}
{$lang.fax}:{$entry.fax}
{$lang.pager}:{$entry.pager}
{$lang.mail}: + {foreach from=$entry.mail item=mail} + {$mail}
+ {/foreach} +
+
+ {if $conf.extended} + {include file="extended_show.tpl"} + {/if} +
+ {$lang.private} +
+ + + + + {if $entry.homephone} + + + + + {/if} + {if $entry.mobile} + + + + + {/if} + {if $entry.url} + + + + + {/if} +
+ {if $entry.homestreet} + {$entry.givenname} {$entry.name}
+ {$entry.homestreet|nl2br}

+ {/if} +
{$lang.homephone}:{$entry.homephone}
{$lang.mobile}:{$entry.mobile}
{$lang.url}:{$entry.url}
+
+ + {if $entry.note} + {$lang.note} +
+ {$entry.note|nl2br} +
+ {/if} + + + {if $managername} + {$lang.manager} +
+ + + + +
+ {$managername} +
+
+ {/if} + +
+


+ diff --git a/templates/entry_vcf.tpl b/templates/entry_vcf.tpl new file mode 100644 index 0000000..ed3776c --- /dev/null +++ b/templates/entry_vcf.tpl @@ -0,0 +1,19 @@ +BEGIN:VCARD +VERSION:2.1 +N:{$entry.name};{$entry.givenname};;{$entry.title} +FN:{$entry.givenname} {$entry.name} +ORG;ENCODING=QUOTED-PRINTABLE:{$entry.organisation|escape:qp};{$entry.office|escape:qp} +NOTE;ENCODING=QUOTED-PRINTABLE:{$entry.note|escape:qp} +TEL;WORK;VOICE;ENCODING=QUOTED-PRINTABLE:{$entry.phone|escape:qp} +TEL;HOME;VOICE;ENCODING=QUOTED-PRINTABLE:{$entry.homephone|escape:qp} +TEL;CELL;VOICE;ENCODING=QUOTED-PRINTABLE:{$entry.mobile|escape:qp} +TEL;WORK;FAX;ENCODING=QUOTED-PRINTABLE:{$entry.fax|escape:qp} +TEL;WORK;PAGER;ENCODING=QUOTED-PRINTABLE:{$entry.pager|escape:qp} +{foreach from=$entry.mail item=mail} +EMAIL;INTERNET:{$mail} +{/foreach} +ADR;WORK;ENCODING=QUOTED-PRINTABLE:;;{$entry.street|escape:qp};{$entry.location|escape:qp};;{$entry.plz|escape:qp}; +ADR;HOME;ENCODING=QUOTED-PRINTABLE:;;{$entry.homestreet|escape:qp} +URL;WORK:{$entry.url} +BDAY:{$entry.anniversary} +END:VCARD diff --git a/templates/error.tpl b/templates/error.tpl new file mode 100644 index 0000000..6f8d460 --- /dev/null +++ b/templates/error.tpl @@ -0,0 +1,10 @@ + +

An error occured

+ +{include file="ldaperror.tpl"} + + + + + +
{$error}
diff --git a/templates/extended_edit.tpl b/templates/extended_edit.tpl new file mode 100644 index 0000000..8139fde --- /dev/null +++ b/templates/extended_edit.tpl @@ -0,0 +1,20 @@ + + + {$lang.extended} + + + {$lang.anniversary}:
({$lang.msg_dateformat}) + + + + + {$lang.marker}: + + +
+
+ + + diff --git a/templates/extended_show.tpl b/templates/extended_show.tpl new file mode 100644 index 0000000..985dbcf --- /dev/null +++ b/templates/extended_show.tpl @@ -0,0 +1,22 @@ +{$lang.extended} +
+ + + {if $entry.anniversary} + + + + + {/if} + {if $entry.marker} + + + + + {/if} +
{$lang.anniversary}:{$entry.anniversary|date_format:$conf.dateformat}
{$lang.marker}: + {foreach from=$entry.marker item=marker} + {$marker}
+ {/foreach} +
+
diff --git a/templates/footer.tpl b/templates/footer.tpl new file mode 100644 index 0000000..ccadac9 --- /dev/null +++ b/templates/footer.tpl @@ -0,0 +1,42 @@ + + + + + + + + +
+ {$lang.orgs} + + {if $dn} + {$lang.vcfexport} + {/if} + {if $user} + {$lang.vcfimport} + {if $dn} + {if $smarty.request.mode == 'edit'} + {$lang.show} + {elseif $smarty.request.mode != 'copy'} + {$lang.edit} + {$lang.copy} + {$lang.delete} + {/if} + {/if} + {$lang.new} + {/if} +
+ + + + + {if $user == ''} + {$lang.login}    + {$lang.notloggedin} + {else} + {$lang.logout}    + {$lang.loggedinas} {$user} + {/if} + + + diff --git a/templates/header.tpl b/templates/header.tpl new file mode 100644 index 0000000..9467e8a --- /dev/null +++ b/templates/header.tpl @@ -0,0 +1,23 @@ + + + LDAPab - {$lang.ldapab} + + + + + + + + + + + + + + + + + diff --git a/templates/import_entry.tpl b/templates/import_entry.tpl new file mode 100644 index 0000000..fd4854b --- /dev/null +++ b/templates/import_entry.tpl @@ -0,0 +1,39 @@ + + + + + + + + diff --git a/templates/ldaperror.tpl b/templates/ldaperror.tpl new file mode 100644 index 0000000..fbcea18 --- /dev/null +++ b/templates/ldaperror.tpl @@ -0,0 +1,5 @@ +{if $LDAPERRORS != ''} + +{/if} diff --git a/templates/list.tpl b/templates/list.tpl new file mode 100644 index 0000000..fe16dfd --- /dev/null +++ b/templates/list.tpl @@ -0,0 +1,14 @@ +

+
+ + + +
+ + - {$lang.ldapab} + +  {$lang.help} +
+
diff --git a/templates/help.tpl b/templates/help.tpl new file mode 100644 index 0000000..efa29af --- /dev/null +++ b/templates/help.tpl @@ -0,0 +1,43 @@ + +

Adding LDAP-Access to your Mailclient

+ +

Public Addressbook

+ +

Use these settings to connect to the public addressbook:

+
+
LDAP-Server
+
{$conf.ldapserver}
+ +
Bind-DN
+
leave empty (anonymous bind)
+ +
Bind-Password
+
leave empty (anonymous bind)
+ +
Base/Search-DN
+
{$conf.publicbook}
+
+ +

Private Addressbook

+ +{if $binddn} +

To access your persanal addressdata use these settings:

+
+
LDAP-Server
+
{$conf.ldapserver}
+ +
Bind-DN
+
{$binddn}
+ +
Bind-Password
+
your password (The one you used to login here)
+ +
Base/Search-DN
+
{$conf.privatebook},{$binddn}
+
+{else} +

Login to see this data

+{/if} + + +

diff --git a/templates/import.tpl b/templates/import.tpl new file mode 100644 index 0000000..f1dd5f5 --- /dev/null +++ b/templates/import.tpl @@ -0,0 +1,25 @@ + + + + +
+
+ {$lang.msg_uploadvcf}: + +
+
+ +

+ + {if $list == ''} + + + + {else} + {* $list is a concatenation of multiple importVCF_entry.tpl *} + {$list} + {/if} +
+ {$error} +
+


diff --git a/templates/importVCF.tpl b/templates/importVCF.tpl new file mode 100644 index 0000000..1e13444 --- /dev/null +++ b/templates/importVCF.tpl @@ -0,0 +1,25 @@ + + + + +
+
+ {$lang.msg_uploadvcf}: + +
+
+ +

+ + {if $list == ''} + + + + {else} + {* $list is a concatenation of multiple importVCF_entry.tpl *} + {$list} + {/if} +
+ {$error} +
+


diff --git a/templates/importVCF_entry.tpl b/templates/importVCF_entry.tpl new file mode 100644 index 0000000..b2361ad --- /dev/null +++ b/templates/importVCF_entry.tpl @@ -0,0 +1,39 @@ +
+ {$entry.name}, {$entry.givenname} + + + + + + + + + + + + + + + + + + {foreach from=$entry.mail item=mail} + + {/foreach} + + + + + +
+ {$entry.name}, {$entry.givenname} + + + + + + + + + + + + + + + + + + {foreach from=$entry.mail item=mail} + + {/foreach} + + + + + +
+ {if $list == ''} + + + + {else} + {* $list is a concatenation of multiple list_entry.tpl *} + {$list} + {/if} +
+ {$lang.err_noentries} +
+


diff --git a/templates/list_entry.tpl b/templates/list_entry.tpl new file mode 100644 index 0000000..27f4f05 --- /dev/null +++ b/templates/list_entry.tpl @@ -0,0 +1,25 @@ + + + + + + {$entry.name}, {$entry.givenname} + + + {$entry.organization}  + + + {$entry.phone}  + + + {$entry.mail[0]}  + + + {if $entry.photo} + + {else} +   + {/if} + + + diff --git a/templates/list_filter.tpl b/templates/list_filter.tpl new file mode 100644 index 0000000..1b9f714 --- /dev/null +++ b/templates/list_filter.tpl @@ -0,0 +1,50 @@ + + + +{if $conf.extended} + +{/if} + + +
+ A + B + C + D + E + F + G + H + I + J + K + L + M + N + O + P + Q + R + S + T + U + V + W + X + Y + Z + # + +
+ + +
+
+
+ + +
+
diff --git a/templates/login.tpl b/templates/login.tpl new file mode 100644 index 0000000..d4196f6 --- /dev/null +++ b/templates/login.tpl @@ -0,0 +1,21 @@ + +


+
+ + + + + + + + + + + + + + + +
{$msg}

{$lang.username}:
{$lang.password}:
+
+


diff --git a/templates/orgs.tpl b/templates/orgs.tpl new file mode 100644 index 0000000..fcfe45a --- /dev/null +++ b/templates/orgs.tpl @@ -0,0 +1,18 @@ + +{foreach from=$orgs item=org} + + + + +{foreachelse} + + + +{/foreach} +
+ + + {$org}
+
+

{$lang.err_noentries}

+
diff --git a/templates/pngbehavior.htc b/templates/pngbehavior.htc new file mode 100644 index 0000000..7849c8d --- /dev/null +++ b/templates/pngbehavior.htc @@ -0,0 +1,53 @@ +// this is an ugly fix to make Internet Explorer work with transparent +// PNG images - do your self a favour and use a real browser! + + + + + diff --git a/templates/style.css b/templates/style.css new file mode 100644 index 0000000..ed951e6 --- /dev/null +++ b/templates/style.css @@ -0,0 +1,92 @@ +body,p,div,td {font-family:Lucida,Helvetica,Verdana,Arial,Sans-Serif; font-size: 14px;} +a:link { text-decoration:none; color:#0033CC } +a:visited { text-decoration:none; color:#0033CC } +a:active { text-decoration:none; color:#0033CC } +a:hover { text-decoration:underline; color:#FF6600 } + +/* IE PNG bugfix */ +img { behavior: url("templates/pngbehavior.htc"); } + +/* debugging style +table {background-color:#cccc00;margin:3px} +tr {background-color:#99FF99;margin:3px} +td {background-color:#66CCFF:margin:3px} +*/ + +.logo {font-size:25px; font-weight:bolder} +.logosmall {font-size:16px; font-weight:bold} + +.headrow {border-bottom-width:1px; border-bottom-style:solid} +.footrow {border-top-width:1px; border-top-style:solid} +.buttonrow {border-top-width:1px; + border-top-style:solid; + border-top-color:#cccccc;} +.filterrow {border-bottom-width:1px; + border-bottom-style:solid; + border-bottom-color:#cccccc;} + +.tableborder {border-width:1px; border-style:solid} + +.result {border-bottom-width:1px; + border-bottom-style:dashed; + border-bottom-color:#cccccc; + padding-top:3px; + padding-top:4px;} + +.searchfield {border-width:1px; + border-style:solid; + border-color:#000000; + margin:2px; + font-family:Lucida,Helvetica,Verdana,Arial,Sans-Serif; + font-size: 12px; + width: 120px;} +.searchbutton {border-width:1px; + border-style:solid; + border-color:#000000; + margin:2px; + font-family:Lucida,Helvetica,Verdana,Arial,Sans-Serif; + font-size: 12px; + width: 70px;} +.upload {border-width:1px; + border-style:solid; + border-color:#000000; + margin:2px; + font-family:Lucida,Helvetica,Verdana,Arial,Sans-Serif; + font-size: 12px;} + +.photo {border-width:1px; + border-style:solid; + border-color:#000000; + padding:3px; + } + +.input {border-width:1px; + border-style:solid; + border-color:#000000; + font-family:Lucida,Helvetica,Verdana,Arial,Sans-Serif; + font-size: 12px; + width: 250px;} + +.inputbr {border-width:1px; + border-style:solid; + border-color:#000000; + font-family:Lucida,Helvetica,Verdana,Arial,Sans-Serif; + font-size: 12px; + width: 250px; + margin-top:3px;} + + +.radio {border-width:0px;} + +.note {width: 350px} + +.ldaperror {border-width:1px; + border-style:solid; + border-color:#ff0000; + margin:2px; + font-family:Lucida,Helvetica,Verdana,Arial,Sans-Serif; + font-size: 12px;} + +code, pre {color:#008000;} + +.hint {font-size:10px; color:#990099;} diff --git a/xml.php b/xml.php new file mode 100644 index 0000000..2f987f7 --- /dev/null +++ b/xml.php @@ -0,0 +1,139 @@ +parse($xml); + $xml_parser->destruct(); + return $data; +} +################################################################################### +# XML_serialize: serializes any PHP data structure into XML +# Takes one parameter: the data to serialize. Must be an array. +################################################################################### +function & XML_serialize(&$data, $level = 0, $prior_key = NULL){ + #assumes a hash, keys are the tag names + $xml_parts = ''; + while(list($key, $value) = each($data)){ + if(!strpos($key, ' attr')){ #if it's not an attribute + #... we don't treat attributes by themselves. + #note that implies that for an empty element that has attributes, you still + #need to set the element to NULL + + $attributes = array(); + if(array_key_exists("$key attr", $data)){ #if there's an attribute for this element + while(list($attr_name, $attr_value) = each($data["$key attr"])) + $attributes[] = $attr_name.'="'.htmlspecialchars($attr_value).'"'; + reset($data["$key attr"]); + } + + if(is_array($value) and array_key_exists(0, $value)){ + #numeric array (note that you can't have numeric keys at two levels in a row) + $xml_parts .= XML_serialize($value, $level, $key); + }else{ + if($prior_key) $key = $prior_key; + #(i.e. if we're in a numeric array, replace the number with the actual tag) + + $xml_parts .= str_repeat("\t", $level).'<'.$key; + if($attributes) $xml_parts .= ' '.join(' ',$attributes); + + if(is_null($value)) + $xml_parts .= " />\r\n"; + elseif(!is_array($value)) + $xml_parts .= '>'.htmlspecialchars($value)."\r\n"; + else + $xml_parts .= ">\r\n".XML_serialize($value, $level+1).str_repeat("\t", $level)."\r\n"; + } + } + } + reset($data); + if($level == 0) return "\r\n".$xml_parts; + return $xml_parts; +} +################################################################################### +# XML class: utility class to be used with PHP's XML handling functions +################################################################################### +class XML { + var $parser; #a reference to the XML parser + var $document; #the entire XML structure built up so far + var $parent; #a pointer to the current parent - the parent will be an array + var $stack; #a stack of the most recent parent at each nesting level + var $last_opened_tag; #keeps track of the last tag opened. + + function XML(){ + $this->parser = &xml_parser_create(); + xml_parser_set_option(&$this->parser, XML_OPTION_CASE_FOLDING, 0); + xml_set_object(&$this->parser, &$this); + xml_set_element_handler(&$this->parser, 'open','close'); + xml_set_character_data_handler(&$this->parser, 'data'); + } + function destruct(){ + xml_parser_free(&$this->parser); + } + function & parse(&$data){ + $this->document = array(); + $this->parent = &$this->document; + $this->stack = array(); + return xml_parse(&$this->parser, &$data, true) ? $this->document : NULL; + } + function open(&$parser, $tag, $attributes){ + $this->data = array(); #stores temporary cdata + $this->last_opened_tag = $tag; + if(is_array($this->parent) and array_key_exists($tag,$this->parent)){ #if you've seen this tag before + if(is_array($this->parent[$tag]) and array_key_exists(0,$this->parent[$tag])){ #if the keys are numeric + #this is the third or later instance of $tag we've come across + $key = count_numeric_items($this->parent[$tag]); + }else{ + #this is the second instance of $tag that we've seen + #shift around + if(array_key_exists("$tag attr",$this->parent)){ + $arr = array('0 attr'=>&$this->parent["$tag attr"], &$this->parent[$tag]); unset($this->parent["$tag attr"]); + }else{ + $arr = array(&$this->parent[$tag]); + } + $this->parent[$tag] = &$arr; + $key = 1; + } + $this->parent = &$this->parent[$tag]; + }else{ + $key = $tag; + } + if($attributes) + $this->parent["$key attr"] = $attributes; + + $this->parent[$key] = NULL; #it turns out you can take a reference to NULL :) + $this->parent = &$this->parent[$key]; + $this->stack[] = &$this->parent; + } + function data(&$parser, $data){ + if($this->last_opened_tag != NULL) #you don't need to store whitespace in between tags + $this->data[] = $data; + } + function close(&$parser, $tag){ + static $just_closed = false; + if($this->last_opened_tag == $tag){ + if($this->data) + $this->parent = join('',$this->data); + $this->last_opened_tag = NULL; + } + array_pop($this->stack); + if($this->stack) + $this->parent = &$this->stack[count($this->stack)-1]; + } +} +function count_numeric_items(&$array){ + return is_array($array) ? count(array_filter(array_keys($array), 'is_numeric')) : 0; +} +?> \ No newline at end of file -- 2.39.5