%PDF- %PDF-
Direktori : /home/lightco1/www/lightingrepublic.com.au/components/com_akeeba/models/ |
Current File : /home/lightco1/www/lightingrepublic.com.au/components/com_akeeba/models/jsons.php |
<?php /** * @package AkeebaBackup * @copyright Copyright (c)2009-2013 Nicholas K. Dionysopoulos * @license GNU General Public License version 3, or later * * @since 3.0 */ // Protect from unauthorized access defined('_JEXEC') or die(); // JSON API version number define('AKEEBA_JSON_API_VERSION', '320'); /* * Short API version history: * 300 First draft. Basic backup working. Encryption semi-broken. * 316 Fixed download feature. */ // Force load the AEUtilEncrypt class if it's Akeeba Backup Professional if(AKEEBA_PRO == 1) $dummy = new AEUtilEncrypt; if(!defined('AKEEBA_BACKUP_ORIGIN')) { define('AKEEBA_BACKUP_ORIGIN','json'); } class AkeebaModelJsons extends FOFModel { const STATUS_OK = 200; // Normal reply const STATUS_NOT_AUTH = 401; // Invalid credentials const STATUS_NOT_ALLOWED = 403; // Not enough privileges const STATUS_NOT_FOUND = 404; // Requested resource not found const STATUS_INVALID_METHOD = 405; // Unknown JSON method const STATUS_ERROR = 500; // An error occurred const STATUS_NOT_IMPLEMENTED = 501; // Not implemented feature const STATUS_NOT_AVAILABLE = 503; // Remote service not activated const ENCAPSULATION_RAW = 1; // Data in plain-text JSON const ENCAPSULATION_AESCTR128 = 2; // Data in AES-128 stream (CTR) mode encrypted JSON const ENCAPSULATION_AESCTR256 = 3; // Data in AES-256 stream (CTR) mode encrypted JSON const ENCAPSULATION_AESCBC128 = 4; // Data in AES-128 standard (CBC) mode encrypted JSON const ENCAPSULATION_AESCBC256 = 5; // Data in AES-256 standard (CBC) mode encrypted JSON private $json_errors = array( 'JSON_ERROR_NONE' => 'No error has occurred (probably emtpy data passed)', 'JSON_ERROR_DEPTH' => 'The maximum stack depth has been exceeded', 'JSON_ERROR_CTRL_CHAR' => 'Control character error, possibly incorrectly encoded', 'JSON_ERROR_SYNTAX' => 'Syntax error' ); /** @var int The status code */ private $status = 200; /** @var int Data encapsulation format */ private $encapsulation = 1; /** @var mixed Any data to be returned to the caller */ private $data = ''; /** @var string A password passed to us by the caller */ private $password = null; /** @var string The method called by the client */ private $method_name = null; public function execute($json) { // Check if we're activated $enabled = AEPlatform::getInstance()->get_platform_configuration_option('frontend_enable', 0); if(!$enabled) { $this->data = 'Access denied'; $this->status = self::STATUS_NOT_AVAILABLE; $this->encapsulation = self::ENCAPSULATION_RAW; return $this->getResponse(); } // Try to JSON-decode the request's input first $request = @$this->json_decode($json, false); if(is_null($request)) { // Could not decode JSON $this->data = 'JSON decoding error'; $this->status = self::STATUS_ERROR; $this->encapsulation = self::ENCAPSULATION_RAW; return $this->getResponse(); } // Decode the request body // Request format: {encapsulation, body{ [key], [challenge], method, [data] }} or {[challenge], method, [data]} if( isset($request->encapsulation) && isset($request->body) ) { if(!class_exists('AEUtilEncrypt') && !($request->encapsulation == self::ENCAPSULATION_RAW)) { // Encrypted request found, but there is no encryption class available! $this->data = 'This server does not support encrypted requests'; $this->status = self::STATUS_NOT_AVAILABLE; $this->encapsulation = self::ENCAPSULATION_RAW; return $this->getResponse(); } // Fully specified request switch( $request->encapsulation ) { case self::ENCAPSULATION_AESCBC128: if(!isset($body)) { $request->body = base64_decode($request->body); $body = AEUtilEncrypt::AESDecryptCBC($request->body, $this->serverKey(), 128); } break; case self::ENCAPSULATION_AESCBC256: if(!isset($body)) { $request->body = base64_decode($request->body); $body = AEUtilEncrypt::AESDecryptCBC($request->body, $this->serverKey(), 256); } break; case self::ENCAPSULATION_AESCTR128: if(!isset($body)) { $body = AEUtilEncrypt::AESDecryptCtr($request->body, $this->serverKey(), 128); } break; case self::ENCAPSULATION_AESCTR256: if(!isset($body)) { $body = AEUtilEncrypt::AESDecryptCtr($request->body, $this->serverKey(), 256); } break; case self::ENCAPSULATION_RAW: $body = $request->body; break; } if(!empty($request->body)) { $body = rtrim( $body, chr(0) ); $request->body = $this->json_decode($body); if(is_null($request->body)) { // Decryption failed. The user is an imposter! Go away, hacker! $this->data = 'Authentication failed'; $this->status = self::STATUS_NOT_AUTH; $this->encapsulation = self::ENCAPSULATION_RAW; return $this->getResponse(); } } } elseif( isset($request->body) ) { // Partially specified request, assume RAW encapsulation $request->encapsulation = self::ENCAPSULATION_RAW; $request->body = $this->json_decode($request->body); } else { // Legacy request $legacyRequest = clone $request; $request = (object) array( 'encapsulation' => self::ENCAPSULATION_RAW, 'body' => null ); $request->body = $this->json_decode($legacyRequest); unset($legacyRequest); } // Authenticate the user. Do note that if an encrypted request was made, we can safely assume that // the user is authenticated (he already knows the server key!) if($request->encapsulation == self::ENCAPSULATION_RAW) { $authenticated = false; if(isset($request->body->challenge)) { list($challenge,$check) = explode(':', $request->body->challenge); $crosscheck = strtolower(md5($challenge.$this->serverKey())); $authenticated = ($crosscheck == $check); } if(!$authenticated) { // If the challenge was missing or it was wrong, don't let him go any further $this->data = 'Invalid login credentials'; $this->status = self::STATUS_NOT_AUTH; $this->encapsulation = self::ENCAPSULATION_RAW; return $this->getResponse(); } } // Replicate the encapsulation preferences of the client for our own output $this->encapsulation = $request->encapsulation; // Store the client-specified key, or use the server key if none specified and the request // came encrypted. $this->password = isset($request->body->key) ? $request->body->key : null; $hasKey = (isset($request->body->key) || property_exists($request->body, 'key')) ? !is_null($request->body->key) : false; if(!$hasKey && ($request->encapsulation != self::ENCAPSULATION_RAW) ) { $this->password = $this->serverKey(); } // Does the specified method exist? $method_exists = false; $method_name = ''; if(isset($request->body->method)) { $method_name = ucfirst($request->body->method); $this->method_name = $method_name; $method_exists = method_exists($this, '_api'.$method_name ); } if(!$method_exists) { // The requested method doesn't exist. Oops! $this->data = "Invalid method $method_name"; $this->status = self::STATUS_INVALID_METHOD; $this->encapsulation = self::ENCAPSULATION_RAW; return $this->getResponse(); } // Run the method $params = array(); if(isset($request->body->data)) $params = (array)$request->body->data; $this->data = call_user_func( array($this, '_api'.$method_name) , $params); return $this->getResponse(); } /** * Packages the response to a JSON-encoded object, optionally encrypting the * data part with a caller-supplied password. * @return string The JSON-encoded response */ private function getResponse() { // Initialize the response $response = array( 'encapsulation' => $this->encapsulation, 'body' => array( 'status' => $this->status, 'data' => null ) ); switch($this->method_name) { case 'Download': $data = json_encode($this->data); break; default: $data = $this->json_encode($this->data); break; } if(empty($this->password)) $this->encapsulation = self::ENCAPSULATION_RAW; switch($this->encapsulation) { case self::ENCAPSULATION_RAW: break; case self::ENCAPSULATION_AESCTR128: $data = AEUtilEncrypt::AESEncryptCtr($data, $this->password, 128); break; case self::ENCAPSULATION_AESCTR256: $data = AEUtilEncrypt::AESEncryptCtr($data, $this->password, 256); break; case self::ENCAPSULATION_AESCBC128: $data = base64_encode(AEUtilEncrypt::AESEncryptCBC($data, $this->password, 128)); break; case self::ENCAPSULATION_AESCBC256: $data = base64_encode(AEUtilEncrypt::AESEncryptCBC($data, $this->password, 256)); break; } $response['body']['data'] = $data; switch($this->method_name) { case 'Download': return '###' . json_encode($response) . '###'; break; default: return '###' . $this->json_encode($response) . '###'; break; } } private function serverKey() { static $key = null; if(is_null($key)) { $key = AEPlatform::getInstance()->get_platform_configuration_option('frontend_secret_word', ''); } return $key; } private function _apiGetVersion() { require_once JPATH_ROOT.'/administrator/components/com_akeeba/liveupdate/liveupdate.php'; $updateInformation = LiveUpdate::getUpdateInformation(); $edition = AKEEBA_PRO ? 'pro' : 'core'; return (object)array( 'api' => AKEEBA_JSON_API_VERSION, 'component' => AKEEBA_VERSION, 'date' => AKEEBA_DATE, 'edition' => $edition, 'updateinfo' => $updateInformation, ); } private function _apiGetProfiles() { require_once JPATH_SITE.'/administrator/components/com_akeeba/models/profiles.php'; $model = new AkeebaModelProfiles(); $profiles = $model->getProfilesList(true); $ret = array(); if(count($profiles)) { foreach($profiles as $profile) { $temp = new stdClass(); $temp->id = $profile->id; $temp->name = $profile->description; $ret[] = $temp; } } return $ret; } private function _apiStartBackup($config) { // Get the passed configuration values $defConfig = array( 'profile' => 1, 'description' => '', 'comment' => '' ); $config = array_merge($defConfig, $config); foreach($config as $key => $value) { if(!array_key_exists($key, $defConfig)) unset($config[$key]); } extract($config); // Nuke the factory AEFactory::nuke(); // Set the profile $profile = (int)$profile; if(!is_numeric($profile)) $profile = 1; $session = JFactory::getSession(); $session->set('profile', $profile, 'akeeba'); AEPlatform::getInstance()->load_configuration($profile); // Use the default description if none specified if(empty($description)) { JLoader::import('joomla.utilities.date'); $dateNow = new JDate(); /* $user = JFactory::getUser(); $userTZ = $user->getParam('timezone',0); $dateNow->setOffset($userTZ); */ $description = JText::_('BACKUP_DEFAULT_DESCRIPTION').' '.$dateNow->format(JText::_('DATE_FORMAT_LC2'), true); } // Start the backup AECoreKettenrad::reset(array( 'maxrun' => 0 )); AEUtilTempvars::reset(AKEEBA_BACKUP_ORIGIN); $kettenrad = AECoreKettenrad::load(AKEEBA_BACKUP_ORIGIN); $options = array( 'description' => $description, 'comment' => $comment, 'tag' => AKEEBA_BACKUP_ORIGIN ); $kettenrad->setup($options); // Setting up the engine $array = $kettenrad->tick(); // Initializes the init domain AECoreKettenrad::save(AKEEBA_BACKUP_ORIGIN); $array = $kettenrad->getStatusArray(); if($array['Error'] != '') { // A backup error had occurred. Why are we here?! $this->status = self::STATUS_ERROR; $this->encapsulation = self::ENCAPSULATION_RAW; return 'A backup error had occurred: '.$array['Error']; } else { $statistics = AEFactory::getStatistics(); $array['BackupID'] = $statistics->getId(); $array['HasRun'] = 1; // Force the backup to go on. return $array; } } private function _apiStartSRPBackup($config) { // Get the passed configuration values $defConfig = array( 'tag' => 'restorepoint', 'type' => 'component', 'name' => 'akeeba', 'group' => '', 'customdirs' => array(), 'extraprefixes' => array(), 'customtables' => array(), 'skiptables' => array(), 'xmlname' => '', ); $config = array_merge($defConfig, $config); foreach($config as $key => $value) { if(!array_key_exists($key, $defConfig)) unset($config[$key]); } // Fetch the extension's version information require_once JPATH_ADMINISTRATOR.'/components/com_akeeba/liveupdate/classes/xmlslurp.php'; $slurp = new LiveUpdateXMLSlurp(); $exttype = $config['type']; switch($exttype) { case 'component': $extname = 'com_'; break; case 'module': $extname = 'mod_'; break; case 'plugin': $extname = 'plg_'; break; case 'template': $extname = 'tpl_'; break; } $extname .= $config['name']; $info = $slurp->getInfo($extname, ''); $configOverrides = array( 'akeeba.basic.archive_name' => 'restore-point-[DATE]-[TIME]', 'akeeba.basic.backup_type' => 'full', 'akeeba.basic.backup_type' => 'full', 'akeeba.advanced.archiver_engine' => 'jpa', 'akeeba.advanced.proc_engine' => 'none', 'akeeba.advanced.embedded_installer' => 'none', 'engine.archiver.common.dereference_symlinks' => true, // hopefully no extension has symlinks inside its own directories... 'core.filters.srp.type' => $config['type'], 'core.filters.srp.group' => $config['group'], 'core.filters.srp.name' => $config['name'], 'core.filters.srp.customdirs' => $config['customdirs'], 'core.filters.srp.customfiles' => $config['customfiles'], 'core.filters.srp.extraprefixes' => $config['extraprefixes'], 'core.filters.srp.customtables' => $config['customtables'], 'core.filters.srp.skiptables' => $config['skiptables'], 'core.filters.srp.langfiles' => $config['langfiles'] ); // Parse a local file stored in (backend)/assets/srpdefs/$extname.xml JLoader::import('joomla.filesystem.file'); $filename = JPATH_COMPONENT_ADMINISTRATOR.'/assets/srpdefs/'.$extname.'.xml'; if(JFile::exists($filename)) { $xml = JFactory::getXMLParser('simple'); if($xml->loadFile($filename)) { $extraConfig = $this->parseRestorePointXML($xml->document); if($extraConfig !== false) $this->mergeSRPConfig($configOverrides, $extraConfig); } unset($xml); } // Parse the extension's manifest file and look for a <restorepoint> tag if(!empty($info['xmlfile'])) { $xml = JFactory::getXMLParser('simple'); if($xml->loadFile($info['xmlfile'])) { $restorepoint = $xml->document->getElementByPath('restorepoint'); if($restorepoint) { $extraConfig = $this->parseRestorePointXML($restorepoint); if($extraConfig !== false) $this->mergeSRPConfig($configOverrides, $extraConfig); } } unset($restorepoint); unset($xml); } // Create an SRP descriptor $srpdescriptor = array( 'type' => $config['type'], 'name' => $config['name'], 'group' => $config['group'], 'version' => $info['version'], 'date' => $info['date'] ); // Set the description and comment $description = "System Restore Point - ".JText::_($exttype).": $extname"; $comment = "---BEGIN SRP---\n".json_encode($srpdescriptor)."\n---END SRP---"; $jpskey = ''; $angiekey = ''; // Set a custom finalization action queue $configOverrides['volatile.core.finalization.action_handlers'] = array( new AEFinalizationSrpquotas() ); $configOverrides['volatile.core.finalization.action_queue'] = array( 'remove_temp_files', 'update_statistics', 'update_filesizes', 'apply_srp_quotas' ); // Apply the configuration overrides, please $platform = AEPlatform::getInstance(); $platform->configOverrides = $configOverrides; // Nuke the factory AEFactory::nuke(); $profile = 1; $session = JFactory::getSession(); $session->set('profile', $profile, 'akeeba'); AEPlatform::getInstance()->load_configuration($profile); AEUtilTempvars::reset('restorepoint'); $kettenrad = AECoreKettenrad::load('restorepoint'); $options = array( 'description' => $description, 'comment' => $comment, 'tag' => 'restorepoint' ); $kettenrad->setup($options); // Setting up the engine $kettenrad->tick(); if( ($kettenrad->getState() != 'running') && ($tag == 'restorepoint') ) { $kettenrad->tick(); } $kettenrad->resetWarnings(); // So as not to have duplicate warnings reports AECoreKettenrad::save($tag); $array = $kettenrad->getStatusArray(); if($array['Error'] != '') { // A backup error had occurred. Why are we here?! $this->status = self::STATUS_ERROR; $this->encapsulation = self::ENCAPSULATION_RAW; return 'A backup error had occurred: '.$array['Error']; } else { $statistics = AEFactory::getStatistics(); $array['BackupID'] = $statistics->getId(); $array['HasRun'] = 1; // Force the backup to go on. return $array; } } private function _apiStepBackup($config) { $defConfig = array( 'profile' => null, 'tag' => AKEEBA_BACKUP_ORIGIN ); $config = array_merge($defConfig, $config); extract($config); // Try to set the profile from the setup parameters if(!empty($profile)) { $registry = AEFactory::getConfiguration(); $session = JFactory::getSession(); $session->set('profile', $profile, 'akeeba'); } $kettenrad = AECoreKettenrad::load($tag); $registry = AEFactory::getConfiguration(); $session = JFactory::getSession(); $session->set('profile', $registry->activeProfile, 'akeeba'); $array = $kettenrad->tick(); $ret_array = $kettenrad->getStatusArray(); $array['Progress'] = $ret_array['Progress']; AECoreKettenrad::save($tag); if($array['Error'] != '') { // A backup error had occurred. Why are we here?! $this->status = self::STATUS_ERROR; $this->encapsulation = self::ENCAPSULATION_RAW; return 'A backup error had occurred: '.$array['Error']; } elseif($array['HasRun'] == false) { AEFactory::nuke(); AEUtilTempvars::reset(); } return $array; } private function _apiListBackups($config) { $defConfig = array( 'from' => 0, 'limit' => 50 ); $config = array_merge($defConfig, $config); extract($config); require_once JPATH_COMPONENT_ADMINISTRATOR.'/models/statistics.php'; $model = new AkeebaModelStatistics(); $model->setState('limitstart', $from); $model->setState('limit', $limit); return $model->getStatisticsListWithMeta(false); } private function _apiGetBackupInfo($config) { $defConfig = array( 'backup_id' => '0' ); $config = array_merge($defConfig, $config); extract($config); // Get the basic statistics $record = AEPlatform::getInstance()->get_statistics($backup_id); // Get a list of filenames $backup_stats = AEPlatform::getInstance()->get_statistics($backup_id); // Backup record doesn't exist if(empty($backup_stats)) { $this->status = self::STATUS_NOT_FOUND; $this->encapsulation = self::ENCAPSULATION_RAW; return 'Invalid backup record identifier'; } $filenames = AEUtilStatistics::get_all_filenames($record); if(empty($filenames)) { // Archives are not stored on the server or no files produced $record['filenames'] = array(); } else { $filedata = array(); $i = 0; // Get file sizes per part foreach($filenames as $file) { $i++; $size = @filesize($file); $size = is_numeric($size) ? $size : 0; $filedata[] = array( 'part' => $i, 'name' => basename($file), 'size' => $size ); } // Add the file info to $record['filenames'] $record['filenames'] = $filedata; } return $record; } private function _apiDownload($config) { $defConfig = array( 'backup_id' => 0, 'part_id' => 1, 'segment' => 1, 'chunk_size' => 1 ); $config = array_merge($defConfig, $config); extract($config); $backup_stats = AEPlatform::getInstance()->get_statistics($backup_id); if(empty($backup_stats)) { // Backup record doesn't exist $this->status = self::STATUS_NOT_FOUND; $this->encapsulation = self::ENCAPSULATION_RAW; return 'Invalid backup record identifier'; } $files = AEUtilStatistics::get_all_filenames($backup_stats); if( (count($files) < $part_id) || ($part_id <= 0) ) { // Invalid part $this->status = self::STATUS_NOT_FOUND; $this->encapsulation = self::ENCAPSULATION_RAW; return 'Invalid backup part'; } $file = $files[$part_id-1]; $filesize = @filesize($file); $seekPos = $chunk_size * 1048756 * ($segment - 1); if($seekPos > $filesize) { // Trying to seek past end of file $this->status = self::STATUS_NOT_FOUND; $this->encapsulation = self::ENCAPSULATION_RAW; return 'Invalid segment'; } $fp = fopen($file, 'rb'); if($fp === false) { // Could not read file $this->status = self::STATUS_ERROR; $this->encapsulation = self::ENCAPSULATION_RAW; return 'Error reading backup archive'; } rewind($fp); if(fseek($fp, $seekPos, SEEK_SET) === -1) { // Could not seek to position $this->status = self::STATUS_ERROR; $this->encapsulation = self::ENCAPSULATION_RAW; return 'Error reading specified segment'; } $buffer = fread($fp, 1048756); if($buffer === false) { // Could not read $this->status = self::STATUS_ERROR; $this->encapsulation = self::ENCAPSULATION_RAW; return 'Error reading specified segment'; } fclose($fp); switch($this->encapsulation) { case self::ENCAPSULATION_RAW: return base64_encode($buffer); break; case self::ENCAPSULATION_AESCTR128: $this->encapsulation = self::ENCAPSULATION_AESCBC128; return $buffer; break; case self::ENCAPSULATION_AESCTR256: $this->encapsulation = self::ENCAPSULATION_AESCBC256; return $buffer; break; default: // On encrypted comms the encryption will take care of transport encoding return $buffer; break; } } private function _apiDelete($config) { $defConfig = array( 'backup_id' => 0 ); $config = array_merge($defConfig, $config); extract($config); require_once JPATH_COMPONENT_ADMINISTRATOR.'/models/statistics.php'; $model = new AkeebaModelStatistics(); $model->setState('id', (int)$backup_id); $result = $model->delete(); if(!$result) { $this->status = self::STATUS_ERROR; $this->encapsulation = self::ENCAPSULATION_RAW; return $model->getError(); } else { return true; } } private function _apiDeleteFiles($config) { $defConfig = array( 'backup_id' => 0 ); $config = array_merge($defConfig, $config); extract($config); require_once JPATH_COMPONENT_ADMINISTRATOR.'/models/statistics.php'; $model = new AkeebaModelStatistics(); $model->setState('id', (int)$backup_id); $result = $model->deleteFile(); if(!$result) { $this->status = self::STATUS_ERROR; $this->encapsulation = self::ENCAPSULATION_RAW; return $model->getError(); } else { return true; } } private function _apiGetLog($config) { $defConfig = array( 'tag' => 'remote' ); $config = array_merge($defConfig, $config); extract($config); $filename = AEUtilLogger::logName($tag); $buffer = file_get_contents($filename); switch($this->encapsulation) { case self::ENCAPSULATION_RAW: return base64_encode($buffer); break; case self::ENCAPSULATION_AESCTR128: $this->encapsulation = self::ENCAPSULATION_AESCBC128; return $buffer; break; case self::ENCAPSULATION_AESCTR256: $this->encapsulation = self::ENCAPSULATION_AESCBC256; return $buffer; break; default: // On encrypted comms the encryption will take care of transport encoding return $buffer; break; } } private function _apiDownloadDirect($config) { $defConfig = array( 'backup_id' => 0, 'part_id' => 1 ); $config = array_merge($defConfig, $config); extract($config); $backup_stats = AEPlatform::getInstance()->get_statistics($backup_id); if(empty($backup_stats)) { // Backup record doesn't exist $this->status = self::STATUS_NOT_FOUND; $this->encapsulation = self::ENCAPSULATION_RAW; @ob_end_clean(); header('HTTP/1.1 500 Invalid backup record identifier'); flush(); JFactory::getApplication()->close(); } $files = AEUtilStatistics::get_all_filenames($backup_stats); if( (count($files) < $part_id) || ($part_id <= 0) ) { // Invalid part $this->status = self::STATUS_NOT_FOUND; $this->encapsulation = self::ENCAPSULATION_RAW; @ob_end_clean(); header('HTTP/1.1 500 Invalid backup part'); flush(); JFactory::getApplication()->close(); } $filename = $files[$part_id-1]; @clearstatcache(); // For a certain unmentionable browser -- Thank you, Nooku, for the tip if(function_exists('ini_get') && function_exists('ini_set')) { if(ini_get('zlib.output_compression')) { ini_set('zlib.output_compression', 'Off'); } } // Remove php's time limit -- Thank you, Nooku, for the tip if(function_exists('ini_get') && function_exists('set_time_limit')) { if(!ini_get('safe_mode') ) { @set_time_limit(0); } } $basename = @basename($filename); $filesize = @filesize($filename); $extension = strtolower(str_replace(".", "", strrchr($filename, "."))); while (@ob_end_clean()); @clearstatcache(); // Send MIME headers header('MIME-Version: 1.0'); header('Content-Disposition: attachment; filename="'.$basename.'"'); header('Content-Transfer-Encoding: binary'); header('Accept-Ranges: bytes'); switch($extension) { case 'zip': // ZIP MIME type header('Content-Type: application/zip'); break; default: // Generic binary data MIME type header('Content-Type: application/octet-stream'); break; } // Notify of filesize, if this info is available if($filesize > 0) header('Content-Length: '.@filesize($filename)); // Disable caching header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); header("Expires: 0"); header('Pragma: no-cache'); flush(); if($filesize > 0) { // If the filesize is reported, use 1M chunks for echoing the data to the browser $blocksize = 1048756; //1M chunks $handle = @fopen($filename, "r"); // Now we need to loop through the file and echo out chunks of file data if($handle !== false) while(!@feof($handle)){ echo @fread($handle, $blocksize); @ob_flush(); flush(); } if($handle !== false) @fclose($handle); } else { // If the filesize is not reported, hope that readfile works @readfile($filename); } flush(); JFactory::getApplication()->close(); } private function _apiUpdateGetInformation($config) { $defConfig = array( 'force' => 0 ); $config = array_merge($defConfig, $config); extract($config); require_once JPATH_ROOT.'/administrator/components/com_akeeba/liveupdate/liveupdate.php'; $updateInformation = LiveUpdate::getUpdateInformation($force); return (object)$updateInformation; } private function _apiUpdateDownload($config) { require_once JPATH_ROOT.'/administrator/components/com_akeeba/liveupdate/liveupdate.php'; require_once JPATH_ROOT.'/administrator/components/com_akeeba/liveupdate/classes/model.php'; // Do we need to update? $updateInformation = LiveUpdate::getUpdateInformation(); if(!$updateInformation->hasUpdates) { return (object)array( 'download' => 0 ); } $model = new LiveupdateModel(); $ret = $model->download(); $session = JFactory::getSession(); $target = $session->get('target', '', 'liveupdate'); $tempdir = $session->get('tempdir', '', 'liveupdate'); // Save the target and tempdir $session = JFactory::getSession(); $session->set('profile', 1, 'akeeba'); AEPlatform::getInstance()->load_configuration(1); $config = AEFactory::getConfiguration(); $config->set('remoteupdate.target', $target); $config->set('remoteupdate.tempdir', $tempdir); AEPlatform::getInstance()->save_configuration(1); if(!$ret) { // An error ocurred :( $this->status = self::STATUS_ERROR; $this->encapsulation = self::ENCAPSULATION_RAW; return "Could not download the update package"; } else { return (object)array( 'download' => 1 ); } } private function _apiUpdateExtract($config) { $session = JFactory::getSession(); $session->set('profile', 1, 'akeeba'); AEPlatform::getInstance()->load_configuration(1); $config = AEFactory::getConfiguration(); $target = $config->get('remoteupdate.target', ''); $tempdir = $config->get('remoteupdate.tempdir', ''); $session = JFactory::getSession(); $session->set('target', $target, 'liveupdate'); $session->set('tempdir', $tempdir, 'liveupdate'); require_once JPATH_ROOT.'/administrator/components/com_akeeba/liveupdate/liveupdate.php'; require_once JPATH_ROOT.'/administrator/components/com_akeeba/liveupdate/classes/model.php'; $model = new LiveupdateModel(); $ret = $model->extract(); JLoader::import('joomla.filesystem.file'); JFile::delete($target); if(!$ret) { // An error ocurred :( $this->status = self::STATUS_ERROR; $this->encapsulation = self::ENCAPSULATION_RAW; return "Could not extract the update package"; } else { return (object)array( 'extract' => 1 ); } } private function _apiUpdateInstall($config) { $session = JFactory::getSession(); $session->set('profile', 1, 'akeeba'); AEPlatform::getInstance()->load_configuration(1); $config = AEFactory::getConfiguration(); $target = $config->get('remoteupdate.target', ''); $tempdir = $config->get('remoteupdate.tempdir', ''); $session = JFactory::getSession(); $session->set('tempdir', $tempdir, 'liveupdate'); require_once JPATH_ROOT.'/administrator/components/com_akeeba/liveupdate/liveupdate.php'; require_once JPATH_ROOT.'/administrator/components/com_akeeba/liveupdate/classes/model.php'; $model = new LiveupdateModel(); $ret = $model->install(); if(!$ret) { // An error ocurred :( $this->status = self::STATUS_ERROR; $this->encapsulation = self::ENCAPSULATION_RAW; return "Could not install the update package"; } else { return (object)array( 'install' => 1 ); } } private function _apiUpdateCleanup($config) { $session = JFactory::getSession(); $session->set('profile', 1, 'akeeba'); AEPlatform::getInstance()->load_configuration(1); $config = AEFactory::getConfiguration(); $target = $config->get('remoteupdate.target', ''); $tempdir = $config->get('remoteupdate.tempdir', ''); $session = JFactory::getSession(); $session->set('target', $target, 'liveupdate'); $session->set('tempdir', $tempdir, 'liveupdate'); require_once JPATH_ROOT.'/administrator/components/com_akeeba/liveupdate/liveupdate.php'; require_once JPATH_ROOT.'/administrator/components/com_akeeba/liveupdate/classes/model.php'; $model = new LiveupdateModel(); $ret = $model->cleanup(); JLoader::import('joomla.filesystem.file'); JFile::delete($target); $config->set('remoteupdate.target', null); $config->set('remoteupdate.tempdir', null); AEPlatform::getInstance()->save_configuration(1); return (object)array( 'cleanup' => 1 ); } /** * Encodes a variable to JSON using PEAR's Services_JSON * @param mixed $value The value to encode * @param int $options Encoding preferences flags * @return string The JSON-encoded string */ private function json_encode($value, $options = 0) { $flags = SERVICES_JSON_LOOSE_TYPE; if( $options & JSON_FORCE_OBJECT ) $flags = 0; $encoder = new Akeeba_Services_JSON($flags); return $encoder->encode($value); } /** * Decodes a JSON string to a variable using PEAR's Services_JSON * @param string $value The JSON-encoded string * @param bool $assoc True to return an associative array instead of an object * @return mixed The decoded variable */ private function json_decode($value, $assoc = false) { $flags = 0; if($assoc) $flags = SERVICES_JSON_LOOSE_TYPE; $decoder = new Akeeba_Services_JSON($flags); return $decoder->decode($value); } private function parseRestorePointXML($xml) { if(!count($xml->children())) return false; $ret = array(); // 1. Group name -- core.filters.srp.group $group = $xml->getElementByPath('group'); if($group) { $ret['core.filters.srp.group'] = $group->data(); } // 2. Custom dirs -- core.filters.srp.customdirs $customdirs = $xml->getElementByPath('customdirs'); if($customdirs) { $stack = array(); if(count($customdirs->children())) { $children = $customdirs->children(); foreach($children as $child) { if($child->name() == 'dir') { $stack[] = $child->data(); } } } if(!empty($stack)) $ret['core.filters.srp.customdirs'] = $stack; } // 3. Extra prefixes -- core.filters.srp.extraprefixes $extraprefixes = $xml->getElementByPath('extraprefixes'); if($extraprefixes) { $stack = array(); if(count($extraprefixes->children())) { $children = $extraprefixes->children(); foreach($children as $child) { if($child->name() == 'prefix') { $stack[] = $child->data(); } } } if(!empty($stack)) $ret['core.filters.srp.extraprefixes'] = $stack; } // 4. Custom tables -- core.filters.srp.customtables $customtables = $xml->getElementByPath('customtables'); if($customtables) { $stack = array(); if(count($customtables->children())) { $children = $customtables->children(); foreach($children as $child) { if($child->name() == 'table') { $stack[] = $child->data(); } } } if(!empty($stack)) $ret['core.filters.srp.customtables'] = $stack; } // 5. Skip tables -- core.filters.srp.skiptables $skiptables = $xml->getElementByPath('skiptables'); if($skiptables) { $stack = array(); if(count($skiptables->children())) { $children = $skiptables->children(); foreach($children as $child) { if($child->name() == 'table') { $stack[] = $child->data(); } } } if(!empty($stack)) $ret['core.filters.srp.skiptables'] = $stack; } // 6. Language files -- core.filters.srp.langfiles $langfiles = $xml->getElementByPath('langfiles'); if($langfiles) { $stack = array(); if(count($langfiles->children())) { $children = $langfiles->children(); foreach($children as $child) { if($child->name() == 'lang') { $stack[] = $child->data(); } } } if(!empty($stack)) $ret['core.filters.srp.langfiles'] = $stack; } // 7. Custom files -- core.filters.srp.customfiles $customfiles = $xml->getElementByPath('customfiles'); if($customfiles) { $stack = array(); if(count($customfiles->children())) { $children = $customfiles->children(); foreach($children as $child) { if($child->name() == 'file') { $stack[] = $child->data(); } } } if(!empty($stack)) $ret['core.filters.srp.customfiles'] = $stack; } if(empty($ret)) return false; return $ret; } private function mergeSRPConfig(&$config, $extraConfig) { foreach($config as $key => $value) { if(array_key_exists($key, $extraConfig)) { if(is_array($value) && is_array($extraConfig[$key])) { $config[$key] = array_merge($extraConfig[$key], $value); } } } } }