/** * Helper function to see if there is a valid upgrade path from the current version installed * to the version of the code available. * * @return bool */ private function _checkUpgradePath(){ // Check that if the version installed is not what's in the component file, that there is a valid upgrade path. if($this->_versionDB && $this->_version != $this->_versionDB){ // Assemble an array of upgrade paths, with the key/pairs being from//to versions. $paths = array(); foreach ($this->_xmlloader->getRootDOM()->getElementsByTagName('upgrade') as $u) { $from = $u->getAttribute('from'); $to = $u->getAttribute('to'); if(!isset($paths[$from])) $paths[$from] = array(); $paths[$from][] = $to; } if(!sizeof($paths)){ // No upgrade paths even defined! return false; } // Sort them version descending, makes finding the highest version number easier foreach($paths as $k => $vs){ rsort($paths[$k], SORT_NATURAL); } $current = $this->_versionDB; $x = 0; // My anti-infinite-loop counter. while($current != $this->_version && $x < 20){ ++$x; if(isset($paths[$current])){ $current = $paths[$current][0]; } else{ return false; } } // Yay, if it's gotten here, that means that there was a valid upgrade path! return true; } else{ // Easy enough :) // The else is that it's installed and up to date. return true; } }
/** * Set the version of this theme * * This affects the theme.xml metafile of the package. * * @param $vers string * * @return void */ public function setVersion($vers) { if ($vers == $this->_version) { return; } // Switch over any unversioned upgrade directives to this version. // First, check just a plain <upgrade> directive. if ($upg = $this->_xmlloader->getElement('/upgrades/upgrade[@from=""][@to=""]', false)) { // Add the current and dest. attribute to it. $upg->setAttribute('from', $this->_version); $upg->setAttribute('to', $vers); } elseif ($upg = $this->_xmlloader->getElement('/upgrades/upgrade[@from="' . $this->_version . '"][@to=""]', false)) { $upg->setAttribute('to', $vers); } else { // No node found... just create a new one. $this->_xmlloader->getElement('/upgrades/upgrade[@from="' . $this->_version . '"][@to="' . $vers . '"]'); } $this->_version = $vers; $this->_xmlloader->getRootDOM()->setAttribute('version', $vers); }
} 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; $bundles[] = [ 'file' => '', 'name' => SITENAME,
/** * 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]; }