Guest
Public paste!

Mrasnika

By: a guest | May 15th, 2010 | Syntax: PHP | Size: 12.60 KB | Hits: 114 | Expires: Never
Copy text to clipboard
  1. <?
  2. // - - - - - - - - - - - - - - - - - -
  3. //
  4. // Template Handiling Class with subtemplate integration
  5. //
  6. // AUTHOR:
  7. //  Kaloyan K. Tzvetkov
  8. //      kaloyan@rousse.bg
  9. //      mrasnika@hotmail.com
  10. //
  11. // - - - - - - - - - - - - - - - - - -
  12.  
  13. class Template {
  14.   var $FILES;
  15.   // repository for the template files
  16.   //
  17.   //    name: assigned name to the template, all in
  18.   //            upper-case in order to make the
  19.   //            naming case-insensitive
  20.   //    filename: template filename
  21.   //
  22.   //    source: source code of the template file in raw
  23.   //            format, before initial template parsing
  24.  
  25.   var $TEMPLATES;
  26.   // repository for the templates, extracted when
  27.   // template files are pre-parsed (this means that
  28.   // the dynamic templates are extracted from the
  29.   // static ones); static template is the main template
  30.   // for the template file, and dynamic templates are
  31.   // all the templates declared in it
  32.   //
  33.   //    name: name of the template file, used in FILES, all in
  34.   //            upper-case in order to make the
  35.   //            naming case-insensitive
  36.   //    template: name of the template; this field is
  37.   //            empty if this is the main template
  38.   //            (static) for the template file, identified
  39.   //            by name in FILES
  40.   //    main: source code of the template; when
  41.   //            pre-parsed, sub-templates (dynamic
  42.   //            templates) are replaced by special
  43.   //            delimiters, like this
  44.   //            &%NAME_OF_THE_TEMPLATES%&
  45.   //    parsed: parsed template code of template
  46.   //            default un-parsed template is stored in this->main
  47.   //            while parsed templates are accumulated in this->parsed
  48.   //    loops: how many times the template is parsed,
  49.   //            when used in loops
  50.  
  51.   var $SUBS;
  52.   // array with substitude items, that will be
  53.   // placed when templatea are parsed
  54.   //
  55.   //    key: name of the substitude item, all in
  56.   //            upper-case in order to make the
  57.   //            naming case-insensitive
  58.   //    value: value of the substitude item
  59.  
  60.  
  61.   var $MESSAGES;
  62.   // array with text messages stored in template files
  63.   //
  64.   //    key: name of the text message, all in
  65.   //            upper-case in order to make the
  66.   //            naming case-insensitive
  67.   //    value: value of the text message
  68.  
  69.  var $error;
  70.  // text string contining the last error, occured
  71.  // with the template object
  72.  
  73.   var $error_file;
  74.   // filename for the error log, where the template
  75.   // object errors are appended
  76.  
  77.  var $path;
  78.  // this is the path to the templates, which is used
  79.  // for reading them; must have trailing slash at the end
  80.  
  81.  
  82.  // constructor Template(path, subs_array, msg_array)
  83.  // paremeters:
  84.  //     path - where the template files are stored
  85.  //
  86.  //     error_file - name of the file, where template
  87.  //             object errors are appended
  88.  //     default_file - name of the default messages and
  89.  //             template file, used for storing "global"
  90.  //             text messages and templates; must be
  91.  //             in this->path folder
  92.  //
  93.  function Template() {
  94.  
  95.         if (!$this->path = @func_get_arg(0)) {
  96.                 unset($this->path);
  97.                 $this->error (sprintf("Template path is empty"));
  98.                 return;
  99.                 }
  100.  
  101.         if ($this->error_file = @func_get_arg(1)) {
  102.                 if (!file_exists($this->error_file)) {
  103.                         $this->error (sprintf("Template error log [%s] not found", $this->error_file));
  104.                         }
  105.                 } else {
  106.                 unset($this->error_file);
  107.                 }
  108.        
  109.         if ($default_file = @func_get_arg(2)) {
  110.                 if (!file_exists($this->path . $default_file)) {
  111.                         $this->error (sprintf("Default message template file [%s] not found",
  112.                                 $this->path . $default_file));
  113.                         } else {
  114.                         // load the file
  115.                         $this->FILES[''][filename] = $default_file;
  116.                         $this->FILES[''][source] = $this->load($this->FILES[''][filename]);
  117.  
  118.                         // extract messages
  119.                         $this->extract();
  120.                         }
  121.                 }
  122.         }
  123.  
  124.  // checkes whether there is a template file,
  125.  // and if it can be accessed for reading.
  126.  // if successful, the template file is read
  127.  // and stored in this->source
  128.  function load($path) {
  129.  
  130.         if (!file_exists($this->path . $path)) {
  131.                 $this->error(sprintf("Template file [%s] not found ",$this->path . $path));
  132.                 return;
  133.                 }
  134.                
  135.         if (!$file = @file($this->path . $path)) {
  136.                 $this->error(sprintf("Template file [%s] is empty or can not be read ",$this->path . $path));
  137.                 return;
  138.                 }
  139.        
  140.         $file = join('' , $file);
  141.         return $file;
  142.         }
  143.  
  144.  
  145.   // applies html convesion to the value in order
  146.   // to convert html sensible characters like &, ", <, >
  147.   function htmlEncode ($value) {
  148.         return htmlSpecialChars($value);
  149.         }
  150.  
  151.  // returns parsed template
  152.  // if array is provided, it is used as substitude storage
  153.  // all substitudes are case insensitive
  154.  //
  155.  //     template: name of the sub, template that's about
  156.  //             to be parsed; if none, main template is
  157.  //             parsed instead
  158.  //
  159.  //     name: name of the template file, that carries
  160.  //             the subtemplate you wanted parsed
  161.  //             if empty, default template & messages
  162.  //             file used instead
  163.  //
  164.  // substitude markers:
  165.  //     #%name_of_substitude_value%#
  166.  //     - plain text substitudes
  167.  //
  168.  //     %%name_of_substitude_value%%
  169.  //     - html sensitive substitudes
  170.  //
  171.  //     NOTE: an array may be used for
  172.  //     batch parse of templates; in this
  173.  //     case parse() function takes
  174.  //     only 1 paramter - the arrray
  175.  function parse($key) {
  176.        
  177.         //check if array
  178.         if (is_array($key)) {
  179.                 while (list($k, $v) = each($key)) {
  180.                         $this->parse($v);
  181.                         }
  182.                 return;
  183.                 }
  184.  
  185.         $key = strToUpper($key);
  186.         if (!$this->TEMPLATES[$key]) {
  187.                 $this->error(sprintf("Template [%s] not found", $key));
  188.                 } else {
  189.                 $s_main = $this->TEMPLATES[$key][main];
  190.  
  191.                 //check for sub-templates
  192.                 while (preg_match('~&%(.*)%&~iUs', $s_main, $R)) {
  193.                         $s_key = $R[1];
  194.                         $s_main = str_replace($R[0], $this->TEMPLATES[$s_key][parsed], $s_main);
  195.                         }
  196.  
  197.                 // parse the plain text substitutes
  198.                 while (preg_match('/#%(.*)%#/iUs', $s_main, $R)) {
  199.                         $s_key = strToUpper($R[1]);
  200.                         $s_value = $this->SUBS[$s_key];
  201.                         $s_main = str_replace($R[0], $s_value, $s_main);
  202.                         }
  203.  
  204.                 // parse the html sensitive substitutes
  205.                 while (preg_match('/%%(.*)%%/iUs', $s_main, $R)) {
  206.                         $s_key = strToUpper($R[1]);
  207.                         $s_value = $this->SUBS[$s_key];
  208.                         $s_value = $this->htmlEncode($s_value);
  209.                         $s_main = str_replace($R[0], $s_value, $s_main);
  210.                         }
  211.  
  212.                 $this->TEMPLATES[$key][parsed] .= ereg_replace("[\n\r\t]+" , "\n", $s_main);
  213.                 $this->TEMPLATES[$key][loops]++;
  214.                 }
  215.         }
  216.  
  217.   // saves the last error in this->error, and appends
  218.   // the error message to the error log, if set
  219.   function error($error) {
  220.         $this->error = $error;
  221.        
  222.         if ($this->error_file) {
  223.                 if ($fp = @fopen($this->error_file, 'a')) {
  224.                         $error_msg = date("Y-M-d H:i:s\t") . $this->error . "\n";
  225.  
  226.                         if (!@fwrite($fp, $error_msg)) {
  227.                                 $this->error = sprintf("Unable to write to template error log [%s]",
  228.                                         $this->error_file);
  229.                                 }
  230.                         @fclose ($fp);
  231.                         } else {
  232.                         $this->error = sprintf("Unable to open template error log [%s]", $this->error_file);
  233.                         }
  234.                 }
  235.         }
  236.  
  237.   // pre-parses the template, identified by name
  238.   // if name is empty, default messages template
  239.   // is pre-parsed instead
  240.   // parses this->FILES[name][source] to extract the
  241.   // main template, dynamic templates, and
  242.   // text messages stored in the template file
  243.   // delimiters:
  244.   //    <TEMPLATE name_of_the_template> ... </TEMPLATE>
  245.   //    dynamic subtemplates
  246.   //
  247.   //    <MESSAGE> ... </MESSAGE>
  248.   //    <MESSAGES> ... </MESSAGES>
  249.   //    text messages
  250.   //
  251.   //    <!--# template_comments #-->
  252.   //    comments
  253.   //
  254.   // message format
  255.   //    message_name : message_text ;
  256.   //
  257.   // extracted subtemplates
  258.   //    &%name_of_the_template%&
  259.   //
  260.   function extract() {
  261.  
  262.         //get source
  263.         $name = strToUpper(@func_get_arg(0));
  264.         $source = $this->FILES[$name][source] = $this->load($this->FILES[$name][filename]);
  265.  
  266.         //strip comments
  267.         while (preg_match('/<!--#.*#-->/iUs', $source, $R)) {
  268.                 $source = str_replace($R[0], '', $source);
  269.                 }
  270.  
  271.         //get messages
  272.         while (preg_match('|<MESSAGES?(.*)>(.*)</MESSAGES?>|iUs' , $source, $R)) {
  273.                 $msg = trim($R[2]);
  274.  
  275.                 while (preg_match('/^(([a-z0-9 _]+)\s*:(.*)?)(\n[^\s]+\s*:.*)?$/sUi',$msg, $M)) {
  276.                         $key = strToUpper(trim($M[2]));
  277.                        
  278.                         $message = trim($M[3]);
  279.                         if (isset($this->MESSAGES[$key])) {
  280.                                 $this->error(sprintf("Duplicate MESSAGES entry for template [%s] with key [%s]",
  281.                                         $this->FILES[$name][filename], $key));
  282.                                 }
  283.                         $this->MESSAGES[$key] = $message;
  284.                        
  285.                         $msg = trim(substr($msg, strlen($M[1])));
  286.                         }
  287.                
  288.                 //strip parsed message block
  289.                 $source = str_replace($R[0],'', $source);
  290.                 }
  291.  
  292.         //get subtemplates
  293.         $sourceU = strToUpper($source); //to make the search case-insensitive
  294.         while ($s2 = strPos($sourceU, '</TEMPLATE')) {
  295.                 $chunk = strRev(subStr($sourceU, 0, $s2));
  296.                 if (!$s1 = strPos($chunk, 'ETALPMET<')) {
  297.                         $this->error(sprintf("Syntax error in template [%s] with value [%s]",
  298.                                 $name, $source));
  299.                         } else {
  300.  
  301.                         $len = $s1 + 20;
  302.                         $where = strLen($chunk) -$s1 -9;
  303.                         $sub = trim(subStr($source, $where, $len));
  304.                         if (!preg_match('~<TEMPLATE(.*)>(.*)</TEMPLATE>~iUs', $sub, $R)) {
  305.                                 $this->error(sprintf("Syntax error in template [%s] with value [%s]",
  306.                                         $name, $sub));
  307.                                 } else {
  308.                                 $key = trim(strToUpper($R[1]));
  309.                                 $main = $R[2];
  310.  
  311.                                 if (isset($this->TEMPLATES[$key])) {
  312.                                         $this->error(sprintf("Duplicate TEMPLATES entry for template [%s] with key [%s]",
  313.                                                 $this->FILES[$name][filename], $key));
  314.                                         }
  315.                                 $this->TEMPLATES[$key] = array(main=>$main);
  316.                                 }
  317.                         $source = str_replace($sub, "&%$key%&", $source);
  318.                         $sourceU = strToUpper($source);
  319.                         }
  320.                 }
  321.         if (trim($source)) {
  322.                 if (isset($this->TEMPLATES[$name])) {
  323.                         $this->error(sprintf("Duplicate TEMPLATES entry for template [%s] with key [%s]",
  324.                                 $this->FILES[$name][filename], $name));
  325.                         }
  326.                 $this->TEMPLATES[$name] = array(main=>$source);
  327.                 }
  328.         }
  329.  
  330.   // defines a combination of name & filename
  331.   // to the FILES array in the template object
  332.   //    NOTE: array(key=>value) may be used for
  333.   //    batch define of templates; in this case
  334.   //    define() function takes only 1 paramter: key-value
  335.   //    pairs array
  336.   function define($name) {
  337.  
  338.         //check for arrays
  339.         if (is_array($name)) {
  340.                 while (list($k,$v) = each($name)) {
  341.                         $this->define($k,$v);
  342.                         }
  343.                 return;
  344.                 }
  345.        
  346.         $name = strToUpper($name);
  347.         $filename = @func_get_arg(1);
  348.  
  349.         if ($this->FILES[$name]) {
  350.                 $this->error(sprintf("Duplicate FILES entry [%s] with file [%s]",
  351.                         $name, $filename));
  352.                 }
  353.         $this->FILES[$name] = array(filename=>$filename, source=>'');
  354.         }
  355.  
  356.   // assigns value to SUBS[key] variable to be
  357.   // used when templates are parsed (interpolated)
  358.   //
  359.   //    key: name of the SUBS variable, all in
  360.   //            upper-case in order to make the
  361.   //            naming case-insensitive
  362.   //
  363.   //    value: value for the SUBS variable
  364.   //
  365.   //    NOTE: array(key=>value) may be used for
  366.   //    batch assign of SUBS variables
  367.   //
  368.   function assign($key) {
  369.        
  370.         //check for arrays
  371.         if (is_array($key)) {
  372.                 while (list($k, $v) = each($key)) {
  373.                         $this->assign($k, $v);
  374.                         }
  375.                 return;
  376.                 }
  377.        
  378.         $key = strToUpper($key);
  379.         $value = @func_get_arg(1);
  380.  
  381.         $this->SUBS[$key] = $value;
  382.         }
  383.  
  384.   // returns the parsed data for a template
  385.   //    name: name of the template file, empty
  386.   //            string if you want to use default
  387.   //            template & messages file instead
  388.   //
  389.   //    template: name of the sub-template you want
  390.   //            returned; if none, main template will
  391.   //            be returned instead
  392.   function fetch($template) {
  393.         $template = strToUpper($template);
  394.        
  395.         if (!$r = $this->TEMPLATES[$template][parsed]) {
  396.                 $this->error(sprintf("TEMPLATES entry [%s] not found", $template));
  397.                 } else {
  398.                 return $r;
  399.                 }
  400.         }
  401.  
  402.  // returns text message from a template file
  403.  //     subs: name of the SUBS variable, that
  404.  //             will receive the value of the message
  405.  //     key: name of the message which
  406.  //             is about to be passed
  407.  //
  408.  //     NOTE: array(key=>value) may be used for
  409.  //     batch assign messages
  410.  //
  411.  function message($subs) {
  412.         //check arrays
  413.         if (is_array($subs)) {
  414.                 while (list($k, $v) = each($subs)) {
  415.                         $this->message($k, $v);
  416.                         }
  417.                 return;
  418.                 }
  419.        
  420.         $subs = strToUpper($subs);
  421.         $key = strToUpper(@func_get_arg(1));
  422.        
  423.         if (!$msg = $this->MESSAGES[$key]) {
  424.                 $this->error(sprintf("MESSAGES entry [%s] not found", $key ));
  425.                 } else $this->assign($subs, $msg, $name);
  426.         }
  427.  
  428.  // returns an assigned variable
  429.  // from SUBS array
  430.  function get_subs($key) {
  431.         return $this->SUBS[strToUpper($key)];
  432.         }
  433.  
  434.  // returns a text message from
  435.  // the MESSAGES array
  436.  function get_message($key) {
  437.         return $this->MESSAGES[strToUpper($key)];
  438.         }
  439.  
  440.  // clears out a template
  441.  function clear($key) {
  442.         $key = strToUpper($key);
  443.         unset($this->TEMPLATES[$key][parsed]);
  444.         unset($this->TEMPLATES[$key][loops]);
  445.         }
  446.  
  447.  }
  448. ?>