Exemple #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;
 }
Exemple #2
0
 /**
 		Parse each URL recursively and generate sitemap
 			@param $_url string
 			@public
 	**/
 public static function sitemap($_url = '/')
 {
     $_map =& F3::$global['SITEMAP'];
     if (array_key_exists($_url, $_map) && $_map[$_url]['status'] !== NULL) {
         // Already crawled
         return;
     }
     preg_match('/^http[s]*:\\/\\/([^\\/$]+)/', $_url, $_host);
     if (!empty($_host) && $_host[1] != $_SERVER['SERVER_NAME']) {
         // Remote URL
         $_map[$_url]['status'] = FALSE;
         return;
     }
     F3::$global['QUIET'] = TRUE;
     F3::mock('GET ' . $_url);
     F3::run();
     // Check if an error occurred or no HTTP response
     if (F3::$global['ERROR'] || !F3::$global['RESPONSE']) {
         $_map[$_url]['status'] = FALSE;
         // Reset error flag for next page
         unset(F3::$global['ERROR']);
         return;
     }
     $_doc = new XMLTree('1.0', F3::$global['ENCODING']);
     if ($_doc->loadHTML(F3::$global['RESPONSE'])) {
         // Valid HTML; add to sitemap
         if (!$_map[$_url]['level']) {
             // Web root
             $_map[$_url]['level'] = 0;
         }
         $_map[$_url]['status'] = TRUE;
         $_map[$_url]['mod'] = time();
         $_map[$_url]['freq'] = 0;
         // Cached page
         $_hash = 'url.' . F3::hashCode('GET ' . $_url);
         $_cached = Cache::cached($_hash);
         if ($_cached) {
             $_map[$_url]['mod'] = $_cached['time'];
             $_map[$_url]['freq'] = $_SERVER['REQUEST_TTL'];
         }
         // Parse all links
         $_links = $_doc->getElementsByTagName('a');
         foreach ($_links as $_link) {
             $_ref = $_link->getAttribute('href');
             $_rel = $_link->getAttribute('rel');
             if (!$_ref || $_rel && preg_match('/nofollow/', $_rel)) {
                 // Don't crawl this link!
                 continue;
             }
             if (!array_key_exists($_ref, $_map)) {
                 $_map[$_ref] = array('level' => $_map[$_url]['level'] + 1, 'status' => NULL);
             }
         }
         // Parse each link
         array_walk(array_keys($_map), 'self::sitemap');
     }
     unset($_doc);
     if (!$_map[$_url]['level']) {
         // Finalize sitemap
         $_depth = 1;
         while ($_ref = current($_map)) {
             // Find depest level while iterating
             if (!$_ref['status']) {
                 // Remove remote URLs and pages with errors
                 unset($_map[key($_map)]);
             } else {
                 $_depth = max($_depth, $_ref['level'] + 1);
                 next($_map);
             }
         }
         // Create XML document
         $_xml = simplexml_load_string('<?xml version="1.0" encoding="' . F3::$global['ENCODING'] . '"?>' . '<urlset xmlns="' . 'http://www.sitemaps.org/schemas/sitemap/0.9' . '"/>');
         $_host = 'http://' . $_SERVER['SERVER_NAME'];
         foreach ($_map as $_key => $_ref) {
             // Add new URL
             $_item = $_xml->addChild('url');
             // Add URL elements
             $_item->addChild('loc', $_host . $_key);
             $_item->addChild('lastMod', date('c', $_ref['mod']));
             $_item->addChild('changefreq', self::frequency($_ref['freq']));
             $_item->addChild('priority', sprintf('%1.1f', 1 - $_ref['level'] / $_depth));
         }
         // Send output
         F3::$global['QUIET'] = FALSE;
         if (PHP_SAPI != 'cli' && !headers_sent()) {
             header(F3::HTTP_Content . ': application/xhtml+xml; ' . 'charset=' . F3::$global['ENCODING']);
         }
         $_xml = dom_import_simplexml($_xml)->ownerDocument;
         $_xml->formatOutput = TRUE;
         echo $_xml->saveXML();
     }
 }
Exemple #3
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);
 }