diff --git a/boot.php b/boot.php index 973e3578a6..78c952a61b 100644 --- a/boot.php +++ b/boot.php @@ -10,9 +10,9 @@ require_once('include/nav.php'); require_once('include/cache.php'); define ( 'FRIENDICA_PLATFORM', 'Friendica'); -define ( 'FRIENDICA_VERSION', '3.0.1388' ); +define ( 'FRIENDICA_VERSION', '3.0.1402' ); define ( 'DFRN_PROTOCOL_VERSION', '2.23' ); -define ( 'DB_UPDATE_VERSION', 1151 ); +define ( 'DB_UPDATE_VERSION', 1153 ); define ( 'EOL', "
\r\n" ); define ( 'ATOM_TIME', 'Y-m-d\TH:i:s\Z' ); @@ -34,6 +34,24 @@ define ( 'JPEG_QUALITY', 100 ); */ define ( 'PNG_QUALITY', 8 ); +/** + * + * An alternate way of limiting picture upload sizes. Specify the maximum pixel + * length that pictures are allowed to be (for non-square pictures, it will apply + * to the longest side). Pictures longer than this length will be resized to be + * this length (on the longest side, the other side will be scaled appropriately). + * Modify this value using + * + * $a->config['system']['max_image_length'] = n; + * + * in .htconfig.php + * + * If you don't want to set a maximum length, set to -1. The default value is + * defined by 'MAX_IMAGE_LENGTH' below. + * + */ +define ( 'MAX_IMAGE_LENGTH', -1 ); + /** * Not yet used @@ -177,6 +195,22 @@ define ( 'NOTIFY_TAGSHARE', 0x0100 ); define ( 'NOTIFY_SYSTEM', 0x8000 ); +/** + * Tag/term types + */ + +define ( 'TERM_UNKNOWN', 0 ); +define ( 'TERM_HASHTAG', 1 ); +define ( 'TERM_MENTION', 2 ); +define ( 'TERM_CATEGORY', 3 ); +define ( 'TERM_PCATEGORY', 4 ); +define ( 'TERM_FILE', 5 ); + +define ( 'TERM_OBJ_POST', 1 ); +define ( 'TERM_OBJ_PHOTO', 2 ); + + + /** * various namespaces we may need to parse */ @@ -352,6 +386,16 @@ if(! class_exists('App')) { if(x($_SERVER,'SERVER_NAME')) { $this->hostname = $_SERVER['SERVER_NAME']; + + // See bug 437 - this didn't work so disabling it + //if(stristr($this->hostname,'xn--')) { + // PHP or webserver may have converted idn to punycode, so + // convert punycode back to utf-8 + // require_once('library/simplepie/idn/idna_convert.class.php'); + // $x = new idna_convert(); + // $this->hostname = $x->decode($_SERVER['SERVER_NAME']); + //} + if(x($_SERVER,'SERVER_PORT') && $_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) $this->hostname .= ':' . $_SERVER['SERVER_PORT']; /** @@ -369,6 +413,7 @@ if(! class_exists('App')) { . 'include' . PATH_SEPARATOR . 'library' . PATH_SEPARATOR . 'library/phpsec' . PATH_SEPARATOR + . 'library/langdet' . PATH_SEPARATOR . '.' ); if((x($_SERVER,'QUERY_STRING')) && substr($_SERVER['QUERY_STRING'],0,2) === "q=") { @@ -434,8 +479,8 @@ if(! class_exists('App')) { $this->pager['page'] = ((x($_GET,'page') && intval($_GET['page']) > 0) ? intval($_GET['page']) : 1); $this->pager['itemspage'] = 50; $this->pager['start'] = ($this->pager['page'] * $this->pager['itemspage']) - $this->pager['itemspage']; - if($this->pager['start'] < 1) - $this->pager['start'] = 1; + if($this->pager['start'] < 0) + $this->pager['start'] = 0; $this->pager['total'] = 0; } diff --git a/database.sql b/database.sql index b3b8c3a060..1d0a321760 100644 --- a/database.sql +++ b/database.sql @@ -598,6 +598,19 @@ CREATE TABLE IF NOT EXISTS `item_id` ( -- -------------------------------------------------------- +-- +-- Table structure for table `locks` +-- + +CREATE TABLE `locks` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` char(128) NOT NULL, + `locked` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + -- -- Table structure for table `mail` -- @@ -987,6 +1000,26 @@ CREATE TABLE IF NOT EXISTS `spam` ( -- -------------------------------------------------------- +-- +-- Table structure for table `term` +-- + +CREATE TABLE IF NOT EXISTS `term` ( + `tid` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `oid` INT UNSIGNED NOT NULL , + `otype` TINYINT( 3 ) UNSIGNED NOT NULL , + `type` TINYINT( 3 ) UNSIGNED NOT NULL , + `term` CHAR( 255 ) NOT NULL , + `url` CHAR( 255 ) NOT NULL, + PRIMARY KEY (`tid`), + KEY `oid` ( `oid` ), + KEY `otype` ( `otype` ), + KEY `type` ( `type` ), + KEY `term` ( `term` ) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + -- -- Table structure for table `tokens` -- diff --git a/include/Photo.php b/include/Photo.php index 3af1691ee7..ba4241a7b8 100644 --- a/include/Photo.php +++ b/include/Photo.php @@ -143,7 +143,7 @@ class Photo { public function orient($filename) { // based off comment on http://php.net/manual/en/function.imagerotate.php - if(! function_exists('exif_read_data')) + if( (! function_exists('exif_read_data')) || ($this->getType() !== 'image/jpeg') ) return; $exif = exif_read_data($filename); diff --git a/include/Scrape.php b/include/Scrape.php index 4f53effe92..b784650cd1 100644 --- a/include/Scrape.php +++ b/include/Scrape.php @@ -432,7 +432,7 @@ function probe_url($url, $mode = PROBE_NORMAL) { intval(local_user()) ); if(count($x) && count($r)) { - $mailbox = construct_mailbox_name($r[0]); + $mailbox = construct_mailbox_name($r[0]); $password = ''; openssl_private_decrypt(hex2bin($r[0]['pass']),$password,$x[0]['prvkey']); $mbox = email_connect($mailbox,$r[0]['user'],$password); diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php index 4a82635e57..436412dbd4 100644 --- a/include/bb2diaspora.php +++ b/include/bb2diaspora.php @@ -7,6 +7,66 @@ require_once("include/html2bbcode.php"); require_once("include/bbcode.php"); require_once("include/markdownify/markdownify.php"); + +function get_bb_tag_pos($s, $name, $occurance = 1) { + + if($occurance < 1) + $occurance = 1; + + $start_open = -1; + for($i = 1; $i <= $occurance; $i++) { + if( $start_open !== false) + $start_open = strpos($s, '[' . $name, $start_open + 1); // allow [name= type tags + } + + if( $start_open === false) + return false; + + $start_equal = strpos($s, '=', $start_open); + $start_close = strpos($s, ']', $start_open); + + if( $start_close === false) + return false; + + $start_close++; + + $end_open = strpos($s, '[/' . $name . ']', $start_close); + + if( $end_open === false) + return false; + + $res = array( 'start' => array('open' => $start_open, 'close' => $start_close), + 'end' => array('open' => $end_open, 'close' => $end_open + strlen('[/' . $name . ']')) ); + if( $start_equal !== false) + $res['start']['equal'] = $start_equal + 1; + + return $res; +} + +function bb_tag_preg_replace($pattern, $replace, $name, $s) { + + $string = $s; + + $occurance = 1; + $pos = get_bb_tag_pos($string, $name, $occurance); + while($pos !== false && $occurance < 1000) { + + $start = substr($string, 0, $pos['start']['open']); + $subject = substr($string, $pos['start']['open'], $pos['end']['close'] - $pos['start']['open']); + $end = substr($string, $pos['end']['close']); + if($end === false) + $end = ''; + + $subject = preg_replace($pattern, $replace, $subject); + $string = $start . $subject . $end; + + $occurance++; + $pos = get_bb_tag_pos($string, $name, $occurance); + } + + return $string; +} + // we don't want to support a bbcode specific markdown interpreter // and the markdown library we have is pretty good, but provides HTML output. // So we'll use that to convert to HTML, then convert the HTML back to bbcode, @@ -38,20 +98,23 @@ function diaspora2bb($s) { $s = Markdown($s); $s = str_replace('#','#',$s); - - $s = str_replace("\n",'
',$s); +// we seem to have double linebreaks +// $s = str_replace("\n",'
',$s); $s = html2bbcode($s); // $s = str_replace('*','*',$s); + // protect the recycle symbol from turning into a tag, but without unescaping angles and naked ampersands + $s = str_replace('♲',html_entity_decode('♲',ENT_QUOTES,'UTF-8'),$s); + // Convert everything that looks like a link to a link $s = preg_replace("/([^\]\=]|^)(https?\:\/\/)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url=$2$3]$2$3[/url]',$s); //$s = preg_replace("/([^\]\=]|^)(https?\:\/\/)(vimeo|youtu|www\.youtube|soundcloud)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url=$2$3$4]$2$3$4[/url]',$s); - $s = preg_replace("/\[url\=?(.*?)\]https?:\/\/www.youtube.com\/watch\?v\=(.*?)\[\/url\]/ism",'[youtube]$2[/youtube]',$s); - $s = preg_replace("/\[url\=https?:\/\/www.youtube.com\/watch\?v\=(.*?)\].*?\[\/url\]/ism",'[youtube]$1[/youtube]',$s); - $s = preg_replace("/\[url\=?(.*?)\]https?:\/\/vimeo.com\/([0-9]+)(.*?)\[\/url\]/ism",'[vimeo]$2[/vimeo]',$s); - $s = preg_replace("/\[url\=https?:\/\/vimeo.com\/([0-9]+)\](.*?)\[\/url\]/ism",'[vimeo]$1[/vimeo]',$s); + $s = bb_tag_preg_replace("/\[url\=?(.*?)\]https?:\/\/www.youtube.com\/watch\?v\=(.*?)\[\/url\]/ism",'[youtube]$2[/youtube]','url',$s); + $s = bb_tag_preg_replace("/\[url\=https?:\/\/www.youtube.com\/watch\?v\=(.*?)\].*?\[\/url\]/ism",'[youtube]$1[/youtube]','url',$s); + $s = bb_tag_preg_replace("/\[url\=?(.*?)\]https?:\/ \/vimeo.com\/([0-9]+)(.*?)\[\/url\]/ism",'[vimeo]$2[/vimeo]','url',$s); + $s = bb_tag_preg_replace("/\[url\=https?:\/\/vimeo.com\/([0-9]+)\](.*?)\[\/url\]/ism",'[vimeo]$1[/vimeo]','url',$s); // remove duplicate adjacent code tags $s = preg_replace("/(\[code\])+(.*?)(\[\/code\])+/ism","[code]$2[/code]", $s); @@ -67,6 +130,12 @@ function stripdcode_br_cb($s) { } +////////////////////// +// The following "diaspora_ul" and "diaspora_ol" are only appropriate for the +// pre-Markdownify conversion. If Markdownify isn't used, use the non-Markdownify +// versions below +////////////////////// +/* function diaspora_ul($s) { // Replace "[*]" followed by any number (including zero) of // spaces by "* " to match Diaspora's list format @@ -100,32 +169,33 @@ function diaspora_ol($s) { else return $s[0]; } +*/ + +////////////////////// +// Non-Markdownify versions of "diaspora_ol" and "diaspora_ul" +////////////////////// +function diaspora_ul($s) { + // Replace "[\\*]" followed by any number (including zero) of + // spaces by "* " to match Diaspora's list format + return preg_replace("/\[\\\\\*\]( *)/", "* ", $s[1]); +} + +function diaspora_ol($s) { + // A hack: Diaspora will create a properly-numbered ordered list even + // if you use '1.' for each element of the list, like: + // 1. First element + // 1. Second element + // 1. Third element + return preg_replace("/\[\\\\\*\]( *)/", "1. ", $s[1]); +} function bb2diaspora($Text,$preserve_nl = false) { - // bbcode() will convert "[*]" into "
  • " with no closing "
  • " - // Markdownify() is unable to handle these, as it makes each new - // "
  • " into a deeper nested element until it crashes. So pre-format - // the lists as Diaspora lists before sending the $Text to bbcode() - // - // Note that to get nested lists to work for Diaspora, we would need - // to define the closing tag for the list elements. So nested lists - // are going to be flattened out in Diaspora for now -/* $endlessloop = 0; - while ((((strpos($Text, "[/list]") !== false) && (strpos($Text, "[list") !== false)) || - ((strpos($Text, "[/ol]") !== false) && (strpos($Text, "[ol]") !== false)) || - ((strpos($Text, "[/ul]") !== false) && (strpos($Text, "[ul]") !== false))) && (++$endlessloop < 20)) { - $Text = preg_replace_callback("/\[list\](.*?)\[\/list\]/is", 'diaspora_ul', $Text); - $Text = preg_replace_callback("/\[list=1\](.*?)\[\/list\]/is", 'diaspora_ol', $Text); - $Text = preg_replace_callback("/\[list=i\](.*?)\[\/list\]/s",'diaspora_ol', $Text); - $Text = preg_replace_callback("/\[list=I\](.*?)\[\/list\]/s", 'diaspora_ol', $Text); - $Text = preg_replace_callback("/\[list=a\](.*?)\[\/list\]/s", 'diaspora_ol', $Text); - $Text = preg_replace_callback("/\[list=A\](.*?)\[\/list\]/s", 'diaspora_ol', $Text); - $Text = preg_replace_callback("/\[ul\](.*?)\[\/ul\]/is", 'diaspora_ul', $Text); - $Text = preg_replace_callback("/\[ol\](.*?)\[\/ol\]/is", 'diaspora_ol', $Text); - } -*/ + // Re-enabling the converter again. + // The bbcode parser now handles youtube-links (and the other stuff) correctly. + // Additionally the html code is now fixed so that lists are now working. + // Convert it to HTML - don't try oembed $Text = bbcode($Text, $preserve_nl, false); @@ -142,7 +212,9 @@ function bb2diaspora($Text,$preserve_nl = false) { // Remove all unconverted tags $Text = strip_tags($Text); -/* + +/* Old routine + $ev = bbtoevent($Text); // Replace any html brackets with HTML Entities to prevent executing HTML or script @@ -225,15 +297,21 @@ function bb2diaspora($Text,$preserve_nl = false) { $Text = preg_replace("(\[size=(.*?)\](.*?)\[\/size\])is","$2",$Text); // Check for list text - $Text = preg_replace_callback("/\[list\](.*?)\[\/list\]/is", 'diaspora_ul', $Text); - $Text = preg_replace_callback("/\[ul\](.*?)\[\/ul\]/is", 'diaspora_ul', $Text); - $Text = preg_replace_callback("/\[list=1\](.*?)\[\/list\]/is", 'diaspora_ol', $Text); - $Text = preg_replace_callback("/\[list=i\](.*?)\[\/list\]/s",'diaspora_ol', $Text); - $Text = preg_replace_callback("/\[list=I\](.*?)\[\/list\]/s", 'diaspora_ol', $Text); - $Text = preg_replace_callback("/\[list=a\](.*?)\[\/list\]/s", 'diaspora_ol', $Text); - $Text = preg_replace_callback("/\[list=A\](.*?)\[\/list\]/s", 'diaspora_ol', $Text); - $Text = preg_replace_callback("/\[ol\](.*?)\[\/ol\]/is", 'diaspora_ol', $Text); -// $Text = preg_replace("/\[li\](.*?)\[\/li\]/s", '
  • $1
  • ' ,$Text); + $endlessloop = 0; + while ((((strpos($Text, "[/list]") !== false) && (strpos($Text, "[list") !== false)) || + ((strpos($Text, "[/ol]") !== false) && (strpos($Text, "[ol]") !== false)) || + ((strpos($Text, "[/ul]") !== false) && (strpos($Text, "[ul]") !== false)) || + ((strpos($Text, "[/li]") !== false) && (strpos($Text, "[li]") !== false))) && (++$endlessloop < 20)) { + $Text = preg_replace_callback("/\[list\](.*?)\[\/list\]/is", 'diaspora_ul', $Text); + $Text = preg_replace_callback("/\[list=1\](.*?)\[\/list\]/is", 'diaspora_ol', $Text); + $Text = preg_replace_callback("/\[list=i\](.*?)\[\/list\]/s",'diaspora_ol', $Text); + $Text = preg_replace_callback("/\[list=I\](.*?)\[\/list\]/s", 'diaspora_ol', $Text); + $Text = preg_replace_callback("/\[list=a\](.*?)\[\/list\]/s", 'diaspora_ol', $Text); + $Text = preg_replace_callback("/\[list=A\](.*?)\[\/list\]/s", 'diaspora_ol', $Text); + $Text = preg_replace_callback("/\[ul\](.*?)\[\/ul\]/is", 'diaspora_ul', $Text); + $Text = preg_replace_callback("/\[ol\](.*?)\[\/ol\]/is", 'diaspora_ol', $Text); + $Text = preg_replace("/\[li\]( *)(.*?)\[\/li\]/s", '* $2' ,$Text); + } // Just get rid of table tags since Diaspora doesn't support tables $Text = preg_replace("/\[th\](.*?)\[\/th\]/s", '$1' ,$Text); @@ -295,12 +373,13 @@ function bb2diaspora($Text,$preserve_nl = false) { // If we found an event earlier, strip out all the event code and replace with a reformatted version. - if(x($ev,'desc') && x($ev,'start')) { + if(x($ev,'start')) { $sub = format_event_diaspora($ev); - $Text = preg_replace("/\[event\-description\](.*?)\[\/event\-description\]/is",$sub,$Text); - $Text = preg_replace("/\[event\-start\](.*?)\[\/event\-start\]/is",'',$Text); + $Text = preg_replace("/\[event\-summary\](.*?)\[\/event\-summary\]/is",'',$Text); + $Text = preg_replace("/\[event\-description\](.*?)\[\/event\-description\]/is",'',$Text); + $Text = preg_replace("/\[event\-start\](.*?)\[\/event\-start\]/is",$sub,$Text); $Text = preg_replace("/\[event\-finish\](.*?)\[\/event\-finish\]/is",'',$Text); $Text = preg_replace("/\[event\-location\](.*?)\[\/event\-location\]/is",'',$Text); $Text = preg_replace("/\[event\-adjust\](.*?)\[\/event\-adjust\]/is",'',$Text); @@ -309,6 +388,7 @@ function bb2diaspora($Text,$preserve_nl = false) { $Text = preg_replace("/\<(.*?)(src|href)=(.*?)\&\;(.*?)\>/ism",'<$1$2=$3&$4>',$Text); $Text = preg_replace_callback('/\[(.*?)\]\((.*?)\)/ism','unescape_underscores_in_links',$Text); + */ // Remove any leading or trailing whitespace, as this will mess up @@ -336,7 +416,7 @@ function format_event_diaspora($ev) { $o = 'Friendica event notification:' . "\n"; - $o .= '**' . bb2diaspora($ev['desc']) . '**' . "\n"; + $o .= '**' . (($ev['summary']) ? bb2diaspora($ev['summary']) : bb2diaspora($ev['desc'])) . '**' . "\n"; $o .= t('Starts:') . ' ' . '[' . (($ev['adjust']) ? day_translate(datetime_convert('UTC', 'UTC', diff --git a/include/bbcode.php b/include/bbcode.php index e212ec4aed..4aac33f112 100644 --- a/include/bbcode.php +++ b/include/bbcode.php @@ -47,6 +47,67 @@ function bb_unspacefy_and_trim($st) { return $unspacefied; } +if(! function_exists('bb_extract_images')) { +function bb_extract_images($body) { + + $saved_image = array(); + $orig_body = $body; + $new_body = ''; + + $cnt = 0; + $img_start = strpos($orig_body, '[img'); + $img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false); + $img_end = ($img_start !== false ? strpos(substr($orig_body, $img_start), '[/img]') : false); + while(($img_st_close !== false) && ($img_end !== false)) { + + $img_st_close++; // make it point to AFTER the closing bracket + $img_end += $img_start; + + if(! strcmp(substr($orig_body, $img_start + $img_st_close, 5), 'data:')) { + // This is an embedded image + + $saved_image[$cnt] = substr($orig_body, $img_start + $img_st_close, $img_end - ($img_start + $img_st_close)); + $new_body = $new_body . substr($orig_body, 0, $img_start) . '[$#saved_image' . $cnt . '#$]'; + + $cnt++; + } + else + $new_body = $new_body . substr($orig_body, 0, $img_end + strlen('[/img]')); + + $orig_body = substr($orig_body, $img_end + strlen('[/img]')); + + if($orig_body === false) // in case the body ends on a closing image tag + $orig_body = ''; + + $img_start = strpos($orig_body, '[img'); + $img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false); + $img_end = ($img_start !== false ? strpos(substr($orig_body, $img_start), '[/img]') : false); + } + + $new_body = $new_body . $orig_body; + + return array('body' => $new_body, 'images' => $saved_image); +}} + +if(! function_exists('bb_replace_images')) { +function bb_replace_images($body, $images) { + + $newbody = $body; + + $cnt = 0; + foreach($images as $image) { + // We're depending on the property of 'foreach' (specified on the PHP website) that + // it loops over the array starting from the first element and going sequentially + // to the last element + $newbody = str_replace('[$#saved_image' . $cnt . '#$]', '' . t('Image/photo') . '', $newbody); + $cnt++; + } + + return $newbody; +}} + + + // BBcode 2 HTML was written by WAY2WEB.net // extended to work with Mistpark/Friendica - Mike Macgirvin @@ -54,29 +115,21 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true) { $a = get_app(); - // Hide all [noparse] contained bbtags spacefying them + // Hide all [noparse] contained bbtags by spacefying them + // POSSIBLE BUG --> Will the 'preg' functions crash if there's an embedded image? $Text = preg_replace_callback("/\[noparse\](.*?)\[\/noparse\]/ism", 'bb_spacefy',$Text); $Text = preg_replace_callback("/\[nobb\](.*?)\[\/nobb\]/ism", 'bb_spacefy',$Text); $Text = preg_replace_callback("/\[pre\](.*?)\[\/pre\]/ism", 'bb_spacefy',$Text); - // Extract a single private image which uses data url's since preg has issues with - // large data sizes. Stash it away while we do bbcode conversion, and then put it back + // Extract the private images which use data url's since preg has issues with + // large data sizes. Stash them away while we do bbcode conversion, and then put them back // in after we've done all the regex matching. We cannot use any preg functions to do this. - $saved_image = ''; - $img_start = strpos($Text,'[img]data:'); - $img_end = strpos($Text,'[/img]'); - - if($img_start !== false && $img_end !== false && $img_end > $img_start) { - $start_fragment = substr($Text,0,$img_start); - $img_start += strlen('[img]'); - $saved_image = substr($Text,$img_start,$img_end - $img_start); - $end_fragment = substr($Text,$img_end + strlen('[/img]')); -// logger('saved_image: ' . $saved_image,LOGGER_DEBUG); - $Text = $start_fragment . '[$#saved_image#$]' . $end_fragment; - } + $extracted = bb_extract_images($Text); + $Text = $extracted['body']; + $saved_image = $extracted['images']; // If we find any event code, turn it into an event. // After we're finished processing the bbcode we'll @@ -93,11 +146,19 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true) { // Convert new line chars to html
    tags - $Text = nl2br($Text); + // nlbr seems to be hopelessly messed up + // $Text = nl2br($Text); + + // We'll emulate it. + + $Text = str_replace("\r\n","\n", $Text); + $Text = str_replace(array("\r","\n"), array('
    ','
    '), $Text); + if($preserve_nl) $Text = str_replace(array("\n","\r"), array('',''),$Text); + // Set up the parameters for a URL search string $URLSearchString = "^\[\]"; // Set up the parameters for a MAIL search string @@ -158,14 +219,14 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true) { // Check for list text $Text = str_replace("[*]", "
  • ", $Text); - $Text = preg_replace("/\[li\](.*?)\[\/li\]/ism", '
  • $1
  • ' ,$Text); // handle nested lists $endlessloop = 0; while ((((strpos($Text, "[/list]") !== false) && (strpos($Text, "[list") !== false)) || ((strpos($Text, "[/ol]") !== false) && (strpos($Text, "[ol]") !== false)) || - ((strpos($Text, "[/ul]") !== false) && (strpos($Text, "[ul]") !== false))) && (++$endlessloop < 20)) { + ((strpos($Text, "[/ul]") !== false) && (strpos($Text, "[ul]") !== false)) || + ((strpos($Text, "[/li]") !== false) && (strpos($Text, "[li]") !== false))) && (++$endlessloop < 20)) { $Text = preg_replace("/\[list\](.*?)\[\/list\]/ism", '' ,$Text); $Text = preg_replace("/\[list=\](.*?)\[\/list\]/ism", '' ,$Text); $Text = preg_replace("/\[list=1\](.*?)\[\/list\]/ism", '' ,$Text); @@ -175,6 +236,7 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true) { $Text = preg_replace("/\[list=((?-i)A)\](.*?)\[\/list\]/ism", '' ,$Text); $Text = preg_replace("/\[ul\](.*?)\[\/ul\]/ism", '' ,$Text); $Text = preg_replace("/\[ol\](.*?)\[\/ol\]/ism", '' ,$Text); + $Text = preg_replace("/\[li\](.*?)\[\/li\]/ism", '
  • $1
  • ' ,$Text); } $Text = preg_replace("/\[th\](.*?)\[\/th\]/sm", '$1' ,$Text); @@ -196,7 +258,7 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true) { // Declare the format for [code] layout - $Text = preg_replace_callback("/\[code\](.*?)\[\/code\]/ism",'stripcode_br_cb',$Text); +// $Text = preg_replace_callback("/\[code\](.*?)\[\/code\]/ism",'stripcode_br_cb',$Text); $CodeLayout = '$1'; // Check for [code] text @@ -335,8 +397,9 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true) { // fix any escaped ampersands that may have been converted into links $Text = preg_replace("/\<(.*?)(src|href)=(.*?)\&\;(.*?)\>/ism",'<$1$2=$3&$4>',$Text); - if(strlen($saved_image)) - $Text = str_replace('[$#saved_image#$]','' . t('Image/photo') . '',$Text); + + if($saved_image) + $Text = bb_replace_images($Text, $saved_image); // Clean up the HTML by loading and saving the HTML with the DOM // Only do it when it has to be done - for performance reasons diff --git a/include/conversation.php b/include/conversation.php index f2fb2e97b4..6c3f13477f 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -1,30 +1,91 @@ $new_body, 'images' => $saved_image); +}} + +if(! function_exists('item_redir_and_replace_images')) { +function item_redir_and_replace_images($body, $images, $cid) { + + $origbody = $body; + $newbody = ''; + + for($i = 0; $i < count($images); $i++) { + $search = '/\[url\=(.*?)\]\[!#saved_image' . $i . '#!\]\[\/url\]' . '/is'; + $replace = '[url=' . z_path() . '/redir/' . $cid + . '?f=1&url=' . '$1' . '][!#saved_image' . $i . '#!][/url]' ; + + $img_end = strpos($origbody, '[!#saved_image' . $i . '#!][/url]') + strlen('[!#saved_image' . $i . '#!][/url]'); + $process_part = substr($origbody, 0, $img_end); + $origbody = substr($origbody, $img_end); + + $process_part = preg_replace($search, $replace, $process_part); + $newbody = $newbody . $process_part; + } + $newbody = $newbody . $origbody; + + $cnt = 0; + foreach($images as $image) { + // We're depending on the property of 'foreach' (specified on the PHP website) that + // it loops over the array starting from the first element and going sequentially + // to the last element + $newbody = str_replace('[!#saved_image' . $cnt . '#!]', '[img]' . $image . '[/img]', $newbody); + $cnt++; + } + return $newbody; +}} + + + /** * Render actions localized */ function localize_item(&$item){ - $Text = $item['body']; - $saved_image = ''; - $img_start = strpos($Text,'[img]data:'); - $img_end = strpos($Text,'[/img]'); - - if($img_start !== false && $img_end !== false && $img_end > $img_start) { - $start_fragment = substr($Text,0,$img_start); - $img_start += strlen('[img]'); - $saved_image = substr($Text,$img_start,$img_end - $img_start); - $end_fragment = substr($Text,$img_end + strlen('[/img]')); - $Text = $start_fragment . '[!#saved_image#!]' . $end_fragment; - $search = '/\[url\=(.*?)\]\[!#saved_image#!\]\[\/url\]' . '/is'; - $replace = '[url=' . z_path() . '/redir/' . $item['contact-id'] - . '?f=1&url=' . '$1' . '][!#saved_image#!][/url]' ; - - $Text = preg_replace($search,$replace,$Text); - - if(strlen($saved_image)) - $item['body'] = str_replace('[!#saved_image#!]', '[img]' . $saved_image . '[/img]',$Text); - } + $extracted = item_extract_images($item['body']); + if($extracted['images']) + $item['body'] = item_redir_and_replace_images($extracted['body'], $extracted['images'], $item['contact-id']); $xmlhead="<"."?xml version='1.0' encoding='UTF-8' ?".">"; if ($item['verb']=== ACTIVITY_LIKE || $item['verb']=== ACTIVITY_DISLIKE){ @@ -173,6 +234,7 @@ function localize_item(&$item){ $item['body'] = str_replace($mtch[0],'@[url=' . zrl($mtch[1]). ']',$item['body']); } } + // add zrl's to public images if(preg_match_all('/\[url=(.*?)\/photos\/(.*?)\/image\/(.*?)\]\[img(.*?)\]h(.*?)\[\/img\]\[\/url\]/is',$item['body'],$matches,PREG_SET_ORDER)) { foreach($matches as $mtch) { @@ -180,6 +242,17 @@ function localize_item(&$item){ } } + // add sparkle links to appropriate permalinks + + $x = stristr($item['plink'],'/display/'); + if($x) { + $sparkle = false; + $y = best_link_url($item,$sparkle,true); + if(strstr($y,'/redir/')) + $item['plink'] = $y . '?f=&url=' . $item['plink']; + } + + } @@ -546,7 +619,7 @@ function conversation(&$a, $items, $mode, $update, $preview = false) { } $likebuttons = ''; - $shareable = ((($profile_owner == local_user()) && (! $item['private'] == 1)) ? true : false); + $shareable = ((($profile_owner == local_user()) && ($item['private'] != 1)) ? true : false); if($page_writeable) { /* if($toplevelpost) { */ diff --git a/include/crypto.php b/include/crypto.php index 6fc9a287e4..ed0a35704e 100644 --- a/include/crypto.php +++ b/include/crypto.php @@ -261,39 +261,6 @@ function aes_unencapsulate($data,$prvkey) { return AES256CBC_decrypt(base64url_decode($data['data']),$k,$i); } - -// This has been superceded. - -function zot_encapsulate($data,$envelope,$pubkey) { -$res = aes_encapsulate($data,$pubkey); - -return <<< EOT - - - {$res['key']} - {$res['iv']} - $s1 - $sig - AES-256-CBC - {$res['data']} - -EOT; - -} - -// so has this - -function zot_unencapsulate($data,$prvkey) { - $ret = array(); - $c = array(); - $x = parse_xml_string($data); - $c = array('key' => $x->key,'iv' => $x->iv,'data' => $x->data); - openssl_private_decrypt(base64url_decode($x->sender),$s,$prvkey); - $ret['sender'] = $s; - $ret['data'] = aes_unencapsulate($x,$prvkey); - return $ret; -} - function new_keypair($bits) { $openssl_options = array( diff --git a/include/dba.php b/include/dba.php index d37b756aee..879d7e67e1 100644 --- a/include/dba.php +++ b/include/dba.php @@ -285,3 +285,9 @@ function dbesc_array(&$arr) { array_walk($arr,'dbesc_array_cb'); } }} + + +function dba_timer() { + return microtime(true); +} + diff --git a/include/diaspora.php b/include/diaspora.php index a398007e19..af9a91f028 100755 --- a/include/diaspora.php +++ b/include/diaspora.php @@ -5,6 +5,7 @@ require_once('include/items.php'); require_once('include/bb2diaspora.php'); require_once('include/contact_selectors.php'); require_once('include/queue_fn.php'); +require_once('include/lock.php'); function diaspora_dispatch_public($msg) { @@ -60,10 +61,10 @@ function diaspora_dispatch($importer,$msg) { $ret = diaspora_request($importer,$xmlbase->request); } elseif($xmlbase->status_message) { - $ret = diaspora_post($importer,$xmlbase->status_message); + $ret = diaspora_post($importer,$xmlbase->status_message,$msg); } elseif($xmlbase->profile) { - $ret = diaspora_profile($importer,$xmlbase->profile); + $ret = diaspora_profile($importer,$xmlbase->profile,$msg); } elseif($xmlbase->comment) { $ret = diaspora_comment($importer,$xmlbase->comment,$msg); @@ -72,10 +73,10 @@ function diaspora_dispatch($importer,$msg) { $ret = diaspora_like($importer,$xmlbase->like,$msg); } elseif($xmlbase->asphoto) { - $ret = diaspora_asphoto($importer,$xmlbase->asphoto); + $ret = diaspora_asphoto($importer,$xmlbase->asphoto,$msg); } elseif($xmlbase->reshare) { - $ret = diaspora_reshare($importer,$xmlbase->reshare); + $ret = diaspora_reshare($importer,$xmlbase->reshare,$msg); } elseif($xmlbase->retraction) { $ret = diaspora_retraction($importer,$xmlbase->retraction,$msg); @@ -113,27 +114,93 @@ function diaspora_get_contact_by_handle($uid,$handle) { } function find_diaspora_person_by_handle($handle) { + + $person = false; $update = false; - $r = q("select * from fcontact where network = '%s' and addr = '%s' limit 1", - dbesc(NETWORK_DIASPORA), - dbesc($handle) - ); - if(count($r)) { - logger('find_diaspora_person_by handle: in cache ' . print_r($r,true), LOGGER_DEBUG); - // update record occasionally so it doesn't get stale - $d = strtotime($r[0]['updated'] . ' +00:00'); - if($d > strtotime('now - 14 days')) - return $r[0]; - $update = true; - } - logger('find_diaspora_person_by_handle: refresh',LOGGER_DEBUG); - require_once('include/Scrape.php'); - $r = probe_url($handle, PROBE_DIASPORA); - if((count($r)) && ($r['network'] === NETWORK_DIASPORA)) { - add_fcontact($r,$update); - return ($r); - } - return false; + $got_lock = false; + + $endlessloop = 0; + $maxloops = 10; + + do { + $r = q("select * from fcontact where network = '%s' and addr = '%s' limit 1", + dbesc(NETWORK_DIASPORA), + dbesc($handle) + ); + if(count($r)) { + $person = $r[0]; + logger('find_diaspora_person_by handle: in cache ' . print_r($r,true), LOGGER_DEBUG); + + // update record occasionally so it doesn't get stale + $d = strtotime($person['updated'] . ' +00:00'); + if($d < strtotime('now - 14 days')) + $update = true; + } + + + // FETCHING PERSON INFORMATION FROM REMOTE SERVER + // + // If the person isn't in our 'fcontact' table, or if he/she is but + // his/her information hasn't been updated for more than 14 days, then + // we want to fetch the person's information from the remote server. + // + // Note that $person isn't changed by this block of code unless the + // person's information has been successfully fetched from the remote + // server. So if $person was 'false' to begin with (because he/she wasn't + // in the local cache), it'll stay false, and if $person held the local + // cache information to begin with, it'll keep that information. That way + // if there's a problem with the remote fetch, we can at least use our + // cached information--it's better than nothing. + + if((! $person) || ($update)) { + // Lock the function to prevent race conditions if multiple items + // come in at the same time from a person who doesn't exist in + // fcontact + // + // Don't loop forever. On the last loop, try to create the contact + // whether the function is locked or not. Maybe the locking thread + // has died or something. At any rate, a duplicate in 'fcontact' + // is a much smaller problem than a deadlocked thread + $got_lock = lock_function('find_diaspora_person_by_handle', false); + if(($endlessloop + 1) >= $maxloops) + $got_lock = true; + + if($got_lock) { + logger('find_diaspora_person_by_handle: create or refresh', LOGGER_DEBUG); + require_once('include/Scrape.php'); + $r = probe_url($handle, PROBE_DIASPORA); + + // Note that Friendica contacts can return a "Diaspora person" + // if Diaspora connectivity is enabled on their server + if((count($r)) && ($r['network'] === NETWORK_DIASPORA)) { + add_fcontact($r,$update); + $person = ($r); + } + + unlock_function('find_diaspora_person_by_handle'); + } + else { + logger('find_diaspora_person_by_handle: couldn\'t lock function', LOGGER_DEBUG); + if(! $person) + block_on_function_lock('find_diaspora_person_by_handle'); + } + } + } while((! $person) && (! $got_lock) && (++$endlessloop < $maxloops)); + // We need to try again if the person wasn't in 'fcontact' but the function was locked. + // The fact that the function was locked may mean that another process was creating the + // person's record. It could also mean another process was creating or updating an unrelated + // person. + // + // At any rate, we need to keep trying until we've either got the person or had a chance to + // try to fetch his/her remote information. But we don't want to block on locking the + // function, because if the other process is creating the record, then when we acquire the lock + // we'll dive right into creating another, duplicate record. We DO want to at least wait + // until the lock is released, so we don't flood the database with requests. + // + // If the person was in the 'fcontact' table, don't try again. It's not worth the time, since + // we do have some information for the person + + return $person; } @@ -654,12 +721,17 @@ function diaspora_post_allow($importer,$contact) { } -function diaspora_post($importer,$xml) { +function diaspora_post($importer,$xml,$msg) { $a = get_app(); $guid = notags(unxmlify($xml->guid)); $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); + if($diaspora_handle != $msg['author']) { + logger('diaspora_post: Potential forgery. Message handle is not the same as envelope sender.'); + return 202; + } + $contact = diaspora_get_contact_by_handle($importer['uid'],$diaspora_handle); if(! $contact) return; @@ -770,7 +842,7 @@ function diaspora_post($importer,$xml) { } -function diaspora_reshare($importer,$xml) { +function diaspora_reshare($importer,$xml,$msg) { logger('diaspora_reshare: init: ' . print_r($xml,true)); @@ -779,6 +851,11 @@ function diaspora_reshare($importer,$xml) { $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); + if($diaspora_handle != $msg['author']) { + logger('diaspora_post: Potential forgery. Message handle is not the same as envelope sender.'); + return 202; + } + $contact = diaspora_get_contact_by_handle($importer['uid'],$diaspora_handle); if(! $contact) return; @@ -844,7 +921,7 @@ function diaspora_reshare($importer,$xml) { else $details = $orig_author; - $prefix = '♲ ' . $details . "\n"; + $prefix = html_entity_decode("♲ ", ENT_QUOTES, 'UTF-8') . $details . "\n"; // allocate a guid on our system - we aren't fixing any collisions. @@ -924,13 +1001,18 @@ function diaspora_reshare($importer,$xml) { } -function diaspora_asphoto($importer,$xml) { +function diaspora_asphoto($importer,$xml,$msg) { logger('diaspora_asphoto called'); $a = get_app(); $guid = notags(unxmlify($xml->guid)); $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); + if($diaspora_handle != $msg['author']) { + logger('diaspora_post: Potential forgery. Message handle is not the same as envelope sender.'); + return 202; + } + $contact = diaspora_get_contact_by_handle($importer['uid'],$diaspora_handle); if(! $contact) return; @@ -1154,6 +1236,7 @@ function diaspora_comment($importer,$xml,$msg) { $datarray['uid'] = $importer['uid']; $datarray['contact-id'] = $contact['id']; + $datarray['type'] = 'remote-comment'; $datarray['wall'] = $parent_item['wall']; $datarray['gravity'] = GRAVITY_COMMENT; $datarray['guid'] = $guid; @@ -1190,7 +1273,7 @@ function diaspora_comment($importer,$xml,$msg) { if(($parent_item['origin']) && (! $parent_author_signature)) { q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", intval($message_id), - dbesc($author_signed_data), + dbesc($signed_data), dbesc(base64_encode($author_signature)), dbesc($diaspora_handle) ); @@ -1591,8 +1674,8 @@ function diaspora_like($importer,$xml,$msg) { // likes on comments not supported here and likes on photos not supported by Diaspora - if($target_type !== 'Post') - return; +// if($target_type !== 'Post') +// return; $contact = diaspora_get_contact_by_handle($importer['uid'],$msg['author']); if(! $contact) { @@ -1773,7 +1856,7 @@ EOT; if(! $parent_author_signature) { q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", intval($message_id), - dbesc($author_signed_data), + dbesc($signed_data), dbesc(base64_encode($author_signature)), dbesc($diaspora_handle) ); @@ -1923,11 +2006,17 @@ function diaspora_signed_retraction($importer,$xml,$msg) { // NOTREACHED } -function diaspora_profile($importer,$xml) { +function diaspora_profile($importer,$xml,$msg) { $a = get_app(); $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); + + if($diaspora_handle != $msg['author']) { + logger('diaspora_post: Potential forgery. Message handle is not the same as envelope sender.'); + return 202; + } + $contact = diaspora_get_contact_by_handle($importer['uid'],$diaspora_handle); if(! $contact) return; @@ -2165,22 +2254,30 @@ function diaspora_send_followup($item,$owner,$contact,$public_batch = false) { $myaddr = $owner['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3); // $theiraddr = $contact['addr']; - // The first item in the `item` table with the parent id is the parent. However, MySQL doesn't always - // return the items ordered by `item`.`id`, in which case the wrong item is chosen as the parent. - // The only item with `parent` and `id` as the parent id is the parent item. - $p = q("select guid from item where parent = %d and id = %d limit 1", - intval($item['parent']), - intval($item['parent']) - ); + if($item['thr-parent']) { + $p = q("select guid, type, uri, `parent-uri` from item where uri = '%s' limit 1", + dbesc($item['thr-parent']) + ); + } + else { + // The first item in the `item` table with the parent id is the parent. However, MySQL doesn't always + // return the items ordered by `item`.`id`, in which case the wrong item is chosen as the parent. + // The only item with `parent` and `id` as the parent id is the parent item. + $p = q("select guid, type, uri, `parent-uri` from item where parent = %d and id = %d limit 1", + intval($item['parent']), + intval($item['parent']) + ); + } if(count($p)) - $parent_guid = $p[0]['guid']; + $parent = $p[0]; else return; if($item['verb'] === ACTIVITY_LIKE) { $tpl = get_markup_template('diaspora_like.tpl'); $like = true; - $target_type = 'Post'; + $target_type = ( $parent['uri'] === $parent['parent-uri'] ? 'Post' : 'Comment'); +// $target_type = (strpos($parent['type'], 'comment') ? 'Comment' : 'Post'); // $positive = (($item['deleted']) ? 'false' : 'true'); $positive = 'true'; @@ -2197,15 +2294,15 @@ function diaspora_send_followup($item,$owner,$contact,$public_batch = false) { // sign it if($like) - $signed_text = $item['guid'] . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $myaddr; + $signed_text = $item['guid'] . ';' . $target_type . ';' . $parent['guid'] . ';' . $positive . ';' . $myaddr; else - $signed_text = $item['guid'] . ';' . $parent_guid . ';' . $text . ';' . $myaddr; + $signed_text = $item['guid'] . ';' . $parent['guid'] . ';' . $text . ';' . $myaddr; $authorsig = base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256')); $msg = replace_macros($tpl,array( '$guid' => xmlify($item['guid']), - '$parent_guid' => xmlify($parent_guid), + '$parent_guid' => xmlify($parent['guid']), '$target_type' =>xmlify($target_type), '$authorsig' => xmlify($authorsig), '$body' => xmlify($text), @@ -2233,15 +2330,22 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { $text = html_entity_decode(bb2diaspora($body)); - // The first item in the `item` table with the parent id is the parent. However, MySQL doesn't always - // return the items ordered by `item`.`id`, in which case the wrong item is chosen as the parent. - // The only item with `parent` and `id` as the parent id is the parent item. - $p = q("select guid from item where parent = %d and id = %d limit 1", - intval($item['parent']), - intval($item['parent']) - ); + if($item['thr-parent']) { + $p = q("select guid, type, uri, `parent-uri` from item where uri = '%s' limit 1", + dbesc($item['thr-parent']) + ); + } + else { + // The first item in the `item` table with the parent id is the parent. However, MySQL doesn't always + // return the items ordered by `item`.`id`, in which case the wrong item is chosen as the parent. + // The only item with `parent` and `id` as the parent id is the parent item. + $p = q("select guid, type, uri, `parent-uri` from item where parent = %d and id = %d limit 1", + intval($item['parent']), + intval($item['parent']) + ); + } if(count($p)) - $parent_guid = $p[0]['guid']; + $parent = $p[0]; else return; @@ -2259,7 +2363,8 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { elseif($item['verb'] === ACTIVITY_LIKE) { $like = true; - $target_type = 'Post'; + $target_type = ( $parent['uri'] === $parent['parent-uri'] ? 'Post' : 'Comment'); +// $target_type = (strpos($parent['type'], 'comment') ? 'Comment' : 'Post'); // $positive = (($item['deleted']) ? 'false' : 'true'); $positive = 'true'; @@ -2294,9 +2399,9 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { if($relay_retract) $sender_signed_text = $item['guid'] . ';' . $target_type; elseif($like) - $sender_signed_text = $item['guid'] . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $handle; + $sender_signed_text = $item['guid'] . ';' . $target_type . ';' . $parent['guid'] . ';' . $positive . ';' . $handle; else - $sender_signed_text = $item['guid'] . ';' . $parent_guid . ';' . $text . ';' . $handle; + $sender_signed_text = $item['guid'] . ';' . $parent['guid'] . ';' . $text . ';' . $handle; // Sign the relayable with the top-level owner's signature // @@ -2313,7 +2418,7 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { $msg = replace_macros($tpl,array( '$guid' => xmlify($item['guid']), - '$parent_guid' => xmlify($parent_guid), + '$parent_guid' => xmlify($parent['guid']), '$target_type' =>xmlify($target_type), '$authorsig' => xmlify($authorsig), '$parentsig' => xmlify($parentauthorsig), @@ -2429,7 +2534,7 @@ function diaspora_send_mail($item,$owner,$contact) { } -function diaspora_transmit($owner,$contact,$slap,$public_batch) { +function diaspora_transmit($owner,$contact,$slap,$public_batch,$queue_run=false) { $enabled = intval(get_config('system','diaspora_enabled')); if(! $enabled) { @@ -2446,7 +2551,7 @@ function diaspora_transmit($owner,$contact,$slap,$public_batch) { logger('diaspora_transmit: ' . $logid . ' ' . $dest_url); - if(was_recently_delayed($contact['id'])) { + if( (! $queue_run) && (was_recently_delayed($contact['id'])) ) { $return_code = 0; } else { diff --git a/include/enotify.php b/include/enotify.php index 134e42f8e3..814bd06a4c 100644 --- a/include/enotify.php +++ b/include/enotify.php @@ -54,6 +54,20 @@ function notification($params) { $parent_id = $params['parent']; + // Check to see if there was already a tag notify for this post. + // If so don't create a second notification + + $p = null; + $p = q("select id from notify where type = %d and link = '%s' and uid = %d limit 1", + intval(NOTIFY_TAGSELF), + dbesc($params['link']), + intval($params['uid']) + ); + if($p and count($p)) { + pop_lang(); + return; + } + // if it's a post figure out who's post it is. @@ -110,9 +124,9 @@ function notification($params) { $preamble = sprintf( t('%1$s posted to your profile wall at %2$s') , $params['source_name'], $sitename); - $epreamble = sprintf( t('%1$s posted to [url=%2s]your wall[/url]') , + $epreamble = sprintf( t('%1$s posted to [url=%2$s]your wall[/url]') , '[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]', - $itemlink); + $params['link']); $sitelink = t('Please visit %s to view and/or reply to the conversation.'); $tsitelink = sprintf( $sitelink, $siteurl ); diff --git a/include/html2bbcode.php b/include/html2bbcode.php index 69ccf41b71..985c36eaa4 100644 --- a/include/html2bbcode.php +++ b/include/html2bbcode.php @@ -124,7 +124,7 @@ function html2bbcode($message) $node->nodeValue = str_replace("\n", "\r", $node->nodeValue); $message = $doc->saveHTML(); - $message = str_replace(array("\n<", ">\n", "\r", "\n", "\xC3\x82\xC2\xA0"), array("<", ">", "
    ", " ", ""), $message); + $message = str_replace(array("\n<", ">\n", "\r", "\n", "\xC3\x82\xC2\xA0"), array("<", ">", "
    ", " ", ""), $message); $message = preg_replace('= [\s]*=i', " ", $message); @$doc->loadHTML($message); diff --git a/include/items.php b/include/items.php index d888f314de..b81208f366 100755 --- a/include/items.php +++ b/include/items.php @@ -4,6 +4,8 @@ require_once('include/bbcode.php'); require_once('include/oembed.php'); require_once('include/salmon.php'); require_once('include/crypto.php'); +require_once('include/Photo.php'); + function get_feed_for(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) { @@ -278,7 +280,99 @@ function construct_activity_target($item) { } return ''; -} +} + +/* limit_body_size() + * + * The purpose of this function is to apply system message length limits to + * imported messages without including any embedded photos in the length + */ +if(! function_exists('limit_body_size')) { +function limit_body_size($body) { + + logger('limit_body_size: start', LOGGER_DEBUG); + + $maxlen = get_max_import_size(); + + // If the length of the body, including the embedded images, is smaller + // than the maximum, then don't waste time looking for the images + if($maxlen && (strlen($body) > $maxlen)) { + + logger('limit_body_size: the total body length exceeds the limit', LOGGER_DEBUG); + + $orig_body = $body; + $new_body = ''; + $textlen = 0; + $max_found = false; + + $img_start = strpos($orig_body, '[img'); + $img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false); + $img_end = ($img_start !== false ? strpos(substr($orig_body, $img_start), '[/img]') : false); + while(($img_st_close !== false) && ($img_end !== false)) { + + $img_st_close++; // make it point to AFTER the closing bracket + $img_end += $img_start; + $img_end += strlen('[/img]'); + + if(! strcmp(substr($orig_body, $img_start + $img_st_close, 5), 'data:')) { + // This is an embedded image + + if( ($textlen + $img_start) > $maxlen ) { + if($textlen < $maxlen) { + logger('limit_body_size: the limit happens before an embedded image', LOGGER_DEBUG); + $new_body = $new_body . substr($orig_body, 0, $maxlen - $textlen); + $textlen = $maxlen; + } + } + else { + $new_body = $new_body . substr($orig_body, 0, $img_start); + $textlen += $img_start; + } + + $new_body = $new_body . substr($orig_body, $img_start, $img_end - $img_start); + } + else { + + if( ($textlen + $img_end) > $maxlen ) { + if($textlen < $maxlen) { + logger('limit_body_size: the limit happens before the end of a non-embedded image', LOGGER_DEBUG); + $new_body = $new_body . substr($orig_body, 0, $maxlen - $textlen); + $textlen = $maxlen; + } + } + else { + $new_body = $new_body . substr($orig_body, 0, $img_end); + $textlen += $img_end; + } + } + $orig_body = substr($orig_body, $img_end); + + if($orig_body === false) // in case the body ends on a closing image tag + $orig_body = ''; + + $img_start = strpos($orig_body, '[img'); + $img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false); + $img_end = ($img_start !== false ? strpos(substr($orig_body, $img_start), '[/img]') : false); + } + + if( ($textlen + strlen($orig_body)) > $maxlen) { + if($textlen < $maxlen) { + logger('limit_body_size: the limit happens after the end of the last image', LOGGER_DEBUG); + $new_body = $new_body . substr($orig_body, 0, $maxlen - $textlen); + $textlen = $maxlen; + } + } + else { + logger('limit_body_size: the text size with embedded images extracted did not violate the limit', LOGGER_DEBUG); + $new_body = $new_body . $orig_body; + $textlen += strlen($orig_body); + } + + return $new_body; + } + else + return $body; +}} function title_is_body($title, $body) { @@ -442,9 +536,8 @@ function get_atom_elements($feed,$item) { $res['body'] = notags(base64url_decode($res['body'])); } - $maxlen = get_max_import_size(); - if($maxlen && (strlen($res['body']) > $maxlen)) - $res['body'] = substr($res['body'],0, $maxlen); + + $res['body'] = limit_body_size($res['body']); // It isn't certain at this point whether our content is plaintext or html and we'd be foolish to trust // the content type. Our own network only emits text normally, though it might have been converted to @@ -757,6 +850,12 @@ function item_store($arr,$force_parent = false) { if((strpos($arr['body'],'<') !== false) || (strpos($arr['body'],'>') !== false)) $arr['body'] = strip_tags($arr['body']); + require_once('Text/LanguageDetect.php'); + $naked_body = preg_replace('/\[(.+?)\]/','',$arr['body']); + $l = new Text_LanguageDetect; + $lng = $l->detectConfidence($naked_body); + $arr['postopts'] = (($lng['language']) ? 'lang=' . $lng['language'] . ';' . $lng['confidence'] : ''); + $arr['wall'] = ((x($arr,'wall')) ? intval($arr['wall']) : 0); $arr['uri'] = ((x($arr,'uri')) ? notags(trim($arr['uri'])) : random_string()); @@ -825,7 +924,7 @@ function item_store($arr,$force_parent = false) { if($r[0]['uri'] != $r[0]['parent-uri']) { $arr['thr-parent'] = $arr['parent-uri']; $arr['parent-uri'] = $r[0]['parent-uri']; - $z = q("SELECT `id` FROM `item` WHERE `uri` = '%s' AND `parent-uri` = '%s' AND `uid` = %d + $z = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `parent-uri` = '%s' AND `uid` = %d ORDER BY `id` ASC LIMIT 1", dbesc($r[0]['parent-uri']), dbesc($r[0]['parent-uri']), @@ -2304,7 +2403,8 @@ function local_delivery($importer,$data) { } if($item['uri'] == $item['parent-uri']) { - $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s' + $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s', + `body` = '', `title` = '' WHERE `parent-uri` = '%s' AND `uid` = %d", dbesc($when), dbesc(datetime_convert()), @@ -2313,7 +2413,8 @@ function local_delivery($importer,$data) { ); } else { - $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s' + $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s', + `body` = '', `title` = '' WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($when), dbesc(datetime_convert()), @@ -3119,20 +3220,33 @@ function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) { return $o; } -function fix_private_photos($s,$uid, $item = null, $cid = 0) { +function fix_private_photos($s, $uid, $item = null, $cid = 0) { $a = get_app(); logger('fix_private_photos', LOGGER_DEBUG); $site = substr($a->get_baseurl(),strpos($a->get_baseurl(),'://')); - if(preg_match("/\[img(.*?)\](.*?)\[\/img\]/is",$s,$matches)) { - $image = $matches[2]; + $orig_body = $s; + $new_body = ''; + + $img_start = strpos($orig_body, '[img'); + $img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false); + $img_len = ($img_start !== false ? strpos(substr($orig_body, $img_start + $img_st_close + 1), '[/img]') : false); + while( ($img_st_close !== false) && ($img_len !== false) ) { + + $img_st_close++; // make it point to AFTER the closing bracket + $image = substr($orig_body, $img_start + $img_st_close, $img_len); + logger('fix_private_photos: found photo ' . $image, LOGGER_DEBUG); + + if(stristr($image , $site . '/photo/')) { + // Only embed locally hosted photos $replace = false; $i = basename($image); $i = str_replace(array('.jpg','.png'),array('',''),$i); $x = strpos($i,'-'); + if($x) { $res = substr($i,$x+1); $i = substr($i,0,$x); @@ -3150,14 +3264,6 @@ function fix_private_photos($s,$uid, $item = null, $cid = 0) { // 3. Otherwise, if we have an item, see if the item permissions match the photo // permissions, regardless of order but first check to see if they're an exact // match to save some processing overhead. - - // Currently we only embed one private photo per message so as not to hit import - // size limits at the receiving end. - - // To embed multiples, we would need to parse out the embedded photos on message - // receipt and limit size based only on the text component. Would also need to - // ignore all photos during bbcode translation and item localisation, as these - // will hit internal regex backtrace limits. if(has_permissions($r[0])) { if($cid) { @@ -3172,15 +3278,45 @@ function fix_private_photos($s,$uid, $item = null, $cid = 0) { } } if($replace) { + $data = $r[0]['data']; + $type = $r[0]['type']; + + // If a custom width and height were specified, apply before embedding + if(preg_match("/\[img\=([0-9]*)x([0-9]*)\]/is", substr($orig_body, $img_start, $img_st_close), $match)) { + logger('fix_private_photos: scaling photo', LOGGER_DEBUG); + + $width = intval($match[1]); + $height = intval($match[2]); + + $ph = new Photo($data, $type); + if($ph->is_valid()) { + $ph->scaleImage(max($width, $height)); + $data = $ph->imageString(); + $type = $ph->getType(); + } + } + logger('fix_private_photos: replacing photo', LOGGER_DEBUG); - $s = str_replace($image, 'data:' . $r[0]['type'] . ';base64,' . base64_encode($r[0]['data']), $s); - logger('fix_private_photos: replaced: ' . $s, LOGGER_DATA); + $image = 'data:' . $type . ';base64,' . base64_encode($data); + logger('fix_private_photos: replaced: ' . $image, LOGGER_DATA); } } } } + + $new_body = $new_body . substr($orig_body, 0, $img_start + $img_st_close) . $image . '[/img]'; + $orig_body = substr($orig_body, $img_start + $img_st_close + $img_len + strlen('[/img]')); + if($orig_body === false) + $orig_body = ''; + + $img_start = strpos($orig_body, '[img'); + $img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false); + $img_len = ($img_start !== false ? strpos(substr($orig_body, $img_start + $img_st_close + 1), '[/img]') : false); } - return($s); + + $new_body = $new_body . $orig_body; + + return($new_body); } @@ -3524,7 +3660,9 @@ function posted_dates($uid,$wall) { $dnow = substr($dthen,0,8) . '28'; $ret = array(); - while($dnow >= $dthen) { + // Starting with the current month, get the first and last days of every + // month down to and including the month of the first post + while(substr($dnow, 0, 7) >= substr($dthen, 0, 7)) { $dstart = substr($dnow,0,8) . '01'; $dend = substr($dnow,0,8) . get_dim(intval($dnow),intval(substr($dnow,5))); $start_month = datetime_convert('','',$dstart,'Y-m-d'); @@ -3583,7 +3721,7 @@ function store_diaspora_retract_sig($item, $user, $baseurl) { } else { $r = q("SELECT `nick`, `url` FROM `contact` WHERE `id` = '%d' LIMIT 1", - $item['contact-id'] + $item['contact-id'] // If this function gets called, drop_item() has already checked remote_user() == $item['contact-id'] ); if(count($r)) { // The below handle only works for NETWORK_DFRN. I think that's ok, because this function diff --git a/include/lock.php b/include/lock.php new file mode 100644 index 0000000000..707e33609e --- /dev/null +++ b/include/lock.php @@ -0,0 +1,75 @@ +page['nav'] .= replace_macros($tpl, array( + '$baseurl' => $a->get_baseurl(), '$langselector' => lang_selector(), '$sitelocation' => $sitelocation, '$nav' => $nav, diff --git a/include/network.php b/include/network.php index d69454899a..a95dde535c 100644 --- a/include/network.php +++ b/include/network.php @@ -605,6 +605,9 @@ function validate_url(&$url) { if(! function_exists('validate_email')) { function validate_email($addr) { + if(get_config('system','disable_email_validation')) + return true; + if(! strpos($addr,'@')) return false; $h = substr($addr,strpos($addr,'@') + 1); diff --git a/include/queue.php b/include/queue.php index 7e92705be2..ba3babe70d 100644 --- a/include/queue.php +++ b/include/queue.php @@ -161,7 +161,7 @@ function queue_run($argv, $argc){ case NETWORK_DIASPORA: if($contact['notify']) { logger('queue: diaspora_delivery: item ' . $q_item['id'] . ' for ' . $contact['name']); - $deliver_status = diaspora_transmit($owner,$contact,$data,$public); + $deliver_status = diaspora_transmit($owner,$contact,$data,$public,true); if($deliver_status == (-1)) update_queue_time($q_item['id']); diff --git a/include/security.php b/include/security.php old mode 100755 new mode 100644 diff --git a/include/text.php b/include/text.php index 3b0050d387..409d40d59f 100644 --- a/include/text.php +++ b/include/text.php @@ -656,6 +656,10 @@ function search($s,$id='search-box',$url='/search',$save = false) { if(! function_exists('valid_email')) { function valid_email($x){ + + if(get_config('system','disable_email_validation')) + return true; + if(preg_match('/^[_a-zA-Z0-9\-\+]+(\.[_a-zA-Z0-9\-\+]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)+$/',$x)) return true; return false; @@ -1533,7 +1537,6 @@ function undo_post_tagging($s) { function fix_mce_lf($s) { $s = str_replace("\r\n","\n",$s); - $s = str_replace("\n\n","\n",$s); return $s; } diff --git a/include/user.php b/include/user.php index 383a3b3e1c..039b30bbd1 100644 --- a/include/user.php +++ b/include/user.php @@ -99,11 +99,11 @@ function create_user($arr) { if(! allowed_email($email)) - $result['message'] .= t('Your email domain is not among those allowed on this site.') . EOL; + $result['message'] .= t('Your email domain is not among those allowed on this site.') . EOL; if((! valid_email($email)) || (! validate_email($email))) $result['message'] .= t('Not a valid email address.') . EOL; - + // Disallow somebody creating an account using openid that uses the admin email address, // since openid bypasses email verification. We'll allow it if there is not yet an admin account. diff --git a/js/main.js b/js/main.js index 885e042aa3..a5ce894601 100644 --- a/js/main.js +++ b/js/main.js @@ -357,9 +357,9 @@ function dolike(ident,verb) { unpause(); $('#like-rotator-' + ident.toString()).show(); - $.get('like/' + ident.toString() + '?verb=' + verb ); - if(timer) clearTimeout(timer); - timer = setTimeout(NavUpdate,3000); + $.get('like/' + ident.toString() + '?verb=' + verb, NavUpdate ); +// if(timer) clearTimeout(timer); +// timer = setTimeout(NavUpdate,3000); liking = 1; } diff --git a/library/Smarty/COPYING.lib b/library/Smarty/COPYING.lib new file mode 100644 index 0000000000..02bbb60bc4 --- /dev/null +++ b/library/Smarty/COPYING.lib @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. \ No newline at end of file diff --git a/library/Smarty/README b/library/Smarty/README new file mode 100644 index 0000000000..167462823f --- /dev/null +++ b/library/Smarty/README @@ -0,0 +1,574 @@ +Smarty 3.1.11 + +Author: Monte Ohrt +Author: Uwe Tews + +AN INTRODUCTION TO SMARTY 3 + +NOTICE FOR 3.1 release: + +Please see the SMARTY_3.1_NOTES.txt file that comes with the distribution. + +NOTICE for 3.0.5 release: + +Smarty now follows the PHP error_reporting level by default. If PHP does not mask E_NOTICE and you try to access an unset template variable, you will now get an E_NOTICE warning. To revert to the old behavior: + +$smarty->error_reporting = E_ALL & ~E_NOTICE; + +NOTICE for 3.0 release: + +IMPORTANT: Some API adjustments have been made between the RC4 and 3.0 release. +We felt it is better to make these now instead of after a 3.0 release, then have to +immediately deprecate APIs in 3.1. Online documentation has been updated +to reflect these changes. Specifically: + +---- API CHANGES RC4 -> 3.0 ---- + +$smarty->register->* +$smarty->unregister->* +$smarty->utility->* +$samrty->cache->* + +Have all been changed to local method calls such as: + +$smarty->clearAllCache() +$smarty->registerFoo() +$smarty->unregisterFoo() +$smarty->testInstall() +etc. + +Registration of function, block, compiler, and modifier plugins have been +consolidated under two API calls: + +$smarty->registerPlugin(...) +$smarty->unregisterPlugin(...) + +Registration of pre, post, output and variable filters have been +consolidated under two API calls: + +$smarty->registerFilter(...) +$smarty->unregisterFilter(...) + +Please refer to the online documentation for all specific changes: + +http://www.smarty.net/documentation + +---- + +The Smarty 3 API has been refactored to a syntax geared +for consistency and modularity. The Smarty 2 API syntax is still supported, but +will throw a deprecation notice. You can disable the notices, but it is highly +recommended to adjust your syntax to Smarty 3, as the Smarty 2 syntax must run +through an extra rerouting wrapper. + +Basically, all Smarty methods now follow the "fooBarBaz" camel case syntax. Also, +all Smarty properties now have getters and setters. So for example, the property +$smarty->cache_dir can be set with $smarty->setCacheDir('foo/') and can be +retrieved with $smarty->getCacheDir(). + +Some of the Smarty 3 APIs have been revoked such as the "is*" methods that were +just duplicate functions of the now available "get*" methods. + +Here is a rundown of the Smarty 3 API: + +$smarty->fetch($template, $cache_id = null, $compile_id = null, $parent = null) +$smarty->display($template, $cache_id = null, $compile_id = null, $parent = null) +$smarty->isCached($template, $cache_id = null, $compile_id = null) +$smarty->createData($parent = null) +$smarty->createTemplate($template, $cache_id = null, $compile_id = null, $parent = null) +$smarty->enableSecurity() +$smarty->disableSecurity() +$smarty->setTemplateDir($template_dir) +$smarty->addTemplateDir($template_dir) +$smarty->templateExists($resource_name) +$smarty->loadPlugin($plugin_name, $check = true) +$smarty->loadFilter($type, $name) +$smarty->setExceptionHandler($handler) +$smarty->addPluginsDir($plugins_dir) +$smarty->getGlobal($varname = null) +$smarty->getRegisteredObject($name) +$smarty->getDebugTemplate() +$smarty->setDebugTemplate($tpl_name) +$smarty->assign($tpl_var, $value = null, $nocache = false) +$smarty->assignGlobal($varname, $value = null, $nocache = false) +$smarty->assignByRef($tpl_var, &$value, $nocache = false) +$smarty->append($tpl_var, $value = null, $merge = false, $nocache = false) +$smarty->appendByRef($tpl_var, &$value, $merge = false) +$smarty->clearAssign($tpl_var) +$smarty->clearAllAssign() +$smarty->configLoad($config_file, $sections = null) +$smarty->getVariable($variable, $_ptr = null, $search_parents = true, $error_enable = true) +$smarty->getConfigVariable($variable) +$smarty->getStreamVariable($variable) +$smarty->getConfigVars($varname = null) +$smarty->clearConfig($varname = null) +$smarty->getTemplateVars($varname = null, $_ptr = null, $search_parents = true) +$smarty->clearAllCache($exp_time = null, $type = null) +$smarty->clearCache($template_name, $cache_id = null, $compile_id = null, $exp_time = null, $type = null) + +$smarty->registerPlugin($type, $tag, $callback, $cacheable = true, $cache_attr = array()) + +$smarty->registerObject($object_name, $object_impl, $allowed = array(), $smarty_args = true, $block_methods = array()) + +$smarty->registerFilter($type, $function_name) +$smarty->registerResource($resource_type, $function_names) +$smarty->registerDefaultPluginHandler($function_name) +$smarty->registerDefaultTemplateHandler($function_name) + +$smarty->unregisterPlugin($type, $tag) +$smarty->unregisterObject($object_name) +$smarty->unregisterFilter($type, $function_name) +$smarty->unregisterResource($resource_type) + +$smarty->compileAllTemplates($extention = '.tpl', $force_compile = false, $time_limit = 0, $max_errors = null) +$smarty->clearCompiledTemplate($resource_name = null, $compile_id = null, $exp_time = null) +$smarty->testInstall() + +// then all the getters/setters, available for all properties. Here are a few: + +$caching = $smarty->getCaching(); // get $smarty->caching +$smarty->setCaching(true); // set $smarty->caching +$smarty->setDeprecationNotices(false); // set $smarty->deprecation_notices +$smarty->setCacheId($id); // set $smarty->cache_id +$debugging = $smarty->getDebugging(); // get $smarty->debugging + + +FILE STRUCTURE + +The Smarty 3 file structure is similar to Smarty 2: + +/libs/ + Smarty.class.php +/libs/sysplugins/ + internal.* +/libs/plugins/ + function.mailto.php + modifier.escape.php + ... + +A lot of Smarty 3 core functionality lies in the sysplugins directory; you do +not need to change any files here. The /libs/plugins/ folder is where Smarty +plugins are located. You can add your own here, or create a separate plugin +directory, just the same as Smarty 2. You will still need to create your own +/cache/, /templates/, /templates_c/, /configs/ folders. Be sure /cache/ and +/templates_c/ are writable. + +The typical way to use Smarty 3 should also look familiar: + +require('Smarty.class.php'); +$smarty = new Smarty; +$smarty->assign('foo','bar'); +$smarty->display('index.tpl'); + + +However, Smarty 3 works completely different on the inside. Smarty 3 is mostly +backward compatible with Smarty 2, except for the following items: + +*) Smarty 3 is PHP 5 only. It will not work with PHP 4. +*) The {php} tag is disabled by default. Enable with $smarty->allow_php_tag=true. +*) Delimiters surrounded by whitespace are no longer treated as Smarty tags. + Therefore, { foo } will not compile as a tag, you must use {foo}. This change + Makes Javascript/CSS easier to work with, eliminating the need for {literal}. + This can be disabled by setting $smarty->auto_literal = false; +*) The Smarty 3 API is a bit different. Many Smarty 2 API calls are deprecated + but still work. You will want to update your calls to Smarty 3 for maximum + efficiency. + + +There are many things that are new to Smarty 3. Here are the notable items: + +LEXER/PARSER +============ + +Smarty 3 now uses a lexing tokenizer for its parser/compiler. Basically, this +means Smarty has some syntax additions that make life easier such as in-template +math, shorter/intuitive function parameter options, infinite function recursion, +more accurate error handling, etc. + + +WHAT IS NEW IN SMARTY TEMPLATE SYNTAX +===================================== + +Smarty 3 allows expressions almost anywhere. Expressions can include PHP +functions as long as they are not disabled by the security policy, object +methods and properties, etc. The {math} plugin is no longer necessary but +is still supported for BC. + +Examples: +{$x+$y} will output the sum of x and y. +{$foo = strlen($bar)} function in assignment +{assign var=foo value= $x+$y} in attributes +{$foo = myfunct( ($x+$y)*3 )} as function parameter +{$foo[$x+3]} as array index + +Smarty tags can be used as values within other tags. +Example: {$foo={counter}+3} + +Smarty tags can also be used inside double quoted strings. +Example: {$foo="this is message {counter}"} + +You can define arrays within templates. +Examples: +{assign var=foo value=[1,2,3]} +{assign var=foo value=['y'=>'yellow','b'=>'blue']} +Arrays can be nested. +{assign var=foo value=[1,[9,8],3]} + +There is a new short syntax supported for assigning variables. +Example: {$foo=$bar+2} + +You can assign a value to a specific array element. If the variable exists but +is not an array, it is converted to an array before the new values are assigned. +Examples: +{$foo['bar']=1} +{$foo['bar']['blar']=1} + +You can append values to an array. If the variable exists but is not an array, +it is converted to an array before the new values are assigned. +Example: {$foo[]=1} + +You can use a PHP-like syntax for accessing array elements, as well as the +original "dot" notation. +Examples: +{$foo[1]} normal access +{$foo['bar']} +{$foo['bar'][1]} +{$foo[$x+$x]} index may contain any expression +{$foo[$bar[1]]} nested index +{$foo[section_name]} smarty section access, not array access! + +The original "dot" notation stays, and with improvements. +Examples: +{$foo.a.b.c} => $foo['a']['b']['c'] +{$foo.a.$b.c} => $foo['a'][$b]['c'] with variable index +{$foo.a.{$b+4}.c} => $foo['a'][$b+4]['c'] with expression as index +{$foo.a.{$b.c}} => $foo['a'][$b['c']] with nested index + +note that { and } are used to address ambiguties when nesting the dot syntax. + +Variable names themselves can be variable and contain expressions. +Examples: +$foo normal variable +$foo_{$bar} variable name containing other variable +$foo_{$x+$y} variable name containing expressions +$foo_{$bar}_buh_{$blar} variable name with multiple segments +{$foo_{$x}} will output the variable $foo_1 if $x has a value of 1. + +Object method chaining is implemented. +Example: {$object->method1($x)->method2($y)} + +{for} tag added for looping (replacement for {section} tag): +{for $x=0, $y=count($foo); $x<$y; $x++} .... {/for} +Any number of statements can be used separated by comma as the first +inital expression at {for}. + +{for $x = $start to $end step $step} ... {/for}is in the SVN now . +You can use also +{for $x = $start to $end} ... {/for} +In this case the step value will be automaticall 1 or -1 depending on the start and end values. +Instead of $start and $end you can use any valid expression. +Inside the loop the following special vars can be accessed: +$x@iteration = number of iteration +$x@total = total number of iterations +$x@first = true on first iteration +$x@last = true on last iteration + + +The Smarty 2 {section} syntax is still supported. + +New shorter {foreach} syntax to loop over an array. +Example: {foreach $myarray as $var}...{/foreach} + +Within the foreach loop, properties are access via: + +$var@key foreach $var array key +$var@iteration foreach current iteration count (1,2,3...) +$var@index foreach current index count (0,1,2...) +$var@total foreach $var array total +$var@first true on first iteration +$var@last true on last iteration + +The Smarty 2 {foreach} tag syntax is still supported. + +NOTE: {$bar[foo]} still indicates a variable inside of a {section} named foo. +If you want to access an array element with index foo, you must use quotes +such as {$bar['foo']}, or use the dot syntax {$bar.foo}. + +while block tag is now implemented: +{while $foo}...{/while} +{while $x lt 10}...{/while} + +Direct access to PHP functions: +Just as you can use PHP functions as modifiers directly, you can now access +PHP functions directly, provided they are permitted by security settings: +{time()} + +There is a new {function}...{/function} block tag to implement a template function. +This enables reuse of code sequences like a plugin function. It can call itself recursively. +Template function must be called with the new {call name=foo...} tag. + +Example: + +Template file: +{function name=menu level=0} + +{/function} + +{$menu = ['item1','item2','item3' => ['item3-1','item3-2','item3-3' => + ['item3-3-1','item3-3-2']],'item4']} + +{call name=menu data=$menu} + + +Generated output: + * item1 + * item2 + * item3 + o item3-1 + o item3-2 + o item3-3 + + item3-3-1 + + item3-3-2 + * item4 + +The function tag itself must have the "name" attribute. This name is the tag +name when calling the function. The function tag may have any number of +additional attributes. These will be default settings for local variables. + +New {nocache} block function: +{nocache}...{/nocache} will declare a section of the template to be non-cached +when template caching is enabled. + +New nocache attribute: +You can declare variable/function output as non-cached with the nocache attribute. +Examples: + +{$foo nocache=true} +{$foo nocache} /* same */ + +{foo bar="baz" nocache=true} +{foo bar="baz" nocache} /* same */ + +{time() nocache=true} +{time() nocache} /* same */ + +Or you can also assign the variable in your script as nocache: +$smarty->assign('foo',$something,true); // third param is nocache setting +{$foo} /* non-cached */ + +$smarty.current_dir returns the directory name of the current template. + +You can use strings directly as templates with the "string" resource type. +Examples: +$smarty->display('string:This is my template, {$foo}!'); // php +{include file="string:This is my template, {$foo}!"} // template + + + +VARIABLE SCOPE / VARIABLE STORAGE +================================= + +In Smarty 2, all assigned variables were stored within the Smarty object. +Therefore, all variables assigned in PHP were accessible by all subsequent +fetch and display template calls. + +In Smarty 3, we have the choice to assign variables to the main Smarty object, +to user-created data objects, and to user-created template objects. +These objects can be chained. The object at the end of a chain can access all +variables belonging to that template and all variables within the parent objects. +The Smarty object can only be the root of a chain, but a chain can be isolated +from the Smarty object. + +All known Smarty assignment interfaces will work on the data and template objects. + +Besides the above mentioned objects, there is also a special storage area for +global variables. + +A Smarty data object can be created as follows: +$data = $smarty->createData(); // create root data object +$data->assign('foo','bar'); // assign variables as usual +$data->config_load('my.conf'); // load config file + +$data= $smarty->createData($smarty); // create data object having a parent link to +the Smarty object + +$data2= $smarty->createData($data); // create data object having a parent link to +the $data data object + +A template object can be created by using the createTemplate method. It has the +same parameter assignments as the fetch() or display() method. +Function definition: +function createTemplate($template, $cache_id = null, $compile_id = null, $parent = null) + +The first parameter can be a template name, a smarty object or a data object. + +Examples: +$tpl = $smarty->createTemplate('mytpl.tpl'); // create template object not linked to any parent +$tpl->assign('foo','bar'); // directly assign variables +$tpl->config_load('my.conf'); // load config file + +$tpl = $smarty->createTemplate('mytpl.tpl',$smarty); // create template having a parent link to the Smarty object +$tpl = $smarty->createTemplate('mytpl.tpl',$data); // create template having a parent link to the $data object + +The standard fetch() and display() methods will implicitly create a template object. +If the $parent parameter is not specified in these method calls, the template object +is will link back to the Smarty object as it's parent. + +If a template is called by an {include...} tag from another template, the +subtemplate links back to the calling template as it's parent. + +All variables assigned locally or from a parent template are accessible. If the +template creates or modifies a variable by using the {assign var=foo...} or +{$foo=...} tags, these new values are only known locally (local scope). When the +template exits, none of the new variables or modifications can be seen in the +parent template(s). This is same behavior as in Smarty 2. + +With Smarty 3, we can assign variables with a scope attribute which allows the +availablility of these new variables or modifications globally (ie in the parent +templates.) + +Possible scopes are local, parent, root and global. +Examples: +{assign var=foo value='bar'} // no scope is specified, the default 'local' +{$foo='bar'} // same, local scope +{assign var=foo value='bar' scope='local'} // same, local scope + +{assign var=foo value='bar' scope='parent'} // Values will be available to the parent object +{$foo='bar' scope='parent'} // (normally the calling template) + +{assign var=foo value='bar' scope='root'} // Values will be exported up to the root object, so they can +{$foo='bar' scope='root'} // be seen from all templates using the same root. + +{assign var=foo value='bar' scope='global'} // Values will be exported to global variable storage, +{$foo='bar' scope='global'} // they are available to any and all templates. + + +The scope attribute can also be attached to the {include...} tag. In this case, +the specified scope will be the default scope for all assignments within the +included template. + + +PLUGINS +======= + +Smarty3 are following the same coding rules as in Smarty2. +The only difference is that the template object is passed as additional third parameter. + +smarty_plugintype_name (array $params, object $smarty, object $template) + +The Smarty 2 plugins are still compatible as long as they do not make use of specific Smarty2 internals. + + +TEMPLATE INHERITANCE: +===================== + +With template inheritance you can define blocks, which are areas that can be +overriden by child templates, so your templates could look like this: + +parent.tpl: + + + {block name='title'}My site name{/block} + + +

    {block name='page-title'}Default page title{/block}

    +
    + {block name='content'} + Default content + {/block} +
    + + + +child.tpl: +{extends file='parent.tpl'} +{block name='title'} +Child title +{/block} + +grandchild.tpl: +{extends file='child.tpl'} +{block name='title'}Home - {$smarty.block.parent}{/block} +{block name='page-title'}My home{/block} +{block name='content'} + {foreach $images as $img} + {$img.description} + {/foreach} +{/block} + +We redefined all the blocks here, however in the title block we used {$smarty.block.parent}, +which tells Smarty to insert the default content from the parent template in its place. +The content block was overriden to display the image files, and page-title has also be +overriden to display a completely different title. + +If we render grandchild.tpl we will get this: + + + Home - Child title + + +

    My home

    +
    + image + image + image +
    + + + +NOTE: In the child templates everything outside the {extends} or {block} tag sections +is ignored. + +The inheritance tree can be as big as you want (meaning you can extend a file that +extends another one that extends another one and so on..), but be aware that all files +have to be checked for modifications at runtime so the more inheritance the more overhead you add. + +Instead of defining the parent/child relationships with the {extends} tag in the child template you +can use the resource as follow: + +$smarty->display('extends:parent.tpl|child.tpl|grandchild.tpl'); + +Child {block} tags may optionally have a append or prepend attribute. In this case the parent block content +is appended or prepended to the child block content. + +{block name='title' append} My title {/block} + + +PHP STREAMS: +============ + +(see online documentation) + +VARIBLE FILTERS: +================ + +(see online documentation) + + +STATIC CLASS ACCESS AND NAMESPACE SUPPORT +========================================= + +You can register a class with optional namespace for the use in the template like: + +$smarty->register->templateClass('foo','name\name2\myclass'); + +In the template you can use it like this: +{foo::method()} etc. + + +======================= + +Please look through it and send any questions/suggestions/etc to the forums. + +http://www.phpinsider.com/smarty-forum/viewtopic.php?t=14168 + +Monte and Uwe diff --git a/library/Smarty/SMARTY_2_BC_NOTES.txt b/library/Smarty/SMARTY_2_BC_NOTES.txt new file mode 100644 index 0000000000..79a2cb1b66 --- /dev/null +++ b/library/Smarty/SMARTY_2_BC_NOTES.txt @@ -0,0 +1,109 @@ += Known incompatibilities with Smarty 2 = + +== Syntax == + +Smarty 3 API has a new syntax. Much of the Smarty 2 syntax is supported +by a wrapper but deprecated. See the README that comes with Smarty 3 for more +information. + +The {$array|@mod} syntax has always been a bit confusing, where an "@" is required +to apply a modifier to an array instead of the individual elements. Normally you +always want the modifier to apply to the variable regardless of its type. In Smarty 3, +{$array|mod} and {$array|@mod} behave identical. It is safe to drop the "@" and the +modifier will still apply to the array. If you really want the modifier to apply to +each array element, you must loop the array in-template, or use a custom modifier that +supports array iteration. Most smarty functions already escape values where necessary +such as {html_options} + +== PHP Version == +Smarty 3 is PHP 5 only. It will not work with PHP 4. + +== {php} Tag == +The {php} tag is disabled by default. The use of {php} tags is +deprecated. It can be enabled with $smarty->allow_php_tag=true. + +But if you scatter PHP code which belongs together into several +{php} tags it may not work any longer. + +== Delimiters and whitespace == +Delimiters surrounded by whitespace are no longer treated as Smarty tags. +Therefore, { foo } will not compile as a tag, you must use {foo}. This change +Makes Javascript/CSS easier to work with, eliminating the need for {literal}. +This can be disabled by setting $smarty->auto_literal = false; + +== Unquoted Strings == +Smarty 2 was a bit more forgiving (and ambiguous) when it comes to unquoted strings +in parameters. Smarty3 is more restrictive. You can still pass strings without quotes +so long as they contain no special characters. (anything outside of A-Za-z0-9_) + +For example filename strings must be quoted + +{include file='path/foo.tpl'} + + +== Extending the Smarty class == +Smarty 3 makes use of the __construct method for initialization. If you are extending +the Smarty class, its constructor is not called implicitly if the your child class defines +its own constructor. In order to run Smarty's constructor, a call to parent::__construct() +within your child constructor is required. + + +class MySmarty extends Smarty { + function __construct() { + parent::__construct(); + + // your initialization code goes here + + } +} + + +== Autoloader == +Smarty 3 does register its own autoloader with spl_autoload_register. If your code has +an existing __autoload function then this function must be explicitly registered on +the __autoload stack. See http://us3.php.net/manual/en/function.spl-autoload-register.php +for further details. + +== Plugin Filenames == +Smarty 3 optionally supports the PHP spl_autoloader. The autoloader requires filenames +to be lower case. Because of this, Smarty plugin file names must also be lowercase. +In Smarty 2, mixed case file names did work. + +== Scope of Special Smarty Variables == +In Smarty 2 the special Smarty variables $smarty.section... and $smarty.foreach... +had global scope. If you had loops with the same name in subtemplates you could accidentally +overwrite values of parent template. + +In Smarty 3 these special Smarty variable have only local scope in the template which +is defining the loop. If you need their value in a subtemplate you have to pass them +as parameter. + +{include file='path/foo.tpl' index=$smarty.section.foo.index} + + +== SMARTY_RESOURCE_CHAR_SET == +Smarty 3 sets the constant SMARTY_RESOURCE_CHAR_SET to utf-8 as default template charset. +This is now used also on modifiers like escape as default charset. If your templates use +other charsets make sure that you define the constant accordingly. Otherwise you may not +get any output. + +== newline at {if} tags == +A \n was added to the compiled code of the {if},{else},{elseif},{/if} tags to get output of newlines as expected by the template source. +If one of the {if} tags is at the line end you will now get a newline in the HTML output. + +== trigger_error() == +The API function trigger_error() has been removed because it did just map to PHP trigger_error. +However it's still included in the Smarty2 API wrapper. + +== Smarty constants == +The constants +SMARTY_PHP_PASSTHRU +SMARTY_PHP_QUOTE +SMARTY_PHP_REMOVE +SMARTY_PHP_ALLOW +have been replaced with class constants +Smarty::PHP_PASSTHRU +Smarty::PHP_QUOTE +Smarty::PHP_REMOVE +Smarty::PHP_ALLOW + diff --git a/library/Smarty/SMARTY_3.0_BC_NOTES.txt b/library/Smarty/SMARTY_3.0_BC_NOTES.txt new file mode 100644 index 0000000000..fd8b540c26 --- /dev/null +++ b/library/Smarty/SMARTY_3.0_BC_NOTES.txt @@ -0,0 +1,24 @@ +== Smarty2 backward compatibility == +All Smarty2 specific API functions and deprecated functionallity has been moved +to the SmartyBC class. + +== {php} Tag == +The {php} tag is no longer available in the standard Smarty calls. +The use of {php} tags is deprecated and only available in the SmartyBC class. + +== {include_php} Tag == +The {include_php} tag is no longer available in the standard Smarty calls. +The use of {include_php} tags is deprecated and only available in the SmartyBC class. + +== php template resource == +The support of the php template resource is removed. + +== $cache_dir, $compile_dir, $config_dir, $template_dir access == +The mentioned properties can't be accessed directly any longer. You must use +corresponding getter/setters like addConfigDir(), setConfigDir(), getConfigDir() + +== obsolete Smarty class properties == +The following no longer used properties are removed: +$allow_php_tag +$allow_php_template +$deprecation_notices \ No newline at end of file diff --git a/library/Smarty/SMARTY_3.1_NOTES.txt b/library/Smarty/SMARTY_3.1_NOTES.txt new file mode 100644 index 0000000000..e56e56f67f --- /dev/null +++ b/library/Smarty/SMARTY_3.1_NOTES.txt @@ -0,0 +1,306 @@ +Smarty 3.1 Notes +================ + +Smarty 3.1 is a departure from 2.0 compatibility. Most notably, all +backward compatibility has been moved to a separate class file named +SmartyBC.class.php. If you require compatibility with 2.0, you will +need to use this class. + +Some differences from 3.0 are also present. 3.1 begins the journey of +requiring setters/getters for property access. So far this is only +implemented on the five directory properties: template_dir, +plugins_dir, configs_dir, compile_dir and cache_dir. These properties +are now protected, it is required to use the setters/getters instead. +That said, direct property access will still work, however slightly +slower since they will now fall through __set() and __get() and in +turn passed through the setter/getter methods. 3.2 will exhibit a full +list of setter/getter methods for all (currently) public properties, +so code-completion in your IDE will work as expected. + +There is absolutely no PHP allowed in templates any more. All +deprecated features of Smarty 2.0 are gone. Again, use the SmartyBC +class if you need any backward compatibility. + +Internal Changes + + Full UTF-8 Compatibility + +The plugins shipped with Smarty 3.1 have been rewritten to fully +support UTF-8 strings if Multibyte String is available. Without +MBString UTF-8 cannot be handled properly. For those rare cases where +templates themselves have to juggle encodings, the new modifiers +to_charset and from_charset may come in handy. + + Plugin API and Performance + +All Plugins (modifiers, functions, blocks, resources, +default_template_handlers, etc) are now receiving the +Smarty_Internal_Template instance, where they were supplied with the +Smarty instance in Smarty 3.0. *. As The Smarty_Internal_Template +mimics the behavior of Smarty, this API simplification should not +require any changes to custom plugins. + +The plugins shipped with Smarty 3.1 have been rewritten for better +performance. Most notably {html_select_date} and {html_select_time} +have been improved vastly. Performance aside, plugins have also been +reviewed and generalized in their API. {html_select_date} and +{html_select_time} now share almost all available options. + +The escape modifier now knows the $double_encode option, which will +prevent entities from being encoded again. + +The capitalize modifier now know the $lc_rest option, which makes sure +all letters following a captial letter are lower-cased. + +The count_sentences modifier now accepts (.?!) as +legitimate endings of a sentence - previously only (.) was +accepted + +The new unescape modifier is there to reverse the effects of the +escape modifier. This applies to the escape formats html, htmlall and +entity. + + default_template_handler_func + +The invocation of $smarty->$default_template_handler_func had to be +altered. Instead of a Smarty_Internal_Template, the fifth argument is +now provided with the Smarty instance. New footprint: + + +/** + * Default Template Handler + * + * called when Smarty's file: resource is unable to load a requested file + * + * @param string $type resource type (e.g. "file", "string", "eval", "resource") + * @param string $name resource name (e.g. "foo/bar.tpl") + * @param string &$content template's content + * @param integer &$modified template's modification time + * @param Smarty $smarty Smarty instance + * @return string|boolean path to file or boolean true if $content and $modified + * have been filled, boolean false if no default template + * could be loaded + */ +function default_template_handler_func($type, $name, &$content, &$modified, Smarty $smarty) { + if (false) { + // return corrected filepath + return "/tmp/some/foobar.tpl"; + } elseif (false) { + // return a template directly + $content = "the template source"; + $modified = time(); + return true; + } else { + // tell smarty that we failed + return false; + } +} + + Stuff done to the compiler + +Many performance improvements have happened internally. One notable +improvement is that all compiled templates are now handled as PHP +functions. This speeds up repeated templates tremendously, as each one +calls an (in-memory) PHP function instead of performing another file +include/scan. + +New Features + + Template syntax + + {block}..{/block} + +The {block} tag has a new hide option flag. It does suppress the block +content if no corresponding child block exists. +EXAMPLE: +parent.tpl +{block name=body hide} child content "{$smarty.block.child}" was +inserted {block} +In the above example the whole block will be suppressed if no child +block "body" is existing. + + {setfilter}..{/setfilter} + +The new {setfilter} block tag allows the definition of filters which +run on variable output. +SYNTAX: +{setfilter filter1|filter2|filter3....} +Smarty3 will lookup up matching filters in the following search order: +1. varibale filter plugin in plugins_dir. +2. a valid modifier. A modifier specification will also accept +additional parameter like filter2:'foo' +3. a PHP function +{/setfilter} will turn previous filter setting off again. +{setfilter} tags can be nested. +EXAMPLE: +{setfilter filter1} + {$foo} + {setfilter filter2} + {$bar} + {/setfilter} + {$buh} +{/setfilter} +{$blar} +In the above example filter1 will run on the output of $foo, filter2 +on $bar, filter1 again on $buh and no filter on $blar. +NOTES: +- {$foo nofilter} will suppress the filters +- These filters will run in addition to filters defined by +registerFilter('variable',...), autoLoadFilter('variable',...) and +defined default modifier. +- {setfilter} will effect only the current template, not included +subtemplates. + + Resource API + +Smarty 3.1 features a new approach to resource management. The +Smarty_Resource API allows simple, yet powerful integration of custom +resources for templates and configuration files. It offers simple +functions for loading data from a custom resource (e.g. database) as +well as define new template types adhering to the special +non-compiling (e,g, plain php) and non-compile-caching (e.g. eval: +resource type) resources. + +See demo/plugins/resource.mysql.php for an example custom database +resource. + +Note that old-fashioned registration of callbacks for resource +management has been deprecated but is still possible with SmartyBC. + + CacheResource API + +In line with the Resource API, the CacheResource API offers a more +comfortable handling of output-cache data. With the +Smarty_CacheResource_Custom accessing databases is made simple. With +the introduction of Smarty_CacheResource_KeyValueStore the +implementation of resources like memcache or APC became a no-brainer; +simple hash-based storage systems are now supporting hierarchical +output-caches. + +See demo/plugins/cacheresource.mysql.php for an example custom +database CacheResource. +See demo/plugins/cacheresource.memcache.php for an example custom +memcache CacheResource using the KeyValueStore helper. + +Note that old-fashioned registration of $cache_handler is not possible +anymore. As the functionality had not been ported to Smarty 3.0.x +properly, it has been dropped from 3.1 completely. + +Locking facilities have been implemented to avoid concurrent cache +generation. Enable cache locking by setting +$smarty->cache_locking = true; + + Relative Paths in Templates (File-Resource) + +As of Smarty 3.1 {include file="../foo.tpl"} and {include +file="./foo.tpl"} will resolve relative to the template they're in. +Relative paths are available with {include file="..."} and +{extends file="..."}. As $smarty->fetch('../foo.tpl') and +$smarty->fetch('./foo.tpl') cannot be relative to a template, an +exception is thrown. + + Adressing a specific $template_dir + +Smarty 3.1 introduces the $template_dir index notation. +$smarty->fetch('[foo]bar.tpl') and {include file="[foo]bar.tpl"} +require the template bar.tpl to be loaded from $template_dir['foo']; +Smarty::setTemplateDir() and Smarty::addTemplateDir() offer ways to +define indexes along with the actual directories. + + Mixing Resources in extends-Resource + +Taking the php extends: template resource one step further, it is now +possible to mix resources within an extends: call like +$smarty->fetch("extends:file:foo.tpl|db:bar.tpl"); + +To make eval: and string: resources available to the inheritance +chain, eval:base64:TPL_STRING and eval:urlencode:TPL_STRING have been +introduced. Supplying the base64 or urlencode flags will trigger +decoding the TPL_STRING in with either base64_decode() or urldecode(). + + extends-Resource in template inheritance + +Template based inheritance may now inherit from php's extends: +resource like {extends file="extends:foo.tpl|db:bar.tpl"}. + + New Smarty property escape_html + +$smarty->escape_html = true will autoescape all template variable +output by calling htmlspecialchars({$output}, ENT_QUOTES, +SMARTY_RESOURCE_CHAR_SET). +NOTE: +This is a compile time option. If you change the setting you must make +sure that the templates get recompiled. + + New option at Smarty property compile_check + +The automatic recompilation of modified templates can now be +controlled by the following settings: +$smarty->compile_check = COMPILECHECK_OFF (false) - template files +will not be checked +$smarty->compile_check = COMPILECHECK_ON (true) - template files will +always be checked +$smarty->compile_check = COMPILECHECK_CACHEMISS - template files will +be checked if caching is enabled and there is no existing cache file +or it has expired + + Automatic recompilation on Smarty version change + +Templates will now be automatically recompiled on Smarty version +changes to avoide incompatibillities in the compiled code. Compiled +template checked against the current setting of the SMARTY_VERSION +constant. + + default_config_handler_func() + +Analogous to the default_template_handler_func() +default_config_handler_func() has been introduced. + + default_plugin_handler_func() + +An optional default_plugin_handler_func() can be defined which gets called +by the compiler on tags which can't be resolved internally or by plugins. +The default_plugin_handler() can map tags to plugins on the fly. + +New getters/setters + +The following setters/getters will be part of the official +documentation, and will be strongly recommended. Direct property +access will still work for the foreseeable future... it will be +transparently routed through the setters/getters, and consequently a +bit slower. + +array|string getTemplateDir( [string $index] ) +replaces $smarty->template_dir; and $smarty->template_dir[$index]; +Smarty setTemplateDir( array|string $path ) +replaces $smarty->template_dir = "foo"; and $smarty->template_dir = +array("foo", "bar"); +Smarty addTemplateDir( array|string $path, [string $index]) +replaces $smarty->template_dir[] = "bar"; and +$smarty->template_dir[$index] = "bar"; + +array|string getConfigDir( [string $index] ) +replaces $smarty->config_dir; and $smarty->config_dir[$index]; +Smarty setConfigDir( array|string $path ) +replaces $smarty->config_dir = "foo"; and $smarty->config_dir = +array("foo", "bar"); +Smarty addConfigDir( array|string $path, [string $index]) +replaces $smarty->config_dir[] = "bar"; and +$smarty->config_dir[$index] = "bar"; + +array getPluginsDir() +replaces $smarty->plugins_dir; +Smarty setPluginsDir( array|string $path ) +replaces $smarty->plugins_dir = "foo"; +Smarty addPluginsDir( array|string $path ) +replaces $smarty->plugins_dir[] = "bar"; + +string getCompileDir() +replaces $smarty->compile_dir; +Smarty setCompileDir( string $path ) +replaces $smarty->compile_dir = "foo"; + +string getCacheDir() +replaces $smarty->cache_dir; +Smarty setCacheDir( string $path ) +replaces $smarty->cache_dir; diff --git a/library/Smarty/change_log.txt b/library/Smarty/change_log.txt new file mode 100644 index 0000000000..27c506db69 --- /dev/null +++ b/library/Smarty/change_log.txt @@ -0,0 +1,2078 @@ +===== trunk ===== +===== Smarty-3.1.11 ===== +30.06.2012 +- bugfix {block.. hide} did not work as nested child (Forum Topic 22216) + +25.06.2012 +- bugfix the default plugin handler did not allow static class methods for modifier (issue 85) + +24.06.2012 +- bugfix escape modifier support for PHP < 5.2.3 (Forum Topic 21176) + +11.06.2012 +- bugfix the patch for Topic 21856 did break tabs between tag attributes (Forum Topic 22124) + +===== Smarty-3.1.10 ===== +09.06.2012 +- bugfix the compiler did ignore registered compiler plugins for closing tags (Forum Topic 22094) +- bugfix the patch for Topic 21856 did break multiline tags (Forum Topic 22124) + +===== Smarty-3.1.9 ===== +07.06.2012 +- bugfix fetch() and display() with relative paths (Issue 104) +- bugfix treat "0000-00-00" as 0 in modifier.date_format (Issue 103) + +24.05.2012 +- bugfix Smarty_Internal_Write_File::writeFile() could cause race-conditions on linux systems (Issue 101) +- bugfix attribute parameter names of plugins may now contain also "-" and ":" (Forum Topic 21856) +- bugfix add compile_id to cache key of of source (Issue 97) + +22.05.2012 +- bugfix recursive {include} within {section} did fail (Smarty developer group) + +12.05.2012 +- bugfix {html_options} did not properly escape values (Issue 98) + +03.05.2012 +- bugfix make HTTP protocall version variable (issue 96) + +02.05.2012 +- bugfix {nocache}{block}{plugin}... did produce wrong compiled code when caching is disabled (Forum Topic 21572, issue 95) + +12.04.2012 +- bugfix Smarty did eat the linebreak after the closing tag (Issue 93) +- bugfix concurrent cache updates could create a warning (Forum Topic 21403) + +08.04.2012 +- bugfix "\\" was not escaped correctly when generating nocache code (Forum Topic 21364) + +30.03.2012 +- bugfix template inheritance did not throw exception when a parent template was deleted (issue 90) + +27.03.2012 +- bugfix prefilter did run multiple times on inline subtemplates compiled into several main templates (Forum Topic 21325) +- bugfix implement Smarty2's behaviour of variables assigned by reference in SmartyBC. {assign} will affect all references. + (issue 88) + +21.03.2012 +- bugfix compileAllTemplates() and compileAllConfig() did not return the number of compiled files (Forum Topic 21286) + +13.03.2012 +- correction of yesterdays bugfix (Forum Topic 21175 and 21182) + +12.03.2012 +- bugfix a double quoted string of "$foo" did not compile into PHP "$foo" (Forum Topic 21175) +- bugfix template inheritance did set $merge_compiled_includes globally true + +03.03.2012 +- optimization of compiling speed when same modifier was used several times + +02.03.2012 +- enhancement the default plugin handler can now also resolve undefined modifier (Smarty::PLUGIN_MODIFIER) + (Issue 85) + +===== Smarty-3.1.8 ===== +19.02.2012 +- bugfix {include} could result in a fatal error if used in appended or prepended nested {block} tags + (reported by mh and Issue 83) +- enhancement added Smarty special variable $smarty.template_object to return the current template object (Forum Topic 20289) + + +07.02.2012 +- bugfix increase entropy of internal function names in compiled and cached template files (Forum Topic 20996) +- enhancement cacheable parameter added to default plugin handler, same functionality as in registerPlugin (request by calguy1000) + +06.02.2012 +- improvement stream_resolve_include_path() added to Smarty_Internal_Get_Include_Path (Forum Topic 20980) +- bugfix fetch('extends:foo.tpl') always yielded $source->exists == true (Forum Topic 20980) +- added modifier unescape:"url", fix (Forum Topic 20980) +- improvement replaced some calls of preg_replace with str_replace (Issue 73) + +30.01.2012 +- bugfix Smarty_Security internal $_resource_dir cache wasn't properly propagated + +27.01.2012 +- bugfix Smarty did not a template name of "0" (Forum Topic 20895) + +20.01.2012 +- bugfix typo in Smarty_Internal_Get_IncludePath did cause runtime overhead (Issue 74) +- improvment remove unneeded assigments (Issue 75 and 76) +- fixed typo in template parser +- bugfix output filter must not run before writing cache when template does contain nocache code (Issue 71) + +02.01.2012 +- bugfix {block foo nocache} did not load plugins within child {block} in nocache mode (Forum Topic 20753) + +29.12.2011 +- bugfix enable more entropy in Smarty_Internal_Write_File for "more uniqueness" and Cygwin compatibility (Forum Topic 20724) +- bugfix embedded quotes in single quoted strings did not compile correctly in {nocache} sections (Forum Topic 20730) + +28.12.2011 +- bugfix Smarty's internal header code must be excluded from postfilters (issue 71) + +22.12.2011 +- bugfix the new lexer of 17.12.2011 did fail if mbstring.func_overload != 0 (issue 70) (Forum Topic 20680) +- bugfix template inheritace did fail if mbstring.func_overload != 0 (issue 70) (Forum Topic 20680) + +20.12.2011 +- bugfix template inheritance: {$smarty.block.child} in nested child {block} tags did not return + content after {$smarty.block.child} (Forum Topic 20564) + +===== Smarty-3.1.7 ===== +18.12.2011 +- bugfix strings ending with " in multiline strings of config files failed to compile (issue #67) +- added chaining to Smarty_Internal_Templatebase +- changed unloadFilter() to not return a boolean in favor of chaining and API conformity +- bugfix unregisterObject() raised notice when object to unregister did not exist +- changed internals to use Smarty::$_MBSTRING ($_CHARSET, $_DATE_FORMAT) for better unit testing +- added Smarty::$_UTF8_MODIFIER for proper PCRE charset handling (Forum Topic 20452) +- added Smarty_Security::isTrustedUri() and Smarty_Security::$trusted_uri to validate + remote resource calls through {fetch} and {html_image} (Forum Topic 20627) + +17.12.2011 +- improvement of compiling speed by new handling of plain text blocks in the lexer/parser (issue #68) + +16.12.2011 +- bugfix the source exits flag and timestamp was not setup when template was in php include path (issue #69) + +9.12.2011 +- bugfix {capture} tags around recursive {include} calls did throw exception (Forum Topic 20549) +- bugfix $auto_literal = false did not work with { block} tags in child templates (Forum Topic 20581) +- bugfix template inheritance: do not include code of {include} in overloaded {block} into compiled + parent template (Issue #66} +- bugfix template inheritance: {$smarty.block.child} in nested child {block} tags did not return expected + result (Forum Topic 20564) + +===== Smarty-3.1.6 ===== +30.11.2011 +- bugfix is_cache() for individual cached subtemplates with $smarty->caching = CACHING_OFF did produce + an exception (Forum Topic 20531) + +29.11.2011 +- bugfix added exception if the default plugin handler did return a not static callback (Forum Topic 20512) + +25.11.2011 +- bugfix {html_select_date} and {html_slecet_time} did not default to current time if "time" was not specified + since r4432 (issue 60) + +24.11.2011 +- bugfix a subtemplate later used as main template did use old variable values + +21.11.2011 +- bugfix cache file could include unneeded modifier plugins under certain condition + +18.11.2011 +- bugfix declare all directory properties private to map direct access to getter/setter also on extended Smarty class + +16.11.2011 +- bugfix Smarty_Resource::load() did not always return a proper resource handler (Forum Topic 20414) +- added escape argument to html_checkboxes and html_radios (Forum Topic 20425) + +===== Smarty-3.1.5 ===== +14.11.2011 +- bugfix allow space between function name and open bracket (forum topic 20375) + +09.11.2011 +- bugfix different behaviour of uniqid() on cygwin. See https://bugs.php.net/bug.php?id=34908 + (forum topic 20343) + +01.11.2011 +- bugfix {if} and {while} tags without condition did not throw a SmartyCompilerException (Issue #57) +- bugfix multiline strings in config files could fail on longer strings (reopened Issue #55) + +22.10.2011 +- bugfix smarty_mb_from_unicode() would not decode unicode-points properly +- bugfix use catch Exception instead UnexpectedValueException in + clearCompiledTemplate to be PHP 5.2 compatible + +21.10.2011 +- bugfix apostrophe in plugins_dir path name failed (forum topic 20199) +- improvement sha1() for array keys longer than 150 characters +- add Smarty::$allow_ambiguous_resources to activate unique resource handling (Forum Topic 20128) + +20.10.2011 +- @silenced unlink() in Smarty_Internal_Write_File since debuggers go haywire without it. +- bugfix Smarty::clearCompiledTemplate() threw an Exception if $cache_id was not present in $compile_dir when $use_sub_dirs = true. +- bugfix {html_select_date} and {html_select_time} did not properly handle empty time arguments (Forum Topic 20190) +- improvement removed unnecessary sha1() + +19.10.2011 +- revert PHP4 constructor message +- fixed PHP4 constructor message + +===== Smarty-3.1.4 ===== +19.10.2011 +- added exception when using PHP4 style constructor + +16.10.2011 +- bugfix testInstall() did not propery check cache_dir and compile_dir + +15.10.2011 +- bugfix Smarty_Resource and Smarty_CacheResource runtime caching (Forum Post 75264) + +14.10.2011 +- bugfix unique_resource did not properly apply to compiled resources (Forum Topic 20128) +- add locking to custom resources (Forum Post 75252) +- add Smarty_Internal_Template::clearCache() to accompany isCached() fetch() etc. + +13.10.2011 +- add caching for config files in Smarty_Resource +- bugfix disable of caching after isCached() call did not work (Forum Topic 20131) +- add concept unique_resource to combat potentially ambiguous template_resource values when custom resource handlers are used (Forum Topic 20128) +- bugfix multiline strings in config files could fail on longer strings (Issue #55) + +11.10.2011 +- add runtime checks for not matching {capture}/{/capture} calls (Forum Topic 20120) + +10.10.2011 +- bugfix variable name typo in {html_options} and {html_checkboxes} (Issue #54) +- bugfix tag did create wrong output when caching enabled and the tag was in included subtemplate +- bugfix Smarty_CacheResource_mysql example was missing strtotime() calls + +===== Smarty-3.1.3 ===== +07.10.2011 +- improvement removed html comments from {mailto} (Forum Topic 20092) +- bugfix testInstall() would not show path to internal plugins_dir (Forum Post 74627) +- improvement testInstall() now showing resolved paths and checking the include_path if necessary +- bugfix html_options plugin did not handle object values properly (Issue #49, Forum Topic 20049) +- improvement html_checkboxes and html_radios to accept null- and object values, and label_ids attribute +- improvement removed some unnecessary count()s +- bugfix parent pointer was not set when fetch() for other template was called on template object + +06.10.2011 +- bugfix switch lexer internals depending on mbstring.func_overload +- bugfix start_year and end_year of {html_select_date} did not use current year as offset base (Issue #53) + +05.10.2011 +- bugfix of problem introduced with r4342 by replacing strlen() with isset() +- add environment configuration issue with mbstring.func_overload Smarty cannot compensate for (Issue #45) +- bugfix nofilter tag option did not disable default modifier +- bugfix html_options plugin did not handle null- and object values properly (Issue #49, Forum Topic 20049) + +04.10.2011 +- bugfix assign() in plugins called in subtemplates did change value also in parent template +- bugfix of problem introduced with r4342 on math plugin +- bugfix output filter should not run on individually cached subtemplates +- add unloadFilter() method +- bugfix has_nocache_code flag was not reset before compilation + +===== Smarty-3.1.2 ===== +03.10.2011 +- improvement add internal $joined_template_dir property instead computing it on the fly several times + +01.10.2011 +- improvement replaced most in_array() calls by more efficient isset() on array_flip()ed haystacks +- improvement replaced some strlen($foo) > 3 calls by isset($foo[3]) +- improvement Smarty_Internal_Utility::clearCompiledTemplate() removed redundant strlen()s + +29.09.2011 +- improvement of Smarty_Internal_Config::loadConfigVars() dropped the in_array for index look up + +28.09.2011 +- bugfix on template functions called nocache calling other template functions + +27.09.2011 +- bugfix possible warning "attempt to modify property of non-object" in {section} (issue #34) +- added chaining to Smarty_Internal_Data so $smarty->assign('a',1)->assign('b',2); is possible now +- bugfix remove race condition when a custom resource did change timestamp during compilation +- bugfix variable property did not work on objects variable in template +- bugfix smarty_make_timestamp() failed to process DateTime objects properly +- bugfix wrong resource could be used on compile check of custom resource + +26.09.2011 +- bugfix repeated calls to same subtemplate did not make use of cached template object + +24.09.2011 +- removed internal muteExpectedErrors() calls in favor of having the implementor call this once from his application +- optimized muteExpectedErrors() to pass errors to the latest registered error handler, if appliccable +- added compile_dir and cache_dir to list of muted directories +- improvment better error message for undefined templates at {include} + +23.09.2011 +- remove unused properties +- optimization use real function instead anonymous function for preg_replace_callback +- bugfix a relative {include} in child template blocks failed +- bugfix direct setting of $template_dir, $config_dir, $plugins_dir in __construct() of an + extended Smarty class created problems +- bugfix error muting was not implemented for cache locking + +===== Smarty 3.1.1 ===== +22.09.2011 +- bugfix {foreachelse} does fail if {section} was nested inside {foreach} +- bugfix debug.tpl did not display correctly when it was compiled with escape_html = true + +21.09.2011 +- bugfix look for mixed case plugin file names as in 3.0 if not found try all lowercase +- added $error_muting to suppress error messages even for badly implemented error_handlers +- optimized autoloader +- reverted ./ and ../ handling in fetch() and display() - they're allowed again + +20.09.2011 +- bugfix removed debug echo output while compiling template inheritance +- bugfix relative paths in $template_dir broke relative path resolving in {include "../foo.tpl"} +- bugfix {include} did not work inside nested {block} tags +- bugfix {assign} with scope root and global did not work in all cases + +19.09.2011 +- bugfix regression in Smarty_CacheReource_KeyValueStore introduced by r4261 +- bugfix output filter shall not run on included subtemplates + +18.09.2011 +- bugfix template caching did not care about file.tpl in different template_dir +- bugfix {include $file} was broken when merge_compiled_incluges = true +- bugfix {include} was broken when merge_compiled_incluges = true and same indluded template + was used in different main templates in one compilation run +- bugfix for Smarty2 style compiler plugins on unnamed attribute passing like {tag $foo $bar} +- bugfix debug.tpl did not display correctly when it was compiled with escape_html = true + +17.09.2011 +- bugfix lock_id for file resource would create invalid filepath +- bugfix resource caching did not care about file.tpl in different template_dir + +===== Smarty 3.1.0 ===== +15/09/2011 +- optimization of {foreach}; call internal _count() method only when "total" or "last" {foreach} properties are used + +11/09/2011 +- added unregisterObject() method + +06/09/2011 +- bugfix isset() did not work in templates on config variables + +03/09/2011 +- bugfix createTemplate() must default to cache_id and compile_id of Smarty object +- bugfix Smarty_CacheResource_KeyValueStore must include $source->uid in cache filepath to keep templates with same + name but different folders seperated +- added cacheresource.apc.php example in demo folder + +02/09/2011 +- bugfix cache lock file must use absolute filepath + +01/09/2011 +- update of cache locking + +30/08/2011 +- added locking mechanism to CacheResource API (implemented with File and KeyValueStores) + +28/08/2011 +- bugfix clearCompileTemplate() did not work for specific template subfolder or resource + +27/08/2011 +- bugfix {$foo|bar+1} did create syntax error + +26/08/2011 +- bugfix when generating nocache code which contains double \ +- bugfix handle race condition if cache file was deleted between filemtime and include + +17/08/2011 +- bugfix CacheResource_Custom bad internal fetch() call + +15/08/2011 +- bugfix CacheResource would load content twice for KeyValueStore and Custom handlers + +06/08/2011 +- bugfix {include} with scope attribute could execute in wrong scope +- optimization of compile_check processing + +03/08/2011 +- allow comment tags to comment {block} tags out in child templates + +26/07/2011 +- bugfix experimental getTags() method did not work + +24/07/2011 +- sure opened output buffers are closed on exception +- bugfix {foreach} did not work on IteratorAggregate + +22/07/2011 +- clear internal caches on clearAllCache(), clearCache(), clearCompiledTemplate() + +21/07/2011 +- bugfix value changes of variable values assigned to Smarty object could not be seen on repeated $smarty->fetch() calls + +17/07/2011 +- bugfix {$smarty.block.child} did drop a notice at undefined child + +15/07/2011 +- bugfix individual cache_lifetime of {include} did not work correctly inside {block} tags +- added caches for Smarty_Template_Source and Smarty_Template_Compiled to reduce I/O for multiple cache_id rendering + +14/07/2011 +- made Smarty::loadPlugin() respect the include_path if required + +13/07/2011 +- optimized internal file write functionality +- bugfix PHP did eat line break on nocache sections +- fixed typo of Smarty_Security properties $allowed_modifiers and $disabled_modifiers + +06/07/2011 +- bugfix variable modifier must run befor gereral filtering/escaping + +04/07/2011 +- bugfix use (?P) syntax at preg_match as some pcre libraries failed on (?) +- some performance improvement when using generic getter/setter on template objects + +30/06/2011 +- bugfix generic getter/setter of Smarty properties used on template objects did throw exception +- removed is_dir and is_readable checks from directory setters for better performance + +28/06/2011 +- added back support of php template resource as undocumented feature +- bugfix automatic recompilation on version change could drop undefined index notice on old 3.0 cache and compiled files +- update of README_3_1_DEV.txt and moved into the distribution folder +- improvement show first characters of eval and string templates instead sha1 Uid in debug window + +===== Smarty 3.1-RC1 ===== +25/06/2011 +- revert change of 17/06/2011. $_smarty varibale removed. call loadPlugin() from inside plugin code if required +- code cleanup, remove no longer used properties and methods +- update of PHPdoc comments + +23/06/2011 +- bugfix {html_select_date} would not respect current time zone + +19/06/2011 +- added $errors argument to testInstall() functions to suppress output. +- added plugin-file checks to testInstall() + +18/06/2011 +- bugfix mixed use of same subtemplate inline and not inline in same script could cause a warning during compilation + +17/06/2011 +- bugfix/change use $_smarty->loadPlugin() when loading nested depending plugins via loadPlugin +- bugfix {include ... inline} within {block}...{/block} did fail + +16/06/2011 +- bugfix do not overwrite '$smarty' template variable when {include ... scope=parent} is called +- bugfix complete empty inline subtemplates did fail + +15/06/2011 +- bugfix template variables where not accessable within inline subtemplates + +12/06/2011 +- bugfix removed unneeded merging of template variable when fetching includled subtemplates + +10/06/2011 +- made protected properties $template_dir, $plugins_dir, $cache_dir, $compile_dir, $config_dir accessible via magic methods + +09/06/2011 +- fix smarty security_policy issue in plugins {html_image} and {fetch} + +05/06/2011 +- update of SMARTY_VERSION +- bugfix made getTags() working again + +04/06/2011 +- allow extends resource in file attribute of {extends} tag + +03/06/2011 +- added {setfilter} tag to set filters for variable output +- added escape_html property to control autoescaping of variable output + +27/05/2011 +- added allowed/disabled tags and modifiers in security for sandboxing + +23/05/2011 +- added base64: and urlencode: arguments to eval and string resource types + +22/05/2011 +- made time-attribute of {html_select_date} and {html_select_time} accept arrays as defined by attributes prefix and field_array + +13/05/2011 +- remove setOption / getOption calls from SamrtyBC class + +02/05/2011 +- removed experimental setOption() getOption() methods +- output returned content also on opening tag calls of block plugins +- rewrite of default plugin handler +- compile code of variable filters for better performance + +20/04/2011 +- allow {php} {include_php} tags and PHP_ALLOW handling only with the SmartyBC class +- removed support of php template resource + +20/04/2011 +- added extendsall resource example +- optimization of template variable access +- optimization of subtemplate handling {include} +- optimization of template class + +01/04/2011 +- bugfix quote handling in capitalize modifier + +28/03/2011 +- bugfix stripslashes() requried when using PCRE e-modifier + +04/03/2011 +- upgrade to new PHP_LexerGenerator version 0.4.0 for better performance + +27/02/2011 +- ignore .svn folders when clearing cache and compiled files +- string resources do not need a modify check + +26/02/2011 +- replaced smarty_internal_wrapper by SmartyBC class +- load utility functions as static methods instead through __call() +- bugfix in extends resource when subresources are used +- optimization of modify checks + +25/02/2011 +- use $smarty->error_unassigned to control NOTICE handling on unassigned variables + +21/02/2011 +- added new new compile_check mode COMPILECHECK_CACHEMISS +- corrected new cloning behaviour of createTemplate() +- do no longer store the compiler object as property in the compile_tag classes to avoid possible memory leaks + during compilation + +19/02/2011 +- optimizations on merge_compiled_includes handling +- a couple of optimizations and bugfixes related to new resource structure + +17/02/2011 +- changed ./ and ../ behaviour + +14/02/2011 +- added {block ... hide} option to supress block if no child is defined + +13/02/2011 +- update handling of recursive subtemplate calls +- bugfix replace $smarty->triggerError() by exception in smarty_internal_resource_extends.php + +12/02/2011 +- new class Smarty_Internal_TemplateBase with shared methods of Smarty and Template objects +- optimizations of template processing +- made register... methods permanet +- code for default_plugin_handler +- add automatic recompilation at version change + +04/02/2011 +- change in Smarty_CacheResource_Custom +- bugfix cache_lifetime did not compile correctly at {include} after last update +- moved isCached processing into CacheResource class +- bugfix new CacheResource API did not work with disabled compile_check + +03/02/2011 +- handle template content as function to improve speed on multiple calls of same subtemplate and isCached()/display() calls +- bugfixes and improvents in the new resource API +- optimizations of template class code + +25/01/2011 +- optimized function html_select_time + +22/01/2011 +- added Smarty::$use_include_path configuration directive for Resource API + +21/01/2011 +- optimized function html_select_date + +19/01/2011 +- optimized outputfilter trimwhitespace + +18/01/2011 +- bugfix Config to use Smarty_Resource to fetch sources +- optimized Smarty_Security's isTrustedDir() and isTrustedPHPDir() + +17/01/2011 +- bugfix HTTP headers for CGI SAPIs + +16/01/2011 +- optimized internals of Smarty_Resource and Smarty_CacheResource + +14/01/2011 +- added modifiercompiler escape to improve performance of escaping html, htmlall, url, urlpathinfo, quotes, javascript +- added support to choose template_dir to load from: [index]filename.tpl + +12/01/2011 +- added unencode modifier to revert results of encode modifier +- added to_charset and from_charset modifier for character encoding + +11/01/2011 +- added SMARTY_MBSTRING to generalize MBString detection +- added argument $lc_rest to modifier.capitalize to lower-case anything but the first character of a word +- changed strip modifier to consider unicode white-space, too +- changed wordwrap modifier to accept UTF-8 strings +- changed count_sentences modifier to consider unicode characters and treat sequences delimited by ? and ! as sentences, too +- added argument $double_encode to modifier.escape (applies to html and htmlall only) +- changed escape modifier to be UTF-8 compliant +- changed textformat block to be UTF-8 compliant +- optimized performance of mailto function +- fixed spacify modifier so characters are not prepended and appended, made it unicode compatible +- fixed truncate modifier to properly use mb_string if possible +- removed UTF-8 frenzy from count_characters modifier +- fixed count_words modifier to treat "hello-world" as a single word like str_count_words() does +- removed UTF-8 frenzy from upper modifier +- removed UTF-8 frenzy from lower modifier + +01/01/2011 +- optimize smarty_modified_escape for hex, hexentity, decentity. + +28/12/2010 +- changed $tpl_vars, $config_vars and $parent to belong to Smarty_Internal_Data +- added Smarty::registerCacheResource() for dynamic cache resource object registration + +27/12/2010 +- added Smarty_CacheResource API and refactored existing cache resources accordingly +- added Smarty_CacheResource_Custom and Smarty_CacheResource_Mysql + +26/12/2010 +- added Smarty_Resource API and refactored existing resources accordingly +- added Smarty_Resource_Custom and Smarty_Resource_Mysql +- bugfix Smarty::createTemplate() to return properly cloned template instances + +24/12/2010 +- optimize smarty_function_escape_special_chars() for PHP >= 5.2.3 + +===== SVN 3.0 trunk ===== +14/05/2011 +- bugfix error handling at stream resources + +13/05/2011 +- bugfix condition starting with "-" did fail at {if} and {while} tags + +22/04/2011 +- bugfix allow only fixed string as file attribute at {extends} tag + +01/04/2011 +- bugfix do not run filters and default modifier when displaying the debug template +- bugfix of embedded double quotes within multi line strings (""") + +29/03/2011 +- bugfix on error message in smarty_internal_compile_block.php +- bugfix mb handling in strip modifier +- bugfix for Smarty2 style registered compiler function on unnamed attribute passing like {tag $foo $bar} + +17/03/2011 +- bugfix on default {function} parameters when {function} was used in nocache sections +- bugfix on compiler object destruction. compiler_object property was by mistake unset. + +09/03/2011 +-bugfix a variable filter should run before modifers on an output tag (see change of 23/07/2010) + +08/03/2011 +- bugfix loading config file without section should load only defaults + +03/03/2011 +- bugfix "smarty" template variable was not recreated when cached templated had expired +- bugfix internal rendered_content must be cleared after subtemplate was included + +01/03/2011 +- bugfix replace modifier did not work in 3.0.7 on systems without multibyte support +- bugfix {$smarty.template} could return in 3.0.7 parent template name instead of + child name when it needed to compile + +25/02/2011 +- bugfix for Smarty2 style compiler plugins on unnamed attribute passing like {tag $foo $bar} + +24/02/2011 +- bugfix $smarty->clearCache('some.tpl') did by mistake cache the template object + +18/02/2011 +- bugfix removed possible race condition when isCached() was called for an individually cached subtemplate +- bugfix force default debug.tpl to be loaded by the file resource + +17/02/2011 +-improvement not to delete files starting with '.' from cache and template_c folders on clearCompiledTemplate() and clearCache() + +16/02/2011 +-fixed typo in exception message of Smarty_Internal_Template +-improvement allow leading spaces on } tag closing if auto_literal is enabled + +13/02/2011 +- bufix replace $smarty->triggerError() by exception +- removed obsolete {popup_init..} plugin from demo templates +- bugfix replace $smarty->triggerError() by exception in smarty_internal_resource_extends.php + +===== Smarty 3.0.7 ===== +09/02/2011 +- patched vulnerability when using {$smarty.template} + +01/02/2011 +- removed assert() from config and template parser + +31/01/2011 +- bugfix the lexer/parser did fail on special characters like VT + +16/01/2011 +-bugfix of ArrayAccess object handling in internal _count() method +-bugfix of Iterator object handling in internal _count() method + +14/01/2011 +-bugfix removed memory leak while processing compileAllTemplates + +12/01/2011 +- bugfix in {if} and {while} tag compiler when using assignments as condition and nocache mode + +10/01/2011 +- bugfix when using {$smarty.block.child} and name of {block} was in double quoted string +- bugfix updateParentVariables() was called twice when leaving {include} processing + +- bugfix mb_str_replace in replace and escape modifiers work with utf8 + +31/12/2010 +- bugfix dynamic configuration of $debugging_crtl did not work +- bugfix default value of $config_read_hidden changed to false +- bugfix format of attribute array on compiler plugins +- bugfix getTemplateVars() could return value from wrong scope + +28/12/2010 +- bugfix multiple {append} tags failed to compile. + +22/12/2010 +- update do not clone the Smarty object an internal createTemplate() calls to increase performance + +21/12/2010 +- update html_options to support class and id attrs + +17/12/2010 +- bugfix added missing support of $cache_attrs for registered plugins + +15/12/2010 +- bugfix assignment as condition in {while} did drop an E_NOTICE + +14/12/2010 +- bugfix when passing an array as default parameter at {function} tag + +13/12/2010 +- bugfix {$smarty.template} in child template did not return right content +- bugfix Smarty3 did not search the PHP include_path for template files + +===== Smarty 3.0.6 ===== + +12/12/2010 +- bugfix fixed typo regarding yesterdays change to allow streamWrapper + +11/12/2010 +- bugfix nested block tags in template inheritance child templates did not work correctly +- bugfix {$smarty.current_dir} in child template did not point to dir of child template +- bugfix changed code when writing temporary compiled files to allow stream_wrapper + +06/12/2010 +- bugfix getTemplateVars() should return 'null' instead dropping E_NOTICE on an unassigned variable + +05/12/2010 +- bugfix missing declaration of $smarty in Smarty class +- bugfix empty($foo) in {if} did drop a notice when $foo was not assigned + +01/12/2010 +- improvement of {debug} tag output + +27/11/2010 +-change run output filter before cache file is written. (same as in Smarty2) + +24/11/2011 +-bugfix on parser at !$foo|modifier +-change parser logic when assignments used as condition in {if] and {while} to allow assign to array element + +23/11/2011 +-bugfix allow integer as attribute name in plugin calls +-change trimm whitespace from error message, removed long list of expected tokens + +22/11/2010 +- bugfix on template inheritance when an {extends} tag was inserted by a prefilter +- added error message for illegal variable file attributes at {extends...} tags + +===== Smarty 3.0.5 ===== + + +19/11/2010 +- bugfix on block plugins with modifiers + +18/11/2010 +- change on handling of unassigned template variable -- default will drop E_NOTICE +- bugfix on Smarty2 wrapper load_filter() did not work + +17/11/2010 +- bugfix on {call} with variable function name +- bugfix on {block} if name did contain '-' +- bugfix in function.fetch.php , referece to undefined $smarty + +16/11/2010 +- bugfix whitespace in front of "fetch()/display() have been used in plugins + (introduced with 3.0.2) +- code cleanup + +===== Smarty 3.0.3 ===== + +13/11/2010 +- bugfix on {debug} +- reverted location of loadPlugin() to Smarty class +- fixed comments in plugins +- fixed internal_config (removed unwanted code line) +- improvement remove last linebreak from {function} definition + +===== Smarty 3.0.2 ===== + +12/11/2010 +- reactivated $error_reporting property handling +- fixed typo in compile_continue +- fixed security in {fetch} plugin +- changed back plugin parameters to two. second is template object + with transparent access to Smarty object +- fixed {config_load} scoping form compile time to run time + +===== Smarty 3.0.0 ===== + + + +11/11/2010 +- major update including some API changes + +10/11/2010 +- observe compile_id also for config files + +09/11/2010 +-bugfix on complex expressions as start value for {for} tag +request_use_auto_globals +04/11/2010 +- bugfix do not allow access of dynamic and private object members of assigned objects when + security is enabled. + +01/11/2010 +- bugfix related to E_NOTICE change. {if empty($foo)} did fail when $foo contained a string + +28/10/2010 +- bugfix on compiling modifiers within $smarty special vars like {$smarty.post.{$foo|lower}} + +27/10/2010 +- bugfix default parameter values did not work for template functions included with {include} + +25/10/2010 +- bugfix for E_NOTICE change, array elements did not work as modifier parameter + +20/10/2010 +- bugfix for the E_NOTICE change + +19/10/2010 +- change Smarty does no longer mask out E_NOTICE by default during template processing + +13/10/2010 +- bugfix removed ambiguity between ternary and stream variable in template syntax +- bugfix use caching properties of template instead of smarty object when compiling child {block} +- bugfix {*block}...{/block*} did throw an exception in template inheritance +- bugfix on template inheritance using nested eval or string resource in {extends} tags +- bugfix on output buffer handling in isCached() method + +===== RC4 ===== + +01/10/2010 +- added {break} and {continue} tags for flow control of {foreach},{section},{for} and {while} loops +- change of 'string' resource. It's no longer evaluated and compiled files are now stored +- new 'eval' resource which evaluates a template without saving the compiled file +- change in isCached() method to allow multiple calls for the same template + +25/09/2010 +- bugfix on some compiling modifiers + +24/09/2010 +- bugfix merge_compiled_includes flag was not restored correctly in {block} tag + +22/09/2010 +- bugfix on default modifier + +18/09/2010 +- bugfix untility compileAllConfig() did not create sha1 code for compiled template file names if template_dir was defined with no trailing DS +- bugfix on templateExists() for extends resource + +17/09/2010 +- bugfix {$smarty.template} and {$smarty.current_dir} did not compile correctly within {block} tags +- bugfix corrected error message on missing template files in extends resource +- bugfix untility compileAllTemplates() did not create sha1 code for compiled template file names if template_dir was defined with no trailing DS + +16/09/2010 +- bugfix when a doublequoted modifier parameter did contain Smarty tags and ':' + +15/09/2010 +- bugfix resolving conflict between '<%'/'%>' as custom Smarty delimiter and ASP tags +- use ucfirst for resource name on internal resource class names + +12/09/2010 +- bugfix for change of 08/09/2010 (final {block} tags in subtemplates did not produce correct results) + +10/09/2010 +- bugfix for change of 08/09/2010 (final {block} tags in subtemplates did not produce correct results) + +08/09/2010 +- allow multiple template inheritance branches starting in subtemplates + +07/09/2010 +- bugfix {counter} and {cycle} plugin assigned result to smarty variable not in local(template) scope +- bugfix templates containing just {strip} {/strip} tags did produce an error + + +23/08/2010 +- fixed E_STRICT errors for uninitialized variables + +22/08/2010 +- added attribute cache_id to {include} tag + +13/08/2010 +- remove exception_handler property from Smarty class +- added Smarty's own exceptions SmartyException and SmartyCompilerException + +09/08/2010 +- bugfix on modifier with doublequoted strings as parameter containing embedded tags + +06/08/2010 +- bugfix when cascading some modifier like |strip|strip_tags modifier + +05/08/2010 +- added plugin type modifiercompiler to produce compiled modifier code +- changed standard modifier plugins to the compiling versions whenever possible +- bugfix in nocache sections {include} must not cache the subtemplate + +02/08/2010 +- bugfix strip did not work correctly in conjunction with comment lines + +31/07/2010 +- bugfix on nocache attribute at {assign} and {append} + +30/07/2010 +- bugfix passing scope attributes in doublequoted strings did not work at {include} {assign} and {append} + +25/07/2010 +- another bugfix of change from 23/07/2010 when compiling modifer + +24/07/2010 +- bugfix of change from 23/07/2010 when compiling modifer + +23/07/2010 +- changed execution order. A variable filter does now run before modifiers on output of variables +- bugfix use always { and } as delimiter for debug.tpl + + +22/07/2010 +- bugfix in templateExists() method + +20/07/2010 +- fixed handling of { strip } tag with whitespaces + +15/07/2010 +- bufix {$smarty.template} does include now the relative path, not just filename + +===== RC3 ===== + + + + +15/07/2010 +- make the date_format modifier work also on objects of the DateTime class +- implementation of parsetrees in the parser to close security holes and remove unwanted empty line in HTML output + +08/07/2010 +- bugfix on assigning multidimensional arrays within templates +- corrected bugfix for truncate modifier + +07/07/2010 +- bugfix the truncate modifier needs to check if the string is utf-8 encoded or not +- bugfix support of script files relative to trusted_dir + +06/07/2010 +- create exception on recursive {extends} calls +- fixed reported line number at "unexpected closing tag " exception +- bugfix on escape:'mail' modifier +- drop exception if 'item' variable is equal 'from' variable in {foreach} tag + +01/07/2010 +- removed call_user_func_array calls for optimization of compiled code when using registered modifiers and plugins + +25/06/2010 +- bugfix escaping " when block tags are used within doublequoted strings + +24/06/2010 +- replace internal get_time() calls with standard PHP5 microtime(true) calls in Smarty_Internal_Utility +- added $smarty->register->templateClass() and $smarty->unregister->templateClass() methods for supporting static classes with namespace + + +22/06/2010 +- allow spaces between typecast and value in template syntax +- bugfix get correct count of traversables in {foreach} tag + +21/06/2010 +- removed use of PHP shortags SMARTY_PHP_PASSTHRU mode +- improved speed of cache->clear() when a compile_id was specified and use_sub_dirs is true + +20/06/2010 +- replace internal get_time() calls with standard PHP5 microtime(true) calls +- closed security hole when php.ini asp_tags = on + +18/06/2010 +- added __toString method to the Smarty_Variable class + + +14/06/2010 +- make handling of Smarty comments followed by newline BC to Smarty2 + + +===== RC2 ===== + + + +13/06/2010 +- bugfix Smarty3 did not handle hexadecimals like 0x0F as numerical value +- bugifx Smarty3 did not accept numerical constants like .1 or 2. (without a leading or trailing digit) + +11/06/2010 +- bugfix the lexer did fail on larger {literal} ... {/literal} sections + +03/06/2010 +- bugfix on calling template functions like Smarty tags + +01/06/2010 +- bugfix on template functions used with template inheritance +- removed /* vim: set expandtab: */ comments +- bugfix of auto literal problem introduce with fix of 31/05/2010 + +31/05/2010 +- bugfix the parser did not allow some smarty variables with special name like $for, $if, $else and others. + +27/05/2010 +- bugfix on object chaining using variable properties +- make scope of {counter} and {cycle} tags again global as in Smarty2 + +26/05/2010 +- bugfix removed decrepated register_resource call in smarty_internal_template.php + +25/05/2010 +- rewrite of template function handling to improve speed +- bugfix on file dependency when merge_compiled_includes = true + + +16/05/2010 +- bugfix when passing parameter with numeric name like {foo 1='bar' 2='blar'} + +14/05/2010 +- bugfix compile new config files if compile_check and force_compile = false +- added variable static classes names to template syntax + +11/05/2010 +- bugfix make sure that the cache resource is loaded in all conditions when template methods getCached... are called externally +- reverted the change 0f 30/04/2010. With the exception of forward references template functions can be again called by a standard tag. + +10/05/2010 +- bugfix on {foreach} and {for} optimizations of 27/04/2010 + +09/05/2010 +- update of template and config file parser because of minor parser generator bugs + +07/05/2010 +- bugfix on {insert} + +06/05/2010 +- bugfix when merging compiled templates and objects are passed as parameter of the {include} tag + +05/05/2010 +- bugfix on {insert} to cache parameter +- implementation of $smarty->default_modifiers as in Smarty2 +- bugfix on getTemplateVars method + +01/05/2010 +- bugfix on handling of variable method names at object chaning + +30/04/2010 +- bugfix when comparing timestamps in sysplugins/smarty_internal_config.php +- work around of a substr_compare bug in older PHP5 versions +- bugfix on template inheritance for tag names starting with "block" +- bugfix on {function} tag with name attribute in doublequoted strings +- fix to make calling of template functions unambiguously by madatory usage of the {call} tag + +===== RC1 ===== + +27/04/2010 +- change default of $debugging_ctrl to 'NONE' +- optimization of compiled code of {foreach} and {for} loops +- change of compiler for config variables + +27/04/2010 +- bugfix in $smarty->cache->clear() method. (do not cache template object) + + +17/04/2010 +- security fix in {math} plugin + + +12/04/2010 +- bugfix in smarty_internal_templatecompilerbase (overloaded property) +- removed parser restrictions in using true,false and null as ID + +07/04/2010 +- bugfix typo in smarty_internal_templatecompilerbase + +31/03/2010 +- compile locking by touching old compiled files to avoid concurrent compilations + +29/03/2010 +- bugfix allow array definitions as modifier parameter +- bugfix observe compile_check property when loading config files +- added the template object as third filter parameter + +25/03/2010 +- change of utility->compileAllTemplates() log messages +- bugfix on nocache code in {function} tags +- new method utility->compileAllConfig() to compile all config files + +24/03/2010 +- bugfix on register->modifier() error messages + +23/03/2010 +- bugfix on template inheritance when calling multiple child/parent relations +- bugfix on caching mode SMARTY_CACHING_LIFETIME_SAVED and cache_lifetime = 0 + +22/03/2010 +- bugfix make directory separator operating system independend in compileAllTemplates() + +21/03/2010 +- removed unused code in compileAllTemplates() + +19/03/2010 +- bugfix for multiple {/block} tags on same line + +17/03/2010 +- bugfix make $smarty->cache->clear() function independent from caching status + +16/03/2010 +- bugfix on assign attribute at registered template objects +- make handling of modifiers on expression BC to Smarty2 + +15/03/2010 +- bugfix on block plugin calls + +11/03/2010 +- changed parsing of back to Smarty2 behaviour + +08/03/2010 +- bugfix on uninitialized properties in smarty_internal_template +- bugfix on $smarty->disableSecurity() + +04/03/2010 +- bugfix allow uppercase chars in registered resource names +- bugfix on accessing chained objects of static classes + +01/03/2010 +- bugfix on nocache code in {block} tags if child template was included by {include} + +27/02/2010 +- allow block tags inside double quoted string + +26/02/2010 +- cache modified check implemented +- support of access to a class constant from an object (since PHP 5.3) + +24/02/2010 +- bugfix on expressions in doublequoted string enclosed in backticks +- added security property $static_classes for static class security + +18/02/2010 +- bugfix on parsing Smarty tags inside +- bugfix on truncate modifier + +17/02/2010 +- removed restriction that modifiers did require surrounding parenthesis in some cases +- added {$smarty.block.child} special variable for template inheritance + +16/02/2010 +- bugfix on tags for all php_handling modes +- bugfix on parameter of variablefilter.htmlspecialchars.php plugin + +14/02/2010 +- added missing _plugins property in smarty.class.php +- bugfix $smarty.const... inside doublequoted strings and backticks was compiled into wrong PHP code + +12/02/2010 +- bugfix on nested {block} tags +- changed Smarty special variable $smarty.parent to $smarty.block.parent +- added support of nested {bock} tags + +10/02/2010 +- avoid possible notice on $smarty->cache->clear(...), $smarty->clear_cache(....) +- allow Smarty tags inside tags in SMARTY_PHP_QUOTE and SMARTY_PHP_PASSTHRU mode +- bugfix at new "for" syntax like {for $x=1 to 10 step 2} + +09/02/2010 +- added $smarty->_tag_stack for tracing block tag hierarchy + +08/02/2010 +- bugfix use template fullpath at §smarty->cache->clear(...), $smarty->clear_cache(....) +- bugfix of cache filename on extended templates when force_compile=true + +07/02/2010 +- bugfix on changes of 05/02/2010 +- preserve line endings type form template source +- API changes (see README file) + +05/02/2010 +- bugfix on modifier and block plugins with same name + +02/02/2010 +- retaining newlines at registered functions and function plugins + +01/25/2010 +- bugfix cache resource was not loaded when caching was globally off but enabled at a template object +- added test that $_SERVER['SCRIPT_NAME'] does exist in Smarty.class.php + +01/22/2010 +- new method $smarty->createData([$parent]) for creating a data object (required for bugfixes below) +- bugfix config_load() method now works also on a data object +- bugfix get_config_vars() method now works also on a data and template objects +- bugfix clear_config() method now works also on a data and template objects + +01/19/2010 +- bugfix on plugins if same plugin was called from a nocache section first and later from a cached section + + +###beta 7### + + +01/17/2010 +- bugfix on $smarty.const... in double quoted strings + +01/16/2010 +- internal change of config file lexer/parser on handling of section names +- bugfix on registered objects (format parameter of register_object was not handled correctly) + +01/14/2010 +- bugfix on backslash within single quoted strings +- bugfix allow absolute filepath for config files +- bugfix on special Smarty variable $smarty.cookies +- revert handling of newline on no output tags like {if...} +- allow special characters in config file section names for Smarty2 BC + +01/13/2010 +- bugfix on {if} tags + +01/12/2010 +- changed back modifer handling in parser. Some restrictions still apply: + if modifiers are used in side {if...} expression or in mathematical expressions + parentheses must be used. +- bugfix the {function..} tag did not accept the name attribute in double quotes +- closed possible security hole at tags +- bugfix of config file parser on large config files + + +###beta 6#### + +01/11/2010 +- added \n to the compiled code of the {if},{else},{elseif},{/if} tags to get output of newlines as expected by the template source +- added missing support of insert plugins +- added optional nocache attribute to {block} tags in parent template +- updated handling supporting now heredocs and newdocs. (thanks to Thue Jnaus Kristensen) + +01/09/2010 +- bugfix on nocache {block} tags in parent templates + +01/08/2010 +- bugfix on variable filters. filter/nofilter attributes did not work on output statements + +01/07/2010 +- bugfix on file dependency at template inheritance +- bugfix on nocache code at template inheritance + +01/06/2010 +- fixed typo in smarty_internal_resource_registered +- bugfix for custom delimiter at extends resource and {extends} tag + +01/05/2010 +- bugfix sha1() calculations at extends resource and some general improvments on sha1() handling + + +01/03/2010 +- internal change on building cache files + +01/02/2010 +- update cached_timestamp at the template object after cache file is written to avoid possible side effects +- use internally always SMARTY_CACHING_LIFETIME_* constants + +01/01/2010 +- bugfix for obtaining plugins which must be included (related to change of 12/30/2009) +- bugfix for {php} tag (trow an exception if allow_php_tag = false) + +12/31/2009 +- optimization of generated code for doublequoted strings containing variables +- rewrite of {function} tag handling + - can now be declared in an external subtemplate + - can contain nocache sections (nocache_hash handling) + - can be called in noccache sections (nocache_hash handling) + - new {call..} tag to call template functions with a variable name {call name=$foo} +- fixed nocache_hash handling in merged compiled templates + +12/30/2009 +- bugfix for plugins defined in the script as smarty_function_foo + +12/29/2009 +- use sha1() for filepath encoding +- updates on nocache_hash handling +- internal change on merging some data +- fixed cache filename for custom resources + +12/28/2009 +- update for security fixes +- make modifier plugins always trusted +- fixed bug loading modifiers in child template at template inheritance + +12/27/2009 +--- this is a major update with a couple of internal changes --- +- new config file lexer/parser (thanks to Thue Jnaus Kristensen) +- template lexer/parser fixes for PHP and {literal} handing (thanks to Thue Jnaus Kristensen) +- fix on registered plugins with different type but same name +- rewrite of plugin handling (optimized execution speed) +- closed a security hole regarding PHP code injection into cache files +- fixed bug in clear cache handling +- Renamed a couple of internal classes +- code cleanup for merging compiled templates +- couple of runtime optimizations (still not all done) +- update of getCachedTimestamp() +- fixed bug on modifier plugins at nocache output + +12/19/2009 +- bugfix on comment lines in config files + +12/17/2009 +- bugfix of parent/global variable update at included/merged subtemplates +- encode final template filepath into filename of compiled and cached files +- fixed {strip} handling in auto literals + +12/16/2009 +- update of changelog +- added {include file='foo.tpl' inline} inline option to merge compiled code of subtemplate into the calling template + +12/14/2009 +- fixed sideefect of last modification (objects in array index did not work anymore) + +12/13/2009 +- allow boolean negation ("!") as operator on variables outside {if} tag + +12/12/2009 +- bugfix on single quotes inside {function} tag +- fix short append/prepend attributes in {block} tags + +12/11/2009 +- bugfix on clear_compiled_tpl (avoid possible warning) + +12/10/2009 +- bugfix on {function} tags and template inheritance + +12/05/2009 +- fixed problem when a cached file was fetched several times +- removed unneeded lexer code + +12/04/2009 +- added max attribute to for loop +- added security mode allow_super_globals + +12/03/2009 +- template inheritance: child templates can now call functions defined by the {function} tag in the parent template +- added {for $foo = 1 to 5 step 2} syntax +- bugfix for {$foo.$x.$y.$z} + +12/01/2009 +- fixed parsing of names of special formated tags like if,elseif,while,for,foreach +- removed direct access to constants in templates because of some syntax problems +- removed cache resource plugin for mysql from the distribution +- replaced most hard errors (exceptions) by softerrors(trigger_error) in plugins +- use $template_class property for template class name when compiling {include},{eval} and {extends} tags + +11/30/2009 +- map 'true' to SMARTY_CACHING_LIFETIME_CURRENT for the $smarty->caching parameter +- allow {function} tags within {block} tags + +11/28/2009 +- ignore compile_id at debug template +- added direct access to constants in templates +- some lexer/parser optimizations + +11/27/2009 +- added cache resource MYSQL plugin + +11/26/2009 +- bugfix on nested doublequoted strings +- correct line number on unknown tag error message +- changed {include} compiled code +- fix on checking dynamic varibales with error_unassigned = true + +11/25/2009 +- allow the following writing for boolean: true, TRUE, True, false, FALSE, False +- {strip} tag functionality rewritten + +11/24/2009 +- bugfix for $smarty->config_overwrite = false + +11/23/2009 +- suppress warnings on unlink caused by race conditions +- correct line number on unknown tag error message + +------- beta 5 +11/23/2009 +- fixed configfile parser for text starting with a numeric char +- the default_template_handler_func may now return a filepath to a template source + +11/20/2009 +- bugfix for empty config files +- convert timestamps of registered resources to integer + +11/19/2009 +- compiled templates are no longer touched with the filemtime of template source + +11/18/2009 +- allow integer as attribute name in plugin calls + +------- beta 4 +11/18/2009 +- observe umask settings when setting file permissions +- avoide unneeded cache file creation for subtemplates which did occur in some situations +- make $smarty->_current_file available during compilation for Smarty2 BC + +11/17/2009 +- sanitize compile_id and cache_id (replace illegal chars with _) +- use _dir_perms and _file_perms properties at file creation +- new constant SMARTY_RESOURCE_DATE_FORMAT (default '%b %e, %Y') which is used as default format in modifier date_format +- added {foreach $array as $key=>$value} syntax +- renamed extend tag and resource to extends: {extends file='foo.tol'} , $smarty->display('extends:foo.tpl|bar.tpl); +- bugfix cycle plugin + +11/15/2009 +- lexer/parser optimizations on quoted strings + +11/14/2009 +- bugfix on merging compiled templates when source files got removed or renamed. +- bugfix modifiers on registered object tags +- fixed locaion where outputfilters are running +- fixed config file definitions at EOF +- fix on merging compiled templates with nocache sections in nocache includes +- parser could run into a PHP error on wrong file attribute + +11/12/2009 +- fixed variable filenames in {include_php} and {insert} +- added scope to Smarty variables in the {block} tag compiler +- fix on nocache code in child {block} tags + +11/11/2009 +- fixed {foreachelse}, {forelse}, {sectionelse} compiled code at nocache variables +- removed checking for reserved variables +- changed debugging handling + +11/10/2009 +- fixed preg_qoute on delimiters + +11/09/2009 +- lexer/parser bugfix +- new SMARTY_SPL_AUTOLOAD constant to control the autoloader option +- bugfix for {function} block tags in included templates + +11/08/2009 +- fixed alphanumeric array index +- bugfix on complex double quoted strings + +11/05/2009 +- config_load method can now be called on data and template objects + +11/04/2009 +- added typecasting support for template variables +- bugfix on complex indexed special Smarty variables + +11/03/2009 +- fixed parser error on objects with special smarty vars +- fixed file dependency for {incude} inside {block} tag +- fixed not compiling on non existing compiled templates when compile_check = false +- renamed function names of autoloaded Smarty methods to Smarty_Method_.... +- new security_class property (default is Smarty_Security) + +11/02/2009 +- added neq,lte,gte,mod as aliases to if conditions +- throw exception on illegal Smarty() constructor calls + +10/31/2009 +- change of filenames in sysplugins folder for internal spl_autoload function +- lexer/parser changed for increased compilation speed + +10/27/2009 +- fixed missing quotes in include_php.php + +10/27/2009 +- fixed typo in method.register_resource +- pass {} through as literal + +10/26/2009 +- merge only compiled subtemplates into the compiled code of the main template + +10/24/2009 +- fixed nocache vars at internal block tags +- fixed merging of recursive includes + +10/23/2009 +- fixed nocache var problem + +10/22/2009 +- fix trimwhitespace outputfilter parameter + +10/21/2009 +- added {$foo++}{$foo--} syntax +- buxfix changed PHP "if (..):" to "if (..){" because of possible bad code when concenating PHP tags +- autoload Smarty internal classes +- fixed file dependency for config files +- some code optimizations +- fixed function definitions on some autoloaded methods +- fixed nocache variable inside if condition of {if} tag + +10/20/2009 +- check at compile time for variable filter to improve rendering speed if no filter is used +- fixed bug at combination of {elseif} tag and {...} in double quoted strings of static class parameter + +10/19/2009 +- fixed compiled template merging on variable double quoted strings as name +- fixed bug in caching mode 2 and cache_lifetime -1 +- fixed modifier support on block tags + +10/17/2009 +- remove ?>\n'bar','foo2'=>'blar'); + $smarty->display('my.tpl',$data); + +09/29/2009 +- changed {php} tag handling +- removed support of Smarty::instance() +- removed support of PHP resource type +- improved execution speed of {foreach} tags +- fixed bug in {section} tag + +09/23/2009 +- improvements and bugfix on {include} tag handling +NOTICE: existing compiled template and cache files must be deleted + +09/19/2009 +- replace internal "eval()" calls by "include" during rendering process +- speed improvment for templates which have included subtemplates + the compiled code of included templates is merged into the compiled code of the parent template +- added logical operator "xor" for {if} tag +- changed parameter ordering for Smarty2 BC + fetch($template, $cache_id = null, $compile_id = null, $parent = null) + display($template, $cache_id = null, $compile_id = null, $parent = null) + createTemplate($template, $cache_id = null, $compile_id = null, $parent = null) +- property resource_char_set is now replaced by constant SMARTY_RESOURCE_CHAR_SET +- fixed handling of classes in registered blocks +- speed improvement of lexer on text sections + +09/01/2009 +- dropped nl2br as plugin +- added '<>' as comparission operator in {if} tags +- cached caching_lifetime property to cache_liftime for backward compatibility with Smarty2. + {include} optional attribute is also now cache_lifetime +- fixed trigger_error method (moved into Smarty class) +- version is now Beta!!! + + +08/30/2009 +- some speed optimizations on loading internal plugins + + +08/29/2009 +- implemented caching of registered Resources +- new property 'auto_literal'. if true(default) '{ ' and ' }' interpreted as literal, not as Smarty delimiter + + +08/28/2009 +- Fix on line breaks inside {if} tags + +08/26/2009 +- implemented registered resources as in Smarty2. NOTE: caching does not work yet +- new property 'force_cache'. if true it forces the creation of a new cache file +- fixed modifiers on arrays +- some speed optimization on loading internal classes + + +08/24/2009 +- fixed typo in lexer definition for '!==' operator +- bugfix - the ouput of plugins was not cached +- added global variable SCRIPT_NAME + +08/21/2009 +- fixed problems whitespace in conjuction with custom delimiters +- Smarty tags can now be used as value anywhere + +08/18/2009 +- definition of template class name moded in internal.templatebase.php +- whitespace parser changes + +08/12/2009 +- fixed parser problems + +08/11/2009 +- fixed parser problems with custom delimiter + +08/10/2009 +- update of mb support in plugins + + +08/09/2009 +- fixed problems with doublequoted strings at name attribute of {block} tag +- bugfix at scope attribute of {append} tag + +08/08/2009 +- removed all internal calls of Smarty::instance() +- fixed code in double quoted strings + +08/05/2009 +- bugfix mb_string support +- bugfix of \n.\t etc in double quoted strings + +07/29/2009 +- added syntax for variable config vars like #$foo# + +07/28/2009 +- fixed parsing of $smarty.session vars containing objects + +07/22/2009 +- fix of "$" handling in double quoted strings + +07/21/2009 +- fix that {$smarty.current_dir} return correct value within {block} tags. + +07/20/2009 +- drop error message on unmatched {block} {/block} pairs + +07/01/2009 +- fixed smarty_function_html_options call in plugin function.html_select_date.php (missing ,) + +06/24/2009 +- fixed smarty_function_html_options call in plugin function.html_select_date.php + +06/22/2009 +- fix on \n and spaces inside smarty tags +- removed request_use_auto_globals propert as it is no longer needed because Smarty 3 will always run under PHP 5 + + +06/18/2009 +- fixed compilation of block plugins when caching enabled +- added $smarty.current_dir which returns the current working directory + +06/14/2009 +- fixed array access on super globals +- allow smarty tags within xml tags + +06/13/2009 +- bugfix at extend resource: create unique files for compiled template and cache for each combination of template files +- update extend resource to handle appen and prepend block attributes +- instantiate classes of plugins instead of calling them static + +06/03/2009 +- fixed repeat at block plugins + +05/25/2009 +- fixed problem with caching of compiler plugins + +05/14/2009 +- fixed directory separator handling + +05/09/2009 +- syntax change for stream variables +- fixed bug when using absolute template filepath and caching + +05/08/2009 +- fixed bug of {nocache} tag in included templates + +05/06/2009 +- allow that plugins_dir folder names can end without directory separator + +05/05/2009 +- fixed E_STRICT incompabilities +- {function} tag bug fix +- security policy definitions have been moved from plugins folder to file Security.class.php in libs folder +- added allow_super_global configuration to security + +04/30/2009 +- functions defined with the {function} tag now always have global scope + +04/29/2009 +- fixed problem with directory setter methods +- allow that cache_dir can end without directory separator + +04/28/2009 +- the {function} tag can no longer overwrite standard smarty tags +- inherit functions defined by the {fuction} tag into subtemplates +- added {while } sytax to while tag + +04/26/2009 +- added trusted stream checking to security +- internal changes at file dependency check for caching + +04/24/2009 +- changed name of {template} tag to {function} +- added new {template} tag + +04/23/2009 +- fixed access of special smarty variables from included template + +04/22/2009 +- unified template stream syntax with standard Smarty resource syntax $smarty->display('mystream:mytemplate') + +04/21/2009 +- change of new style syntax for forach. Now: {foreach $array as $var} like in PHP + +04/20/2009 +- fixed "$foo.bar ..." variable replacement in double quoted strings +- fixed error in {include} tag with variable file attribute + +04/18/2009 +- added stream resources ($smarty->display('mystream://mytemplate')) +- added stream variables {$mystream:myvar} + +04/14/2009 +- fixed compile_id handling on {include} tags +- fixed append/prepend attributes in {block} tag +- added {if 'expression' is in 'array'} syntax +- use crc32 as hash for compiled config files. + +04/13/2009 +- fixed scope problem with parent variables when appending variables within templates. +- fixed code for {block} without childs (possible sources for notice errors removed) + +04/12/2009 +- added append and prepend attribute to {block} tag + +04/11/2009 +- fixed variables in 'file' attribute of {extend} tag +- fixed problems in modifiers (if mb string functions not present) + +04/10/2009 +- check if mb string functions available otherwise fallback to normal string functions +- added global variable scope SMARTY_GLOBAL_SCOPE +- enable 'variable' filter by default +- fixed {$smarty.block.parent.foo} +- implementation of a 'variable' filter as replacement for default modifier + +04/09/2009 +- fixed execution of filters defined by classes +- compile the always the content of {block} tags to make shure that the filters are running over it +- syntax corrections on variable object property +- syntax corrections on array access in dot syntax + +04/08/2009 +- allow variable object property + +04/07/2009 +- changed variable scopes to SMARTY_LOCAL_SCOPE, SMARTY_PARENT_SCOPE, SMARTY_ROOT_SCOPE to avoid possible conflicts with user constants +- Smarty variable global attribute replaced with scope attribute + +04/06/2009 +- variable scopes LOCAL_SCOPE, PARENT_SCOPE, ROOT_SCOPE +- more getter/setter methods + +04/05/2009 +- replaced new array looping syntax {for $foo in $array} with {foreach $foo in $array} to avoid confusion +- added append array for short form of assign {$foo[]='bar'} and allow assignments to nested arrays {$foo['bla']['blue']='bar'} + +04/04/2009 +- make output of template default handlers cachable and save compiled source +- some fixes on yesterdays update + +04/03/2006 +- added registerDefaultTemplateHandler method and functionallity +- added registerDefaultPluginHandler method and functionallity +- added {append} tag to extend Smarty array variabled + +04/02/2009 +- added setter/getter methods +- added $foo@first and $foo@last properties at {for} tag +- added $set_timezone (true/false) property to setup optionally the default time zone + +03/31/2009 +- bugfix smarty.class and internal.security_handler +- added compile_check configuration +- added setter/getter methods + +03/30/2009 +- added all major setter/getter methods + +03/28/2009 +- {block} tags can be nested now +- md5 hash function replace with crc32 for speed optimization +- file order for exted resource inverted +- clear_compiled_tpl and clear_cache_all will not touch .svn folder any longer + +03/27/2009 +- added extend resource + +03/26/2009 +- fixed parser not to create error on `word` in double quoted strings +- allow PHP array(...) +- implemented $smarty.block.name.parent to access parent block content +- fixed smarty.class + + +03/23/2009 +- fixed {foreachelse} and {forelse} tags + +03/22/2009 +- fixed possible sources for notice errors +- rearrange SVN into distribution and development folders + +03/21/2009 +- fixed exceptions in function plugins +- fixed notice error in Smarty.class.php +- allow chained objects to span multiple lines +- fixed error in modifers + +03/20/2009 +- moved /plugins folder into /libs folder +- added noprint modifier +- autoappend a directory separator if the xxxxx_dir definition have no trailing one + +03/19/2009 +- allow array definition as modifer parameter +- changed modifier to use multi byte string funktions. + +03/17/2009 +- bugfix + +03/15/2009 +- added {include_php} tag for BC +- removed @ error suppression +- bugfix fetch did always repeat output of first call when calling same template several times +- PHPunit tests extended + +03/13/2009 +- changed block syntax to be Smarty like {block:titel} -> {block name=titel} +- compiling of {block} and {extend} tags rewriten for better performance +- added special Smarty variable block ($smarty.block.foo} returns the parent definition of block foo +- optimization of {block} tag compiled code. +- fixed problem with escaped double quotes in double quoted strings + +03/12/2009 +- added support of template inheritance by {extend } and {block } tags. +- bugfix comments within literals +- added scope attribuie to {include} tag + +03/10/2009 +- couple of bugfixes and improvements +- PHPunit tests extended + +03/09/2009 +- added support for global template vars. {assign_global...} $smarty->assign_global(...) +- added direct_access_security +- PHPunit tests extended +- added missing {if} tag conditions like "is div by" etc. + +03/08/2009 +- splitted up the Compiler class to make it easier to use a coustom compiler +- made default plugins_dir relative to Smarty root and not current working directory +- some changes to make the lexer parser better configurable +- implemented {section} tag for Smarty2 BC + +03/07/2009 +- fixed problem with comment tags +- fixed problem with #xxxx in double quoted string +- new {while} tag implemented +- made lexer and paser class configurable as $smarty property +- Smarty method get_template_vars implemented +- Smarty method get_registered_object implemented +- Smarty method trigger_error implemented +- PHPunit tests extended + +03/06/2009 +- final changes on config variable handling +- parser change - unquoted strings will by be converted into single quoted strings +- PHPunit tests extended +- some code cleanup +- fixed problem on catenate strings with expression +- update of count_words modifier +- bugfix on comment tags + + +03/05/2009 +- bugfix on tag with caching enabled +- changes on exception handling (by Monte) + +03/04/2009 +- added support for config variables +- bugfix on tag + +03/02/2009 +- fixed unqouted strings within modifier parameter +- bugfix parsing of mofifier parameter + +03/01/2009 +- modifier chaining works now as in Smarty2 + +02/28/2009 +- changed handling of unqouted strings + +02/26/2009 +- bugfix +- changed $smarty.capture.foo to be global for Smarty2 BC. + +02/24/2009 +- bugfix {php} {/php} tags for backward compatibility +- bugfix for expressions on arrays +- fixed usage of "null" value +- added $smarty.foreach.foo.first and $smarty.foreach.foo.last + +02/06/2009 +- bugfix for request variables without index for example $smarty.get +- experimental solution for variable functions in static class + +02/05/2009 +- update of popup plugin +- added config variables to template parser (load config functions still missing) +- parser bugfix for empty quoted strings + +02/03/2009 +- allow array of objects as static class variabales. +- use htmlentities at source output at template errors. + +02/02/2009 +- changed search order on modifiers to look at plugins folder first +- parser bug fix for modifier on array elements $foo.bar|modifier +- parser bug fix on single quoted srings +- internal: splitted up compiler plugin files + +02/01/2009 +- allow method chaining on static classes +- special Smarty variables $smarty.... implemented +- added {PHP} {/PHP} tags for backward compatibility + +01/31/2009 +- added {math} plugin for Smarty2 BC +- added template_exists method +- changed Smarty3 method enable_security() to enableSecurity() to follow camelCase standards + +01/30/2009 +- bugfix in single quoted strings +- changed syntax for variable property access from $foo:property to $foo@property because of ambiguous syntax at modifiers + +01/29/2009 +- syntax for array definition changed from (1,2,3) to [1,2,3] to remove ambiguous syntax +- allow {for $foo in [1,2,3]} syntax +- bugfix in double quoted strings +- allow tags in template even if short_tags are enabled + +01/28/2009 +- fixed '!==' if condition. + +01/28/2009 +- added support of {strip} {/strip} tag. + +01/27/2009 +- bug fix on backticks in double quoted strings at objects + +01/25/2009 +- Smarty2 modfiers added to SVN + +01/25/2009 +- bugfix allow arrays at object properties in Smarty syntax +- the template object is now passed as additional parameter at plugin calls +- clear_compiled_tpl method completed + +01/20/2009 +- access to class constants implemented ( class::CONSTANT ) +- access to static class variables implemented ( class::$variable ) +- call of static class methods implemented ( class::method() ) + +01/16/2009 +- reallow leading _ in variable names {$_var} +- allow array of objects {$array.index->method()} syntax +- finished work on clear_cache and clear_cache_all methods + +01/11/2009 +- added support of {literal} tag +- added support of {ldelim} and {rdelim} tags +- make code compatible to run with E_STRICT error setting + +01/08/2009 +- moved clear_assign and clear_all_assign to internal.templatebase.php +- added assign_by_ref, append and append_by_ref methods + +01/02/2009 +- added load_filter method +- fished work on filter handling +- optimization of plugin loading + +12/30/2008 +- added compiler support of registered object +- added backtick support in doubled quoted strings for backward compatibility +- some minor bug fixes and improvments + +12/23/2008 +- fixed problem of not working "not" operator in if-expressions +- added handling of compiler function plugins +- finished work on (un)register_compiler_function method +- finished work on (un)register_modifier method +- plugin handling from plugins folder changed for modifier plugins + deleted - internal.modifier.php +- added modifier chaining to parser + +12/17/2008 +- finished (un)register_function method +- finished (un)register_block method +- added security checking for PHP functions in PHP templates +- plugin handling from plugins folder rewritten + new - internal.plugin_handler.php + deleted - internal.block.php + deleted - internal.function.php +- removed plugin checking from security handler + +12/16/2008 + +- new start of this change_log file diff --git a/library/Smarty/demo/configs/test.conf b/library/Smarty/demo/configs/test.conf new file mode 100644 index 0000000000..5eac748ec3 --- /dev/null +++ b/library/Smarty/demo/configs/test.conf @@ -0,0 +1,5 @@ +title = Welcome to Smarty! +cutoff_size = 40 + +[setup] +bold = true diff --git a/library/Smarty/demo/index.php b/library/Smarty/demo/index.php new file mode 100644 index 0000000000..74c8e89712 --- /dev/null +++ b/library/Smarty/demo/index.php @@ -0,0 +1,33 @@ +force_compile = true; +$smarty->debugging = true; +$smarty->caching = true; +$smarty->cache_lifetime = 120; + +$smarty->assign("Name","Fred Irving Johnathan Bradley Peppergill",true); +$smarty->assign("FirstName",array("John","Mary","James","Henry")); +$smarty->assign("LastName",array("Doe","Smith","Johnson","Case")); +$smarty->assign("Class",array(array("A","B","C","D"), array("E", "F", "G", "H"), + array("I", "J", "K", "L"), array("M", "N", "O", "P"))); + +$smarty->assign("contacts", array(array("phone" => "1", "fax" => "2", "cell" => "3"), + array("phone" => "555-4444", "fax" => "555-3333", "cell" => "760-1234"))); + +$smarty->assign("option_values", array("NY","NE","KS","IA","OK","TX")); +$smarty->assign("option_output", array("New York","Nebraska","Kansas","Iowa","Oklahoma","Texas")); +$smarty->assign("option_selected", "NE"); + +$smarty->display('index.tpl'); +?> diff --git a/library/Smarty/demo/plugins/cacheresource.apc.php b/library/Smarty/demo/plugins/cacheresource.apc.php new file mode 100644 index 0000000000..00ba598178 --- /dev/null +++ b/library/Smarty/demo/plugins/cacheresource.apc.php @@ -0,0 +1,77 @@ + $v) { + $_res[$k] = $v; + } + return $_res; + } + + /** + * Save values for a set of keys to cache + * + * @param array $keys list of values to save + * @param int $expire expiration time + * @return boolean true on success, false on failure + */ + protected function write(array $keys, $expire=null) + { + foreach ($keys as $k => $v) { + apc_store($k, $v, $expire); + } + return true; + } + + /** + * Remove values from cache + * + * @param array $keys list of keys to delete + * @return boolean true on success, false on failure + */ + protected function delete(array $keys) + { + foreach ($keys as $k) { + apc_delete($k); + } + return true; + } + + /** + * Remove *all* values from cache + * + * @return boolean true on success, false on failure + */ + protected function purge() + { + return apc_clear_cache('user'); + } +} diff --git a/library/Smarty/demo/plugins/cacheresource.memcache.php b/library/Smarty/demo/plugins/cacheresource.memcache.php new file mode 100644 index 0000000000..230607d696 --- /dev/null +++ b/library/Smarty/demo/plugins/cacheresource.memcache.php @@ -0,0 +1,91 @@ +memcache = new Memcache(); + $this->memcache->addServer( '127.0.0.1', 11211 ); + } + + /** + * Read values for a set of keys from cache + * + * @param array $keys list of keys to fetch + * @return array list of values with the given keys used as indexes + * @return boolean true on success, false on failure + */ + protected function read(array $keys) + { + $_keys = $lookup = array(); + foreach ($keys as $k) { + $_k = sha1($k); + $_keys[] = $_k; + $lookup[$_k] = $k; + } + $_res = array(); + $res = $this->memcache->get($_keys); + foreach ($res as $k => $v) { + $_res[$lookup[$k]] = $v; + } + return $_res; + } + + /** + * Save values for a set of keys to cache + * + * @param array $keys list of values to save + * @param int $expire expiration time + * @return boolean true on success, false on failure + */ + protected function write(array $keys, $expire=null) + { + foreach ($keys as $k => $v) { + $k = sha1($k); + $this->memcache->set($k, $v, 0, $expire); + } + return true; + } + + /** + * Remove values from cache + * + * @param array $keys list of keys to delete + * @return boolean true on success, false on failure + */ + protected function delete(array $keys) + { + foreach ($keys as $k) { + $k = sha1($k); + $this->memcache->delete($k); + } + return true; + } + + /** + * Remove *all* values from cache + * + * @return boolean true on success, false on failure + */ + protected function purge() + { + return $this->memcache->flush(); + } +} diff --git a/library/Smarty/demo/plugins/cacheresource.mysql.php b/library/Smarty/demo/plugins/cacheresource.mysql.php new file mode 100644 index 0000000000..ab8c475164 --- /dev/null +++ b/library/Smarty/demo/plugins/cacheresource.mysql.php @@ -0,0 +1,152 @@ +CREATE TABLE IF NOT EXISTS `output_cache` ( + * `id` CHAR(40) NOT NULL COMMENT 'sha1 hash', + * `name` VARCHAR(250) NOT NULL, + * `cache_id` VARCHAR(250) NULL DEFAULT NULL, + * `compile_id` VARCHAR(250) NULL DEFAULT NULL, + * `modified` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + * `content` LONGTEXT NOT NULL, + * PRIMARY KEY (`id`), + * INDEX(`name`), + * INDEX(`cache_id`), + * INDEX(`compile_id`), + * INDEX(`modified`) + * ) ENGINE = InnoDB; + * + * @package CacheResource-examples + * @author Rodney Rehm + */ +class Smarty_CacheResource_Mysql extends Smarty_CacheResource_Custom { + // PDO instance + protected $db; + protected $fetch; + protected $fetchTimestamp; + protected $save; + + public function __construct() { + try { + $this->db = new PDO("mysql:dbname=test;host=127.0.0.1", "smarty", "smarty"); + } catch (PDOException $e) { + throw new SmartyException('Mysql Resource failed: ' . $e->getMessage()); + } + $this->fetch = $this->db->prepare('SELECT modified, content FROM output_cache WHERE id = :id'); + $this->fetchTimestamp = $this->db->prepare('SELECT modified FROM output_cache WHERE id = :id'); + $this->save = $this->db->prepare('REPLACE INTO output_cache (id, name, cache_id, compile_id, content) + VALUES (:id, :name, :cache_id, :compile_id, :content)'); + } + + /** + * fetch cached content and its modification time from data source + * + * @param string $id unique cache content identifier + * @param string $name template name + * @param string $cache_id cache id + * @param string $compile_id compile id + * @param string $content cached content + * @param integer $mtime cache modification timestamp (epoch) + * @return void + */ + protected function fetch($id, $name, $cache_id, $compile_id, &$content, &$mtime) + { + $this->fetch->execute(array('id' => $id)); + $row = $this->fetch->fetch(); + $this->fetch->closeCursor(); + if ($row) { + $content = $row['content']; + $mtime = strtotime($row['modified']); + } else { + $content = null; + $mtime = null; + } + } + + /** + * Fetch cached content's modification timestamp from data source + * + * @note implementing this method is optional. Only implement it if modification times can be accessed faster than loading the complete cached content. + * @param string $id unique cache content identifier + * @param string $name template name + * @param string $cache_id cache id + * @param string $compile_id compile id + * @return integer|boolean timestamp (epoch) the template was modified, or false if not found + */ + protected function fetchTimestamp($id, $name, $cache_id, $compile_id) + { + $this->fetchTimestamp->execute(array('id' => $id)); + $mtime = strtotime($this->fetchTimestamp->fetchColumn()); + $this->fetchTimestamp->closeCursor(); + return $mtime; + } + + /** + * Save content to cache + * + * @param string $id unique cache content identifier + * @param string $name template name + * @param string $cache_id cache id + * @param string $compile_id compile id + * @param integer|null $exp_time seconds till expiration time in seconds or null + * @param string $content content to cache + * @return boolean success + */ + protected function save($id, $name, $cache_id, $compile_id, $exp_time, $content) + { + $this->save->execute(array( + 'id' => $id, + 'name' => $name, + 'cache_id' => $cache_id, + 'compile_id' => $compile_id, + 'content' => $content, + )); + return !!$this->save->rowCount(); + } + + /** + * Delete content from cache + * + * @param string $name template name + * @param string $cache_id cache id + * @param string $compile_id compile id + * @param integer|null $exp_time seconds till expiration or null + * @return integer number of deleted caches + */ + protected function delete($name, $cache_id, $compile_id, $exp_time) + { + // delete the whole cache + if ($name === null && $cache_id === null && $compile_id === null && $exp_time === null) { + // returning the number of deleted caches would require a second query to count them + $query = $this->db->query('TRUNCATE TABLE output_cache'); + return -1; + } + // build the filter + $where = array(); + // equal test name + if ($name !== null) { + $where[] = 'name = ' . $this->db->quote($name); + } + // equal test compile_id + if ($compile_id !== null) { + $where[] = 'compile_id = ' . $this->db->quote($compile_id); + } + // range test expiration time + if ($exp_time !== null) { + $where[] = 'modified < DATE_SUB(NOW(), INTERVAL ' . intval($exp_time) . ' SECOND)'; + } + // equal test cache_id and match sub-groups + if ($cache_id !== null) { + $where[] = '(cache_id = '. $this->db->quote($cache_id) + . ' OR cache_id LIKE '. $this->db->quote($cache_id .'|%') .')'; + } + // run delete query + $query = $this->db->query('DELETE FROM output_cache WHERE ' . join(' AND ', $where)); + return $query->rowCount(); + } +} diff --git a/library/Smarty/demo/plugins/resource.extendsall.php b/library/Smarty/demo/plugins/resource.extendsall.php new file mode 100644 index 0000000000..d8c40b5bae --- /dev/null +++ b/library/Smarty/demo/plugins/resource.extendsall.php @@ -0,0 +1,60 @@ +smarty->getTemplateDir() as $key => $directory) { + try { + $s = Smarty_Resource::source(null, $source->smarty, '[' . $key . ']' . $source->name ); + if (!$s->exists) { + continue; + } + $sources[$s->uid] = $s; + $uid .= $s->filepath; + } + catch (SmartyException $e) {} + } + + if (!$sources) { + $source->exists = false; + $source->template = $_template; + return; + } + + $sources = array_reverse($sources, true); + reset($sources); + $s = current($sources); + + $source->components = $sources; + $source->filepath = $s->filepath; + $source->uid = sha1($uid); + $source->exists = $exists; + if ($_template && $_template->smarty->compile_check) { + $source->timestamp = $s->timestamp; + } + // need the template at getContent() + $source->template = $_template; + } +} + +?> \ No newline at end of file diff --git a/library/Smarty/demo/plugins/resource.mysql.php b/library/Smarty/demo/plugins/resource.mysql.php new file mode 100644 index 0000000000..312f3fc73c --- /dev/null +++ b/library/Smarty/demo/plugins/resource.mysql.php @@ -0,0 +1,76 @@ +CREATE TABLE IF NOT EXISTS `templates` ( + * `name` varchar(100) NOT NULL, + * `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + * `source` text, + * PRIMARY KEY (`name`) + * ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + * + * Demo data: + *
    INSERT INTO `templates` (`name`, `modified`, `source`) VALUES ('test.tpl', "2010-12-25 22:00:00", '{$x="hello world"}{$x}');
    + * + * @package Resource-examples + * @author Rodney Rehm + */ +class Smarty_Resource_Mysql extends Smarty_Resource_Custom { + // PDO instance + protected $db; + // prepared fetch() statement + protected $fetch; + // prepared fetchTimestamp() statement + protected $mtime; + + public function __construct() { + try { + $this->db = new PDO("mysql:dbname=test;host=127.0.0.1", "smarty", "smarty"); + } catch (PDOException $e) { + throw new SmartyException('Mysql Resource failed: ' . $e->getMessage()); + } + $this->fetch = $this->db->prepare('SELECT modified, source FROM templates WHERE name = :name'); + $this->mtime = $this->db->prepare('SELECT modified FROM templates WHERE name = :name'); + } + + /** + * Fetch a template and its modification time from database + * + * @param string $name template name + * @param string $source template source + * @param integer $mtime template modification timestamp (epoch) + * @return void + */ + protected function fetch($name, &$source, &$mtime) + { + $this->fetch->execute(array('name' => $name)); + $row = $this->fetch->fetch(); + $this->fetch->closeCursor(); + if ($row) { + $source = $row['source']; + $mtime = strtotime($row['modified']); + } else { + $source = null; + $mtime = null; + } + } + + /** + * Fetch a template's modification time from database + * + * @note implementing this method is optional. Only implement it if modification times can be accessed faster than loading the comple template source. + * @param string $name template name + * @return integer timestamp (epoch) the template was modified + */ + protected function fetchTimestamp($name) { + $this->mtime->execute(array('name' => $name)); + $mtime = $this->mtime->fetchColumn(); + $this->mtime->closeCursor(); + return strtotime($mtime); + } +} diff --git a/library/Smarty/demo/plugins/resource.mysqls.php b/library/Smarty/demo/plugins/resource.mysqls.php new file mode 100644 index 0000000000..f9fe1c2f21 --- /dev/null +++ b/library/Smarty/demo/plugins/resource.mysqls.php @@ -0,0 +1,62 @@ +CREATE TABLE IF NOT EXISTS `templates` ( + * `name` varchar(100) NOT NULL, + * `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + * `source` text, + * PRIMARY KEY (`name`) + * ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + * + * Demo data: + *
    INSERT INTO `templates` (`name`, `modified`, `source`) VALUES ('test.tpl', "2010-12-25 22:00:00", '{$x="hello world"}{$x}');
    + * + * @package Resource-examples + * @author Rodney Rehm + */ +class Smarty_Resource_Mysqls extends Smarty_Resource_Custom { + // PDO instance + protected $db; + // prepared fetch() statement + protected $fetch; + + public function __construct() { + try { + $this->db = new PDO("mysql:dbname=test;host=127.0.0.1", "smarty", "smarty"); + } catch (PDOException $e) { + throw new SmartyException('Mysql Resource failed: ' . $e->getMessage()); + } + $this->fetch = $this->db->prepare('SELECT modified, source FROM templates WHERE name = :name'); + } + + /** + * Fetch a template and its modification time from database + * + * @param string $name template name + * @param string $source template source + * @param integer $mtime template modification timestamp (epoch) + * @return void + */ + protected function fetch($name, &$source, &$mtime) + { + $this->fetch->execute(array('name' => $name)); + $row = $this->fetch->fetch(); + $this->fetch->closeCursor(); + if ($row) { + $source = $row['source']; + $mtime = strtotime($row['modified']); + } else { + $source = null; + $mtime = null; + } + } +} diff --git a/library/Smarty/demo/templates/footer.tpl b/library/Smarty/demo/templates/footer.tpl new file mode 100644 index 0000000000..e04310fdd2 --- /dev/null +++ b/library/Smarty/demo/templates/footer.tpl @@ -0,0 +1,2 @@ + + diff --git a/library/Smarty/demo/templates/header.tpl b/library/Smarty/demo/templates/header.tpl new file mode 100644 index 0000000000..783210a187 --- /dev/null +++ b/library/Smarty/demo/templates/header.tpl @@ -0,0 +1,5 @@ + + +{$title} - {$Name} + + diff --git a/library/Smarty/demo/templates/index.tpl b/library/Smarty/demo/templates/index.tpl new file mode 100644 index 0000000000..38d2334121 --- /dev/null +++ b/library/Smarty/demo/templates/index.tpl @@ -0,0 +1,82 @@ +{config_load file="test.conf" section="setup"} +{include file="header.tpl" title=foo} + +
    +
    +{* bold and title are read from the config file *}
    +{if #bold#}{/if}
    +{* capitalize the first letters of each word of the title *}
    +Title: {#title#|capitalize}
    +{if #bold#}{/if}
    +
    +The current date and time is {$smarty.now|date_format:"%Y-%m-%d %H:%M:%S"}
    +
    +The value of global assigned variable $SCRIPT_NAME is {$SCRIPT_NAME}
    +
    +Example of accessing server environment variable SERVER_NAME: {$smarty.server.SERVER_NAME}
    +
    +The value of {ldelim}$Name{rdelim} is {$Name}
    +
    +variable modifier example of {ldelim}$Name|upper{rdelim}
    +
    +{$Name|upper}
    +
    +
    +An example of a section loop:
    +
    +{section name=outer 
    +loop=$FirstName}
    +{if $smarty.section.outer.index is odd by 2}
    +	{$smarty.section.outer.rownum} . {$FirstName[outer]} {$LastName[outer]}
    +{else}
    +	{$smarty.section.outer.rownum} * {$FirstName[outer]} {$LastName[outer]}
    +{/if}
    +{sectionelse}
    +	none
    +{/section}
    +
    +An example of section looped key values:
    +
    +{section name=sec1 loop=$contacts}
    +	phone: {$contacts[sec1].phone}
    + fax: {$contacts[sec1].fax}
    + cell: {$contacts[sec1].cell}
    +{/section} +

    + +testing strip tags +{strip} + + + + +
    + + This is a test + +
    +{/strip} + +

    + +This is an example of the html_select_date function: + +
    +{html_select_date start_year=1998 end_year=2010} +
    + +This is an example of the html_select_time function: + +
    +{html_select_time use_24_hours=false} +
    + +This is an example of the html_options function: + +
    + +
    + +{include file="footer.tpl"} diff --git a/library/Smarty/libs/Smarty.class.php b/library/Smarty/libs/Smarty.class.php new file mode 100644 index 0000000000..f776aaf7cc --- /dev/null +++ b/library/Smarty/libs/Smarty.class.php @@ -0,0 +1,1517 @@ + + * @author Uwe Tews + * @author Rodney Rehm + * @package Smarty + * @version 3.1-DEV + */ + +/** + * define shorthand directory separator constant + */ +if (!defined('DS')) { + define('DS', DIRECTORY_SEPARATOR); +} + +/** + * set SMARTY_DIR to absolute path to Smarty library files. + * Sets SMARTY_DIR only if user application has not already defined it. + */ +if (!defined('SMARTY_DIR')) { + define('SMARTY_DIR', dirname(__FILE__) . DS); +} + +/** + * set SMARTY_SYSPLUGINS_DIR to absolute path to Smarty internal plugins. + * Sets SMARTY_SYSPLUGINS_DIR only if user application has not already defined it. + */ +if (!defined('SMARTY_SYSPLUGINS_DIR')) { + define('SMARTY_SYSPLUGINS_DIR', SMARTY_DIR . 'sysplugins' . DS); +} +if (!defined('SMARTY_PLUGINS_DIR')) { + define('SMARTY_PLUGINS_DIR', SMARTY_DIR . 'plugins' . DS); +} +if (!defined('SMARTY_MBSTRING')) { + define('SMARTY_MBSTRING', function_exists('mb_strlen')); +} +if (!defined('SMARTY_RESOURCE_CHAR_SET')) { + // UTF-8 can only be done properly when mbstring is available! + /** + * @deprecated in favor of Smarty::$_CHARSET + */ + define('SMARTY_RESOURCE_CHAR_SET', SMARTY_MBSTRING ? 'UTF-8' : 'ISO-8859-1'); +} +if (!defined('SMARTY_RESOURCE_DATE_FORMAT')) { + /** + * @deprecated in favor of Smarty::$_DATE_FORMAT + */ + define('SMARTY_RESOURCE_DATE_FORMAT', '%b %e, %Y'); +} + +/** + * register the class autoloader + */ +if (!defined('SMARTY_SPL_AUTOLOAD')) { + define('SMARTY_SPL_AUTOLOAD', 0); +} + +if (SMARTY_SPL_AUTOLOAD && set_include_path(get_include_path() . PATH_SEPARATOR . SMARTY_SYSPLUGINS_DIR) !== false) { + $registeredAutoLoadFunctions = spl_autoload_functions(); + if (!isset($registeredAutoLoadFunctions['spl_autoload'])) { + spl_autoload_register(); + } +} else { + spl_autoload_register('smartyAutoload'); +} + +/** + * Load always needed external class files + */ +include_once SMARTY_SYSPLUGINS_DIR.'smarty_internal_data.php'; +include_once SMARTY_SYSPLUGINS_DIR.'smarty_internal_templatebase.php'; +include_once SMARTY_SYSPLUGINS_DIR.'smarty_internal_template.php'; +include_once SMARTY_SYSPLUGINS_DIR.'smarty_resource.php'; +include_once SMARTY_SYSPLUGINS_DIR.'smarty_internal_resource_file.php'; +include_once SMARTY_SYSPLUGINS_DIR.'smarty_cacheresource.php'; +include_once SMARTY_SYSPLUGINS_DIR.'smarty_internal_cacheresource_file.php'; + +/** + * This is the main Smarty class + * @package Smarty + */ +class Smarty extends Smarty_Internal_TemplateBase { + + /**#@+ + * constant definitions + */ + + /** + * smarty version + */ + const SMARTY_VERSION = 'Smarty-3.1.11'; + + /** + * define variable scopes + */ + const SCOPE_LOCAL = 0; + const SCOPE_PARENT = 1; + const SCOPE_ROOT = 2; + const SCOPE_GLOBAL = 3; + /** + * define caching modes + */ + const CACHING_OFF = 0; + const CACHING_LIFETIME_CURRENT = 1; + const CACHING_LIFETIME_SAVED = 2; + /** + * define compile check modes + */ + const COMPILECHECK_OFF = 0; + const COMPILECHECK_ON = 1; + const COMPILECHECK_CACHEMISS = 2; + /** + * modes for handling of "" tags in templates. + */ + const PHP_PASSTHRU = 0; //-> print tags as plain text + const PHP_QUOTE = 1; //-> escape tags as entities + const PHP_REMOVE = 2; //-> escape tags as entities + const PHP_ALLOW = 3; //-> escape tags as entities + /** + * filter types + */ + const FILTER_POST = 'post'; + const FILTER_PRE = 'pre'; + const FILTER_OUTPUT = 'output'; + const FILTER_VARIABLE = 'variable'; + /** + * plugin types + */ + const PLUGIN_FUNCTION = 'function'; + const PLUGIN_BLOCK = 'block'; + const PLUGIN_COMPILER = 'compiler'; + const PLUGIN_MODIFIER = 'modifier'; + const PLUGIN_MODIFIERCOMPILER = 'modifiercompiler'; + + /**#@-*/ + + /** + * assigned global tpl vars + */ + public static $global_tpl_vars = array(); + + /** + * error handler returned by set_error_hanlder() in Smarty::muteExpectedErrors() + */ + public static $_previous_error_handler = null; + /** + * contains directories outside of SMARTY_DIR that are to be muted by muteExpectedErrors() + */ + public static $_muted_directories = array(); + /** + * Flag denoting if Multibyte String functions are available + */ + public static $_MBSTRING = SMARTY_MBSTRING; + /** + * The character set to adhere to (e.g. "UTF-8") + */ + public static $_CHARSET = SMARTY_RESOURCE_CHAR_SET; + /** + * The date format to be used internally + * (accepts date() and strftime()) + */ + public static $_DATE_FORMAT = SMARTY_RESOURCE_DATE_FORMAT; + /** + * Flag denoting if PCRE should run in UTF-8 mode + */ + public static $_UTF8_MODIFIER = 'u'; + + /** + * Flag denoting if operating system is windows + */ + public static $_IS_WINDOWS = false; + + /**#@+ + * variables + */ + + /** + * auto literal on delimiters with whitspace + * @var boolean + */ + public $auto_literal = true; + /** + * display error on not assigned variables + * @var boolean + */ + public $error_unassigned = false; + /** + * look up relative filepaths in include_path + * @var boolean + */ + public $use_include_path = false; + /** + * template directory + * @var array + */ + private $template_dir = array(); + /** + * joined template directory string used in cache keys + * @var string + */ + public $joined_template_dir = null; + /** + * joined config directory string used in cache keys + * @var string + */ + public $joined_config_dir = null; + /** + * default template handler + * @var callable + */ + public $default_template_handler_func = null; + /** + * default config handler + * @var callable + */ + public $default_config_handler_func = null; + /** + * default plugin handler + * @var callable + */ + public $default_plugin_handler_func = null; + /** + * compile directory + * @var string + */ + private $compile_dir = null; + /** + * plugins directory + * @var array + */ + private $plugins_dir = array(); + /** + * cache directory + * @var string + */ + private $cache_dir = null; + /** + * config directory + * @var array + */ + private $config_dir = array(); + /** + * force template compiling? + * @var boolean + */ + public $force_compile = false; + /** + * check template for modifications? + * @var boolean + */ + public $compile_check = true; + /** + * use sub dirs for compiled/cached files? + * @var boolean + */ + public $use_sub_dirs = false; + /** + * allow ambiguous resources (that are made unique by the resource handler) + * @var boolean + */ + public $allow_ambiguous_resources = false; + /** + * caching enabled + * @var boolean + */ + public $caching = false; + /** + * merge compiled includes + * @var boolean + */ + public $merge_compiled_includes = false; + /** + * cache lifetime in seconds + * @var integer + */ + public $cache_lifetime = 3600; + /** + * force cache file creation + * @var boolean + */ + public $force_cache = false; + /** + * Set this if you want different sets of cache files for the same + * templates. + * + * @var string + */ + public $cache_id = null; + /** + * Set this if you want different sets of compiled files for the same + * templates. + * + * @var string + */ + public $compile_id = null; + /** + * template left-delimiter + * @var string + */ + public $left_delimiter = "{"; + /** + * template right-delimiter + * @var string + */ + public $right_delimiter = "}"; + /**#@+ + * security + */ + /** + * class name + * + * This should be instance of Smarty_Security. + * + * @var string + * @see Smarty_Security + */ + public $security_class = 'Smarty_Security'; + /** + * implementation of security class + * + * @var Smarty_Security + */ + public $security_policy = null; + /** + * controls handling of PHP-blocks + * + * @var integer + */ + public $php_handling = self::PHP_PASSTHRU; + /** + * controls if the php template file resource is allowed + * + * @var bool + */ + public $allow_php_templates = false; + /** + * Should compiled-templates be prevented from being called directly? + * + * {@internal + * Currently used by Smarty_Internal_Template only. + * }} + * + * @var boolean + */ + public $direct_access_security = true; + /**#@-*/ + /** + * debug mode + * + * Setting this to true enables the debug-console. + * + * @var boolean + */ + public $debugging = false; + /** + * 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.
    • + *
    + * @var string + */ + public $debugging_ctrl = 'NONE'; + /** + * Name of debugging URL-param. + * + * Only used when $debugging_ctrl is set to 'URL'. + * The name of the URL-parameter that activates debugging. + * + * @var type + */ + public $smarty_debug_id = 'SMARTY_DEBUG'; + /** + * Path of debug template. + * @var string + */ + public $debug_tpl = null; + /** + * When set, smarty uses this value as error_reporting-level. + * @var int + */ + public $error_reporting = null; + /** + * Internal flag for getTags() + * @var boolean + */ + public $get_used_tags = false; + + /**#@+ + * config var settings + */ + + /** + * Controls whether variables with the same name overwrite each other. + * @var boolean + */ + public $config_overwrite = true; + /** + * Controls whether config values of on/true/yes and off/false/no get converted to boolean. + * @var boolean + */ + public $config_booleanize = true; + /** + * Controls whether hidden config sections/vars are read from the file. + * @var boolean + */ + public $config_read_hidden = false; + + /**#@-*/ + + /**#@+ + * resource locking + */ + + /** + * locking concurrent compiles + * @var boolean + */ + public $compile_locking = true; + /** + * Controls whether cache resources should emply locking mechanism + * @var boolean + */ + public $cache_locking = false; + /** + * seconds to wait for acquiring a lock before ignoring the write lock + * @var float + */ + public $locking_timeout = 10; + + /**#@-*/ + + /** + * global template functions + * @var array + */ + public $template_functions = array(); + /** + * resource type used if none given + * + * Must be an valid key of $registered_resources. + * @var string + */ + public $default_resource_type = 'file'; + /** + * caching type + * + * Must be an element of $cache_resource_types. + * + * @var string + */ + public $caching_type = 'file'; + /** + * internal config properties + * @var array + */ + public $properties = array(); + /** + * config type + * @var string + */ + public $default_config_type = 'file'; + /** + * cached template objects + * @var array + */ + public $template_objects = array(); + /** + * check If-Modified-Since headers + * @var boolean + */ + public $cache_modified_check = false; + /** + * registered plugins + * @var array + */ + public $registered_plugins = array(); + /** + * plugin search order + * @var array + */ + public $plugin_search_order = array('function', 'block', 'compiler', 'class'); + /** + * registered objects + * @var array + */ + public $registered_objects = array(); + /** + * registered classes + * @var array + */ + public $registered_classes = array(); + /** + * registered filters + * @var array + */ + public $registered_filters = array(); + /** + * registered resources + * @var array + */ + public $registered_resources = array(); + /** + * resource handler cache + * @var array + */ + public $_resource_handlers = array(); + /** + * registered cache resources + * @var array + */ + public $registered_cache_resources = array(); + /** + * cache resource handler cache + * @var array + */ + public $_cacheresource_handlers = array(); + /** + * autoload filter + * @var array + */ + public $autoload_filters = array(); + /** + * default modifier + * @var array + */ + public $default_modifiers = array(); + /** + * autoescape variable output + * @var boolean + */ + public $escape_html = false; + /** + * global internal smarty vars + * @var array + */ + public static $_smarty_vars = array(); + /** + * start time for execution time calculation + * @var int + */ + public $start_time = 0; + /** + * default file permissions + * @var int + */ + public $_file_perms = 0644; + /** + * default dir permissions + * @var int + */ + public $_dir_perms = 0771; + /** + * block tag hierarchy + * @var array + */ + public $_tag_stack = array(); + /** + * self pointer to Smarty object + * @var Smarty + */ + public $smarty; + /** + * required by the compiler for BC + * @var string + */ + public $_current_file = null; + /** + * internal flag to enable parser debugging + * @var bool + */ + public $_parserdebug = false; + /** + * Saved parameter of merged templates during compilation + * + * @var array + */ + public $merged_templates_func = array(); + /**#@-*/ + + /** + * Initialize new Smarty object + * + */ + public function __construct() + { + // selfpointer needed by some other class methods + $this->smarty = $this; + if (is_callable('mb_internal_encoding')) { + mb_internal_encoding(Smarty::$_CHARSET); + } + $this->start_time = microtime(true); + // set default dirs + $this->setTemplateDir('.' . DS . 'templates' . DS) + ->setCompileDir('.' . DS . 'templates_c' . DS) + ->setPluginsDir(SMARTY_PLUGINS_DIR) + ->setCacheDir('.' . DS . 'cache' . DS) + ->setConfigDir('.' . DS . 'configs' . DS); + + $this->debug_tpl = 'file:' . dirname(__FILE__) . '/debug.tpl'; + if (isset($_SERVER['SCRIPT_NAME'])) { + $this->assignGlobal('SCRIPT_NAME', $_SERVER['SCRIPT_NAME']); + } + } + + + /** + * Class destructor + */ + public function __destruct() + { + // intentionally left blank + } + + /** + * <> set selfpointer on cloned object + */ + public function __clone() + { + $this->smarty = $this; + } + + + /** + * <> Generic getter. + * + * Calls the appropriate getter function. + * Issues an E_USER_NOTICE if no valid getter is found. + * + * @param string $name property name + * @return mixed + */ + public function __get($name) + { + $allowed = array( + 'template_dir' => 'getTemplateDir', + 'config_dir' => 'getConfigDir', + 'plugins_dir' => 'getPluginsDir', + 'compile_dir' => 'getCompileDir', + 'cache_dir' => 'getCacheDir', + ); + + if (isset($allowed[$name])) { + return $this->{$allowed[$name]}(); + } else { + trigger_error('Undefined property: '. get_class($this) .'::$'. $name, E_USER_NOTICE); + } + } + + /** + * <> Generic setter. + * + * Calls the appropriate setter function. + * Issues an E_USER_NOTICE if no valid setter is found. + * + * @param string $name property name + * @param mixed $value parameter passed to setter + */ + public function __set($name, $value) + { + $allowed = array( + 'template_dir' => 'setTemplateDir', + 'config_dir' => 'setConfigDir', + 'plugins_dir' => 'setPluginsDir', + 'compile_dir' => 'setCompileDir', + 'cache_dir' => 'setCacheDir', + ); + + if (isset($allowed[$name])) { + $this->{$allowed[$name]}($value); + } else { + trigger_error('Undefined property: ' . get_class($this) . '::$' . $name, E_USER_NOTICE); + } + } + + /** + * Check if a template resource exists + * + * @param string $resource_name template name + * @return boolean status + */ + public function templateExists($resource_name) + { + // create template object + $save = $this->template_objects; + $tpl = new $this->template_class($resource_name, $this); + // check if it does exists + $result = $tpl->source->exists; + $this->template_objects = $save; + return $result; + } + + /** + * Returns a single or all global variables + * + * @param object $smarty + * @param string $varname variable name or null + * @return string variable value or or array of variables + */ + public function getGlobal($varname = null) + { + if (isset($varname)) { + if (isset(self::$global_tpl_vars[$varname])) { + return self::$global_tpl_vars[$varname]->value; + } else { + return ''; + } + } else { + $_result = array(); + foreach (self::$global_tpl_vars AS $key => $var) { + $_result[$key] = $var->value; + } + return $_result; + } + } + + /** + * Empty cache folder + * + * @param integer $exp_time expiration time + * @param string $type resource type + * @return integer number of cache files deleted + */ + function clearAllCache($exp_time = null, $type = null) + { + // load cache resource and call clearAll + $_cache_resource = Smarty_CacheResource::load($this, $type); + Smarty_CacheResource::invalidLoadedCache($this); + return $_cache_resource->clearAll($this, $exp_time); + } + + /** + * Empty cache for a specific template + * + * @param string $template_name template name + * @param string $cache_id cache id + * @param string $compile_id compile id + * @param integer $exp_time expiration time + * @param string $type resource type + * @return integer number of cache files deleted + */ + public function clearCache($template_name, $cache_id = null, $compile_id = null, $exp_time = null, $type = null) + { + // load cache resource and call clear + $_cache_resource = Smarty_CacheResource::load($this, $type); + Smarty_CacheResource::invalidLoadedCache($this); + return $_cache_resource->clear($this, $template_name, $cache_id, $compile_id, $exp_time); + } + + /** + * Loads security class and enables security + * + * @param string|Smarty_Security $security_class if a string is used, it must be class-name + * @return Smarty current Smarty instance for chaining + * @throws SmartyException when an invalid class name is provided + */ + public function enableSecurity($security_class = null) + { + if ($security_class instanceof Smarty_Security) { + $this->security_policy = $security_class; + return $this; + } elseif (is_object($security_class)) { + throw new SmartyException("Class '" . get_class($security_class) . "' must extend Smarty_Security."); + } + if ($security_class == null) { + $security_class = $this->security_class; + } + if (!class_exists($security_class)) { + throw new SmartyException("Security class '$security_class' is not defined"); + } elseif ($security_class !== 'Smarty_Security' && !is_subclass_of($security_class, 'Smarty_Security')) { + throw new SmartyException("Class '$security_class' must extend Smarty_Security."); + } else { + $this->security_policy = new $security_class($this); + } + + return $this; + } + + /** + * Disable security + * @return Smarty current Smarty instance for chaining + */ + public function disableSecurity() + { + $this->security_policy = null; + + return $this; + } + + /** + * Set template directory + * + * @param string|array $template_dir directory(s) of template sources + * @return Smarty current Smarty instance for chaining + */ + public function setTemplateDir($template_dir) + { + $this->template_dir = array(); + foreach ((array) $template_dir as $k => $v) { + $this->template_dir[$k] = rtrim($v, '/\\') . DS; + } + + $this->joined_template_dir = join(DIRECTORY_SEPARATOR, $this->template_dir); + return $this; + } + + /** + * Add template directory(s) + * + * @param string|array $template_dir directory(s) of template sources + * @param string $key of the array element to assign the template dir to + * @return Smarty current Smarty instance for chaining + * @throws SmartyException when the given template directory is not valid + */ + public function addTemplateDir($template_dir, $key=null) + { + // make sure we're dealing with an array + $this->template_dir = (array) $this->template_dir; + + if (is_array($template_dir)) { + foreach ($template_dir as $k => $v) { + if (is_int($k)) { + // indexes are not merged but appended + $this->template_dir[] = rtrim($v, '/\\') . DS; + } else { + // string indexes are overridden + $this->template_dir[$k] = rtrim($v, '/\\') . DS; + } + } + } elseif ($key !== null) { + // override directory at specified index + $this->template_dir[$key] = rtrim($template_dir, '/\\') . DS; + } else { + // append new directory + $this->template_dir[] = rtrim($template_dir, '/\\') . DS; + } + $this->joined_template_dir = join(DIRECTORY_SEPARATOR, $this->template_dir); + return $this; + } + + /** + * Get template directories + * + * @param mixed index of directory to get, null to get all + * @return array|string list of template directories, or directory of $index + */ + public function getTemplateDir($index=null) + { + if ($index !== null) { + return isset($this->template_dir[$index]) ? $this->template_dir[$index] : null; + } + + return (array)$this->template_dir; + } + + /** + * Set config directory + * + * @param string|array $template_dir directory(s) of configuration sources + * @return Smarty current Smarty instance for chaining + */ + public function setConfigDir($config_dir) + { + $this->config_dir = array(); + foreach ((array) $config_dir as $k => $v) { + $this->config_dir[$k] = rtrim($v, '/\\') . DS; + } + + $this->joined_config_dir = join(DIRECTORY_SEPARATOR, $this->config_dir); + return $this; + } + + /** + * Add config directory(s) + * + * @param string|array $config_dir directory(s) of config sources + * @param string key of the array element to assign the config dir to + * @return Smarty current Smarty instance for chaining + */ + public function addConfigDir($config_dir, $key=null) + { + // make sure we're dealing with an array + $this->config_dir = (array) $this->config_dir; + + if (is_array($config_dir)) { + foreach ($config_dir as $k => $v) { + if (is_int($k)) { + // indexes are not merged but appended + $this->config_dir[] = rtrim($v, '/\\') . DS; + } else { + // string indexes are overridden + $this->config_dir[$k] = rtrim($v, '/\\') . DS; + } + } + } elseif( $key !== null ) { + // override directory at specified index + $this->config_dir[$key] = rtrim($config_dir, '/\\') . DS; + } else { + // append new directory + $this->config_dir[] = rtrim($config_dir, '/\\') . DS; + } + + $this->joined_config_dir = join(DIRECTORY_SEPARATOR, $this->config_dir); + return $this; + } + + /** + * Get config directory + * + * @param mixed index of directory to get, null to get all + * @return array|string configuration directory + */ + public function getConfigDir($index=null) + { + if ($index !== null) { + return isset($this->config_dir[$index]) ? $this->config_dir[$index] : null; + } + + return (array)$this->config_dir; + } + + /** + * Set plugins directory + * + * @param string|array $plugins_dir directory(s) of plugins + * @return Smarty current Smarty instance for chaining + */ + public function setPluginsDir($plugins_dir) + { + $this->plugins_dir = array(); + foreach ((array)$plugins_dir as $k => $v) { + $this->plugins_dir[$k] = rtrim($v, '/\\') . DS; + } + + return $this; + } + + /** + * Adds directory of plugin files + * + * @param object $smarty + * @param string $ |array $ plugins folder + * @return Smarty current Smarty instance for chaining + */ + public function addPluginsDir($plugins_dir) + { + // make sure we're dealing with an array + $this->plugins_dir = (array) $this->plugins_dir; + + if (is_array($plugins_dir)) { + foreach ($plugins_dir as $k => $v) { + if (is_int($k)) { + // indexes are not merged but appended + $this->plugins_dir[] = rtrim($v, '/\\') . DS; + } else { + // string indexes are overridden + $this->plugins_dir[$k] = rtrim($v, '/\\') . DS; + } + } + } else { + // append new directory + $this->plugins_dir[] = rtrim($plugins_dir, '/\\') . DS; + } + + $this->plugins_dir = array_unique($this->plugins_dir); + return $this; + } + + /** + * Get plugin directories + * + * @return array list of plugin directories + */ + public function getPluginsDir() + { + return (array)$this->plugins_dir; + } + + /** + * Set compile directory + * + * @param string $compile_dir directory to store compiled templates in + * @return Smarty current Smarty instance for chaining + */ + public function setCompileDir($compile_dir) + { + $this->compile_dir = rtrim($compile_dir, '/\\') . DS; + if (!isset(Smarty::$_muted_directories[$this->compile_dir])) { + Smarty::$_muted_directories[$this->compile_dir] = null; + } + return $this; + } + + /** + * Get compiled directory + * + * @return string path to compiled templates + */ + public function getCompileDir() + { + return $this->compile_dir; + } + + /** + * Set cache directory + * + * @param string $cache_dir directory to store cached templates in + * @return Smarty current Smarty instance for chaining + */ + public function setCacheDir($cache_dir) + { + $this->cache_dir = rtrim($cache_dir, '/\\') . DS; + if (!isset(Smarty::$_muted_directories[$this->cache_dir])) { + Smarty::$_muted_directories[$this->cache_dir] = null; + } + return $this; + } + + /** + * Get cache directory + * + * @return string path of cache directory + */ + public function getCacheDir() + { + return $this->cache_dir; + } + + /** + * Set default modifiers + * + * @param array|string $modifiers modifier or list of modifiers to set + * @return Smarty current Smarty instance for chaining + */ + public function setDefaultModifiers($modifiers) + { + $this->default_modifiers = (array) $modifiers; + return $this; + } + + /** + * Add default modifiers + * + * @param array|string $modifiers modifier or list of modifiers to add + * @return Smarty current Smarty instance for chaining + */ + public function addDefaultModifiers($modifiers) + { + if (is_array($modifiers)) { + $this->default_modifiers = array_merge($this->default_modifiers, $modifiers); + } else { + $this->default_modifiers[] = $modifiers; + } + + return $this; + } + + /** + * Get default modifiers + * + * @return array list of default modifiers + */ + public function getDefaultModifiers() + { + return $this->default_modifiers; + } + + + /** + * Set autoload filters + * + * @param array $filters filters to load automatically + * @param string $type "pre", "output", … specify the filter type to set. Defaults to none treating $filters' keys as the appropriate types + * @return Smarty current Smarty instance for chaining + */ + public function setAutoloadFilters($filters, $type=null) + { + if ($type !== null) { + $this->autoload_filters[$type] = (array) $filters; + } else { + $this->autoload_filters = (array) $filters; + } + + return $this; + } + + /** + * Add autoload filters + * + * @param array $filters filters to load automatically + * @param string $type "pre", "output", … specify the filter type to set. Defaults to none treating $filters' keys as the appropriate types + * @return Smarty current Smarty instance for chaining + */ + public function addAutoloadFilters($filters, $type=null) + { + if ($type !== null) { + if (!empty($this->autoload_filters[$type])) { + $this->autoload_filters[$type] = array_merge($this->autoload_filters[$type], (array) $filters); + } else { + $this->autoload_filters[$type] = (array) $filters; + } + } else { + foreach ((array) $filters as $key => $value) { + if (!empty($this->autoload_filters[$key])) { + $this->autoload_filters[$key] = array_merge($this->autoload_filters[$key], (array) $value); + } else { + $this->autoload_filters[$key] = (array) $value; + } + } + } + + return $this; + } + + /** + * Get autoload filters + * + * @param string $type type of filter to get autoloads for. Defaults to all autoload filters + * @return array array( 'type1' => array( 'filter1', 'filter2', … ) ) or array( 'filter1', 'filter2', …) if $type was specified + */ + public function getAutoloadFilters($type=null) + { + if ($type !== null) { + return isset($this->autoload_filters[$type]) ? $this->autoload_filters[$type] : array(); + } + + return $this->autoload_filters; + } + + /** + * return name of debugging template + * + * @return string + */ + public function getDebugTemplate() + { + return $this->debug_tpl; + } + + /** + * set the debug template + * + * @param string $tpl_name + * @return Smarty current Smarty instance for chaining + * @throws SmartyException if file is not readable + */ + public function setDebugTemplate($tpl_name) + { + if (!is_readable($tpl_name)) { + throw new SmartyException("Unknown file '{$tpl_name}'"); + } + $this->debug_tpl = $tpl_name; + + return $this; + } + + /** + * creates a template object + * + * @param string $template the resource handle of the template file + * @param mixed $cache_id cache id to be used with this template + * @param mixed $compile_id compile id to be used with this template + * @param object $parent next higher level of Smarty variables + * @param boolean $do_clone flag is Smarty object shall be cloned + * @return object template object + */ + public function createTemplate($template, $cache_id = null, $compile_id = null, $parent = null, $do_clone = true) + { + if (!empty($cache_id) && (is_object($cache_id) || is_array($cache_id))) { + $parent = $cache_id; + $cache_id = null; + } + if (!empty($parent) && is_array($parent)) { + $data = $parent; + $parent = null; + } else { + $data = null; + } + // default to cache_id and compile_id of Smarty object + $cache_id = $cache_id === null ? $this->cache_id : $cache_id; + $compile_id = $compile_id === null ? $this->compile_id : $compile_id; + // already in template cache? + if ($this->allow_ambiguous_resources) { + $_templateId = Smarty_Resource::getUniqueTemplateName($this, $template) . $cache_id . $compile_id; + } else { + $_templateId = $this->joined_template_dir . '#' . $template . $cache_id . $compile_id; + } + if (isset($_templateId[150])) { + $_templateId = sha1($_templateId); + } + if ($do_clone) { + if (isset($this->template_objects[$_templateId])) { + // return cached template object + $tpl = clone $this->template_objects[$_templateId]; + $tpl->smarty = clone $tpl->smarty; + $tpl->parent = $parent; + $tpl->tpl_vars = array(); + $tpl->config_vars = array(); + } else { + $tpl = new $this->template_class($template, clone $this, $parent, $cache_id, $compile_id); + } + } else { + if (isset($this->template_objects[$_templateId])) { + // return cached template object + $tpl = $this->template_objects[$_templateId]; + $tpl->parent = $parent; + $tpl->tpl_vars = array(); + $tpl->config_vars = array(); + } else { + $tpl = new $this->template_class($template, $this, $parent, $cache_id, $compile_id); + } + } + // fill data if present + if (!empty($data) && is_array($data)) { + // set up variable values + foreach ($data as $_key => $_val) { + $tpl->tpl_vars[$_key] = new Smarty_variable($_val); + } + } + return $tpl; + } + + + /** + * Takes unknown classes and loads plugin files for them + * class name format: Smarty_PluginType_PluginName + * plugin filename format: plugintype.pluginname.php + * + * @param string $plugin_name class plugin name to load + * @param bool $check check if already loaded + * @return string |boolean filepath of loaded file or false + */ + public function loadPlugin($plugin_name, $check = true) + { + // if function or class exists, exit silently (already loaded) + if ($check && (is_callable($plugin_name) || class_exists($plugin_name, false))) { + return true; + } + // Plugin name is expected to be: Smarty_[Type]_[Name] + $_name_parts = explode('_', $plugin_name, 3); + // class name must have three parts to be valid plugin + // count($_name_parts) < 3 === !isset($_name_parts[2]) + if (!isset($_name_parts[2]) || strtolower($_name_parts[0]) !== 'smarty') { + throw new SmartyException("plugin {$plugin_name} is not a valid name format"); + return false; + } + // if type is "internal", get plugin from sysplugins + if (strtolower($_name_parts[1]) == 'internal') { + $file = SMARTY_SYSPLUGINS_DIR . strtolower($plugin_name) . '.php'; + if (file_exists($file)) { + require_once($file); + return $file; + } else { + return false; + } + } + // plugin filename is expected to be: [type].[name].php + $_plugin_filename = "{$_name_parts[1]}.{$_name_parts[2]}.php"; + + $_stream_resolve_include_path = function_exists('stream_resolve_include_path'); + + // loop through plugin dirs and find the plugin + foreach($this->getPluginsDir() as $_plugin_dir) { + $names = array( + $_plugin_dir . $_plugin_filename, + $_plugin_dir . strtolower($_plugin_filename), + ); + foreach ($names as $file) { + if (file_exists($file)) { + require_once($file); + return $file; + } + if ($this->use_include_path && !preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $_plugin_dir)) { + // try PHP include_path + if ($_stream_resolve_include_path) { + $file = stream_resolve_include_path($file); + } else { + $file = Smarty_Internal_Get_Include_Path::getIncludePath($file); + } + + if ($file !== false) { + require_once($file); + return $file; + } + } + } + } + // no plugin loaded + return false; + } + + /** + * Compile all template files + * + * @param string $extension file extension + * @param bool $force_compile force all to recompile + * @param int $time_limit + * @param int $max_errors + * @return integer number of template files recompiled + */ + public function compileAllTemplates($extention = '.tpl', $force_compile = false, $time_limit = 0, $max_errors = null) + { + return Smarty_Internal_Utility::compileAllTemplates($extention, $force_compile, $time_limit, $max_errors, $this); + } + + /** + * Compile all config files + * + * @param string $extension file extension + * @param bool $force_compile force all to recompile + * @param int $time_limit + * @param int $max_errors + * @return integer number of template files recompiled + */ + public function compileAllConfig($extention = '.conf', $force_compile = false, $time_limit = 0, $max_errors = null) + { + return Smarty_Internal_Utility::compileAllConfig($extention, $force_compile, $time_limit, $max_errors, $this); + } + + /** + * Delete compiled template file + * + * @param string $resource_name template name + * @param string $compile_id compile id + * @param integer $exp_time expiration time + * @return integer number of template files deleted + */ + public function clearCompiledTemplate($resource_name = null, $compile_id = null, $exp_time = null) + { + return Smarty_Internal_Utility::clearCompiledTemplate($resource_name, $compile_id, $exp_time, $this); + } + + + /** + * Return array of tag/attributes of all tags used by an template + * + * @param object $templae template object + * @return array of tag/attributes + */ + public function getTags(Smarty_Internal_Template $template) + { + return Smarty_Internal_Utility::getTags($template); + } + + /** + * Run installation test + * + * @param array $errors Array to write errors into, rather than outputting them + * @return boolean true if setup is fine, false if something is wrong + */ + public function testInstall(&$errors=null) + { + return Smarty_Internal_Utility::testInstall($this, $errors); + } + + /** + * Error Handler to mute expected messages + * + * @link http://php.net/set_error_handler + * @param integer $errno Error level + * @return boolean + */ + public static function mutingErrorHandler($errno, $errstr, $errfile, $errline, $errcontext) + { + $_is_muted_directory = false; + + // add the SMARTY_DIR to the list of muted directories + if (!isset(Smarty::$_muted_directories[SMARTY_DIR])) { + $smarty_dir = realpath(SMARTY_DIR); + Smarty::$_muted_directories[SMARTY_DIR] = array( + 'file' => $smarty_dir, + 'length' => strlen($smarty_dir), + ); + } + + // walk the muted directories and test against $errfile + foreach (Smarty::$_muted_directories as $key => &$dir) { + if (!$dir) { + // resolve directory and length for speedy comparisons + $file = realpath($key); + $dir = array( + 'file' => $file, + 'length' => strlen($file), + ); + } + if (!strncmp($errfile, $dir['file'], $dir['length'])) { + $_is_muted_directory = true; + break; + } + } + + // pass to next error handler if this error did not occur inside SMARTY_DIR + // or the error was within smarty but masked to be ignored + if (!$_is_muted_directory || ($errno && $errno & error_reporting())) { + if (Smarty::$_previous_error_handler) { + return call_user_func(Smarty::$_previous_error_handler, $errno, $errstr, $errfile, $errline, $errcontext); + } else { + return false; + } + } + } + + /** + * Enable error handler to mute expected messages + * + * @return void + */ + public static function muteExpectedErrors() + { + /* + error muting is done because some people implemented custom error_handlers using + http://php.net/set_error_handler and for some reason did not understand the following paragraph: + + It is important to remember that the standard PHP error handler is completely bypassed for the + error types specified by error_types unless the callback function returns FALSE. + error_reporting() settings will have no effect and your error handler will be called regardless - + however you are still able to read the current value of error_reporting and act appropriately. + Of particular note is that this value will be 0 if the statement that caused the error was + prepended by the @ error-control operator. + + Smarty deliberately uses @filemtime() over file_exists() and filemtime() in some places. Reasons include + - @filemtime() is almost twice as fast as using an additional file_exists() + - between file_exists() and filemtime() a possible race condition is opened, + which does not exist using the simple @filemtime() approach. + */ + $error_handler = array('Smarty', 'mutingErrorHandler'); + $previous = set_error_handler($error_handler); + + // avoid dead loops + if ($previous !== $error_handler) { + Smarty::$_previous_error_handler = $previous; + } + } + + /** + * Disable error handler muting expected messages + * + * @return void + */ + public static function unmuteExpectedErrors() + { + restore_error_handler(); + } +} + +// Check if we're running on windows +Smarty::$_IS_WINDOWS = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; + +// let PCRE (preg_*) treat strings as ISO-8859-1 if we're not dealing with UTF-8 +if (Smarty::$_CHARSET !== 'UTF-8') { + Smarty::$_UTF8_MODIFIER = ''; +} + +/** + * Smarty exception class + * @package Smarty + */ +class SmartyException extends Exception { +} + +/** + * Smarty compiler exception class + * @package Smarty + */ +class SmartyCompilerException extends SmartyException { +} + +/** + * Autoloader + */ +function smartyAutoload($class) +{ + $_class = strtolower($class); + $_classes = array( + 'smarty_config_source' => true, + 'smarty_config_compiled' => true, + 'smarty_security' => true, + 'smarty_cacheresource' => true, + 'smarty_cacheresource_custom' => true, + 'smarty_cacheresource_keyvaluestore' => true, + 'smarty_resource' => true, + 'smarty_resource_custom' => true, + 'smarty_resource_uncompiled' => true, + 'smarty_resource_recompiled' => true, + ); + + if (!strncmp($_class, 'smarty_internal_', 16) || isset($_classes[$_class])) { + include SMARTY_SYSPLUGINS_DIR . $_class . '.php'; + } +} + +?> diff --git a/library/Smarty/libs/SmartyBC.class.php b/library/Smarty/libs/SmartyBC.class.php new file mode 100644 index 0000000000..f8f0a138f8 --- /dev/null +++ b/library/Smarty/libs/SmartyBC.class.php @@ -0,0 +1,460 @@ + + * @author Uwe Tews + * @author Rodney Rehm + * @package Smarty + */ +/** + * @ignore + */ +require(dirname(__FILE__) . '/Smarty.class.php'); + +/** + * Smarty Backward Compatability Wrapper Class + * + * @package Smarty + */ +class SmartyBC extends Smarty { + + /** + * Smarty 2 BC + * @var string + */ + public $_version = self::SMARTY_VERSION; + + /** + * Initialize new SmartyBC object + * + * @param array $options options to set during initialization, e.g. array( 'forceCompile' => false ) + */ + public function __construct(array $options=array()) + { + parent::__construct($options); + // register {php} tag + $this->registerPlugin('block', 'php', 'smarty_php_tag'); + } + + /** + * wrapper for assign_by_ref + * + * @param string $tpl_var the template variable name + * @param mixed &$value the referenced value to assign + */ + public function assign_by_ref($tpl_var, &$value) + { + $this->assignByRef($tpl_var, $value); + } + + /** + * wrapper for append_by_ref + * + * @param string $tpl_var the template variable name + * @param mixed &$value the referenced value to append + * @param boolean $merge flag if array elements shall be merged + */ + public function append_by_ref($tpl_var, &$value, $merge = false) + { + $this->appendByRef($tpl_var, $value, $merge); + } + + /** + * clear the given assigned template variable. + * + * @param string $tpl_var the template variable to clear + */ + public function clear_assign($tpl_var) + { + $this->clearAssign($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 + * @param bool $cacheable + * @param mixed $cache_attrs + */ + public function register_function($function, $function_impl, $cacheable=true, $cache_attrs=null) + { + $this->registerPlugin('function', $function, $function_impl, $cacheable, $cache_attrs); + } + + /** + * Unregisters custom function + * + * @param string $function name of template function + */ + public function unregister_function($function) + { + $this->unregisterPlugin('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 array $allowed list of allowed methods (empty = all) + * @param boolean $smarty_args smarty argument format, else traditional + * @param array $block_functs list of methods that are block format + */ + public function register_object($object, $object_impl, $allowed = array(), $smarty_args = true, $block_methods = array()) + { + settype($allowed, 'array'); + settype($smarty_args, 'boolean'); + $this->registerObject($object, $object_impl, $allowed, $smarty_args, $block_methods); + } + + /** + * Unregisters object + * + * @param string $object name of template object + */ + public function unregister_object($object) + { + $this->unregisterObject($object); + } + + /** + * Registers block function to be used in templates + * + * @param string $block name of template block + * @param string $block_impl PHP function to register + * @param bool $cacheable + * @param mixed $cache_attrs + */ + public function register_block($block, $block_impl, $cacheable=true, $cache_attrs=null) + { + $this->registerPlugin('block', $block, $block_impl, $cacheable, $cache_attrs); + } + + /** + * Unregisters block function + * + * @param string $block name of template function + */ + public function unregister_block($block) + { + $this->unregisterPlugin('block', $block); + } + + /** + * Registers compiler function + * + * @param string $function name of template function + * @param string $function_impl name of PHP function to register + * @param bool $cacheable + */ + public function register_compiler_function($function, $function_impl, $cacheable=true) + { + $this->registerPlugin('compiler', $function, $function_impl, $cacheable); + } + + /** + * Unregisters compiler function + * + * @param string $function name of template function + */ + public function unregister_compiler_function($function) + { + $this->unregisterPlugin('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 + */ + public function register_modifier($modifier, $modifier_impl) + { + $this->registerPlugin('modifier', $modifier, $modifier_impl); + } + + /** + * Unregisters modifier + * + * @param string $modifier name of template modifier + */ + public function unregister_modifier($modifier) + { + $this->unregisterPlugin('modifier', $modifier); + } + + /** + * Registers a resource to fetch a template + * + * @param string $type name of resource + * @param array $functions array of functions to handle resource + */ + public function register_resource($type, $functions) + { + $this->registerResource($type, $functions); + } + + /** + * Unregisters a resource + * + * @param string $type name of resource + */ + public function unregister_resource($type) + { + $this->unregisterResource($type); + } + + /** + * Registers a prefilter function to apply + * to a template before compiling + * + * @param callable $function + */ + public function register_prefilter($function) + { + $this->registerFilter('pre', $function); + } + + /** + * Unregisters a prefilter function + * + * @param callable $function + */ + public function unregister_prefilter($function) + { + $this->unregisterFilter('pre', $function); + } + + /** + * Registers a postfilter function to apply + * to a compiled template after compilation + * + * @param callable $function + */ + public function register_postfilter($function) + { + $this->registerFilter('post', $function); + } + + /** + * Unregisters a postfilter function + * + * @param callable $function + */ + public function unregister_postfilter($function) + { + $this->unregisterFilter('post', $function); + } + + /** + * Registers an output filter function to apply + * to a template output + * + * @param callable $function + */ + public function register_outputfilter($function) + { + $this->registerFilter('output', $function); + } + + /** + * Unregisters an outputfilter function + * + * @param callable $function + */ + public function unregister_outputfilter($function) + { + $this->unregisterFilter('output', $function); + } + + /** + * load a filter of specified type and name + * + * @param string $type filter type + * @param string $name filter name + */ + public function load_filter($type, $name) + { + $this->loadFilter($type, $name); + } + + /** + * 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 + */ + public function clear_cache($tpl_file = null, $cache_id = null, $compile_id = null, $exp_time = null) + { + return $this->clearCache($tpl_file, $cache_id, $compile_id, $exp_time); + } + + /** + * clear the entire contents of cache (all templates) + * + * @param string $exp_time expire time + * @return boolean + */ + public function clear_all_cache($exp_time = null) + { + return $this->clearCache(null, null, null, $exp_time); + } + + /** + * 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 boolean + */ + public function is_cached($tpl_file, $cache_id = null, $compile_id = null) + { + return $this->isCached($tpl_file, $cache_id, $compile_id); + } + + /** + * clear all the assigned template variables. + */ + public function clear_all_assign() + { + $this->clearAllAssign(); + } + + /** + * 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()} + */ + public function clear_compiled_tpl($tpl_file = null, $compile_id = null, $exp_time = null) + { + return $this->clearCompiledTemplate($tpl_file, $compile_id, $exp_time); + } + + /** + * Checks whether requested template exists. + * + * @param string $tpl_file + * @return boolean + */ + public function template_exists($tpl_file) + { + return $this->templateExists($tpl_file); + } + + /** + * Returns an array containing template variables + * + * @param string $name + * @return array + */ + public function get_template_vars($name=null) + { + return $this->getTemplateVars($name); + } + + /** + * Returns an array containing config variables + * + * @param string $name + * @return array + */ + public function get_config_vars($name=null) + { + return $this->getConfigVars($name); + } + + /** + * load configuration values + * + * @param string $file + * @param string $section + * @param string $scope + */ + public function config_load($file, $section = null, $scope = 'global') + { + $this->ConfigLoad($file, $section, $scope); + } + + /** + * return a reference to a registered object + * + * @param string $name + * @return object + */ + public function get_registered_object($name) + { + return $this->getRegisteredObject($name); + } + + /** + * clear configuration values + * + * @param string $var + */ + public function clear_config($var = null) + { + $this->clearConfig($var); + } + + /** + * trigger Smarty error + * + * @param string $error_msg + * @param integer $error_type + */ + public function trigger_error($error_msg, $error_type = E_USER_WARNING) + { + trigger_error("Smarty error: $error_msg", $error_type); + } + +} + +/** + * Smarty {php}{/php} block function + * + * @param array $params parameter list + * @param string $content contents of the block + * @param object $template template object + * @param boolean &$repeat repeat flag + * @return string content re-formatted + */ +function smarty_php_tag($params, $content, $template, &$repeat) +{ + eval($content); + return ''; +} + +?> \ No newline at end of file diff --git a/library/Smarty/libs/debug.tpl b/library/Smarty/libs/debug.tpl new file mode 100644 index 0000000000..12eef0ffdb --- /dev/null +++ b/library/Smarty/libs/debug.tpl @@ -0,0 +1,133 @@ +{capture name='_smarty_debug' assign=debug_output} + + + + Smarty Debug Console + + + + +

    Smarty Debug Console - {if isset($template_name)}{$template_name|debug_print_var nofilter}{else}Total Time {$execution_time|string_format:"%.5f"}{/if}

    + +{if !empty($template_data)} +

    included templates & config files (load time in seconds)

    + +
    +{foreach $template_data as $template} + {$template.name} + + (compile {$template['compile_time']|string_format:"%.5f"}) (render {$template['render_time']|string_format:"%.5f"}) (cache {$template['cache_time']|string_format:"%.5f"}) + +
    +{/foreach} +
    +{/if} + +

    assigned template variables

    + + + {foreach $assigned_vars as $vars} + + + + {/foreach} +
    ${$vars@key|escape:'html'}{$vars|debug_print_var nofilter}
    + +

    assigned config file variables (outer template scope)

    + + + {foreach $config_vars as $vars} + + + + {/foreach} + +
    {$vars@key|escape:'html'}{$vars|debug_print_var nofilter}
    + + +{/capture} + diff --git a/library/Smarty/libs/plugins/block.textformat.php b/library/Smarty/libs/plugins/block.textformat.php new file mode 100644 index 0000000000..b22b104a55 --- /dev/null +++ b/library/Smarty/libs/plugins/block.textformat.php @@ -0,0 +1,113 @@ + + * Name: textformat
    + * Purpose: format text a certain way with preset styles + * or custom wrap/indent settings
    + * Params: + *
    + * - style         - string (email)
    + * - indent        - integer (0)
    + * - wrap          - integer (80)
    + * - wrap_char     - string ("\n")
    + * - indent_char   - string (" ")
    + * - wrap_boundary - boolean (true)
    + * 
    + * + * @link http://www.smarty.net/manual/en/language.function.textformat.php {textformat} + * (Smarty online manual) + * @param array $params parameters + * @param string $content contents of the block + * @param Smarty_Internal_Template $template template object + * @param boolean &$repeat repeat flag + * @return string content re-formatted + * @author Monte Ohrt + */ +function smarty_block_textformat($params, $content, $template, &$repeat) +{ + if (is_null($content)) { + return; + } + + $style = null; + $indent = 0; + $indent_first = 0; + $indent_char = ' '; + $wrap = 80; + $wrap_char = "\n"; + $wrap_cut = false; + $assign = null; + + foreach ($params as $_key => $_val) { + switch ($_key) { + case 'style': + case 'indent_char': + case 'wrap_char': + case 'assign': + $$_key = (string)$_val; + break; + + case 'indent': + case 'indent_first': + case 'wrap': + $$_key = (int)$_val; + break; + + case 'wrap_cut': + $$_key = (bool)$_val; + break; + + default: + trigger_error("textformat: unknown attribute '$_key'"); + } + } + + if ($style == 'email') { + $wrap = 72; + } + // split into paragraphs + $_paragraphs = preg_split('![\r\n]{2}!', $content); + $_output = ''; + + + foreach ($_paragraphs as &$_paragraph) { + if (!$_paragraph) { + continue; + } + // convert mult. spaces & special chars to single space + $_paragraph = preg_replace(array('!\s+!' . Smarty::$_UTF8_MODIFIER, '!(^\s+)|(\s+$)!' . Smarty::$_UTF8_MODIFIER), array(' ', ''), $_paragraph); + // indent first line + if ($indent_first > 0) { + $_paragraph = str_repeat($indent_char, $indent_first) . $_paragraph; + } + // wordwrap sentences + if (Smarty::$_MBSTRING) { + require_once(SMARTY_PLUGINS_DIR . 'shared.mb_wordwrap.php'); + $_paragraph = smarty_mb_wordwrap($_paragraph, $wrap - $indent, $wrap_char, $wrap_cut); + } else { + $_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 = implode($wrap_char . $wrap_char, $_paragraphs); + + if ($assign) { + $template->assign($assign, $_output); + } else { + return $_output; + } +} + +?> \ No newline at end of file diff --git a/library/Smarty/libs/plugins/function.counter.php b/library/Smarty/libs/plugins/function.counter.php new file mode 100644 index 0000000000..3906badf0f --- /dev/null +++ b/library/Smarty/libs/plugins/function.counter.php @@ -0,0 +1,78 @@ + + * Name: counter
    + * Purpose: print out a counter value + * + * @author Monte Ohrt + * @link http://www.smarty.net/manual/en/language.function.counter.php {counter} + * (Smarty online manual) + * @param array $params parameters + * @param Smarty_Internal_Template $template template object + * @return string|null + */ +function smarty_function_counter($params, $template) +{ + static $counters = array(); + + $name = (isset($params['name'])) ? $params['name'] : 'default'; + if (!isset($counters[$name])) { + $counters[$name] = array( + 'start'=>1, + 'skip'=>1, + 'direction'=>'up', + 'count'=>1 + ); + } + $counter =& $counters[$name]; + + if (isset($params['start'])) { + $counter['start'] = $counter['count'] = (int)$params['start']; + } + + if (!empty($params['assign'])) { + $counter['assign'] = $params['assign']; + } + + if (isset($counter['assign'])) { + $template->assign($counter['assign'], $counter['count']); + } + + if (isset($params['print'])) { + $print = (bool)$params['print']; + } else { + $print = empty($counter['assign']); + } + + if ($print) { + $retval = $counter['count']; + } else { + $retval = null; + } + + if (isset($params['skip'])) { + $counter['skip'] = $params['skip']; + } + + if (isset($params['direction'])) { + $counter['direction'] = $params['direction']; + } + + if ($counter['direction'] == "down") + $counter['count'] -= $counter['skip']; + else + $counter['count'] += $counter['skip']; + + return $retval; + +} + +?> \ No newline at end of file diff --git a/library/Smarty/libs/plugins/function.cycle.php b/library/Smarty/libs/plugins/function.cycle.php new file mode 100644 index 0000000000..1778ffb538 --- /dev/null +++ b/library/Smarty/libs/plugins/function.cycle.php @@ -0,0 +1,106 @@ + + * Name: cycle
    + * Date: May 3, 2002
    + * Purpose: cycle through given values
    + * Params: + *
    + * - 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://www.smarty.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 $params parameters + * @param Smarty_Internal_Template $template template object + * @return string|null + */ + +function smarty_function_cycle($params, $template) +{ + static $cycle_vars; + + $name = (empty($params['name'])) ? 'default' : $params['name']; + $print = (isset($params['print'])) ? (bool)$params['print'] : true; + $advance = (isset($params['advance'])) ? (bool)$params['advance'] : true; + $reset = (isset($params['reset'])) ? (bool)$params['reset'] : false; + + if (!isset($params['values'])) { + if(!isset($cycle_vars[$name]['values'])) { + trigger_error("cycle: missing 'values' parameter"); + return; + } + } else { + if(isset($cycle_vars[$name]['values']) + && $cycle_vars[$name]['values'] != $params['values'] ) { + $cycle_vars[$name]['index'] = 0; + } + $cycle_vars[$name]['values'] = $params['values']; + } + + if (isset($params['delimiter'])) { + $cycle_vars[$name]['delimiter'] = $params['delimiter']; + } elseif (!isset($cycle_vars[$name]['delimiter'])) { + $cycle_vars[$name]['delimiter'] = ','; + } + + if(is_array($cycle_vars[$name]['values'])) { + $cycle_array = $cycle_vars[$name]['values']; + } else { + $cycle_array = explode($cycle_vars[$name]['delimiter'],$cycle_vars[$name]['values']); + } + + if(!isset($cycle_vars[$name]['index']) || $reset ) { + $cycle_vars[$name]['index'] = 0; + } + + if (isset($params['assign'])) { + $print = false; + $template->assign($params['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; +} + +?> \ No newline at end of file diff --git a/library/Smarty/libs/plugins/function.fetch.php b/library/Smarty/libs/plugins/function.fetch.php new file mode 100644 index 0000000000..eca1182d50 --- /dev/null +++ b/library/Smarty/libs/plugins/function.fetch.php @@ -0,0 +1,214 @@ + + * Name: fetch
    + * Purpose: fetch file, web or ftp data and display results + * + * @link http://www.smarty.net/manual/en/language.function.fetch.php {fetch} + * (Smarty online manual) + * @author Monte Ohrt + * @param array $params parameters + * @param Smarty_Internal_Template $template template object + * @return string|null if the assign parameter is passed, Smarty assigns the result to a template variable + */ +function smarty_function_fetch($params, $template) +{ + if (empty($params['file'])) { + trigger_error("[plugin] fetch parameter 'file' cannot be empty",E_USER_NOTICE); + return; + } + + // strip file protocol + if (stripos($params['file'], 'file://') === 0) { + $params['file'] = substr($params['file'], 7); + } + + $protocol = strpos($params['file'], '://'); + if ($protocol !== false) { + $protocol = strtolower(substr($params['file'], 0, $protocol)); + } + + if (isset($template->smarty->security_policy)) { + if ($protocol) { + // remote resource (or php stream, …) + if(!$template->smarty->security_policy->isTrustedUri($params['file'])) { + return; + } + } else { + // local file + if(!$template->smarty->security_policy->isTrustedResourceDir($params['file'])) { + return; + } + } + } + + $content = ''; + if ($protocol == 'http') { + // 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::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 = $uri_parts['user']; + } + if(!empty($uri_parts['pass'])) { + $pass = $uri_parts['pass']; + } + // 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)) { + trigger_error("[plugin] invalid header format '".$param_value."'",E_USER_NOTICE); + 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 { + trigger_error("[plugin] invalid value for attribute '".$param_key."'",E_USER_NOTICE); + 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 { + trigger_error("[plugin] invalid value for attribute '".$param_key."'",E_USER_NOTICE); + return; + } + break; + default: + trigger_error("[plugin] unrecognized attribute '".$param_key."'",E_USER_NOTICE); + 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) { + trigger_error("[plugin] unable to fetch: $errstr ($errno)",E_USER_NOTICE); + 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"); + } + + fputs($fp, "\r\n"); + while(!feof($fp)) { + $content .= fgets($fp,4096); + } + fclose($fp); + $csplit = preg_split("!\r\n\r\n!",$content,2); + + $content = $csplit[1]; + + if(!empty($params['assign_headers'])) { + $template->assign($params['assign_headers'],preg_split("!\r\n!",$csplit[0])); + } + } + } else { + trigger_error("[plugin fetch] unable to parse URL, check syntax",E_USER_NOTICE); + return; + } + } else { + $content = @file_get_contents($params['file']); + if ($content === false) { + throw new SmartyException("{fetch} cannot read resource '" . $params['file'] ."'"); + } + } + + if (!empty($params['assign'])) { + $template->assign($params['assign'], $content); + } else { + return $content; + } +} + +?> \ No newline at end of file diff --git a/library/Smarty/libs/plugins/function.html_checkboxes.php b/library/Smarty/libs/plugins/function.html_checkboxes.php new file mode 100644 index 0000000000..fb9584bbd4 --- /dev/null +++ b/library/Smarty/libs/plugins/function.html_checkboxes.php @@ -0,0 +1,216 @@ + + * Type: function
    + * Name: html_checkboxes
    + * Date: 24.Feb.2003
    + * Purpose: Prints out a list of checkbox input types
    + * 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} + *
    + * Params: + *
    + * - name       (optional) - string default "checkbox"
    + * - values     (required) - array
    + * - options    (optional) - associative array
    + * - checked    (optional) - array default not set
    + * - separator  (optional) - ie 
    or   + * - output (optional) - the output next to each checkbox + * - assign (optional) - assign the output as an array to this variable + * - escape (optional) - escape the content (not value), defaults to true + *
    + * + * @link http://www.smarty.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 $params parameters + * @param object $template template object + * @return string + * @uses smarty_function_escape_special_chars() + */ +function smarty_function_html_checkboxes($params, $template) +{ + require_once(SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php'); + + $name = 'checkbox'; + $values = null; + $options = null; + $selected = array(); + $separator = ''; + $escape = true; + $labels = true; + $label_ids = false; + $output = null; + + $extra = ''; + + foreach($params as $_key => $_val) { + switch($_key) { + case 'name': + case 'separator': + $$_key = (string) $_val; + break; + + case 'escape': + case 'labels': + case 'label_ids': + $$_key = (bool) $_val; + break; + + case 'options': + $$_key = (array) $_val; + break; + + case 'values': + case 'output': + $$_key = array_values((array) $_val); + break; + + case 'checked': + case 'selected': + if (is_array($_val)) { + $selected = array(); + foreach ($_val as $_sel) { + if (is_object($_sel)) { + if (method_exists($_sel, "__toString")) { + $_sel = smarty_function_escape_special_chars((string) $_sel->__toString()); + } else { + trigger_error("html_checkboxes: selected attribute contains an object of class '". get_class($_sel) ."' without __toString() method", E_USER_NOTICE); + continue; + } + } else { + $_sel = smarty_function_escape_special_chars((string) $_sel); + } + $selected[$_sel] = true; + } + } elseif (is_object($_val)) { + if (method_exists($_val, "__toString")) { + $selected = smarty_function_escape_special_chars((string) $_val->__toString()); + } else { + trigger_error("html_checkboxes: selected attribute is an object of class '". get_class($_val) ."' without __toString() method", E_USER_NOTICE); + } + } else { + $selected = smarty_function_escape_special_chars((string) $_val); + } + break; + + case 'checkboxes': + trigger_error('html_checkboxes: the use of the "checkboxes" attribute is deprecated, use "options" instead', E_USER_WARNING); + $options = (array) $_val; + break; + + case 'assign': + break; + + default: + if(!is_array($_val)) { + $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; + } else { + trigger_error("html_checkboxes: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + } + } + + if (!isset($options) && !isset($values)) + return ''; /* raise error here? */ + + $_html_result = array(); + + if (isset($options)) { + foreach ($options as $_key=>$_val) { + $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels, $label_ids, $escape); + } + } 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, $label_ids, $escape); + } + } + + if(!empty($params['assign'])) { + $template->assign($params['assign'], $_html_result); + } else { + return implode("\n", $_html_result); + } + +} + +function smarty_function_html_checkboxes_output($name, $value, $output, $selected, $extra, $separator, $labels, $label_ids, $escape=true) { + $_output = ''; + + if (is_object($value)) { + if (method_exists($value, "__toString")) { + $value = (string) $value->__toString(); + } else { + trigger_error("html_options: value is an object of class '". get_class($value) ."' without __toString() method", E_USER_NOTICE); + return ''; + } + } else { + $value = (string) $value; + } + + if (is_object($output)) { + if (method_exists($output, "__toString")) { + $output = (string) $output->__toString(); + } else { + trigger_error("html_options: output is an object of class '". get_class($output) ."' without __toString() method", E_USER_NOTICE); + return ''; + } + } else { + $output = (string) $output; + } + + if ($labels) { + if ($label_ids) { + $_id = smarty_function_escape_special_chars(preg_replace('![^\w\-\.]!' . Smarty::$_UTF8_MODIFIER, '_', $name . '_' . $value)); + $_output .= '