public function execute(){ // If it exists and is good, nothing else needs to be done, (other than flush the session data) // This is hit if the user has to manually copy in the configuration.xml data. if(file_exists(ROOT_PDIR . '/config/configuration.xml')){ unset($_SESSION['configs']); $this->setAsPassed(); reload(); } // Load in the configuration example, merge in the SESSION data, and apply them or display the code. $xml = new \XMLLoader(); $xml->setRootName('configuration'); $xml->loadFromFile(ROOT_PDIR . 'config/configuration.example.xml'); $elements = $xml->getElements('return|define'); foreach($elements as $el){ $name = $el->getAttribute('name'); $children = $el->childNodes; foreach($children as $c){ if($c->nodeName == 'value'){ // This one requires a random string. if($name == 'SECRET_ENCRYPTION_PASSPHRASE' && isset($_SESSION['configs'][$name]) && $_SESSION['configs'][$name] == 'RANDOM'){ $value = \Core\random_hex(96); $c->nodeValue = $value; } elseif($name == 'SERVER_ID' && isset($_SESSION['configs'][$name]) && $_SESSION['configs'][$name] == 'RANDOM'){ // The server ID is a 32-digit random string. $value = \Core\random_hex(32); $c->nodeValue = $value; } // An override is provided, use that and overwrite the xml. elseif(isset($_SESSION['configs'][$name])){ $value = $_SESSION['configs'][$name]; $c->nodeValue = $value; } } } } // Try to save this back down. $fdata = $xml->asPrettyXML(); if(is_writable(ROOT_PDIR . '/config')){ // Just automatically copy it over, (with the necessary tranformations). file_put_contents(ROOT_PDIR . 'config/configuration.xml', $fdata); unset($_SESSION['configs']); $this->setAsPassed(); reload(); // :) } else{ // Display the instructions to the user. $this->getTemplate()->assign('contents', $fdata); } }
public function __construct($filename = null) { $this->_file = \Core\Filestore\Factory::File($filename); $this->_xmlloader = new XMLLoader(); $this->_xmlloader->setRootName('component'); if (!$this->_xmlloader->loadFromFile($filename)) { throw new Exception('Parsing of XML Metafile [' . $filename . '] failed, not valid XML.'); } }
/** * Save or get the package XML for this theme. This is useful for the * packager * * @param boolean $minified * @param string $filename */ public function savePackageXML($minified = true, $filename = false) { // Instantiate a new XML Loader object and get it ready to use. $dom = new \XMLLoader(); $dom->setRootName('package'); $dom->load(); // Populate the root attributes for this theme package. $dom->getRootDOM()->setAttribute('type', 'theme'); $dom->getRootDOM()->setAttribute('name', $this->getName()); $dom->getRootDOM()->setAttribute('version', $this->getVersion()); // Declare the packager $dom->createElement('packager[version="' . \Core::GetComponent()->getVersion() . '"]'); /* // Themes don't have any provide directives. // Copy over any provide directives. foreach ($this->_xmlloader->getRootDOM()->getElementsByTagName('provides') as $u) { $newu = $dom->getDOM()->importNode($u); $dom->getRootDOM()->appendChild($newu); } $dom->getElement('/provides[type="component"][name="' . strtolower($this->getName()) . '"][version="' . $this->getVersion() . '"]'); */ /* // Themes don't have any requrie directives. // Copy over any requires directives. foreach ($this->_xmlloader->getRootDOM()->getElementsByTagName('requires') as $u) { $newu = $dom->getDOM()->importNode($u); $dom->getRootDOM()->appendChild($newu); } */ // Copy over any upgrade directives. // This one can be useful for an existing installation to see if this // package can provide a valid upgrade path. foreach ($this->_xmlloader->getRootDOM()->getElementsByTagName('upgrade') as $u) { $newu = $dom->getDOM()->importNode($u); $dom->getRootDOM()->appendChild($newu); } // Tack on description $desc = $this->_xmlloader->getElement('/description', false); if ($desc) { $newd = $dom->getDOM()->importNode($desc); $newd->nodeValue = $desc->nodeValue; $dom->getRootDOM()->appendChild($newd); } $out = $minified ? $dom->asMinifiedXML() : $dom->asPrettyXML(); if ($filename) { file_put_contents($filename, $out); } else { return $out; } }
if(!preg_match('/\.xml$/i', $file)) continue; $bundlefiles[] = $file; } closedir($dh); } } // They should be in alphabetical order... sort($bundlefiles); // Transpose them to the keyname => human readable name. foreach($bundlefiles as $b){ // Open it up $xml = new XMLLoader(); $xml->setRootName('bundler'); $xml->loadFromFile($dir . '/' . $b); $name = $xml->getRootDOM()->getAttribute('name'); $sname = preg_replace('/[^a-z0-9-\.\+]*/i', '', str_replace(' ', '-', $name)); $bundles[] = [ 'file' => $b, 'name' => $name, 'sname' => $sname, 'xml' => $xml, ]; } if(!sizeof($bundles)){ echo "No bundles found, exporting will bundle the entire site." . NL;
public function execute(){ // If there's already a configuration file present... just skip to the next. if(file_exists(ROOT_PDIR . '/config/configuration.xml')){ $this->setAsPassed(); reload(); } // This will contain the temporary configuration values for the installer. if(!isset($_SESSION['configs'])) $_SESSION['configs'] = []; $xml = new \XMLLoader(); $xml->setRootName('configuration'); $xml->loadFromFile(ROOT_PDIR . 'config/configuration.example.xml'); $formelements = []; // Since we're pulling from the ant version, set some nice defaults for the user. $valuedefaults = [ '@{db.server}@' => 'localhost', '@{db.port}@' => '3306', '@{db.type}@' => 'mysqli', '@{db.name}@' => '', '@{db.user}@' => '', '@{db.pass}@' => '', '@{devmode}@' => 'false', '/tmp/coreplus-web/' => '/tmp/' . $_SERVER['HTTP_HOST'] . '-web/', '/tmp/coreplus-cli/' => '/tmp/' . $_SERVER['HTTP_HOST'] . '-cli/', 'RANDOM' => \Core\random_hex(96), ]; $elements = $xml->getElements('return|define'); foreach($elements as $el){ $node = $el->nodeName; $name = $el->getAttribute('name'); $type = $el->getAttribute('type'); $formtype = $el->getAttribute('formtype'); $advanced = $el->getAttribute('advanced'); $children = $el->childNodes; $value = null; $valuenode = null; $description = null; $options = []; // Defaults if($advanced === null || $advanced === '') $advanced = "1"; foreach($children as $c){ switch($c->nodeName){ case 'value': $value = trim($c->nodeValue); $valuenode = $c; break; case 'description': $description = trim($c->nodeValue); break; case 'option': $options[] = trim($c->nodeValue); break; case '#text': break; case '#comment': break; default: trigger_error('Unknown sub-node for ' . $node . ' ' . $name . ': ' . $c->nodeName); } } // Since we're pulling from the ant version, set some nice defaults for the user. if(isset($valuedefaults[$value])){ $value = $valuedefaults[$value]; } // Save the value? if($_SERVER['REQUEST_METHOD'] == 'POST'){ if($type == 'boolean' && $formtype == 'checkbox'){ $value = isset($_POST[$name]) ? 'true' : 'false'; } else{ $value = isset($_POST[$name]) ? $_POST[$name] : ''; } $_SESSION['configs'][$name] = $value; } elseif(isset($_SESSION['configs'][$name])){ $value = $_SESSION['configs'][$name]; } //$value = $el->getElement('value')->nodeValue; // Throw this element onto the array for the template to render out. $formelements[] = [ 'name' => $name, // Make the title more appealing than machine names... 'title' => ucwords(strtolower(str_replace('_', ' ', $name))), // Remap "formtype" to "type", since this will be used in a form afterall! 'type' => $formtype, 'value' => $value, 'description' => $description, 'options' => $options, 'advanced' => $advanced, ]; } // If it's a POST... try the settings and if valid, proceed. $message = null; $instructions = null; if($_SERVER['REQUEST_METHOD'] == 'POST'){ if($message === null){ $connectionresults = $this->testDatabaseConnection(); if($connectionresults['status'] != 'passed'){ //var_dump($connectionresults); die(); $message = $connectionresults['message']; $instructions = $connectionresults['instructions']; } } if($message === null){ // Test the assets too! $results = $this->testDirectoryWritable('assets/'); if($results['status'] != 'passed'){ //var_dump($connectionresults); die(); $message = $results['message']; $instructions = $results['instructions']; } } if($message === null){ // Test the assets too! $results = $this->testDirectoryWritable('public/'); if($results['status'] != 'passed'){ //var_dump($connectionresults); die(); $message = $results['message']; $instructions = $results['instructions']; } } if($message === null){ // Still null after all the tests have ran? // w00t! $this->setAsPassed(); reload(); } } $this->getTemplate()->assign('message', $message); $this->getTemplate()->assign('instructions', $instructions); $this->getTemplate()->assign('formelements', $formelements); //var_dump($formelements);// die(); }
/** * Test that I can load the ATOM page and that it returns valid XML. * The XMLLoader will take care of the validation, since it should be a valid document anyway. */ public function testATOMPage() { // Get the RSS feed and download it to a local file. $rewriteurl = $this->blog->get('rewriteurl'); $this->assertNotEmpty($rewriteurl); // Go to the page and make sure that it loads up! $request = new PageRequest($rewriteurl . '.atom'); $request->execute(); $view = $request->getView(); $this->assertEquals(200, $view->error); $markup = $view->fetch(); $this->assertNotEmpty($markup); // DEVELOPMENT DEBUG //echo $markup; // DEBUG // $xml = new XMLLoader(); $xml->setRootName('feed'); // If it's invalid markup, this load will throw an error, causing phpunit to return an error :) // If the bug is fixed, this will not throw any errors. $xml->loadFromString($markup); $parsedmarkup = $xml->asMinifiedXML(); $this->assertNotEmpty($parsedmarkup); }
closedir($dh); unset($file, $version, $title, $c, $dh); // Load in all themes currently on the system $dir = ROOT_PDIR . 'themes'; $dh = opendir($dir); while(($file = readdir($dh)) !== false){ if($file{0} == '.') continue; if(!is_dir($dir . '/' . $file)) continue; if(!is_readable($dir . '/' . $file . '/' . 'theme.xml')) continue; $t = ThemeHandler::GetTheme($file); // What's this file's version? $xml = new XMLLoader(); $xml->setRootName('theme'); if(!$xml->loadFromFile($dir . '/' . $file . '/theme.xml')){ CLI::PrintLine('Skipping theme ' . $file . ', unable to load XML file'); continue; } // Get the current version, this will be used to autocomplete for the next version. //$version = $xml->getRootDOM()->getAttribute("version"); $version = $t->getVersion(); // If display versions is requested, tack on the version number too! if($opts['listversions']){ $title = 'Theme/' . $t->getName() . ' ' . $version; } else{ $title = ' Theme ' . $t->getName();
/** * Helper utility to import a given remote blog. * * @param bool $verbose Set to true to enable real-time verbose output of the operation. * @return array * * @throws Exception */ public function importFeed($verbose = false) { $blogid = $this->get('id'); if (!$this->exists()) { throw new Exception('Unable to import a blog that does not exist!'); } // Make sure this is a remote blog. if ($this->get('type') != 'remote') { throw new Exception('Cannot import a blog that is not remote!'); } $file = \Core\Filestore\Factory::File($this->get('remote_url')); if (!$file->exists()) { throw new Exception($this->get('remote_url') . ' does not appear to exist'); } $defaults = ['parenturl' => $this->get('baseurl'), 'site' => $this->get('site'), 'component' => 'blog']; $changes = ['added' => 0, 'updated' => 0, 'skipped' => 0, 'deleted' => 0]; $changelog = ''; // I need a list of current articles in this feed. This is because remote deletions won't be coming in on the feed. $map = array(); $articles = BlogArticleModel::FindRaw(['blogid = ' . $blogid]); foreach ($articles as $a) { $map[$a['guid']] = $a['id']; } // I can't trust that remote files list what they actually are because many frameworks, // (WP in specific), do not correctly use content-types :/ $contents = $file->getContents(); // Which feed type is this? $header = substr($contents, 0, 400); // All the standardized records $records = array(); if (strpos($header, '<rss ') !== false) { if ($verbose) { echo 'Found an RSS feed with the URL of ' . $file->getURL() . '!<br/>' . "\n"; ob_flush(); flush(); } $xml = new XMLLoader(); $xml->setRootName('rss'); $xml->loadFromString($contents); foreach ($xml->getElements('channel/item') as $item) { $dat = ['guid' => '', 'link' => '', 'thumbnail' => '', 'published' => '', 'updated' => '', 'description' => '']; foreach ($item->childNodes as $child) { if ($child->nodeName == '#text') { continue; } switch ($child->nodeName) { case 'media:thumbnail': $dat['thumbnail'] = $child->getAttribute('url'); break; case 'pubDate': $dat['published'] = $child->nodeValue; break; default: $dat[$child->nodeName] = $child->nodeValue; } } $records[] = $dat; } } elseif (strpos($header, 'http://www.w3.org/2005/Atom') !== false) { if ($verbose) { echo 'Found an ATOM feed with the URL of ' . $file->getURL() . '!<br/>' . "\n"; ob_flush(); flush(); } $xml = new XMLLoader(); $xml->setRootName('feed'); $xml->loadFromString($contents); foreach ($xml->getRootDOM()->childNodes as $item) { if ($item->nodeName != 'entry') { continue; } $dat = ['guid' => '', 'link' => '', 'thumbnail' => '', 'published' => '', 'updated' => '', 'description' => '']; $imgheight = 0; foreach ($item->childNodes as $child) { if ($child->nodeName == '#text') { continue; } switch ($child->nodeName) { case 'id': $dat['guid'] = $child->nodeValue; break; case 'link': if ($child->getAttribute('rel') == 'alternate' && $child->getAttribute('type') == 'text/html') { if ($child->nodeValue) { $dat['link'] = $child->nodeValue; } else { $dat['link'] = $child->getAttribute('href'); } } break; case 'im:image': if ($child->getAttribute('height') > $imgheight) { $dat['thumbnail'] = $child->nodeValue; $imgheight = $child->getAttribute('height'); } break; case 'updated': $dat['updated'] = strtotime($child->nodeValue); break; case 'summary': if ($dat['description'] != '') { $dat['description'] = $child->nodeValue; } break; case 'content': $dat['description'] = $child->nodeValue; break; default: $dat[$child->nodeName] = $child->nodeValue; } } if (!$dat['published'] && $dat['updated']) { // make sure that there's a published date. $dat['published'] = $dat['updated']; } $records[] = $dat; } } else { throw new Exception('Invalid remote file found, please ensure it is either an RSS or Atom feed!'); } // Now that they're standardized... foreach ($records as $dat) { /** @var PageModel $page */ $page = PageModel::Construct($dat['link']); $published = $dat['published'] == '' || is_numeric($dat['published']) ? $dat['published'] : strtotime($dat['published']); $updated = $dat['updated'] != '' ? is_numeric($dat['updated']) ? $dat['updated'] : strtotime($dat['updated']) : $published; $pagedat = ['published' => $published, 'title' => $dat['title'], 'body' => $dat['description'], 'updated' => $updated]; $newpagedat = array_merge($defaults, ['selectable' => '0']); $page->setFromArray($pagedat); if (!$page->exists()) { // Add the "new" dat only if the page doesn't exist before. $page->setFromArray($newpagedat); } if ($dat['thumbnail']) { $remote = \Core\Filestore\Factory::File($dat['thumbnail']); $new = $remote->copyTo('public/blog/'); $page->setMeta('image', $new->getFilename(false)); } $page->setMeta('guid', $dat['guid']); $thischange = $page->exists() ? 'updated' : 'added'; if ($page->changed()) { $page->save(); $changes[$thischange]++; $changelog .= $thischange . ' ' . $dat['title'] . "<br/>\n"; if ($verbose) { echo $thischange . ' ' . $dat['title'] . "<br/>\n"; ob_flush(); flush(); } } else { $changes['skipped']++; if ($verbose) { echo 'No changes to ' . $dat['title'] . "<br/>\n"; ob_flush(); flush(); } } } return ['status' => 1, 'message' => 'Import feed successfully!', 'added' => $changes['added'], 'updated' => $changes['updated'], 'deleted' => $changes['deleted'], 'skipped' => $changes['skipped'], 'changelog' => $changelog]; }