<?php require __DIR__ . '/lib/base.php'; #F3::set('CACHE',TRUE); F3::set('DEBUG', 1); F3::set('UI', 'ui/'); F3::set('IMPORTS', 'imports/'); F3::set('FACEBOOK.client_id', '***REMOVED***'); F3::set('FACEBOOK.client_secret', '***REMOVED***'); F3::set('FACEBOOK.redirect_uri', 'http://singleyet.com/login/'); F3::set('FACEBOOK.session_key', F3::resolve('fb_{{@FACEBOOK.client_id}}_access_token')); F3::set('DB', new DB('mysql:host=localhost;port=3306;dbname=singleyet', 'singleyet', '***REMOVED***')); F3::call('facebook/facebook.php'); F3::set('Facebook', new Facebook(array('appId' => F3::get('FACEBOOK.client_id'), 'secret' => F3::get('FACEBOOK.client_secret')))); ///////////////////////////////////////////////// // Status Codes // ///////////////////////////////////////////////// # 1 = Single # 2 = In a relationship # 3 = Engaged # 4 = Married # 5 = It's complicated # 6 = In an open relationship # 7 = Widowed # 8 = Separated # 9 = Divorced # 10 = In a civil union # 11 = In a domestic relationship # 12 = Not set ///////////////////////////////////////////////// # Single = 1, 5, 6, 7, 8, 9, 12 //
/** Transmit a file for downloading by HTTP client; If kilobytes per second is specified, output is throttled (bandwidth will not be controlled by default); Return TRUE if successful, FALSE otherwise @param $_file string @param $_kbps integer @public **/ public static function send($_file, $_kbps = 0) { $_file = F3::resolve($_file); if (!file_exists($_file)) { F3::http404(); return FALSE; } if (PHP_SAPI != 'cli' && !F3::$global['QUIET'] && !headers_sent()) { header(F3::HTTP_Content . ': application/octet-stream'); header(F3::HTTP_Disposition . ': ' . 'attachment; filename=' . basename($_file)); header(F3::HTTP_Length . ': ' . filesize($_file)); F3::httpCache(0); ob_end_flush(); } $_max = ini_get('max_execution_time'); $_ctr = 1; $_handle = fopen($_file, 'r'); $_time = time(); while (!feof($_handle) && !connection_aborted()) { if ($_kbps > 0) { // Throttle bandwidth $_ctr++; $_elapsed = microtime(TRUE) - $_time; if ($_ctr / $_kbps > $_elapsed) { usleep(1000000.0 * ($_ctr / $_kbps - $_elapsed)); } } // Send 1KiB and reset timer echo fread($_handle, 1024); set_time_limit($_max); } fclose($_handle); return TRUE; }
/** Grab file contents @return mixed @param $file string @public **/ function grab($file) { $file = F3::resolve($file); if (!ini_get('short_open_tag')) { $text = preg_replace_callback('/<\\?(?:\\s|\\s*(=))(.+?)\\?>/s', function ($tag) { return '<?php ' . ($tag[1] ? 'echo ' : '') . trim($tag[2]) . ' ?>'; }, $orig = self::getfile($file)); if (ini_get('allow_url_fopen') && ini_get('allow_url_include')) { // Stream wrap $file = 'data:text/plain,' . urlencode($text); } elseif ($text != $orig) { // Save re-tagged file in temporary folder if (!is_dir($ref = F3::ref('TEMP'))) { F3::mkdir($ref); } $temp = $ref . $_SERVER['SERVER_NAME'] . '.tpl.' . F3::hash($file); if (!is_file($temp)) { self::mutex(function () use($temp, $text) { file_put_contents($temp, $text); }); } $file = $temp; } } ob_start(); // Render $this->sandbox($file); return ob_get_clean(); }
/** Assign value to Axon-mapped field @return boolean @param $_name string @param $_value mixed @public **/ public function __set($_name, $_value) { if (array_key_exists($_name, $this->fields)) { $this->fields[$_name] = is_string($_value) ? F3::resolve($_value) : $_value; if (!is_null($_value)) { // Axon is now hydrated $this->empty = FALSE; } return; } if (array_key_exists($_name, $this->virtual)) { trigger_error(self::TEXT_AxonReadOnly); return; } F3::$global['CONTEXT'] = $_name; trigger_error(self::TEXT_AxonNotMapped); }
/** Grab file contents @return mixed @param $file string @public **/ function grab($file) { $file = F3::resolve($file); ob_start(); if (!ini_get('short_open_tag')) { $text = preg_replace_callback('/<\\?(?:\\s|\\s*(=))(.+?)\\?>/s', function ($tag) { return '<?php ' . ($tag[1] ? 'echo ' : '') . trim($tag[2]) . ' ?>'; }, $orig = file_get_contents($file)); if (ini_get('allow_url_fopen') && ini_get('allow_url_include')) { // Stream wrap $file = 'data:text/plain,' . urlencode($text); } elseif ($text != $orig) { // Save re-tagged file in temporary folder if (!is_dir($ref = F3::ref('TEMP'))) { F3::mkdir($ref); } $temp = $ref . $_SERVER['SERVER_NAME'] . '.tpl.' . F3::hash($file); if (!is_file($temp)) { // Create semaphore $hash = 'sem.' . F3::hash($file); $cached = Cache::cached($hash); while ($cached) { // Locked by another process usleep(mt_rand(0, 1000)); } Cache::set($hash, TRUE); file_put_contents($temp, $text, LOCK_EX); // Remove semaphore Cache::clear($hash); } $file = $temp; } } // Render $this->sandbox($file); return ob_get_clean(); }
/** Generate identicon from an MD5 hash value @param $_hash string @param $_size integer @public **/ public static function identicon($_hash, $_size = NULL) { $_blox = F3::$global['IBLOCKS']; if (is_null($_size)) { $_size = F3::$global['IPIXELS']; } // Rotatable shapes $_dynamic = array(array(0.5, 1, 1, 0, 1, 1), array(0.5, 0, 1, 0, 0.5, 1, 0, 1), array(0.5, 0, 1, 0, 1, 1, 0.5, 1, 1, 0.5), array(0, 0.5, 0.5, 0, 1, 0.5, 0.5, 1, 0.5, 0.5), array(0, 0.5, 1, 0, 1, 1, 0, 1, 1, 0.5), array(1, 0, 1, 1, 0.5, 1, 1, 0.5, 0.5, 0.5), array(0, 0, 1, 0, 1, 0.5, 0, 0, 0.5, 1, 0, 1), array(0, 0, 0.5, 0, 1, 0.5, 0.5, 1, 0, 1, 0.5, 0.5), array(0.5, 0, 0.5, 0.5, 1, 0.5, 1, 1, 0.5, 1, 0.5, 0.5, 0, 0.5), array(0, 0, 1, 0, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 0, 1), array(0, 0.5, 0.5, 1, 1, 0.5, 0.5, 0, 1, 0, 1, 1, 0, 1), array(0.5, 0, 1, 0, 1, 1, 0.5, 1, 1, 0.75, 0.5, 0.5, 1, 0.25), array(0, 0.5, 0.5, 0, 0.5, 0.5, 1, 0, 1, 0.5, 0.5, 1, 0.5, 0.5, 0, 1), array(0, 0, 1, 0, 1, 1, 0, 1, 1, 0.5, 0.5, 0.25, 0.5, 0.75, 0, 0.5, 0.5, 0.25), array(0, 0.5, 0.5, 0.5, 0.5, 0, 1, 0, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 0, 1), array(0, 0, 1, 0, 0.5, 0.5, 0.5, 0, 0, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 0, 1)); // Fixed shapes (for center sprite) $_static = array(array(), array(0, 0, 1, 0, 1, 1, 0, 1), array(0.5, 0, 1, 0.5, 0.5, 1, 0, 0.5), array(0, 0, 1, 0, 1, 1, 0, 1, 0, 0.5, 0.5, 1, 1, 0.5, 0.5, 0, 0, 0.5), array(0.25, 0, 0.75, 0, 0.5, 0.5, 1, 0.25, 1, 0.75, 0.5, 0.5, 0.75, 1, 0.25, 1, 0.5, 0.5, 0, 0.75, 0, 0.25, 0.5, 0.5), array(0, 0, 0.5, 0.25, 1, 0, 0.75, 0.5, 1, 1, 0.5, 0.75, 0, 1, 0.25, 0.5), array(0.33, 0.33, 0.67, 0.33, 0.67, 0.67, 0.33, 0.67), array(0, 0, 0.33, 0, 0.33, 0.33, 0.67, 0.33, 0.67, 0, 1, 0, 1, 0.33, 0.67, 0.33, 0.67, 0.67, 1, 0.67, 1, 1, 0.67, 1, 0.67, 0.67, 0.33, 0.67, 0.33, 1, 0, 1, 0, 0.67, 0.33, 0.67, 0.33, 0.33, 0, 0.33)); // Parse MD5 hash $_hash = F3::resolve($_hash); list($_bgR, $_bgG, $_bgB) = self::rgb(F3::$global['BGCOLOR']); list($_fgR, $_fgG, $_fgB) = self::rgb(substr($_hash, 0, 6)); $_shapeC = hexdec($_hash[6]); $_angleC = hexdec($_hash[7] % 4); $_shapeX = hexdec($_hash[8]); for ($_i = 0; $_i < $_blox - 2; $_i++) { $_shapeS[$_i] = hexdec($_hash[9 + $_i * 2]); $_angleS[$_i] = hexdec($_hash[10 + $_i * 2] % 4); } // Start with NxN blank slate $_identicon = imagecreatetruecolor($_size * $_blox, $_size * $_blox); imageantialias($_identicon, TRUE); $_bg = imagecolorallocate($_identicon, $_bgR, $_bgG, $_bgB); $_fg = imagecolorallocate($_identicon, $_fgR, $_fgG, $_fgB); // Generate corner sprites $_corner = imagecreatetruecolor($_size, $_size); imagefill($_corner, 0, 0, $_bg); $_sprite = $_dynamic[$_shapeC]; for ($_i = 0, $_len = count($_sprite); $_i < $_len; $_i++) { $_sprite[$_i] = $_sprite[$_i] * $_size; } imagefilledpolygon($_corner, $_sprite, $_len / 2, $_fg); for ($_i = 0; $_i < $_angleC; $_i++) { $_corner = imagerotate($_corner, 90, $_bg); } // Generate side sprites for ($_i = 0; $_i < $_blox - 2; $_i++) { $_side[$_i] = imagecreatetruecolor($_size, $_size); imagefill($_side[$_i], 0, 0, $_bg); $_sprite = $_dynamic[$_shapeS[$_i]]; for ($_j = 0, $_len = count($_sprite); $_j < $_len; $_j++) { $_sprite[$_j] = $_sprite[$_j] * $_size; } imagefilledpolygon($_side[$_i], $_sprite, $_len / 2, $_fg); for ($_j = 0; $_j < $_angleS[$_i]; $_j++) { $_side[$_i] = imagerotate($_side[$_i], 90, $_bg); } } // Generate center sprites for ($_i = 0; $_i < $_blox - 2; $_i++) { $_center[$_i] = imagecreatetruecolor($_size, $_size); imagefill($_center[$_i], 0, 0, $_bg); $_sprite = $_dynamic[$_shapeX]; if ($_blox % 2 > 0 && $_i == $_blox - 3) { // Odd center sprites $_sprite = $_static[$_shapeX % 8]; } $_len = count($_sprite); if ($_len) { for ($_j = 0; $_j < $_len; $_j++) { $_sprite[$_j] = $_sprite[$_j] * $_size; } imagefilledpolygon($_center[$_i], $_sprite, $_len / 2, $_fg); } if ($_i < $_blox - 3) { for ($_j = 0; $_j < $_angleS[$_i]; $_j++) { $_center[$_i] = imagerotate($_center[$_i], 90, $_bg); } } } // Paste sprites for ($_i = 0; $_i < 4; $_i++) { imagecopy($_identicon, $_corner, 0, 0, 0, 0, $_size, $_size); for ($_j = 0; $_j < $_blox - 2; $_j++) { imagecopy($_identicon, $_side[$_j], $_size * ($_j + 1), 0, 0, 0, $_size, $_size); for ($_k = $_j; $_k < $_blox - 3 - $_j; $_k++) { imagecopy($_identicon, $_center[$_k], $_size * ($_k + 1), $_size * ($_j + 1), 0, 0, $_size, $_size); } } $_identicon = imagerotate($_identicon, 90, $_bg); } if ($_blox % 2 > 0) { // Paste odd center sprite imagecopy($_identicon, $_center[$_blox - 3], $_size * floor($_blox / 2), $_size * floor($_blox / 2), 0, 0, $_size, $_size); } // Resize $_resized = imagecreatetruecolor($_size, $_size); imagecopyresampled($_resized, $_identicon, 0, 0, 0, 0, $_size, $_size, $_size * $_blox, $_size * $_blox); // Make the background transparent imagecolortransparent($_resized, $_bg); if (PHP_SAPI != 'cli' && !headers_sent()) { header(F3::HTTP_Content . ': image/png'); } imagepng($_resized, NULL, self::PNG_Compress, PNG_NO_FILTER); }
/** 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; }
/** Bind values to parameters in SQL statement(s) and execute @return mixed @param $_cmds mixed @param $_bind mixed @param $_id string @param $_ttl integer @public **/ public static function sqlBind($_cmds, $_bind = NULL, $_id = 'DB', $_ttl = 0) { $_db =& F3::$global[$_id]; // Connect to database once if (!$_db || !$_db['dsn']) { // Can't connect without a DSN! trigger_error(self::TEXT_DBConnect); return; } if (!isset($_db['pdo'])) { $_ext = 'pdo_' . stristr($_db['dsn'], ':', TRUE); if (!in_array($_ext, get_loaded_extensions())) { // PHP extension not activated F3::$global['CONTEXT'] = $_ext; trigger_error(F3::TEXT_PHPExt); return; } try { $_db['pdo'] = new PDO($_db['dsn'], $_db['user'], $_db['password'], isset($_db['options']) ?: array(PDO::ATTR_EMULATE_PREPARES => FALSE)); } catch (Exception $_xcpt) { } if (!isset($_db['pdo'])) { // Unable to connect trigger_error(self::TEXT_DBConnect); return; } // Define connection attributes $_attrs = explode('|', 'AUTOCOMMIT|ERRMODE|CASE|CLIENT_VERSION|CONNECTION_STATUS|' . 'PERSISTENT|PREFETCH|SERVER_INFO|SERVER_VERSION|TIMEOUT'); // Save attributes in DB global variable foreach ($_attrs as $_attr) { // Suppress warning if PDO driver doesn't support attribute $_val = @$_db['pdo']->getAttribute(constant('PDO::ATTR_' . $_attr)); if ($_val) { $_db['attributes'][$_attr] = $_val; } } } if (!is_array($_cmds)) { // Convert to array to prevent code duplication $_cmds = array($_cmds); } // Remove empty elements $_cmds = array_diff($_cmds, array(NULL)); $_db['result'] = NULL; if (count($_cmds) > 1) { // More than one SQL statement specified $_db['pdo']->beginTransaction(); } foreach ($_cmds as $_cmd) { if (F3::$global['ERROR']) { break; } $_cmd = F3::resolve($_cmd); if ($_ttl) { // Cache results self::sqlCache($_cmd, $_bind, $_id, $_ttl); } else { // Execute SQL statement(s) self::sqlExec($_cmd, $_bind, $_id); } } if (count($_cmds) > 1) { $_func = F3::$global['ERROR'] ? 'rollBack' : 'commit'; call_user_func(array($_db['pdo'], $_func)); } return $_db['result']; }
/** 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); }