/** * Returns true if the passed {@link WizardComponent} validates against this rule. * @param ref object $component * @access public * @return boolean */ function checkValue($component) { $doc = new Harmoni_DOMDocument(); try { $doc->loadXML($component->getAllValues()); } catch (DOMException $e) { $component->setErrorText($e->getMessage()); return false; } try { $doc->schemaValidateWithException($this->xmlSchemaPath); } catch (ValidationFailedException $e) { $component->setErrorText($e->getMessage()); return false; } return true; }
/** * Answer a element that represents the content for this Block * * @return object DOMElement * @access protected * @since 2/12/08 */ protected function getContentElement(DOMElement $mediaElement) { // Content/Description $descElement = $this->sourceXPath->query('./description', $this->sourceElement)->item(0); $descHtml = $this->getStringValue($descElement); $descHtml = $this->rewriteLocalLinks($descHtml); // Content $filename = $this->getStringValue($this->getSingleSourceElement('./filename', $this->sourceElement)); $currentContent = $this->doc->createElement('currentContent'); try { $fileUrlString = $this->attachFile($filename, $mediaElement); $fileUrlString = str_replace('asset_id', 'assetId', $fileUrlString); $fileUrlString = str_replace('record_id', 'recordId', $fileUrlString); // $fileUrlString = str_replace('&', '&', $fileUrlString); $doc = new Harmoni_DOMDocument(); $root = $doc->appendChild($doc->createElement('AudioPlayerPlugin')); $fileNode = $root->appendChild($doc->createElement('File')); $fileNode->setAttribute('show_download_link', 'true'); $idNode = $fileNode->appendChild($doc->createElement('Id', $fileUrlString)); $content = $currentContent->appendChild($this->createCDATAElement('content', $doc->saveXMLWithWhitespace())); } catch (MissingNodeException $e) { $content = $currentContent->appendChild($this->createCDATAElement('content', '')); } catch (Segue1To2_MissingFileException $e) { $content = $currentContent->appendChild($this->createCDATAElement('content', '')); } $rawDesc = $currentContent->appendChild($this->createCDATAElement('rawDescription', $this->cleanHtml($descHtml))); return $currentContent; }
/** * Answer a element that represents the content for this Block * * @return object DOMElement * @access protected * @since 2/12/08 */ protected function getContentElement(DOMElement $mediaElement) { // Content/Description $descElement = $this->sourceXPath->query('./description', $this->sourceElement)->item(0); if ($descElement) { $descHtml = $this->cleanHtml($this->getStringValue($descElement)); } else { $descHtml = ''; } $descHtml = $this->rewriteLocalLinks($descHtml); $title = $this->getDisplayName(); $url = $this->rewriteLocalLinks($this->getStringValue($this->getSingleSourceElement('./url', $this->sourceElement))); // Content $dataDoc = new Harmoni_DOMDocument(); $root = $dataDoc->appendChild($dataDoc->createElement('RssFeedPlugin')); $feed = $root->appendChild($dataDoc->createElement('RssFeed')); $urlElement = $feed->appendChild($dataDoc->createElement('Url', str_replace('&', '&', $url))); $sourceUrlElement = $this->getSingleSourceElement('./url', $this->sourceElement); $this->setAttributes($sourceUrlElement, $feed); $currentContent = $this->doc->createElement('currentContent'); $currentContent->appendChild($this->createCDATAElement('content', $dataDoc->saveXMLWithWhitespace())); $currentContent->appendChild($this->doc->createElement('rawDescription', '')); return $currentContent; }
/** * Update the options XML with a new document * * @param object Harmoni_DOMDocument $optionsDocument * @return null * @access public * @since 5/15/08 */ public function updateOptionsDocument(Harmoni_DOMDocument $optionsDocument) { if (!$this->canModify()) { throw new PermissionDeniedException(); } // Unset the options if we have an empty document. if (!isset($optionsDocument->documentElement)) { $this->updateThemeDataByType('options.xml', ''); return; } // Validate any options document given. $optionsDocument->schemaValidateWithException(HARMONI . '/Gui2/theme_options.xsd'); $this->updateThemeDataByType('options.xml', $optionsDocument->saveXML()); }
/** * Answer an XML document for the options for this theme * * @return object Harmoni_DOMDocument * @access public * @since 5/15/08 */ public function getOptionsDocument() { $options = new Harmoni_DOMDocument(); if (file_exists($this->optionsPath)) { $options->preserveWhiteSpace = false; $options->load($this->optionsPath); $options->schemaValidateWithException(dirname(__FILE__) . '/theme_options.xsd'); } return $options; }
/** * Save the advanced step * * @param array $values * @return boolean * @access protected * @since 5/15/08 */ protected function saveAdvancedStep(array $values) { $component = $this->getSiteComponent(); $theme = $component->getTheme(); if (isset($values['create_copy']) && $values['create_copy']) { // Get the first source that supports admin. $guiMgr = Services::getService('GUIManager'); foreach ($guiMgr->getThemeSources() as $source) { if ($source->supportsThemeAdmin()) { $adminSession = $source->getThemeAdminSession(); $newTheme = $adminSession->createCopy($theme); $component->updateTheme($newTheme); $this->createdCopy = true; return true; } } // Nowhere to copy to. print "<p>" . _("Error: No available source to copy this theme to.") . "</p>"; return false; } /********************************************************* * Return if we are not editing advanced options *********************************************************/ if (!$theme->supportsModification()) { return true; } $modSess = $theme->getModificationSession(); if (!$modSess->canModify()) { return true; } /********************************************************* * Info *********************************************************/ $modSess->updateDisplayName($values['display_name']); $modSess->updateDescription($values['description']); if (!is_null($values['thumbnail']['tmp_name'])) { $file = new Harmoni_Filing_FileSystemFile($values['thumbnail']['tmp_name']); $file->setMimeType($values['thumbnail']['type']); $modSess->updateThumbnail($file); } /********************************************************* * CSS and HTML *********************************************************/ $modSess->updateGlobalCss($values['global_css']); foreach ($modSess->getComponentTypes() as $type) { $modSess->updateCssForType($type, $values[$type . '-css']); $modSess->updateTemplateForType($type, $values[$type . '-html']); } /********************************************************* * Images *********************************************************/ $missingImages = $theme->getImages(); foreach ($values['images'] as $imageVal) { // Add new images if ($imageVal['image']['tmp_name']) { $file = new Harmoni_Filing_FileSystemFile($imageVal['image']['tmp_name']); $file->setMimeType($imageVal['image']['type']); $theme->addImage($file, $imageVal['image']['name'], $imageVal['path_prefix']); } else { if ($imageVal['path_prefix'] != $imageVal['orig_path_prefix']) { $image = $modSess->getImage($imageVal['orig_path_prefix'] . '/' . $imageVal['image']['name']); $image->setPath($imageVal['path_prefix'] . '/' . $imageVal['image']['name']); } } // Mark images as existing if ($imageVal['path_prefix']) { $path = $imageVal['path_prefix'] . '/' . $imageVal['image']['name']; } else { $path = $imageVal['image']['name']; } foreach ($missingImages as $key => $image) { if ($image->getPath() == $path) { unset($missingImages[$key]); } } } // Remove any images that were removed. foreach ($missingImages as $image) { $image->delete(); } /********************************************************* * Options *********************************************************/ $optionsString = trim($values['options']); $optionsDoc = new Harmoni_DOMDocument(); $optionsDoc->preserveWhiteSpace = false; if (strlen($optionsString) && $optionsString != '<?xml version="1.0"?>') { try { $optionsDoc->loadXML($values['options']); } catch (DOMException $e) { print "<strong>" . _("Error in Options Definition:") . " </strong>"; print $e->getMessage(); return false; } } try { $modSess->updateOptionsDocument($optionsDoc); } catch (ValidationFailedException $e) { print "<strong>" . _("Error in Options Definition:") . " </strong>"; print $e->getMessage(); return false; } return true; }
/** * Load feed data, convert and clean it, and return its string value. * * @param string $url * @return string RSS xml * @access protected * @since 7/8/08 */ protected function loadFeedXml($url) { $feedData = @file_get_contents($url); if (!strlen($feedData)) { throw new OperationFailedException("Could not access feed, '" . $url . "'."); } $feed = new DOMDocument(); // If the encoding is not UTF-8, convert the document if (preg_match('/^<\\?xml .*encoding=[\'"]([a-zA-Z0-9-]+)[\'"].*\\?>/m', $feedData, $matches)) { $encoding = $matches[1]; if (strtoupper($encoding) != 'UTF8' && strtoupper($encoding) != 'UTF-8') { $feedData = mb_convert_encoding($feedData, 'UTF-8', strtoupper($encoding)); $feedData = preg_replace('/^(<\\?xml .*encoding=[\'"])([a-zA-Z0-9-]+)([\'"].*\\?>)/m', '\\1UTF-8\\3', $feedData); } } // Convert any non-UTF-8 characters $string = String::withValue($feedData); $string->makeUtf8(); $feedData = $string->asString(); if (!@$feed->loadXML($feedData)) { throw new OperationFailedException("Invalid feed data: \"" . $feedData . "\" for URL: " . $url); } // Handle any format conversions $feed = $this->convertToRss($feed); // Validate Feed. // $tmpFeed = $feed; // $feed = new Harmoni_DOMDocument; // $feed->loadXML($tmpFeed->saveXML()); // unset($tmpFeed); // $feed->schemaValidateWithException(dirname(__FILE__).'/rss-2_0-lax.xsd'); // Run through the titles, authors, and descriptions and clean out any unsafe HTML foreach ($feed->getElementsByTagName('title') as $element) { $element->nodeValue = strip_tags(htmlspecialchars_decode($element->nodeValue)); } foreach ($feed->getElementsByTagName('author') as $element) { $element->nodeValue = strip_tags(htmlspecialchars_decode($element->nodeValue)); } foreach ($feed->getElementsByTagName('comments') as $element) { $element->nodeValue = htmlentities(strip_tags(html_entity_decode($element->nodeValue))); } foreach ($feed->getElementsByTagName('link') as $element) { $element->nodeValue = htmlentities(strip_tags(html_entity_decode($element->nodeValue))); } foreach ($feed->getElementsByTagName('description') as $description) { $html = HtmlString::fromString(htmlspecialchars_decode($description->nodeValue)); $html->cleanXSS(); $description->nodeValue = htmlspecialchars($html->asString()); } // Move the feed into a dom document. $tmpFeed = $feed; $feed = new Harmoni_DOMDocument(); $feed->loadXML($tmpFeed->saveXML()); unset($tmpFeed); // Validate the feed again // $feed->schemaValidateWithException(dirname(__FILE__).'/rss-2_0-lax.xsd'); // Just ensure a few basic things: if (!$feed->documentElement->nodeName == 'rss') { throw new DOMDocumentException("Feed root must be an rss element"); } // Check for channels foreach ($feed->documentElement->childNodes as $element) { if ($element->nodeType == 1 && $element->nodeName != 'channel') { throw new DOMDocumentException("'" . $node->nodeName . "' is not expected, expecting 'channel'."); } } // Check dates foreach ($feed->getElementsByTagName('pubdate') as $element) { if (!preg_match('/(((Mon)|(Tue)|(Wed)|(Thu)|(Fri)|(Sat)|(Sun)), *)?\\d\\d? +((Jan)|(Feb)|(Mar)|(Apr)|(May)|(Jun)|(Jul)|(Aug)|(Sep)|(Oct)|(Nov)|(Dec)) +\\d\\d(\\d\\d)? +\\d\\d:\\d\\d(:\\d\\d)? +(([+\\-]?\\d\\d\\d\\d)|(UT)|(GMT)|(EST)|(EDT)|(CST)|(CDT)|(MST)|(MDT)|(PST)|(PDT)|\\w)/', $element->nodeValue)) { throw new DOMDocumentException("'" . $element->nodeValue . "' is not a valid date."); } } return $feed->saveXMLWithWhitespace(); }
/** * Save our results. Tearing down and unsetting the Wizard is handled by * in {@link runWizard()} and does not need to be implemented here. * * @param string $cacheName * @return boolean TRUE if save was successful and tear-down/cleanup of the * Wizard should ensue. * @access public * @since 1/28/08 */ public function saveWizard($cacheName) { $wizard = $this->getWizard($cacheName); if (!$wizard->validate()) { return false; } $values = $wizard->getAllValues(); // printpre($values); // return false; try { if (!defined('DATAPORT_TMP_DIR')) { throw new Exception("DATAPORT_TMP_DIR must be defined in the Segue configuration."); } $archivePath = $values['mode']['backup_file']['tmp_name']; $archiveName = basename($archivePath); $decompressDir = DATAPORT_TMP_DIR . '/' . $archiveName . '_source'; if (!$values['mode']['backup_file']['size']) { throw new Exception("File upload error - archive was not successfully uploaded and has no size."); } $this->decompressArchive($archivePath, $decompressDir); // Do the import $director = SiteDispatcher::getSiteDirector(); $doc = new Harmoni_DOMDocument(); $doc->load($decompressDir . "/site.xml"); // Validate the document contents $doc->schemaValidateWithException(MYDIR . "/doc/raw/dtds/segue2-site.xsd"); $mediaDir = $decompressDir; switch ($values['mode']['trust']) { case 'all': $class = 'DomImportSiteVisitor'; break; case 'time_only': $class = 'UntrustedAgentDomImportSiteVisitor'; break; default: $class = 'UntrustedAgentAndTimeDomImportSiteVisitor'; } $importer = new $class($doc, $mediaDir, $director); if ($values['mode']['roles'] == '1') { $importer->enableRoleImport(); } if ($values['mode']['comments'] == '0') { $importer->disableCommentImport(); } if (isset($values['owners'])) { $idMgr = Services::getService('Id'); foreach ($values['owners']['admins'] as $adminIdString) { $importer->addSiteAdministrator($idMgr->getId($adminIdString)); } } $importer->enableStatusOutput(); $site = $importer->importAtSlot($values['mode']['slotname']); // Delete the uploaded file unlink($archivePath); // Delete the decompressed Archive $this->deleteRecursive($decompressDir); } catch (Exception $importException) { // Delete the uploaded file try { if (file_exists($archivePath)) { unlink($archivePath); } } catch (Exception $deleteException) { print "\n<div>\n\t"; print $deleteException->getMessage(); print "\n</div>"; } // Delete the decompressed Archive try { if (file_exists($decompressDir)) { $this->deleteRecursive($decompressDir); } } catch (Exception $deleteException) { print "\n<div>\n\t"; print $deleteException->getMessage(); print "\n</div>"; } print "\n<div>\n\t"; print $importException->getMessage(); // print HarmoniErrorHandler::printDebugBacktrace($importException->getTrace()); print "\n</div>"; $wizard->backupFile->setValue(array('name' => null, 'size' => null, 'type' => null)); /********************************************************* * Log the failure *********************************************************/ if (Services::serviceRunning("Logging")) { $loggingManager = Services::getService("Logging"); $log = $loggingManager->getLogForWriting("Segue"); $formatType = new Type("logging", "edu.middlebury", "AgentsAndNodes", "A format in which the acting Agent[s] and the target nodes affected are specified."); $priorityType = new Type("logging", "edu.middlebury", "Error", "Recoverable errors."); $item = new AgentNodeEntryItem("Create Site", "Failure in importing site for placeholder, '" . $values['mode']['slotname'] . "'. " . $importException->getMessage()); $item->setBacktrace($importException->getTrace()); $item->addTextToBactrace("Archive Upload: " . printpre($values['mode']['backup_file'], true)); $log->appendLogWithTypes($item, $formatType, $priorityType); } return false; } /********************************************************* * Log the success *********************************************************/ if (Services::serviceRunning("Logging")) { $loggingManager = Services::getService("Logging"); $log = $loggingManager->getLogForWriting("Segue"); $formatType = new Type("logging", "edu.middlebury", "AgentsAndNodes", "A format in which the acting Agent[s] and the target nodes affected are specified."); $priorityType = new Type("logging", "edu.middlebury", "Event_Notice", "Normal events."); $item = new AgentNodeEntryItem("Create Site", "Site imported for placeholder, '" . $values['mode']['slotname'] . "'."); $item->addNodeId($site->getQualifierId()); $log->appendLogWithTypes($item, $formatType, $priorityType); } return true; }
/** * Dumps the internal XML tree back into a string with added whitespace * (new-lines and tabbing). * * @param optional object DOMNode $node * @param optional int $options * @return string * @access public * @since 1/23/08 */ public function saveXMLWithWhitespace(DOMNode $node = null, $options = null) { $doc = new Harmoni_DOMDocument(); if (is_null($node)) { if ($this->documentElement) { $doc->appendChild($doc->importNode($this->documentElement, true)); } } else { $doc->appendChild($doc->importNode($node, true)); } $doc->addWhitespaceToDocument(); return $doc->saveXML($doc->documentElement, $options); }
/** * Convert a Segue1 export into a Segue2 export * * @param string $destFilePath The path that Segue2 export file will be placed in. * @param string $relativeOutputFilePath The output file path relative to * encode into the xml output. * @return object DOMDocument The Segue2 export document * @access protected * @since 3/14/08 */ protected function convertFrom1To2($destFilePath, $relativeOutputFilePath) { try { $sourcePath = $this->downloadSegue1Export(); $sourceFilePath = $sourcePath . "/media"; $sourceDocPath = $sourcePath . "/site.xml"; $sourceDoc = new Harmoni_DOMDocument(); $sourceDoc->load($sourceDocPath); $converter = new Segue1To2Director($destFilePath, $relativeOutputFilePath); $outputDoc = $converter->convert($sourceDoc, $sourceFilePath); // Delete the source directory $this->cleanUpSourcePath($sourcePath); } catch (DOMException $e) { $size = ByteSize::withValue(filesize($sourceDocPath)); $this->cleanUpSourcePath($sourcePath); if ($e->getCode() === DOMSTRING_SIZE_ERR) { throw new DOMException("The export of '" . $this->getSourceSlotName() . "' is too large to load (" . $size->asString() . ") or contains an element that is too large to load.", DOMSTRING_SIZE_ERR); } throw $e; } catch (Exception $e) { if (isset($sourcePath)) { $this->cleanUpSourcePath($sourcePath); } throw $e; } return $outputDoc; }
/** * Answer a DOM XML Document for the given topic * * @param string $topic * @return object DOMDocument * @access public * @since 12/9/05 */ function getTopicXmlDocument($topic) { $document = new Harmoni_DOMDocument(); $tocPart = $this->_tableOfContents->getTableOfContentsPart($topic); if (!$tocPart || !$tocPart->file || !file_exists($tocPart->file)) { ob_start(); print "<html>\n"; print "\t<head>\n"; print "\t\t<title>"; print dgettext("polyphony", "Topic Not Found"); print "</title>\n"; print "\t</head>\n"; print "\t<body>\n"; print "\t\t<h1>"; print dgettext("polyphony", "Topic Not Found"); print "</h1>\n"; print "\t\t<p>"; print dgettext("polyphony", "The topic that you requested was not found."); print "</p>\n"; print "\t</body>\n"; print "</html>\n"; $document->loadXML(ob_get_clean()); } else { $document->load($tocPart->file); } return $document; }
/** * Apply a single history entry to the plugin's history. * * @param SeguePluginsAPI $plugin * @param object DOMElement $element * @return void * @access protected * @since 1/23/08 */ protected function addPluginHistoryEntry(SeguePluginsAPI $plugin, DOMElement $element) { foreach ($element->childNodes as $child) { if ($child->nodeType == XML_ELEMENT_NODE && $child->nodeName != 'comment') { $doc = new Harmoni_DOMDocument(); $doc->appendChild($doc->importNode($child, true)); break; } } if (!isset($doc)) { throw new Exception("No version found."); } $comment = $this->getPluginHistoryComment($element); $timestamp = $this->getPluginHistoryTimestamp($element); $agentId = $this->getPluginHistoryAgentId($element); $plugin->importVersion($doc, $agentId, $timestamp, $comment); }
/** * Write an option * * @param string $groupId * @return void * @access protected * @since 2/4/09 */ protected function getOptions() { $doc = new Harmoni_DOMDocument(); $doc->preserveWhiteSpace = false; try { $doc->loadXML($this->getContent()); } catch (DOMException $e) { $doc->appendChild($doc->createElement('options')); } if (!$doc->documentElement->nodeName == 'options') { throw new OperationFailedException('Expection root-node "options", found "' . $doc->documentElement->nodeName . '".'); } return $doc; }
/** * Create the new site with this template at the slot specified. * * @param object Slot $slot * @param optional string $displayName * @param optional string $description * @return object SiteNavBlockSiteComponent * @access public * @since 6/11/08 */ public function createSite(Slot $slot, $displayName = 'Untitled', $description = '') { $director = SiteDispatcher::getSiteDirector(); $doc = new Harmoni_DOMDocument(); $doc->load($this->_path . "/site.xml"); // Validate the document contents $doc->schemaValidateWithException(MYDIR . "/doc/raw/dtds/segue2-site.xsd"); $mediaDir = $this->_path . "/media"; if (!file_exists($mediaDir)) { $mediaDir = null; } // @todo Strip out any history. $importer = new StripHistoryImportSiteVisitor($doc, $mediaDir, $director); $importer->disableCommentImport(); $site = $importer->importAtSlot($slot->getShortname()); try { // Replace #SITE_NAME# and #SITE_DESCRIPTION# placeholders $site->acceptVisitor(new Segue_Templates_ReplacePlaceholderVisitor($displayName, $description)); } catch (Exception $e) { $director->deleteSiteComponent($site); $slot->deleteSiteId(); throw $e; } return $site; }
/** * Write an option * * @param string $key * @param string $val * @return void * @access protected * @since 2/4/09 */ protected function writeOption($key, $val) { // The options will look like: /* <options> <targetNodeId>12345</targetNodeId> <defaultSortMethod>alpha</defaultSortMethod> <defaultDisplayType>cloud</defaultDisplayType> </options> */ if (!in_array($key, $this->_allowedOptions)) { throw new InvalidArgumentException("Unknown option, {$key}"); } $doc = new Harmoni_DOMDocument(); $doc->preserveWhiteSpace = false; try { $doc->loadXML($this->getContent()); } catch (DOMException $e) { $doc->appendChild($doc->createElement('options')); } if (!$doc->documentElement->nodeName == 'options') { throw new OperationFailedException('Expection root-node "options", found "' . $doc->documentElement->nodeName . '".'); } // Fetch the existing element or create a new one for this key $xpath = new DOMXPath($doc); $elements = $xpath->query('/options/' . $key); if ($elements->length) { $element = $elements->item(0); } else { $element = $doc->documentElement->appendChild($doc->createElement($key)); } // Set the value and save $element->nodeValue = $val; $this->setContent($doc->saveXMLWithWhitespace()); }