/** * Check if the remote server environment matches our expectations. * * @throws Exception */ private function checkRemoteServerEnvironment() { $session = $this->container->session; $baseUrl = $session->get('transfer.url', '', 'akeeba'); $baseUrl = rtrim($baseUrl, '/'); $downloader = new Download($this->container); $rawData = $downloader->getFromURL($baseUrl . '/kickstart.php?task=serverinfo'); if ($rawData == false) { // Cannot access Kickstart on the remote server throw new RuntimeException(JText::_('COM_AKEEBA_TRANSFER_ERR_CANNOTRUNKICKSTART')); } // Try to get the raw JSON data $pos = strpos($rawData, '###'); if ($pos === false) { // Invalid AJAX data, no leading ### throw new RuntimeException(JText::_('COM_AKEEBA_TRANSFER_ERR_CANNOTRUNKICKSTART')); } // Remove the leading ### $rawData = substr($rawData, $pos + 3); $pos = strpos($rawData, '###'); if ($pos === false) { // Invalid AJAX data, no trailing ### throw new RuntimeException(JText::_('COM_AKEEBA_TRANSFER_ERR_CANNOTRUNKICKSTART')); } // Remove the trailing ### $rawData = substr($rawData, 0, $pos); // Get the JSON response $data = @json_decode($rawData, true); if (empty($data)) { // Invalid AJAX data, can't decode this stuff throw new RuntimeException(JText::_('COM_AKEEBA_TRANSFER_ERR_CANNOTRUNKICKSTART')); } // Does the server have enough disk space? $freeSpace = $data['freeSpace']; $requiredSize = $this->getApproximateSpaceRequired(); if ($requiredSize['size'] > $freeSpace) { $unit = array('b', 'Kb', 'Mb', 'Gb', 'Tb', 'Pb'); $freeSpaceString = @round($freeSpace / pow(1024, $i = floor(log($freeSpace, 1024))), 2) . ' ' . $unit[$i]; throw new RuntimeException(JText::sprintf('COM_AKEEBA_TRANSFER_ERR_NOTENOUGHSPACE', $freeSpaceString, $requiredSize['string'])); } // Can I write to remote files? $canWrite = $data['canWrite']; $canWriteTemp = $data['canWriteTemp']; if (!$canWrite && !$canWriteTemp) { throw new RuntimeException(JText::_('COM_AKEEBA_TRANSFER_ERR_CANNOTWRITEREMOTEFILES')); } if ($canWrite) { $session->set('transfer.targetPath', '', 'akeeba'); } else { $session->set('transfer.targetPath', 'kicktemp', 'akeeba'); } $session->set('transfer.remoteTimeLimit', $data['maxExecTime'], 'akeeba'); }
/** * @covers FOF30\Download\Download::importFromUrl * * @dataProvider FOF30\Tests\Download\DownloadDataprovider::getTestImportFromUrl * * @param array $config * @param array $params * @param array $test */ public function testImportFromUrl(array $config, array $params, array $test) { // Set up the FakeCurl simulator FakeCurl::setUp($config); // Get the download class $download = new Download(static::$container); $download->setAdapter('curl'); // Initialise $loopAllowed = $test['loop']; // Get the output file name $platformDirs = static::$container->platform->getPlatformBaseDirs(); $tmpDir = $platformDirs['tmp']; $localFilename = $tmpDir . '/test.dat'; // Set up the download parameters $params['localFilename'] = $localFilename; #$params['maxExecTime'] = $test['loop'] ? 10000 : 0; $params['maxExecTime'] = 0; if (isset($test['localfile'])) { if (empty($test['localfile'])) { unset($params['localFilename']); } else { $params['localFilename'] = $test['localfile']; } } // Remove the local filename if it's still there @unlink($localFilename); do { $ret = $download->importFromURL($params); if ($loopAllowed) { $loopAllowed = !($ret['frag'] == -1 || $ret['error']); } $params = array_merge($params, $ret); if (isset($params['localFilename']) && !empty($params['localFilename'])) { $localFilename = $params['localFilename']; } } while ($loopAllowed); foreach ($test['expect'] as $k => $v) { // Validate expected parameters $this->assertEquals($v, $ret[$k], $test['message'] . " (returned {$k} does not match)"); } // Check the return size if (!$test['expect']['error']) { $fileSize = @filesize($localFilename); $this->assertEquals($test['retSize'], $fileSize, $test['message'] . " (size doesn't match {$test['retSize']})"); } // Remove the local filename if it's still there @unlink($localFilename); }
/** * Reads an "extension" XML update source and returns all listed update entries. * * If you have a "collection" XML update source you should do something like this: * $collection = new F0FUtilsUpdateCollection(); * $extensionUpdateURL = $collection->getExtensionUpdateSource($url, 'component', 'com_foobar', JVERSION); * $extension = new F0FUtilsUpdateExtension(); * $updates = $extension->getUpdatesFromExtension($extensionUpdateURL); * * @param string $url The extension XML update source URL to read from * * @return array An array of update entries */ public function getUpdatesFromExtension($url) { // Initialise $ret = array(); // Get and parse the XML source $container = Container::getInstance('com_FOOBAR'); $downloader = new Download($container); $xmlSource = $downloader->getFromURL($url); try { $xml = new SimpleXMLElement($xmlSource, LIBXML_NONET); } catch (Exception $e) { return $ret; } // Sanity check if ($xml->getName() != 'updates') { unset($xml); return $ret; } // Let's populate the list of updates /** @var SimpleXMLElement $update */ foreach ($xml->children() as $update) { // Sanity check if ($update->getName() != 'update') { continue; } $entry = array('infourl' => array('title' => '', 'url' => ''), 'downloads' => array(), 'tags' => array(), 'targetplatform' => array()); $properties = get_object_vars($update); foreach ($properties as $nodeName => $nodeContent) { switch ($nodeName) { default: $entry[$nodeName] = $nodeContent; break; case 'infourl': case 'downloads': case 'tags': case 'targetplatform': break; } } $infourlNode = $update->xpath('infourl'); $entry['infourl']['title'] = (string) $infourlNode[0]['title']; $entry['infourl']['url'] = (string) $infourlNode[0]; $downloadNodes = $update->xpath('downloads/downloadurl'); foreach ($downloadNodes as $downloadNode) { $entry['downloads'][] = array('type' => (string) $downloadNode['type'], 'format' => (string) $downloadNode['format'], 'url' => (string) $downloadNode); } $tagNodes = $update->xpath('tags/tag'); foreach ($tagNodes as $tagNode) { $entry['tags'][] = (string) $tagNode; } /** @var SimpleXMLElement[] $targetPlatformNode */ $targetPlatformNode = $update->xpath('targetplatform'); $entry['targetplatform']['name'] = (string) $targetPlatformNode[0]['name']; $entry['targetplatform']['version'] = (string) $targetPlatformNode[0]['version']; $client = $targetPlatformNode[0]->xpath('client'); $entry['targetplatform']['client'] = is_array($client) && count($client) ? (string) $client[0] : ''; $folder = $targetPlatformNode[0]->xpath('folder'); $entry['targetplatform']['folder'] = is_array($folder) && count($folder) ? (string) $folder[0] : ''; $ret[] = $entry; } unset($xml); return $ret; }
/** * Reads a "collection" XML update source and returns the complete tree of categories * and extensions applicable for platform version $jVersion * * @param string $url The collection XML update source URL to read from * @param string $jVersion Joomla! version to fetch updates for, or null to use JVERSION * * @return array A list of update sources applicable to $jVersion */ public function getAllUpdates($url, $jVersion = null) { // Get the target platform if (is_null($jVersion)) { $jVersion = JVERSION; } // Initialise return value $updates = array('metadata' => array('name' => '', 'description' => ''), 'categories' => array(), 'extensions' => array()); // Download and parse the XML file $container = Container::getInstance('com_foobar'); $downloader = new Download($container); $xmlSource = $downloader->getFromURL($url); try { $xml = new SimpleXMLElement($xmlSource, LIBXML_NONET); } catch (Exception $e) { return $updates; } // Sanity check if ($xml->getName() != 'extensionset') { unset($xml); return $updates; } // Initialise return value with the stream metadata (name, description) $rootAttributes = $xml->attributes(); foreach ($rootAttributes as $k => $v) { $updates['metadata'][$k] = (string) $v; } // Initialise the raw list of updates $rawUpdates = array('categories' => array(), 'extensions' => array()); // Segregate the raw list to a hierarchy of extension and category entries /** @var SimpleXMLElement $extension */ foreach ($xml->children() as $extension) { switch ($extension->getName()) { case 'category': // These are the parameters we expect in a category $params = array('name' => '', 'description' => '', 'category' => '', 'ref' => '', 'targetplatformversion' => $jVersion); // These are the attributes of the element $attributes = $extension->attributes(); // Merge them all foreach ($attributes as $k => $v) { $params[$k] = (string) $v; } // We can't have a category with an empty category name if (empty($params['category'])) { continue; } // We can't have a category with an empty ref if (empty($params['ref'])) { continue; } if (empty($params['description'])) { $params['description'] = $params['category']; } if (!array_key_exists($params['category'], $rawUpdates['categories'])) { $rawUpdates['categories'][$params['category']] = array(); } $rawUpdates['categories'][$params['category']][] = $params; break; case 'extension': // These are the parameters we expect in a category $params = array('element' => '', 'type' => '', 'version' => '', 'name' => '', 'detailsurl' => '', 'targetplatformversion' => $jVersion); // These are the attributes of the element $attributes = $extension->attributes(); // Merge them all foreach ($attributes as $k => $v) { $params[$k] = (string) $v; } // We can't have an extension with an empty element if (empty($params['element'])) { continue; } // We can't have an extension with an empty type if (empty($params['type'])) { continue; } // We can't have an extension with an empty version if (empty($params['version'])) { continue; } if (empty($params['name'])) { $params['name'] = $params['element'] . ' ' . $params['version']; } if (!array_key_exists($params['type'], $rawUpdates['extensions'])) { $rawUpdates['extensions'][$params['type']] = array(); } if (!array_key_exists($params['element'], $rawUpdates['extensions'][$params['type']])) { $rawUpdates['extensions'][$params['type']][$params['element']] = array(); } $rawUpdates['extensions'][$params['type']][$params['element']][] = $params; break; default: break; } } unset($xml); if (!empty($rawUpdates['categories'])) { foreach ($rawUpdates['categories'] as $category => $entries) { $update = $this->filterListByPlatform($entries, $jVersion); $updates['categories'][$category] = $update; } } if (!empty($rawUpdates['extensions'])) { foreach ($rawUpdates['extensions'] as $type => $extensions) { $updates['extensions'][$type] = array(); if (!empty($extensions)) { foreach ($extensions as $element => $entries) { $update = $this->filterListByPlatform($entries, $jVersion); $updates['extensions'][$type][$element] = $update; } } } } return $updates; }