Invision Power Services, Inc. * @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc. * @license http://www.invisionpower.com/legal/standards/ * @package IPS Social Suite * @since 28 Jul 2015 * @version SVN_VERSION_NUMBER */ namespace IPS\core\modules\admin\system; /* To prevent PHP errors (extending class does not exist) revealing path */ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) { header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' ); exit; } /** * upgrade */ class _upgrade extends \IPS\Dispatcher\Controller { /** * Manage * * @return void */ protected function manage() { \IPS\Dispatcher::i()->checkAcpPermission( 'upgrade_manage' ); if ( \IPS\NO_WRITES ) { \IPS\Output::i()->error( 'no_writes', '1C287/1', 403, '' ); } $wizard = new \IPS\Helpers\Wizard( array( 'upgrade_confirm_update' => array( $this, '_selectVersion' ), 'upgrade_login' => array( $this, '_login' ), 'upgrade_extract_update' => array( $this, '_extractUpdate' ), 'upgrade_upgrade' => array( $this, '_upgrade' ), ), \IPS\Http\Url::internal( 'app=core&module=system&controller=upgrade' ) ); \IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('ips_suite_upgrade'); \IPS\Output::i()->output = $wizard; } /** * Select Version * * @param array $data Wizard data * @return string|array */ public function _selectVersion( $data ) { /* Check latest version */ $versions = array(); foreach ( \IPS\Db::i()->select( '*', 'core_applications', \IPS\Db::i()->in( 'app_directory', \IPS\Application::$ipsApps ) ) as $app ) { if ( $app['app_enabled'] ) { $versions[] = $app['app_long_version']; } } $version = min( $versions ); $url = \IPS\Http\Url::ips('updateCheck'); if ( \IPS\USE_DEVELOPMENT_BUILDS ) { $url = $url->setQueryString( 'development', 1 ); } try { $response = $url->setQueryString( 'version', $version )->request()->get()->decodeJson(); $coreApp = \IPS\Application::load('core'); $coreApp->update_version = json_encode( $response ); $coreApp->update_last_check = time(); $coreApp->save(); } catch ( \Exception $e ) { } /* Build form */ $form = new \IPS\Helpers\Form( 'select_version' ); $options = array(); $descriptions = array(); $latestVersion = 0; foreach( \IPS\Application::load( 'core' )->availableUpgrade() as $possibleVersion ) { $options[ $possibleVersion['longversion'] ] = $possibleVersion['version']; $descriptions[ $possibleVersion['longversion'] ] = $possibleVersion; if ( $latestVersion < $possibleVersion['longversion'] ) { $latestVersion = $possibleVersion['longversion']; } } $form->add( new \IPS\Helpers\Form\Radio( 'version', $latestVersion, TRUE, array( 'options' => $options, '_details' => $descriptions ) ) ); /* Handle submissions */ if ( $values = $form->values() ) { return array( 'version' => $values['version'] ); } /* Display */ return $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'system' ) ), 'upgradeSelectVersion' ) ); } /** * Login * * @param array $data Wizard data * @return string|array */ public function _login( $data ) { /* Build form */ $form = new \IPS\Helpers\Form( 'login', 'continue' ); $form->hiddenValues['version'] = $data['version']; $form->add( new \IPS\Helpers\Form\Email( 'ips_email_address', NULL ) ); $form->add( new \IPS\Helpers\Form\Password( 'ips_password', NULL ) ); /* Handle submissions */ if ( $values = $form->values() ) { $key = \IPS\IPS::licenseKey(); $url = \IPS\Http\Url::ips( 'build/' . $key['key'] )->setQueryString( 'ip', \IPS\Request::i()->ipAddress() ); if ( \IPS\USE_DEVELOPMENT_BUILDS ) { $url = $url->setQueryString( 'development', 1 ); } elseif ( isset( $values['version'] ) ) { $url = $url->setQueryString( 'versionToDownload', $values['version'] ); } if ( \IPS\CP_DIRECTORY !== 'admin' ) { $url = $url->setQueryString( 'cp_directory', \IPS\CP_DIRECTORY ); } try { $response = $url->request( 30 )->login( $values['ips_email_address'], $values['ips_password'] )->get(); switch ( $response->httpResponseCode ) { case 200: if ( !preg_match( '/^ips_[a-z0-9]{5}$/', (string) $response ) ) { \IPS\Log::i( LOG_ERR )->write( (string) $response ); $form->error = \IPS\Member::loggedIn()->language()->addToStack('download_upgrade_error'); break; } else { $data['key'] = (string) $response; return $data; } case 304: if ( \IPS\Db::i()->select( 'MIN(app_long_version)', 'core_applications', \IPS\Db::i()->in( 'app_directory', \IPS\Application::$ipsApps ) )->first() < \IPS\Application::getAvailableVersion('core') ) { $data['key'] = NULL; return $data; } $form->error = \IPS\Member::loggedIn()->language()->addToStack('download_upgrade_nothing'); break; default: $form->error = (string) $response; } } catch ( \Exception $exception ) { \IPS\Log::i( LOG_ERR )->write( get_class( $exception ) . "\n" . $exception->getCode() . ": " . $exception->getMessage() . "\n" . $exception->getTraceAsString() ); $form->error = \IPS\Member::loggedIn()->language()->addToStack('download_upgrade_error'); } } return (string) $form; } /** * Extract Update * * @param array $data Wizard data * @return string|array */ public function _extractUpdate( $data ) { /* Download & Extract */ if ( $data['key'] and !isset( \IPS\Request::i()->check ) ) { /* Muliple Redirector */ return (string) new \IPS\Helpers\MultipleRedirect( \IPS\Http\Url::internal('app=core&module=system&controller=upgrade'), function( $mrData ) use ( $data ) { /* Init */ if ( !is_array( $mrData ) ) { return array( array( 'status' => 'download' ), \IPS\Member::loggedIn()->language()->addToStack('delta_upgrade_downloading'), 0 ); } /* Download */ elseif ( $mrData['status'] == 'download' ) { if ( !isset( $mrData['tmpFileName'] ) ) { $mrData['tmpFileName'] = tempnam( \IPS\TEMP_DIRECTORY, 'IPS' ) . '.zip'; return array( $mrData, \IPS\Member::loggedIn()->language()->addToStack('delta_upgrade_downloading'), 0 ); } else { if ( !isset( $mrData['range'] ) ) { $mrData['range'] = 0; } $startRange = $mrData['range']; $endRange = $startRange + 1000000 - 1; $response = \IPS\Http\Url::ips("download/{$data['key']}")->request( 30 )->setHeaders( array( 'Range' => "bytes={$startRange}-{$endRange}" ) )->get(); try { \IPS\Log::i( LOG_ERR )->setIpAddress( $_SERVER['REMOTE_ADDR'] )->write( "Fetching download [range={$startRange}-{$endRange}] with a response code: " . $response->httpResponseCode, 'auto_upgrade' ); } catch( \Exception $ex ) { } if ( $response->httpResponseCode == 404 ) { if ( isset( $mrData['tmpFileName'] ) ) { @unlink( $mrData['tmpFileName'] ); } return array( \IPS\Theme::i()->getTemplate('system')->upgradeDeltaFailed( TRUE, isset( $data['key'] ) ? \IPS\Http\Url::ips("download/{$data['key']}") : NULL ) ); } elseif ( $response->httpResponseCode == 206 ) { $totalFileSize = intval( mb_substr( $response->httpHeaders['Content-Range'], mb_strpos( $response->httpHeaders['Content-Range'], '/' ) + 1 ) ); $fh = \fopen( $mrData['tmpFileName'], 'a' ); \fwrite( $fh, (string) $response ); \fclose( $fh ); $mrData['range'] = $endRange + 1; return array( $mrData, \IPS\Member::loggedIn()->language()->addToStack('delta_upgrade_downloading'), 100 / $totalFileSize * $mrData['range'] ); } else { $mrData['status'] = 'extract'; return array( $mrData, \IPS\Member::loggedIn()->language()->addToStack('delta_upgrade_extracting'), 0 ); } } } /* Extract */ elseif ( $mrData['status'] == 'extract' ) { try { try { \IPS\Log::i( LOG_ERR )->setIpAddress( $_SERVER['REMOTE_ADDR'] )->write( "Attempting to extract", 'auto_upgrade' ); } catch( \Exception $ex ) { } /* Open the zip */ $zip = \IPS\Archive\Zip::fromLocalFile( $mrData['tmpFileName'], $data['key'] . '/' ); /* Extract some files */ $numberToDo = 20; if ( !isset( $mrData['extractNumber'] ) ) { $mrData['extractNumber'] = 0; } $offset = $mrData['extractNumber']; if ( $zip->extract( \IPS\ROOT_PATH, $numberToDo, $offset ) === TRUE ) { if ( isset( $mrData['tmpFileName'] ) ) { @unlink( $mrData['tmpFileName'] ); } return NULL; } else { $mrData['extractNumber'] += $numberToDo; $numberOfFiles = $zip->numberOfFiles(); try { \IPS\Log::i( LOG_ERR )->setIpAddress( $_SERVER['REMOTE_ADDR'] )->write( "Extracting files {$mrData['extractNumber']} / {$numberOfFiles}", 'auto_upgrade' ); } catch( \Exception $ex ) { } return array( $mrData, \IPS\Member::loggedIn()->language()->addToStack('delta_upgrade_extracting'), 100 / $numberOfFiles * $mrData['extractNumber'] ); } } catch ( \RuntimeException $e ) { try { \IPS\Log::i( LOG_ERR )->setIpAddress( $_SERVER['REMOTE_ADDR'] )->write( "Extract Failed", 'auto_upgrade' ); \IPS\Log::i( LOG_ERR )->setIpAddress( $_SERVER['REMOTE_ADDR'] )->write( $e, 'auto_upgrade' ); } catch( \Exception $ex ) { } \IPS\Session\Admin::i()->log( ( $e->getCode() === \IPS\Archive\Exception::COULD_NOT_OPEN ) ? 'delta_upgrade_zip_fail' : ( $e->getCode() === \IPS\Archive\Exception::COULD_NOT_WRITE ? 'delta_upgrade_write_fail' : '' ) ); if ( isset( $mrData['tmpFileName'] ) ) { @unlink( $mrData['tmpFileName'] ); } return array( \IPS\Theme::i()->getTemplate('system')->upgradeDeltaFailed( $e->getCode(), isset( $data['key'] ) ? \IPS\Http\Url::ips("download/{$data['key']}") : NULL ) ); } } }, function() { \IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=system&controller=upgrade&check=1') ); } ); } /* Run md5 check */ try { $files = \IPS\Application::md5Check(); if ( count( $files ) ) { return \IPS\Theme::i()->getTemplate('system')->upgradeDeltaFailed( $files, isset( $data['key'] ) ? \IPS\Http\Url::ips("download/{$data['key']}") : NULL ); } } catch ( \Exception $e ) {} /* Nope, we're good! */ return $data; } /** * Upgrade * * @param array $data Wizard data * @return string|array */ public function _upgrade( $data ) { \IPS\Output::i()->redirect( 'upgrade/?adsess=' . \IPS\Request::i()->adsess ); } }