Beispiel #1
0
 /**
 		Parse all directives and render HTML/XML template
 			@return mixed
 			@param $_file string
 			@param $_ishtml boolean
 			@param $_path string
 			@public
 	**/
 public static function serve($_file, $_ishtml = TRUE, $_path = NULL)
 {
     if (is_null($_path)) {
         $_path = self::fixSlashes(self::$global['GUI']);
     }
     // Remove <F3::exclude> blocks
     $_text = preg_replace('/<(?:F3:)?exclude>.*?<\\/(?:F3:)?exclude>/is', '', self::embed($_file, $_path));
     if (!preg_match('/<.+>/s', $_text)) {
         // Plain text
         return self::resolve($_text);
     }
     // Initialize XML tree
     $_tree = new XMLTree('1.0', self::$global['ENCODING']);
     // Suppress errors caused by invalid HTML structures
     libxml_use_internal_errors($_ishtml);
     // Populate XML tree
     if ($_ishtml) {
         // HTML template; Keep track of existing tags so those
         // added by libxml can be removed later
         $_tags = array('/<!DOCTYPE\\s+html.*?>\\h*\\v*/is', '/<[\\/]?html.*?>\\h*\\v*/is', '/<[\\/]?head.*?>\\h*\\v*/is', '/<[\\/]?body.*?>\\h*\\v*/is');
         $_undef = array();
         foreach ($_tags as $_regex) {
             if (!preg_match($_regex, $_text)) {
                 $_undef[] = $_regex;
             }
         }
         $_tree->loadHTML($_text);
     } else {
         // XML template
         $_tree->loadXML($_text, LIBXML_COMPACT | LIBXML_NOERROR);
     }
     // Prepare for XML tree traversal
     $_tree->fragment = $_tree->createDocumentFragment();
     $_2ndp = FALSE;
     $_tree->traverse(function () use($_tree, &$_2ndp) {
         $_node =& $_tree->nodeptr;
         $_tag = $_node->tagName;
         $_next = $_node;
         $_parent = $_node->parentNode;
         // Node removal flag
         $_remove = FALSE;
         if ($_tag == 'repeat') {
             // Process <F3:repeat> directive
             $_inner = $_tree->innerHTML($_node);
             if ($_inner) {
                 // Process attributes
                 foreach ($_node->attributes as $_attr) {
                     preg_match('/{?@(\\w+(\\[[^\\]]+\\]|\\.\\w+)*)}?/', $_attr->value, $_cap);
                     $_name = $_attr->name;
                     if (!$_cap[1] || isset($_cap[2]) && $_name != 'group') {
                         // Invalid attribute
                         F3::$global['CONTEXT'] = $_attr->value;
                         trigger_error(F3::TEXT_Attrib);
                         return;
                     } elseif ($_name == 'key') {
                         $_kvar = '/@' . $_cap[1] . '\\b/';
                     } elseif ($_name == 'index') {
                         $_ivar = '/@' . $_cap[1] . '\\b/';
                     } elseif ($_name == 'group') {
                         $_gcap = '@' . $_cap[1];
                         $_gvar = F3::get($_cap[1]);
                     }
                 }
                 if (is_array($_gvar) && count($_gvar)) {
                     ob_start();
                     // Iterate thru group elements
                     foreach (array_keys($_gvar) as $_key) {
                         echo preg_replace($_ivar, $_gcap . '[\'' . $_key . '\']', isset($_kvar) ? preg_replace($_kvar, '\'' . $_key . '\'', $_inner) : $_inner);
                     }
                     $_block = ob_get_contents();
                     ob_end_clean();
                     if (strlen($_block)) {
                         $_tree->fragment->appendXML($_block);
                         // Insert fragment before current node
                         $_next = $_parent->insertBefore($_tree->fragment, $_node);
                     }
                 }
             }
             $_remove = TRUE;
         } elseif ($_tag == 'check' && !$_2ndp) {
             // Found <F3:check> directive
             $_2ndp = TRUE;
         } elseif (strpos($_tag, '-')) {
             // Process custom template directive
             list($_class, $_method) = explode('-', $_tag);
             // Invoke template directive handler
             call_user_func(array($_class, $_method), $_tree);
             $_remove = TRUE;
         }
         if ($_remove) {
             // Find next node
             if ($_node->isSameNode($_next)) {
                 $_next = $_node->nextSibling ? $_node->nextSibling : $_parent;
             }
             // Remove current node
             $_parent->removeChild($_node);
             // Replace with next node
             $_node = $_next;
         }
     });
     if ($_2ndp) {
         // Second pass; Template contains <F3:check> directive
         $_tree->traverse(function () use($_tree) {
             $_node =& $_tree->nodeptr;
             $_parent = $_node->parentNode;
             $_tag = $_node->tagName;
             // Process <F3:check> directive
             if ($_tag == 'check') {
                 $_cond = var_export((bool) F3::resolve(rawurldecode($_node->getAttribute('if'))), TRUE);
                 ob_start();
                 foreach ($_node->childNodes as $_child) {
                     if ($_child->nodeType == XML_ELEMENT_NODE && preg_match('/' . $_cond . '/i', $_child->tagName)) {
                         echo $_tree->innerHTML($_child) ?: '';
                     }
                 }
                 $_block = ob_get_contents();
                 ob_end_clean();
                 if (strlen($_block)) {
                     $_tree->fragment->appendXML($_block);
                     $_parent->insertBefore($_tree->fragment, $_node);
                 }
                 // Remove current node
                 $_parent->removeChild($_node);
                 // Re-process parent node
                 $_node = $_parent;
             }
         });
     }
     if ($_ishtml) {
         // Fix empty HTML tags
         $_text = preg_replace('/<((?:' . self::HTML_Tags . ')\\b.*?)\\/?>/is', '<$1/>', self::resolve(rawurldecode($_tree->saveHTML())));
         // Remove tags inserted by libxml
         foreach ($_undef as $_regex) {
             $_text = preg_replace($_regex, '', $_text);
         }
     } else {
         $_text = self::xmlEncode(self::resolve(rawurldecode($_tree->saveXML())), TRUE);
     }
     return $_text;
 }
Beispiel #2
0
 /**
 		Parse all directives and render HTML/XML template
 			@return mixed
 			@param $_file string
 			@param $_ishtml boolean
 			@param $_path string
 			@public
 	**/
 public static function serve($_file, $_ishtml = TRUE, $_path = NULL)
 {
     if (is_null($_path)) {
         $_path = self::fixSlashes(self::$global['GUI']);
     }
     // Remove <F3::exclude> blocks
     $_text = preg_replace('/<(?:F3:)?exclude>.*?<\\/(?:F3:)?exclude>/is', '', self::embed($_file, $_path));
     if (preg_match('/<.+>/s', $_text)) {
         // Initialize XML tree
         $_tree = new XMLTree('1.0', self::$global['ENCODING']);
         // Suppress errors caused by invalid HTML structures
         libxml_use_internal_errors($_ishtml);
         // Populate XML tree
         if ($_ishtml) {
             // HTML template; Remember defined tags
             $_deftags = array('/<!DOCTYPE\\s+html.*?>\\h*\\v*/is' => FALSE, '/<[\\/]?html.*?>\\h*\\v*/is' => FALSE, '/<[\\/]?head.*?>\\h*\\v*/is' => FALSE, '/<[\\/]?body.*?>\\h*\\v*/is' => FALSE);
             foreach ($_deftags as $_regex => &$_tag) {
                 $_tag = preg_match($_regex, $_text);
             }
             // Destroy reference
             unset($_tag);
             $_tree->loadHTML($_text);
         } else {
             // XML template
             $_tree->loadXML($_text, LIBXML_COMPACT | LIBXML_NOERROR);
         }
         // Prepare for XML tree traversal
         $_tree->fragment = $_tree->createDocumentFragment();
         $_2ndp = FALSE;
         $_tree->traverse(function () use($_tree, &$_2ndp) {
             $_node =& $_tree->nodeptr;
             $_tag = $_node->tagName;
             $_next = $_node;
             $_parent = $_node->parentNode;
             // Node removal flag
             $_remove = FALSE;
             if ($_tag == 'repeat') {
                 // Process <F3:repeat> directive
                 $_inner = $_tree->innerHTML($_node);
                 if ($_inner) {
                     foreach ($_node->attributes as $_attr) {
                         preg_match('/\\{*@(\\w+\\b(\\[[^\\]]+\\]|\\.\\w+\\b)*)\\}*/', $_attr->value, $_cap);
                         if (!$_cap[1] || isset($_cap[2]) && $_attr->name != 'group') {
                             // Invalid attribute
                             F3::$global['CONTEXT'] = $_attr->value;
                             trigger_error(F3::TEXT_Attrib);
                             return;
                         }
                         if ($_attr->name == 'key') {
                             $_kvar = '/@' . $_cap[1] . '\\b/';
                         } elseif ($_attr->name == 'index') {
                             $_ivar = '/@' . $_cap[1] . '\\b/';
                         } elseif ($_attr->name == 'group') {
                             $_gcap = '@' . $_cap[1];
                             $_gvar = F3::get($_cap[1]);
                         }
                     }
                     if (is_array($_gvar) && count($_gvar)) {
                         $_block = '';
                         // Iterate thru group elements
                         foreach (array_keys($_gvar) as $_key) {
                             $_block .= preg_replace($_ivar, $_gcap . '[\'' . $_key . '\']', isset($_kvar) ? preg_replace($_kvar, var_export($_key, TRUE), $_inner) : $_inner);
                         }
                         if (isset($_block[0])) {
                             $_tree->fragment->appendXML($_block);
                             // Insert fragment before current node
                             $_next = $_parent->insertBefore($_tree->fragment, $_node);
                         }
                     }
                 }
                 $_remove = TRUE;
             } elseif ($_tag == 'check' && !$_2ndp) {
                 // Found <F3:check> directive
                 $_2ndp = TRUE;
             } elseif (strpos($_tag, '-')) {
                 // Process custom template directive
                 list($_class, $_method) = explode('-', $_tag);
                 $_found = FALSE;
                 if (!class_exists($_class, FALSE)) {
                     foreach (explode('|', F3::$global['AUTOLOAD']) as $_auto) {
                         $_file = $_auto . $_class . '.php';
                         // Case-insensitive check for file presence
                         $_glob = glob(dirname($_file) . '/*.php');
                         $_fkey = array_search(strtolower($_file), array_map('strtolower', $_glob));
                         if (is_int($_fkey)) {
                             include $_glob[$_fkey];
                             if (method_exists($_class, 'onLoad')) {
                                 call_user_func(array($_class, 'onLoad'));
                             }
                             $_found = TRUE;
                             break;
                         }
                     }
                 } else {
                     $_found = TRUE;
                 }
                 if ($_found) {
                     // Invoke template directive handler
                     call_user_func(array($_class, $_method), $_tree);
                     $_remove = TRUE;
                 }
             }
             if ($_remove) {
                 // Find next node
                 if ($_node->isSameNode($_next)) {
                     $_next = $_node->nextSibling ? $_node->nextSibling : $_parent;
                 }
                 // Remove current node
                 $_parent->removeChild($_node);
                 // Replace with next node
                 $_node = $_next;
             }
         });
         if ($_2ndp) {
             // Second pass; Template contains <F3:check> directive
             $_tree->traverse(function () use($_tree) {
                 $_node =& $_tree->nodeptr;
                 $_parent = $_node->parentNode;
                 $_tag = $_node->tagName;
                 // Process <F3:check> directive
                 if ($_tag == 'check') {
                     $_cond = var_export((bool) F3::resolve(rawurldecode($_node->getAttribute('if'))), TRUE);
                     $_block = '';
                     foreach ($_node->childNodes as $_child) {
                         if ($_child->nodeType != XML_TEXT_NODE && $_child->tagName == $_cond) {
                             $_inner = $_tree->innerHTML($_child);
                             if ($_inner) {
                                 // Replacement
                                 $_block .= $_inner;
                             }
                         }
                     }
                     if (isset($_block[0])) {
                         $_tree->fragment->appendXML($_block);
                         $_parent->insertBefore($_tree->fragment, $_node);
                     }
                     // Remove current node
                     $_parent->removeChild($_node);
                     // Re-process parent node
                     $_node = $_parent;
                 }
             });
         }
         $_text = self::resolve(rawurldecode($_ishtml ? $_tree->saveHTML() : $_tree->saveXML()));
         if ($_ishtml) {
             // Fix empty HTML tags
             $_text = preg_replace('/<((?:area|base|br|col|frame|hr|img|input|' . 'isindex|link|meta|param).*?)\\/?>/is', '<$1/>', $_text);
             // Remove tags inserted by libxml
             foreach ($_deftags as $_regex => $_tag) {
                 if (!$_tag) {
                     $_text = preg_replace($_regex, '', $_text);
                 }
             }
         } else {
             $_text = self::xmlEncode($_text, TRUE);
         }
         unset($_tree);
     } else {
         // Plain text
         $_text = self::resolve($_text);
     }
     // Remove control characters except whitespaces
     return preg_replace('/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F]/', '', $_text);
 }