export_dir = $dataDir.'/data/_exports'; $this->temp_dir = $dataDir.'/data/_temp'; // @set_time_limit(90); // @ini_set('memory_limit','64M'); $this->Init(); $this->SetExported(); } public function Init(){ global $langmessage; //pages, configuration and addons $this->export_fields['pca']['name'] = 'pca'; $this->export_fields['pca']['label'] = $langmessage['Pages'].', '.$langmessage['configuration'].', '.$langmessage['add-ons']; $this->export_fields['pca']['index'] = $this->bit_pages | $this->bit_config | $this->bit_addons; $this->export_fields['media']['name'] = 'media'; $this->export_fields['media']['label'] = $langmessage['uploaded_files']; $this->export_fields['media']['index'] = $this->bit_media; $this->export_fields['themes']['name'] = 'themes'; $this->export_fields['themes']['label'] = $langmessage['themes']; $this->export_fields['themes']['index'] = $this->bit_themes; $this->export_fields['trash']['name'] = 'trash'; $this->export_fields['trash']['label'] = $langmessage['trash']; $this->export_fields['trash']['index'] = $this->bit_trash; $this->min_import_bits = $this->bit_pages | $this->bit_config | $this->bit_addons; //supported compression types $this->avail_compress = \gp\tool\Archive::Available(); } public function RunScript(){ global $langmessage; $cmd = \gp\tool::GetCommand(); if( empty($this->avail_compress) ){ $cmd = ''; } switch($cmd){ case 'do_export': $this->DoExport(); $this->SetExported(); break; case 'delete': $this->DeleteConfirmed(); $this->SetExported(); break; case 'revert_confirmed': case 'revert': if( $this->Revert($cmd) ){ return; } break; case 'revert_clean': $this->RevertClean(); break; } echo '

'.$langmessage['Export'].'

'; echo $langmessage['Export About']; if( empty($this->avail_compress) ){ echo '

'; echo 'None of PHP\'s archive extensions are enabled. '; echo 'Please enable PharData or ZipArchive in your PHP installation'; echo '

'; }else{ echo $this->iframe; $this->ExportForm(); } echo '
'; $this->Exported(); } /** * * */ protected function Warning(){ } /** * Create an archive of the selected folders * */ public function DoExport(){ global $dataDir, $langmessage, $config; //get list of directories to include $add_dirs = array(); if( isset($_POST['pca']) ){ $add_dirs[] = $dataDir.'/data/_pages'; $add_dirs[] = $dataDir.'/data/_extra'; $add_dirs[] = $dataDir.'/data/_site'; $add_dirs[] = $dataDir.'/data/_menus'; $add_dirs[] = $dataDir.'/data/_addoncode'; $add_dirs[] = $dataDir.'/data/_addondata'; $add_dirs[] = $dataDir.'/addons'; } if( isset($_POST['media']) ){ $add_dirs[] = $dataDir.'/data/_uploaded'; $add_dirs[] = $dataDir.'/data/_resized'; } if( isset($_POST['themes']) ){ $add_dirs[] = $dataDir.'/data/_themes'; $add_dirs[] = $dataDir.'/themes'; } if( isset($_POST['trash']) ){ $add_dirs[] = $dataDir.'/data/_trash'; } //create binary string to identify which areas were exported $which_exported = 0; foreach($this->export_fields as $export_field){ $name = $export_field['name']; if( isset($_POST[$name]) ){ $which_exported += $export_field['index']; } } if( $which_exported === 0 ){ message($langmessage['OOPS'].'(1)'); return false; } $success = $this->Create_Tar($which_exported,$add_dirs); //iframe for download if( $success ){ $this->iframe = ''; } return true; } /** * Create a tar archive of the folders in $add_dirs * */ public function Create_Tar($which_exported,$add_dirs){ global $dataDir, $langmessage; $compression =& $_POST['compression']; if( !$this->NewFile($which_exported,$compression) ){ return false; } try{ $tar_object = new \gp\tool\Archive($this->archive_path); foreach($add_dirs as $dir){ $localname = '/gpexport'.substr($dir, strlen($dataDir)); $tar_object->Add($dir,$localname); } //add ini file $this->Export_Ini($tar_object,$which_exported); $tar_object->compress(); }catch( \Exception $e){ message($langmessage['OOPS'].' (Archive couldn\'t be created)'); return false; } return true; } /** * Generate the name and path of the archive * */ public function NewFile($which_exported,$extension){ global $langmessage; if( !\gp\tool\Files::CheckDir($this->export_dir) ){ message($langmessage['OOPS'].'(Export Dir)'); return false; } $this->archive_name = time().'_'.$which_exported.'_'.rand(1000,9000).'.'.$extension; $this->archive_path = $this->export_dir.'/'.$this->archive_name; return true; } public function Export_Ini($tar_object, $which_exported){ global $dirPrefix, $dataDir; $content = array(); $content[] = 'Export_Version = '.gpversion; $content[] = 'Export_Which = '.$which_exported; $content[] = 'Export_Time = '.time(); $content[] = 'Export_Prefix = '.$dirPrefix; $content[] = 'Export_Root = '.$dataDir; $content[] = $this->GetUsers($which_exported); $content = implode("\n",$content); $tar_object->addFromString('/gpexport/Export.ini',$content); } /** * Add a list of registered users to the export ini file if the export includes pages, config, addons * */ public function GetUsers($which_exported){ if( ($this->min_import_bits & $which_exported) != $this->min_import_bits ){ return; } $users = \gp\tool\Files::Get('_site/users'); $user_array = array_keys($users); return 'Export_Users = '.implode(',',$user_array); } /* * Revert * * * */ public function Revert($cmd){ global $langmessage, $dataDir, $gpAdmin; if( !$this->RevertFilesystem() ){ return false; } $archive =& $_REQUEST['archive']; if( !$this->ArchiveToObject($archive) ){ return false; } $this->import_info = $this->ExtractIni(); if( $this->import_info === false ){ message($langmessage['OOPS'].' (No import info)'); return false; } if( !$this->CanRevert($this->import_info['Export_Which']) ){ message($langmessage['OOPS'].' (Not Compatible)'); return false; } echo '

'.$langmessage['Revert'].'

'; if( !$this->FileSystem->ConnectOrPrompt('Admin/Port') ){ return true; } //confirmed if( ($cmd == 'revert_confirmed') && isset($_POST['cmd']) ){ $successful = $this->RevertConfirmed(); $this->RevertFinished($successful); return true; } echo '

'; $info = $this->FileInfo($archive); $file_count = $this->import_object->count(); echo sprintf($langmessage['archive_contains'],$info['time'],number_format($file_count)); echo '

'; echo '

'; echo $langmessage['revert_notice']; echo '

'; if( version_compare(gpversion,$this->import_info['Export_Version'],'!=') ){ echo '

'; echo sprintf($langmessage['revert_ver_notice'],gpversion,$this->import_info['Export_Version']); echo '

'; } echo '
'; echo ''; echo ''; echo ''; echo ''; echo '
'; return true; } /** * Transfer files from the archive to the active directories * */ public function RevertConfirmed(){ global $langmessage, $dataDir; //extract to temp location $temp_file = $dataDir.\gp\tool\FileSystem::TempFile('/data/_temp/revert'); $temp_name = basename($temp_file); $replace_dirs = array(); try{ $this->import_object->extractTo($temp_file); }catch( \Exception $e){ message($langmessage['OOPS'].' (Archive couldn\'t be extracted)'); return false; } if( $this->import_info['Export_Which'] & $this->bit_themes ){ $replace_dirs['themes'] = false; } if( $this->import_info['Export_Which'] & $this->bit_addons ){ $replace_dirs['addons'] = false; } if( ($this->import_info['Export_Which'] & $this->bit_pages) || ($this->import_info['Export_Which'] & $this->bit_media) ){ $replace_dirs['data'] = true; } foreach($replace_dirs as $dir => $merge){ if( !$this->AddReplaceDir($dir,$temp_name, $merge) ){ return false; } } $replaced = $this->FileSystem->ReplaceDirs( $this->replace_dirs, $this->extra_dirs ); if( $replaced !== true ){ message($langmessage['revert_failed'].$replaced); return false; } $this->TransferSession(); return true; } /** * Add themes, addons or data directories to the replace_dirs list only if they're not empty * */ public function AddReplaceDir($dir, $temp_name, $merge = false){ global $dataDir, $langmessage; $rel_path = '/data/_temp/'.$temp_name.'/gpexport/'.$dir; $full_path = $dataDir.$rel_path; if( !file_exists($full_path) ){ return true; } $files = scandir($full_path); if( count($files) === 0 ){ return true; } // move to location outside of existing /data directory // otherwise ReplaceDirs() will fail when we try to replace the data directory $new_relative = \gp\tool\FileSystem::TempFile( '/themes' ); if( !$this->FileSystem->RelRename($rel_path, $new_relative) ){ message($langmessage['revert_failed'].' (AddReplaceDir Failed)'); return false; } // copy other folders from /data so we don't lose sessions, uploaded content etc if( $merge ){ $source = $dataDir.'/data/'; $new_full = $dataDir.$new_relative; $this->CopyDir( $source, $new_full ); } $this->replace_dirs[$dir] = $new_relative; return true; } /** * Make sure the current user stays logged in after a revert is completed * */ public function TransferSession(){ global $gpAdmin; //unlock if( isset($_COOKIE[gp_session_cookie]) ){ $session_id = $_COOKIE[gp_session_cookie]; \gp\tool\Session::Unlock($session_id); } $username = $gpAdmin['username']; // get user info $users = \gp\tool\Files::Get('_site/users'); $userinfo =& $users[$username]; $session_id = \gp\tool\Session::create($userinfo, $username, $sessions); if( !$session_id ){ return; } //set the cookie for the new data $config = \gp\tool\Files::Get('_site/config'); $session_cookie = 'gpEasy_'.substr(sha1($config['gpuniq']),12,12); \gp\tool\Session::cookie($session_cookie,$session_id); //set the update gpuniq value for the post_nonce $GLOBALS['config']['gpuniq'] = $config['gpuniq']; } public function RevertFinished($successful){ global $langmessage,$dataDir; if( $successful ){ echo '

'; echo $langmessage['Revert_Finished']; echo '

'; } echo '

'; echo $langmessage['old_folders_created']; echo '

'; echo '
'; echo ''; echo ''; echo ''; echo '
'; return true; } public function RevertClean(){ global $langmessage, $dataDir; if( !isset($_POST['old_folder']) || !is_array($_POST['old_folder']) ){ return true; } if( !$this->RevertFilesystem() ){ return false; } if( !$this->FileSystem->connect() ){ return false; } $this->FileSystem->CleanUpFolders($_POST['old_folder'], $not_deleted); return true; } /** * Prepare FileSystem for writing to $dataDir * $dataDir writability is required so that we can create & rename subfolders: $dataDir/data, $dataDir/themes * */ public function RevertFilesystem(){ global $dataDir, $langmessage; $this->FileSystem = \gp\tool\FileSystem::init($dataDir); if( is_null($this->FileSystem) ){ message($langmessage['OOPS'] .' (No filesystem)'); return false; } return true; } public function CopyDir( $source, $dest ){ global $dataDir, $langmessage; $data_files = \gp\tool\Files::ReadDir($source,false); foreach($data_files as $file){ if( $file == '.' || $file == '..' ){ continue; } $source_full = $source.'/'.$file; $dest_full = $dest.'/'.$file; if( file_exists($dest_full) ){ continue; } if( is_dir($source_full) ){ if( !$this->CopyDir( $source_full, $dest_full ) ){ return false; } continue; } $contents = file_get_contents($source_full); if( !\gp\tool\Files::Save($dest_full,$contents) ){ message($langmessage['OOPS'].' Session file not copied (0)'); return false; } } return true; } /** * Fix the target of a symbolic link if it points to a location within the installation * * @param string $link The target path * @return string The fixed path * */ public function FixLink($link){ global $dataDir; //adjust the link target? if( !isset($this->import_info['Export_Root']) ){ return $link; } $export_root = $this->import_info['Export_Root']; if( $export_root == $dataDir ){ return $link; } if( strpos($link,$export_root) === 0 ){ $len = strlen($export_root); return substr_replace($link,$dataDir,0,$len); } return $link; } public function GetImportContents($string){ return $this->import_object->extractInString($string); } /** * Get an archive object * */ public function ArchiveToObject($archive){ global $langmessage; if( empty($archive) || !isset($this->exported[$archive]) ){ message($langmessage['OOPS'].' (Invalid Archive)'); return false; } $full_path = $this->export_dir.'/'.$archive; if( !file_exists($full_path) ){ message($langmessage['OOPS'].' (Archive non-existant)'); return false; } try{ $this->import_object = new \gp\tool\Archive($full_path); }catch( \Exception $e){ message($langmessage['OOPS'].' (Archive couldn\'t be opened)'); return false; } return true; } /** * Get the export.ini contents * */ public function ExtractIni(){ $ini_contents = $this->import_object->getFromName('/gpexport/Export.ini'); if( empty($ini_contents) ){ return false; } return \gp\tool\Ini::ParseString($ini_contents); } public function SetExported(){ $this->exported = \gp\tool\Files::ReadDir($this->export_dir,$this->all_extenstions); arsort($this->exported); } public function DeleteConfirmed(){ global $langmessage; $file =& $_POST['file']; if( !isset($this->exported[$file]) ){ message($langmessage['OOPS']); return; } $full_path = $this->export_dir.'/'.$file; unlink($full_path); unset($this->exported[$file]); } public function FileInfo($file){ global $langmessage; $file = str_replace('_','.',$file); $temp = explode('.',$file); if( count($temp) < 3 ){ return ''; } $info = array(); $info['ext'] = array_pop($temp); $info['bits'] = ''; if( count($temp) >= 3 && is_numeric($temp[0]) && is_numeric($temp[1]) ){ list($time,$exported) = $temp; $info['time'] = \gp\tool::date($langmessage['strftime_datetime'],$time); $info['bits'] = $exported; foreach($this->export_fields as $export_field){ $index = $export_field['index']; if( ($exported & $index) == $index ){ $info['exported'][] = $export_field['label']; } } if( empty($info['exported']) ){ $info['exported'][] = 'Unknown'; } }else{ $info['time'] = $file; $info['exported'][] = 'Unknown'; } return $info; } public function Exported(){ global $langmessage; if( count($this->exported) == 0 ){ return; } echo ''; echo ''; $total_size = 0; $total_count = 0; foreach($this->exported as $file){ $info = $this->FileInfo($file); if( !$info ){ continue; } $full_path = $this->export_dir.'/'.$file; echo ''; $total_count++; $total_size+= $size; } //totals echo ''; echo '
'; echo $langmessage['Previous Exports']; echo '   '; echo $langmessage['File Size']; echo ''; echo $langmessage['options']; echo '
'; echo str_replace(' ',' ',$info['time']); echo ''; echo implode(', ',$info['exported']); echo ''; $size = filesize($full_path); echo \gp\admin\Tools::FormatBytes($size); echo ' '; echo $info['ext']; echo ''; echo ''.$langmessage['Download'].''; echo '  '; if( $this->CanRevert($info['bits']) ){ echo \gp\tool::Link('Admin/Port',$langmessage['Revert'],'cmd=revert&archive='.rawurlencode($file),'',$file); }else{ echo $langmessage['Revert']; } echo '  '; echo \gp\tool::Link('Admin/Port',$langmessage['delete'],'cmd=delete&file='.rawurlencode($file),array('data-cmd'=>'postlink','title'=>$langmessage['delete_confirm'],'class'=>'gpconfirm'),$file); echo '
'; echo $langmessage['Total']; echo ': '; echo $total_count; echo ' '; echo \gp\admin\Tools::FormatBytes($total_size); echo ' 
'; } /** * Determine if the package can be used in the revert process * Either must have bit_pages, bit_config and bit_addons or none of the three * */ public function CanRevert($bits){ if( ($this->min_import_bits & $bits) == $this->min_import_bits ){ return true; } if( ($this->bit_pages & $bits) || ($this->bit_config & $bits) || ($this->bit_addons & $bits) ){ return false; } return true; } public function ExportForm(){ global $langmessage; echo '
'; echo '

'; foreach($this->export_fields as $info){ $this->Checkbox_Export($info['name'],$info['label']); echo '   '; } echo '

'; echo '

'; echo ''; echo $langmessage['Compression'].': '; echo ' '; echo '   '; echo '

'; echo '
'; } public function Checkbox_Export($name,$label){ $checked = false; $class = ''; if( !isset($_POST['cmd']) || ($_POST['cmd'] !== 'do_export') ){ $checked = true; $class = ' checked'; }elseif( isset($_POST[$name]) ){ $checked = true; $class = ' checked'; } echo ''; } }