private function __process($XSLProc, $xml_arg, $xsl_arg, $xslcontainer = null, $args = null, $params = null) { // Start with preparing the arguments $xml_arg = str_replace('arg:', '', $xml_arg); $xsl_arg = str_replace('arg:', '', $xsl_arg); // Create instances of the DomDocument class $xml = new DomDocument(); $xsl = new DomDocument(); // Set up error handling if (function_exists('ini_set')) { $ehOLD = ini_set('html_errors', false); } // Load the xml document set_error_handler('trapXMLError'); $xml->loadXML($args[$xml_arg]); // Must restore the error handler to avoid problems restore_error_handler(); // Load the xml document set_error_handler('trapXSLError'); $xsl->loadXML($args[$xsl_arg]); // Load the xsl template $XSLProc->importStyleSheet($xsl); // Set parameters when defined if ($params) { General::flattenArray($params); foreach ($params as $param => $value) { $XSLProc->setParameter('', $param, $value); } } restore_error_handler(); // Start the transformation set_error_handler('trapXMLError'); $processed = $XSLProc->transformToXML($xml); // Restore error handling if (function_exists('ini_set') && isset($ehOLD)) { ini_set('html_errors', $ehOLD); } restore_error_handler(); // Put the result in a file when specified if ($xslcontainer) { return @file_put_contents($xslcontainer, $processed); } else { return $processed; } }
private function __fetchSectionsFromContext($context) { if (!is_null($this->_sectionsToFlush)) { return; } $this->_sectionsToFlush = array(); if ($context['delegate'] == 'EntryPreDelete' || $context['delegate'] == 'EntriesPostOrder') { require_once TOOLKIT . '/class.entrymanager.php'; $this->_sectionsToFlush[0] = EntryManager::fetchEntrySectionID($context['entry_id'][0]); } elseif ($context['delegate'] == 'EventFinalSaveFilter') { require_once TOOLKIT . '/class.entrymanager.php'; $this->_sectionsToFlush[0] = EntryManager::fetchEntrySectionID($context['entry']->get('id')); } else { $this->_sectionsToFlush[0] = $context['section']->get('id'); } $associatedSections = Symphony::Database()->fetch(sprintf('SELECT DISTINCT `child_section_id` value, `parent_section_id` value FROM `tbl_sections_association` WHERE `parent_section_id` = %d OR `child_section_id` = %d', $this->_sectionsToFlush[0], $this->_sectionsToFlush[0])); General::flattenArray($associatedSections); $associatedSections = array_unique(array_values($associatedSections)); if (is_array($associatedSections) && !empty($associatedSections)) { $this->_sectionsToFlush = array_merge($this->_sectionsToFlush, $associatedSections); } }
private function __buildPage() { $start = precision_timer(); if (!($page = $this->resolvePage())) { $page = $this->_Parent->Database->fetchRow(0, "\n\t\t\t\t\t\t\t\tSELECT `tbl_pages`.* \n\t\t\t\t\t\t\t\tFROM `tbl_pages`, `tbl_pages_types` \n\t\t\t\t\t\t\t\tWHERE `tbl_pages_types`.page_id = `tbl_pages`.id \n\t\t\t\t\t\t\t\tAND tbl_pages_types.`type` = '404' \n\t\t\t\t\t\t\t\tLIMIT 1"); if (empty($page)) { $this->_Parent->customError(E_USER_ERROR, __('Page Not Found'), __('The page you requested does not exist.'), false, true, 'error', array('header' => 'HTTP/1.0 404 Not Found')); } $page['filelocation'] = $this->resolvePageFileLocation($page['path'], $page['handle']); $page['type'] = $this->__fetchPageTypes($page['id']); } #### # Delegate: FrontendPageResolved # Description: Just after having resolved the page, but prior to any commencement of output creation # Global: Yes $this->ExtensionManager->notifyMembers('FrontendPageResolved', '/frontend/', array('page' => &$this, 'page_data' => &$page)); $this->_pageData = $page; $root_page = @array_shift(explode('/', $page['path'])); $current_path = explode(dirname($_SERVER['SCRIPT_NAME']), $_SERVER['REQUEST_URI'], 2); $current_path = '/' . ltrim(end($current_path), '/'); // Get max upload size from php and symphony config then choose the smallest $upload_size_php = ini_size_to_bytes(ini_get('upload_max_filesize')); $upload_size_sym = Frontend::instance()->Configuration->get('max_upload_size', 'admin'); $this->_param = array('today' => DateTimeObj::get('Y-m-d'), 'current-time' => DateTimeObj::get('H:i'), 'this-year' => DateTimeObj::get('Y'), 'this-month' => DateTimeObj::get('m'), 'this-day' => DateTimeObj::get('d'), 'timezone' => DateTimeObj::get('P'), 'website-name' => $this->_Parent->Configuration->get('sitename', 'general'), 'page-title' => $page['title'], 'root' => URL, 'workspace' => URL . '/workspace', 'root-page' => $root_page ? $root_page : $page['handle'], 'current-page' => $page['handle'], 'current-page-id' => $page['id'], 'current-path' => $current_path, 'parent-path' => '/' . $page['path'], 'current-url' => URL . $current_path, 'upload-limit' => min($upload_size_php, $upload_size_sym), 'symphony-build' => $this->_Parent->Configuration->get('build', 'symphony')); if (is_array($this->_env['url'])) { foreach ($this->_env['url'] as $key => $val) { $this->_param[$key] = $val; } } if (is_array($_GET) && !empty($_GET)) { foreach ($_GET as $key => $val) { if (!in_array($key, array('symphony-page', 'debug', 'profile'))) { $this->_param['url-' . $key] = $val; } } } if (is_array($_COOKIE[__SYM_COOKIE_PREFIX_]) && !empty($_COOKIE[__SYM_COOKIE_PREFIX_])) { foreach ($_COOKIE[__SYM_COOKIE_PREFIX_] as $key => $val) { $this->_param['cookie-' . $key] = $val; } } // Flatten parameters: General::flattenArray($this->_param); #### # Delegate: FrontendParamsResolve # Description: Just after having resolved the page params, but prior to any commencement of output creation # Global: Yes $this->ExtensionManager->notifyMembers('FrontendParamsResolve', '/frontend/', array('params' => &$this->_param)); $xml_build_start = precision_timer(); $xml = new XMLElement('data'); $xml->setIncludeHeader(true); $events = new XMLElement('events'); $this->__processEvents($page['events'], $events); $xml->appendChild($events); $this->_events_xml = clone $events; $this->__processDatasources($page['data_sources'], $xml); $this->_Parent->Profiler->seed($xml_build_start); $this->_Parent->Profiler->sample('XML Built', PROFILE_LAP); if (is_array($this->_env['pool']) && !empty($this->_env['pool'])) { foreach ($this->_env['pool'] as $handle => $p) { if (!is_array($p)) { $p = array($p); } foreach ($p as $key => $value) { if (is_array($value) && !empty($value)) { foreach ($value as $kk => $vv) { $this->_param[$handle] .= @implode(', ', $vv) . ','; } } else { $this->_param[$handle] = @implode(', ', $p); } } $this->_param[$handle] = trim($this->_param[$handle], ','); } } #### # Delegate: FrontendParamsPostResolve # Description: Access to the resolved param pool, including additional parameters provided by Data Source outputs # Global: Yes $this->ExtensionManager->notifyMembers('FrontendParamsPostResolve', '/frontend/', array('params' => $this->_param)); ## TODO: Add delegate for adding/removing items in the params $xsl = '<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:import href="./workspace/pages/' . basename($page['filelocation']) . '"/> </xsl:stylesheet>'; $this->_Parent->Profiler->seed(); $this->setXML($xml->generate(true, 0)); $this->_Parent->Profiler->sample('XML Generation', PROFILE_LAP); $this->setXSL($xsl, false); $this->setRuntimeParam($this->_param); $this->_Parent->Profiler->seed($start); $this->_Parent->Profiler->sample('Page Built', PROFILE_LAP); }
/** * This function sets the page's parameters, processes the Datasources and * Events and sets the `$xml` and `$xsl` variables. This functions resolves the `$page` * by calling the `resolvePage()` function. If a page is not found, it attempts * to locate the Symphony 404 page set in the backend otherwise it throws * the default Symphony 404 page. If the page is found, the page's XSL utility * is found, and the system parameters are set, including any URL parameters, * params from the Symphony cookies. Events and Datasources are executed and * any parameters generated by them are appended to the existing parameters * before setting the Page's XML and XSL variables are set to the be the * generated XML (from the Datasources and Events) and the XSLT (from the * file attached to this Page) * * @uses FrontendPageResolved * @uses FrontendParamsResolve * @uses FrontendParamsPostResolve * @see resolvePage() */ private function __buildPage() { $start = precision_timer(); if (!($page = $this->resolvePage())) { throw new FrontendPageNotFoundException(); } /** * Just after having resolved the page, but prior to any commencement of output creation * @delegate FrontendPageResolved * @param string $context * '/frontend/' * @param FrontendPage $page * An instance of this class, passed by reference * @param array $page_data * An associative array of page data, which is a combination from `tbl_pages` and * the path of the page on the filesystem. Passed by reference */ Symphony::ExtensionManager()->notifyMembers('FrontendPageResolved', '/frontend/', array('page' => &$this, 'page_data' => &$page)); $this->_pageData = $page; $path = explode('/', $page['path']); $root_page = is_array($path) ? array_shift($path) : $path; $current_path = explode(dirname($_SERVER['SCRIPT_NAME']), $_SERVER['REQUEST_URI'], 2); $current_path = '/' . ltrim(end($current_path), '/'); $split_path = explode('?', $current_path, 3); $current_path = rtrim(current($split_path), '/'); $querystring = '?' . next($split_path); // Get max upload size from php and symphony config then choose the smallest $upload_size_php = ini_size_to_bytes(ini_get('upload_max_filesize')); $upload_size_sym = Symphony::Configuration()->get('max_upload_size', 'admin'); $this->_param = array('today' => DateTimeObj::get('Y-m-d'), 'current-time' => DateTimeObj::get('H:i'), 'this-year' => DateTimeObj::get('Y'), 'this-month' => DateTimeObj::get('m'), 'this-day' => DateTimeObj::get('d'), 'timezone' => DateTimeObj::get('P'), 'website-name' => Symphony::Configuration()->get('sitename', 'general'), 'page-title' => $page['title'], 'root' => URL, 'workspace' => URL . '/workspace', 'root-page' => $root_page ? $root_page : $page['handle'], 'current-page' => $page['handle'], 'current-page-id' => $page['id'], 'current-path' => $current_path, 'parent-path' => '/' . $page['path'], 'current-query-string' => XMLElement::stripInvalidXMLCharacters(utf8_encode(urldecode($querystring))), 'current-url' => URL . $current_path, 'upload-limit' => min($upload_size_php, $upload_size_sym), 'symphony-version' => Symphony::Configuration()->get('version', 'symphony')); if (is_array($this->_env['url'])) { foreach ($this->_env['url'] as $key => $val) { $this->_param[$key] = $val; } } if (is_array($_GET) && !empty($_GET)) { foreach ($_GET as $key => $val) { if (in_array($key, array('symphony-page', 'debug', 'profile'))) { continue; } // If the browser sends encoded entities for &, ie. a=1&b=2 // this causes the $_GET to output they key as amp;b, which results in // $url-amp;b. This pattern will remove amp; allow the correct param // to be used, $url-b $key = preg_replace('/(^amp;|\\/)/', null, $key); // If the key gets replaced out then it will break the XML so prevent // the parameter being set. if (!General::createHandle($key)) { continue; } $this->_param['url-' . $key] = XMLElement::stripInvalidXMLCharacters(utf8_encode(urldecode($val))); } } if (is_array($_COOKIE[__SYM_COOKIE_PREFIX_]) && !empty($_COOKIE[__SYM_COOKIE_PREFIX_])) { foreach ($_COOKIE[__SYM_COOKIE_PREFIX_] as $key => $val) { $this->_param['cookie-' . $key] = $val; } } // Flatten parameters: General::flattenArray($this->_param); /** * Just after having resolved the page params, but prior to any commencement of output creation * @delegate FrontendParamsResolve * @param string $context * '/frontend/' * @param array $params * An associative array of this page's parameters */ Symphony::ExtensionManager()->notifyMembers('FrontendParamsResolve', '/frontend/', array('params' => &$this->_param)); $xml_build_start = precision_timer(); $xml = new XMLElement('data'); $xml->setIncludeHeader(true); $events = new XMLElement('events'); $this->processEvents($page['events'], $events); $xml->appendChild($events); $this->_events_xml = clone $events; $this->processDatasources($page['data_sources'], $xml); Symphony::Profiler()->seed($xml_build_start); Symphony::Profiler()->sample('XML Built', PROFILE_LAP); if (is_array($this->_env['pool']) && !empty($this->_env['pool'])) { foreach ($this->_env['pool'] as $handle => $p) { if (!is_array($p)) { $p = array($p); } foreach ($p as $key => $value) { if (is_array($value) && !empty($value)) { foreach ($value as $kk => $vv) { $this->_param[$handle] .= @implode(', ', $vv) . ','; } } else { $this->_param[$handle] = @implode(', ', $p); } } $this->_param[$handle] = trim($this->_param[$handle], ','); } } /** * Access to the resolved param pool, including additional parameters provided by Data Source outputs * @delegate FrontendParamsPostResolve * @param string $context * '/frontend/' * @param array $params * An associative array of this page's parameters */ Symphony::ExtensionManager()->notifyMembers('FrontendParamsPostResolve', '/frontend/', array('params' => &$this->_param)); $params = new XMLElement('params'); foreach ($this->_param as $key => $value) { // To support multiple parameters using the 'datasource.field' // we will pop off the field handle prior to sanitizing the // key. This is because of a limitation where General::createHandle // will strip '.' as it's technically punctuation. if (strpos($key, '.') !== false) { $parts = explode('.', $key); $field_handle = '.' . array_pop($parts); $key = implode('', $parts); } else { $field_handle = ''; } $key = Lang::createHandle($key) . $field_handle; $param = new XMLElement($key); // DS output params get flattened to a string, so get the original pre-flattened array if (isset($this->_env['pool'][$key])) { $value = $this->_env['pool'][$key]; } if (is_array($value) && !(count($value) == 1 && empty($value[0]))) { foreach ($value as $key => $value) { $item = new XMLElement('item', General::sanitize($value)); $item->setAttribute('handle', Lang::createHandle($value)); $param->appendChild($item); } } else { if (is_array($value)) { $param->setValue(General::sanitize($value[0])); } else { $param->setValue(General::sanitize($value)); } } $params->appendChild($param); } $xml->prependChild($params); Symphony::Profiler()->seed(); $this->setXML($xml->generate(true, 0)); Symphony::Profiler()->sample('XML Generation', PROFILE_LAP); $xsl = '<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:import href="./workspace/pages/' . basename($page['filelocation']) . '"/> </xsl:stylesheet>'; $this->setXSL($xsl, false); $this->setRuntimeParam($this->_param); Symphony::Profiler()->seed($start); Symphony::Profiler()->sample('Page Built', PROFILE_LAP); }
/** * Uses `DomDocument` to transform the document. Any errors that * occur are trapped by custom error handlers, `trapXMLError` or * `trapXSLError`. * * @param XsltProcessor $XSLProc * An instance of `XsltProcessor` * @param string $xml * The XML for the transformation to be applied to * @param string $xsl * The XSL for the transformation * @param array $parameters * An array of available parameters the XSL will have access to * @return string */ private function __process(XsltProcessor $XSLProc, $xml, $xsl, array $parameters = array()) { // Create instances of the DomDocument class $xmlDoc = new DomDocument(); $xslDoc = new DomDocument(); // Set up error handling if (function_exists('ini_set')) { $ehOLD = ini_set('html_errors', false); } // Load the xml document set_error_handler(array($this, 'trapXMLError')); // Prevent remote entities from being loaded, RE: #1939 $elOLD = libxml_disable_entity_loader(true); $xmlDoc->loadXML($xml, LIBXML_NONET | LIBXML_DTDLOAD | LIBXML_DTDATTR | defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0); libxml_disable_entity_loader($elOLD); // Must restore the error handler to avoid problems restore_error_handler(); // Load the xsl document set_error_handler(array($this, 'trapXSLError')); // Ensure that the XSLT can be loaded with `false`. RE: #1939 // Note that `true` will cause `<xsl:import />` to fail. $elOLD = libxml_disable_entity_loader(false); $xslDoc->loadXML($xsl, LIBXML_NONET | LIBXML_DTDLOAD | LIBXML_DTDATTR | defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0); libxml_disable_entity_loader($elOLD); // Load the xsl template $XSLProc->importStyleSheet($xslDoc); // Set parameters when defined if (!empty($parameters)) { General::flattenArray($parameters); $XSLProc->setParameter('', $parameters); } // Must restore the error handler to avoid problems restore_error_handler(); // Start the transformation set_error_handler(array($this, 'trapXMLError')); $processed = $XSLProc->transformToXML($xmlDoc); // Restore error handling if (function_exists('ini_set') && isset($ehOLD)) { ini_set('html_errors', $ehOLD); } // Must restore the error handler to avoid problems restore_error_handler(); return $processed; }
/** * Uses `DomDocument` to transform the document. Any errors that * occur are trapped by custom error handlers, `trapXMLError` or * `trapXSLError`. * * @param XsltProcessor $XSLProc * An instance of `XsltProcessor` * @param string $xml * The XML for the transformation to be applied to * @param string $xsl * The XSL for the transformation * @param array $parameters * An array of available parameters the XSL will have access to * @return string */ private function __process(XsltProcessor $XSLProc, $xml, $xsl, array $parameters = array()) { // Create instances of the DomDocument class $xmlDoc = new DomDocument(); $xslDoc = new DomDocument(); // Set up error handling if (function_exists('ini_set')) { $ehOLD = ini_set('html_errors', false); } // Load the xml document set_error_handler(array($this, 'trapXMLError')); $xmlDoc->loadXML($xml); // Must restore the error handler to avoid problems restore_error_handler(); // Load the xml document set_error_handler(array($this, 'trapXSLError')); $xslDoc->loadXML($xsl); // Load the xsl template $XSLProc->importStyleSheet($xslDoc); // Set parameters when defined if (!empty($parameters)) { General::flattenArray($parameters); $XSLProc->setParameter('', $parameters); } restore_error_handler(); // Start the transformation set_error_handler(array($this, 'trapXMLError')); $processed = $XSLProc->transformToXML($xmlDoc); // Restore error handling if (function_exists('ini_set') && isset($ehOLD)) { ini_set('html_errors', $ehOLD); } restore_error_handler(); return $processed; }