From: Andreas Gohr Date: Wed, 7 Dec 2005 09:25:29 +0000 (+0100) Subject: initial checkin X-Git-Tag: 0.7.1~110 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=aa36c490d2218814cb6faa20e31c10b5599d4483;p=contagged initial checkin darcs-hash:20051207092529-6e07b-ccd48731093a8d618db0a6e4c11b940f604a938f.gz --- aa36c490d2218814cb6faa20e31c10b5599d4483 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 0000000..eac4d8c Binary files /dev/null and b/pix/copy.png differ diff --git a/pix/delete.png b/pix/delete.png new file mode 100644 index 0000000..6fb193f Binary files /dev/null and b/pix/delete.png differ diff --git a/pix/edit.png b/pix/edit.png new file mode 100644 index 0000000..ce8b226 Binary files /dev/null and b/pix/edit.png differ diff --git a/pix/help.png b/pix/help.png new file mode 100644 index 0000000..3626ba7 Binary files /dev/null and b/pix/help.png differ diff --git a/pix/image.png b/pix/image.png new file mode 100644 index 0000000..fdf5370 Binary files /dev/null and b/pix/image.png differ diff --git a/pix/import.png b/pix/import.png new file mode 100644 index 0000000..df0f16c Binary files /dev/null and b/pix/import.png differ diff --git a/pix/login.png b/pix/login.png new file mode 100644 index 0000000..b490469 Binary files /dev/null and b/pix/login.png differ diff --git a/pix/logout.png b/pix/logout.png new file mode 100644 index 0000000..119e5ef Binary files /dev/null and b/pix/logout.png differ diff --git a/pix/new.png b/pix/new.png new file mode 100644 index 0000000..7be37e8 Binary files /dev/null and b/pix/new.png differ diff --git a/pix/org.png b/pix/org.png new file mode 100644 index 0000000..b5c8949 Binary files /dev/null and b/pix/org.png differ diff --git a/pix/orgs.png b/pix/orgs.png new file mode 100644 index 0000000..7596e67 Binary files /dev/null and b/pix/orgs.png differ diff --git a/pix/private.png b/pix/private.png new file mode 100644 index 0000000..55fb6dd Binary files /dev/null and b/pix/private.png differ diff --git a/pix/public.png b/pix/public.png new file mode 100644 index 0000000..212c6cc Binary files /dev/null and b/pix/public.png differ diff --git a/pix/search.png b/pix/search.png new file mode 100644 index 0000000..4f880ab Binary files /dev/null and b/pix/search.png differ diff --git a/pix/show.png b/pix/show.png new file mode 100644 index 0000000..40762a0 Binary files /dev/null and b/pix/show.png differ diff --git a/pix/vcard.png b/pix/vcard.png new file mode 100644 index 0000000..a8b9429 Binary files /dev/null and b/pix/vcard.png differ diff --git a/slapd.example b/slapd.example new file mode 100644 index 0000000..cd7643a --- /dev/null +++ b/slapd.example @@ -0,0 +1,111 @@ +# This is the main ldapd configuration file. See slapd.conf(5) for more +# info on the configuration options. + +# Schema and objectClass definitions +include /etc/ldap/schema/core.schema +include /etc/ldap/schema/cosine.schema +include /etc/ldap/schema/nis.schema +include /etc/ldap/schema/inetorgperson.schema +include /etc/ldap/schema/samba.schema +include /etc/ldap/schema/courierimap.schema +include /etc/ldap/schema/phpgwaccount.schema +include /etc/ldap/schema/phpgwcontact.schema +include /etc/ldap/schema/ldapab.schema + + +# Schema check allows for forcing entries to +# match schemas for their objectClasses's +schemacheck on + +# Where the pid file is put. The init.d script +# will not stop the server if you change this. +pidfile /var/run/slapd.pid + +# List of arguments that were passed to the server +argsfile /var/run/slapd.args + +# Where to store the replica logs +replogfile /var/lib/ldap/replog + +# Read slapd.conf(5) for possible values +#loglevel 256 +loglevel 0 + +####################################################################### +# ldbm database definitions +####################################################################### + +# The backend type, ldbm, is the default standard +database ldbm + +# The base of your directory +suffix "o=cosmocode,c=de" + +# Where the database file are physically stored +directory "/var/lib/ldap" + +# Indexing options +index objectClass eq + +# Folgende Indizies sind im samba-LDAP-HOWTO empfohlen; + +## support pbb_getsampwnam() +index uid pres,eq +## support pdb_getsampwrid() +index rid eq + +## uncomment these if you are storing posixAccount and +## posixGroup entries in the directory as well +index uidNumber eq +index gidNumber eq +index cn eq +index memberUid eq + +# Save the time that the entry gets modified +lastmod on + +# The userPassword by default can be changed +# by the entry owning it if they are authenticated. +# Others should not be able to see it, except the +# admin entry below +access to attribute=userPassword + by dn="cn=admin,o=cosmocode,c=de" write + by anonymous auth + by self write + by * none + +access to attribute=lmPassword + by dn="cn=admin,o=cosmocode,c=de" write + by anonymous auth + by self write + by * none + +access to attribute=ntPassword + by dn="cn=admin,o=cosmocode,c=de" write + by anonymous auth + by self write + by * none + +# private LDAP Addressbook is readable and writable for the owner only +access to dn="(.*,)?ou=contacts,cn=([^,]+),ou=people,(.*)$" + by dn="cn=$2,ou=people,$3" write + by * none + +# global LDAP Addressbook is writable for all authenticated users +# This entry has to be _before_ any other entry that matches the contact +# tree eg. the * entry +access to dn.subtree="ou=contacts,o=cosmocode,c=de" + by users write + by * read + +# The admin dn has full write access +access to * + by dn="cn=admin,o=cosmocode,c=de" write + by * read + +# For Netscape Roaming support, each user gets a roaming +# profile for which they have write access to +#access to dn=".*,ou=Roaming,o=morsnet" +# by dn="cn=admin,o=cosmocode,c=de" write +# by dnattr=owner write + diff --git a/smarty/Config_File.class.php b/smarty/Config_File.class.php new file mode 100644 index 0000000..f0297cd --- /dev/null +++ b/smarty/Config_File.class.php @@ -0,0 +1,365 @@ + + * @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 0000000..9935f82 Binary files /dev/null and b/templates/blank.gif differ 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