strlen($p_file_list[$i]))
&& (substr($v_header['filename'], 0, strlen($p_file_list[$i]))
== $p_file_list[$i])) {
$v_extract_file = true;
break;
}
}
// ----- It is a file, so compare the file names
elseif ($p_file_list[$i] == $v_header['filename']) {
$v_extract_file = true;
break;
}
}
} else {
$v_extract_file = true;
}
// ----- Look if this file need to be extracted
if (($v_extract_file) && (!$v_listing))
{
if (($p_remove_path != '')
&& (substr($v_header['filename'], 0, $p_remove_path_size)
== $p_remove_path))
$v_header['filename'] = substr($v_header['filename'],
$p_remove_path_size);
if (($p_path != './') && ($p_path != '/')) {
while (substr($p_path, -1) == '/')
$p_path = substr($p_path, 0, strlen($p_path)-1);
if (substr($v_header['filename'], 0, 1) == '/')
$v_header['filename'] = $p_path.$v_header['filename'];
else
$v_header['filename'] = $p_path.'/'.$v_header['filename'];
}
if (file_exists($v_header['filename'])) {
if ( (@is_dir($v_header['filename']))
&& ($v_header['typeflag'] == '')) {
$this->_error('File '.$v_header['filename']
.' already exists as a directory');
return false;
}
if ( ($this->_isArchive($v_header['filename']))
&& ($v_header['typeflag'] == "5")) {
$this->_error('Directory '.$v_header['filename']
.' already exists as a file');
return false;
}
if (!is_writeable($v_header['filename'])) {
//We cannot use $globals['ofc'] here and after restoring the files we are anyways changing the file's permissions according to the perms file. Therefore, using 0644/0755 directly here shouldn't be an issue.
if(!empty($can_write)){
if(is_dir($v_header['filename'])){
$chmod = chmod($v_header['filename'], 0755);
}else{
$chmod = chmod($v_header['filename'], 0644);
}
//The is_writable function always returns false for non-suphp servers and we are passing the FTP stream path which gives us writable permission
if (!is_writeable($v_header['filename'])) {
$this->_error('File '.$v_header['filename']
.' already exists and is write protected');
return false;
}
}else{
if(is_dir($v_header['filename'])){
$chmod = @chmod($v_header['filename'], $globals['odc']);
}else{
$chmod = @chmod($v_header['filename'], $globals['ofc']);
}
}
}
if (filemtime($v_header['filename']) > $v_header['mtime']) {
// To be completed : An error or silent no replace ?
}
}
// ----- Check the directory availability and create it if necessary
elseif (($v_result
= $this->_dirCheck(($v_header['typeflag'] == "5"
?$v_header['filename']
:dirname($v_header['filename'])))) != 1) {
$this->_error('Unable to create path for '.$v_header['filename']);
return false;
}
if ($v_extract_file) {
if ($v_header['typeflag'] == "5") {
if (!@file_exists($v_header['filename'])) {
if (!@mkdir($v_header['filename'], 0777)) {
$this->_error('Unable to create directory {'
.$v_header['filename'].'}');
return false;
}
}
} elseif ($v_header['typeflag'] == "2") {
if (@file_exists($v_header['filename'])) {
@unlink($v_header['filename']);
}
// Symlinks will be created by us using softperms.txt
/*if (!@symlink($v_header['link'], $v_header['filename'])) {
$this->_error('Unable to extract symbolic link {'
.$v_header['filename'].'}');
return false;
}*/
} else {
if(empty($can_write) && preg_match('/^(ftp:\/\/)/is', $v_header['filename'])){
// Allows overwriting of existing files on the remote FTP server
$stream_options = array('ftp' => array('overwrite' => true));
// Creates a stream context resource with the defined options
$stream_context = stream_context_create($stream_options);
// Opens the file for writing and truncates it to zero length
$v_dest_file = fopen($v_header['filename'], "wb", 0, $stream_context);
}else{
$v_dest_file = fopen($v_header['filename'], "wb");
}
if ($v_dest_file == 0) {
$this->_error('Error while opening {'.$v_header['filename']
.'} in write binary mode');
return false;
} else {
$n = floor($v_header['size']/512);
for ($i=0; $i<$n; $i++) {
$v_content = $this->_readBlock();
fwrite($v_dest_file, $v_content, 512);
}
if (($v_header['size'] % 512) != 0) {
$v_content = $this->_readBlock();
fwrite($v_dest_file, $v_content, ($v_header['size'] % 512));
}
@fclose($v_dest_file);
if ($p_preserve) {
@chown($v_header['filename'], $v_header['uid']);
@chgrp($v_header['filename'], $v_header['gid']);
}
// ----- Change the file mode, mtime
@touch($v_header['filename'], $v_header['mtime']);
if ($v_header['mode'] & 0111) {
// make file executable, obey umask
$mode = fileperms($v_header['filename']) | (~umask() & 0111);
@chmod($v_header['filename'], $mode);
}
}
// ----- Check the file size
clearstatcache();
if (!is_file($v_header['filename'])) {
$this->_error('Extracted file '.$v_header['filename']
.'does not exist. Archive may be corrupted.');
return false;
}
$filesize = filesize($v_header['filename']);
if ($filesize != $v_header['size']) {
$this->_error('Extracted file '.$v_header['filename']
.' does not have the correct file size \''
.$filesize
.'\' ('.$v_header['size']
.' expected). Archive may be corrupted.');
return false;
}
}
} else {
$this->_jumpBlock(ceil(($v_header['size']/512)));
}
} else {
$this->_jumpBlock(ceil(($v_header['size']/512)));
}
if ($v_listing || $v_extract_file || $v_extraction_stopped) {
// ----- Log extracted files
if (($v_file_dir = dirname($v_header['filename']))
== $v_header['filename'])
$v_file_dir = '';
if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == ''))
$v_file_dir = '/';
// Only if we are to return the list i.e. in listContent() then we fill full $v_header else we just need the count
$p_list_detail[$v_nb++] = (!empty($v_listing) ? $v_header : '');
if (is_array($p_file_list) && (count($p_list_detail) == count($p_file_list))) {
return true;
}
}
// We can run the scripts for the end time already set
if(time() >= $GLOBALS['end']){
$GLOBALS['end_file'] = $last_file; // set end file so that we know where to start from
break;
}
}
return true;
}
// }}}
// {{{ _openAppend()
function _openAppend()
{
if (filesize($this->_tarname) == 0)
return $this->_openWrite();
if ($this->_compress) {
$this->_close();
if (!@rename($this->_tarname, $this->_tarname.".tmp")) {
$this->_error('Error while renaming \''.$this->_tarname
.'\' to temporary file \''.$this->_tarname
.'.tmp\'');
return false;
}
if ($this->_compress_type == 'gz')
$v_temp_tar = @gzopen($this->_tarname.".tmp", "rb");
elseif ($this->_compress_type == 'bz2')
$v_temp_tar = @bzopen($this->_tarname.".tmp", "r");
if ($v_temp_tar == 0) {
$this->_error('Unable to open file \''.$this->_tarname
.'.tmp\' in binary read mode');
@rename($this->_tarname.".tmp", $this->_tarname);
return false;
}
if (!$this->_openWrite()) {
@rename($this->_tarname.".tmp", $this->_tarname);
return false;
}
if ($this->_compress_type == 'gz') {
$end_blocks = 0;
while (!@gzeof($v_temp_tar)) {
$v_buffer = @gzread($v_temp_tar, 512);
if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
$end_blocks++;
// do not copy end blocks, we will re-make them
// after appending
continue;
} elseif ($end_blocks > 0) {
for ($i = 0; $i < $end_blocks; $i++) {
$this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
}
$end_blocks = 0;
}
$v_binary_data = pack("a512", $v_buffer);
$this->_writeBlock($v_binary_data);
}
@gzclose($v_temp_tar);
}
elseif ($this->_compress_type == 'bz2') {
$end_blocks = 0;
while (strlen($v_buffer = @bzread($v_temp_tar, 512)) > 0) {
if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
$end_blocks++;
// do not copy end blocks, we will re-make them
// after appending
continue;
} elseif ($end_blocks > 0) {
for ($i = 0; $i < $end_blocks; $i++) {
$this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
}
$end_blocks = 0;
}
$v_binary_data = pack("a512", $v_buffer);
$this->_writeBlock($v_binary_data);
}
@bzclose($v_temp_tar);
}
if (!@unlink($this->_tarname.".tmp")) {
$this->_error('Error while deleting temporary file \''
.$this->_tarname.'.tmp\'');
}
} else {
// ----- For not compressed tar, just add files before the last
// one or two 512 bytes block
if (!$this->_openReadWrite())
return false;
clearstatcache();
$v_size = filesize($this->_tarname);
// We might have zero, one or two end blocks.
// The standard is two, but we should try to handle
// other cases.
fseek($this->_file, $v_size - 1024);
if (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
fseek($this->_file, $v_size - 1024);
}
elseif (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
fseek($this->_file, $v_size - 512);
}
}
return true;
}
// }}}
// {{{ _append()
function _append($p_filelist, $p_add_dir='', $p_remove_dir='')
{
if (!$this->_openAppend())
return false;
if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir))
$this->_writeFooter();
$this->_close();
return true;
}
// }}}
// {{{ _dirCheck()
function _dirCheck($p_dir)
{
clearstatcache();
if ((@is_dir($p_dir)) || ($p_dir == ''))
return true;
$p_parent_dir = dirname($p_dir);
if (($p_parent_dir != $p_dir) &&
($p_parent_dir != '') &&
(!$this->_dirCheck($p_parent_dir)))
return false;
if (!@mkdir($p_dir, 0777)) {
$this->_error("Unable to create directory '$p_dir'");
return false;
}
return true;
}
// }}}
// {{{ _pathReduction()
function _pathReduction($p_dir)
{
$v_result = '';
// ----- Look for not empty path
if ($p_dir != '') {
// ----- Explode path by directory names
$v_list = explode('/', $p_dir);
// ----- Study directories from last to first
for ($i=sizeof($v_list)-1; $i>=0; $i--) {
// ----- Look for current path
if ($v_list[$i] == ".") {
// ----- Ignore this directory
// Should be the first $i=0, but no check is done
}
else if ($v_list[$i] == "..") {
// ----- Ignore it and ignore the $i-1
$i--;
}
else if ( ($v_list[$i] == '')
&& ($i!=(sizeof($v_list)-1))
&& ($i!=0)) {
// ----- Ignore only the double '//' in path,
// but not the first and last /
} else {
$v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?'/'
.$v_result:'');
}
}
}
if (defined('OS_WINDOWS') && OS_WINDOWS) {
$v_result = strtr($v_result, '\\', '/');
}
return $v_result;
}
// }}}
// {{{ _translateWinPath()
function _translateWinPath($p_path, $p_remove_disk_letter=true)
{
if (defined('OS_WINDOWS') && OS_WINDOWS) {
// ----- Look for potential disk letter
if ( ($p_remove_disk_letter)
&& (($v_position = strpos($p_path, ':')) != false)) {
$p_path = substr($p_path, $v_position+1);
}
// ----- Change potential windows directory separator
if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) {
$p_path = strtr($p_path, '\\', '/');
}
}
return $p_path;
}
// }}}
}
function can_create_file(){
$file = dirname(__FILE__).'/soft.tmp';
$fp = @fopen($file, 'wb');
if($fp === FALSE){
return false;
}
if(@fwrite($fp, 'ampps') === FALSE){
return false;
}
@fclose($fp);
// Check if the file exists
if(file_exists($file)){
@unlink($file);
return true;
}
return false;
}
function download_archive($tarname){
global $globals, $can_write, $ftp;
$tar_archive = new softtar($tarname, '', true);
$res = $tar_archive->remote_archive_download_loop();
if(!$res){
return false;
}
return true;
}
function optGET($name, $default = ''){
global $error;
//Check the GETED NAME was GETed
if(isset($_GET[$name])){
return inputsec(htmlizer(trim($_GET[$name])));
}else{
return $default;
}
}
function inputsec($string){
//get_magic_quotes_gpc is depricated in php 7.4
if(version_compare(PHP_VERSION, '7.4', '<')){
if(!get_magic_quotes_gpc()){
$string = addslashes($string);
}else{
$string = stripslashes($string);
$string = addslashes($string);
}
}else{
$string = addslashes($string);
}
// This is to replace ` which can cause the command to be executed in exec()
$string = str_replace('`', '\`', $string);
return $string;
}
function htmlizer($string){
global $globals;
$string = htmlentities($string, ENT_QUOTES, 'UTF-8');
preg_match_all('/(&#(\d{1,7}|x[0-9a-fA-F]{1,6});)/', $string, $matches);//r_print($matches);
foreach($matches[1] as $mk => $mv){
$tmp_m = entity_check($matches[2][$mk]);
$string = str_replace($matches[1][$mk], $tmp_m, $string);
}
return $string;
}
function entity_check($string){
//Convert Hexadecimal to Decimal
$num = ((substr($string, 0, 1) === 'x') ? hexdec(substr($string, 1)) : (int) $string);
//Squares and Spaces - return nothing
$string = (($num > 0x10FFFF || ($num >= 0xD800 && $num <= 0xDFFF) || $num < 0x20) ? '' : ''.$num.';');
return $string;
}
function softdie($txt, $l_file = '', $l_readbytes = 0){
global $data, $can_write;
$array = array();
$array['settings'] = $GLOBALS['settings'];
$array['result'] = $txt;
$array['data'] = $GLOBALS['data'];
// Add last read bytes if the download is still pending
if(!empty($l_readbytes)){
$array['l_readbytes'] = $l_readbytes;
}
// AWS stuff
if(!empty($GLOBALS['awss3_part_no'])){
$array['awss3_part_no'] = $GLOBALS['awss3_part_no'];
}
// Was there an error ?
if(!empty($GLOBALS['error'])){
$array['local_tarname'] = $GLOBALS['local_tarname'];
$array['error'] = $GLOBALS['error'];
//Delete the temporarily downloaded archive if some error occur in the restore
unlink($GLOBALS['local_tarname']);
}
if($txt == 'DONE'){
$array['local_tarname'] = $GLOBALS['local_tarname'];
}
echo ''.base64_encode(serialize($array)).'';die();
}
function soft_stream_wrapper_register($protocol, $classname){
$protocols = array('dropbox', 'gdrive', 'softftpes', 'softsftp', 'webdav', 'softaws', 'onedrive');
if(!in_array($protocol, $protocols)){
return true;
}
@include_once('_'.$protocol.'.php');
if(!stream_wrapper_register($protocol, $classname)){
return false;
}
return true;
}
function soft_preg_replace($pattern, $file, &$var, $valuenum, $stripslashes = ''){
preg_match($pattern, $file, $matches);
if(empty($stripslashes)){
$var = @trim($matches[$valuenum]);
}else{
$var = @stripslashes(trim($matches[$valuenum]));
}
}
function r_print($array){
echo '';
print_r($array);
echo '
';
}
// Download a remote file to the local file
function ftp_download_file_loop($path, $localfile, $startpos = 0){
global $error;
$url = parse_url($path);
// By default the port is 21
if(empty($url['port'])){
$url['port'] = 21;
}
if(!function_exists('ftp_connect')){
$error[] = 'ftp_connect is disabled on your server. Please enable the function to continue.';
return false;
}
$ftp_conn = @ftp_connect($url['host'], $url['port'], 90);
if(!$ftp_conn){
$error[] = 'FTP connection not found';
return false;
}
$login_result = @ftp_login($ftp_conn, rawurldecode($url['user']), rawurldecode($url['pass']));
if(!$login_result){
$error[] = 'Please enter correct login details';
return false;
}
stream_wrapper_register('downloader', 'downloader');
$lfp = fopen('downloader://'.rawurlencode($localfile), 'ab');
$ret = ftp_fget($ftp_conn, $lfp, $url['path'], FTP_BINARY, $startpos);
fclose($lfp);
return $ret;
}
class downloader{
var $localfile = '';
function stream_open($path, $mode, $options, &$opened_path){
$url = parse_url($path);
$this->localfile = rawurldecode($url['host']);
return true;
}
function stream_write($data){
if(time() >= $GLOBALS['end']){
$GLOBALS['l_readbytes'] = filesize($this->localfile);
return false;
}
file_put_contents($this->localfile, $data, FILE_APPEND);
return strlen($data);
}
function stream_close(){
return true;
}
function stream_seek($offset, $whence) {
return true;
}
function stream_tell(){
return 0;
}
}
@unlink(__FILE__); // More has to be done here !
// The settings
$settings = unserialize(base64_decode('[[[settings]]]'));
$data = unserialize(base64_decode('[[[data]]]'));
global $globals, $theme, $softpanel, $iscripts, $catwise, $error, $can_write, $ftp;
$can_write = can_create_file(); // Check if we can write
if(!$can_write){
//Installation's ftp stream
$data['softpath'] = $settings['protocol'].'://'.rawurlencode(($settings['protocol'] == 'softsftp' && empty($settings['ftp_pass']) ? $settings['id'] : $settings['ftp_user'])).':'.rawurlencode($settings['ftp_pass']).'@'.$settings['softdomain'].(!empty($settings['port']) ? ':'.$settings['port'] : '').$settings['ftp_softpath'];
soft_stream_wrapper_register($settings['protocol'], $settings['protocol']);
$globals['odc'] = 0777;
$globals['ofc'] = 0666;
}
// Dont abort if user aborts
ignore_user_abort(true);
// We need to stop execution in 25 secs.. We will be called again if the process is incomplete
// Is custom keep alive time defained ?
if(!empty($settings['SOFTACULOUS_KEEP_ALIVE'])){
$keepalive = (int) $settings['SOFTACULOUS_KEEP_ALIVE'];
}
// Set default value
if(empty($keepalive)){
$keepalive = 25;
}
$GLOBALS['end'] = (int) time() + $keepalive;
$GLOBALS['init_readbytes'] = optGET('last_readbytes');
if(!empty($GLOBALS['init_readbytes'])){
$GLOBALS['init_readbytes'] = rawurldecode($GLOBALS['init_readbytes']);
}else{
$GLOBALS['init_readbytes'] = 0;
}
// AWS Stuff
$GLOBALS['awss3_part_no'] = (int) optGET('awss3_part_no');
if(empty($GLOBALS['awss3_part_no'])){
$GLOBALS['awss3_part_no'] = 1;
}
if(!empty($data['restore_dir']) || !empty($data['restore_db']) || !empty($data['restore_datadir']) || !empty($data['restore_wwwdir'])){
$GLOBALS['progress'] = 5;
if(!download_archive($data['backup_dir'].'/'.$data['fname'])){
$error[] = 'There was some error while downloading the archive!';
softdie('downloadeerror');
}
if($GLOBALS['l_readbytes'] > 0 && $GLOBALS['l_readbytes'] != $data['size']){
softdie('INCOMPLETE-'.$GLOBALS['progress'], '', $GLOBALS['l_readbytes']);
}
}
softdie('DONE');