ob_end_clean(); } ob_start(); header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); $cmd = $amp_conf['AMPBIN'] . '/restore.php --restore=' . $_SESSION['backup_restore_path'] . ' --items=' . base64_encode(serialize($restore)) . ' 2>&1'; //start running backup $run = popen($cmd, 'r'); while (($msg = fgets($run)) !== false) { //dbug('backup', $msg); //send results back to the user backup_log($msg); } pclose($run); //send messgae to browser that were done backup_log('END'); exit; break; default: $content = load_view(dirname(__FILE__) . '/views/restore/restore.php', $var); break; } $heading = _("Restore"); ?> <div class="container-fluid"> <h1><?php echo $heading; ?> </h1> <div class = "display full-border">
backup_log(_('Restore complete!')); backup_log(_('Reloading...')); do_reload(); // Trigger sysadmin to reload/regen any settings if available if (is_dir("/var/spool/asterisk/incron")) { $triggers = array('update-dns', 'config-postfix', 'update-ftp', 'fail2ban-generate', 'update-mdadm', 'update-ports', 'update-timezone', 'update-ups'); foreach ($triggers as $f) { $filename = "/var/spool/asterisk/incron/sysadmin.{$f}"; if (file_exists($filename)) { // Odd... @unlink($filename); } @fclose(@fopen($filename, "w")); } } backup_log(_('Done!')); exit; } exit; function show_opts() { $e[] = 'restore.php'; $e[] = ''; $e[] = 'options:'; $e[] = "\t--restore=/path/to/backup/file.tgz"; $e[] = "\t\tSpecify the path to the backup file you wish to restore."; $e[] = "\t--items=..."; $e[] = "\t\tThis is either a base64 encoded, serialized array, which is provided"; $e[] = "\t\tby the web interface, or, a comma separated list of any of the following:"; $e[] = "\t\t\tall\tRestore everything in the backup"; $e[] = "\t\t\t\tThis is the same as enabling all the following options";
//disables registered trunks core_trunks_disable('reg', true); } //apply configs if requested if ($b->b['applyconfigs'] == 'true') { do_reload(true); } if ($b->b['error'] !== false) { backup_log(_('Backup completed with errors!')); } else { backup_log(_('Backup successfully completed!')); } } } else { //invalid backup backup_log('backup id ' . $vars['id'] . ' not found!'); } if (is_object($b) && method_exists($b, 'emailCheck')) { if ($b->b['emailfailonly'] == 1 && $b->b['error'] === false) { //donothing } else { $b->emailCheck(); } } //if the opts option was passed, used for remote backup (warm spare) } elseif (isset($vars['opts']) && $vars['opts']) { //r = remote options if (!($r = unserialize(base64_decode($vars['opts'])))) { echo 'invalid opts'; exit(1); }
private function maintenance($type, $data, $handle = '') { if (!isset($this->b['delete_time']) && !isset($this->b['delete_amount'])) { return true; } $delete = $dir = $files = array(); //get file list switch ($type) { case 'local': $dir = scandir(backup__($data['path']) . '/' . $this->b['_dirname']); break; case 'ftp': $ftplist = $handle->findFilesystems(new Directory($data)); $dir = array(); foreach ($ftplist as $ftpitem) { $dir[] = $ftpitem->getRealpath(); } break; case 'ssh': $cmd[] = fpbx_which('ssh'); $cmd[] = '-o StrictHostKeyChecking=no -i'; $cmd[] = $data['key']; $cmd[] = $data['user'] . '\\@' . $data['host']; $cmd[] = '-p ' . $data['port']; $cmd[] = 'ls -1 ' . $data['path'] . '/' . $this->b['_dirname']; exec(implode(' ', $cmd), $dir); unset($cmd); break; case 'awss3': $contents = $handle->getBucket($data['bucket']); foreach ($contents as $file) { $dir[] = $file['name']; } break; } $dir = is_array($dir) ? $dir : array(); //sanitize file list foreach ($dir as $file) { //dont include the current backup or special items if (in_array($file, array('.', '..', $this->b['_file'])) || !preg_match("/\\d+-\\d+-\\d+(?:-[0-9.]+(?:alpha|beta|rc|RC)?(?:\\d+(?:\\.[^\\.]+)*))?-\\d+.tgz/", $file)) { continue; } $f = explode('-', $file); //remove file sufix $files[$f[2]] = $file; } //sort file list based on backup creation time ksort($files, SORT_NUMERIC); //create delete list based on creation time if (isset($this->b['delete_time']) && $this->b['delete_time']) { $cut_line = strtotime($this->b['delete_time'] . ' ' . $this->b['delete_time_type'] . ' ago'); foreach ($files as $epoch => $file) { if ($epoch < $cut_line) { $delete[$epoch] = $file; } } } //create delete list based on quantity of files if (isset($this->b['delete_amount']) && $this->b['delete_amount']) { for ($i = 0; $i < $this->b['delete_amount']; $i++) { array_pop($files); } $delete = array_merge($files, $delete); } //now delete the actual files foreach ($delete as $key => $file) { switch ($type) { case 'local': unlink(backup__($data['path']) . '/' . $this->b['_dirname'] . '/' . $file); unset($delete[$key]); break; case 'ftp': $f = $handle->findFileByName($file); try { $handle->delete($f); } catch (\Exception $e) { $this->b['error'] = sprintf(_("Error deleting %s"), $file); backup_log($this->b['error']); } unset($delete[$key]); break; case 'awss3': $handle->deleteObject($data['bucket'], baseName($file)); break; case 'ssh': $cmd[] = fpbx_which('ssh'); $cmd[] = '-o StrictHostKeyChecking=no -i'; $cmd[] = $data['key']; $cmd[] = $data['user'] . '\\@' . $data['host']; $cmd[] = '-p ' . $data['port']; $cmd[] = 'rm ' . $data['path'] . '/' . '/' . $this->b['_dirname'] . '/' . $file; exec(implode(' ', $cmd)); unset($delete[$key]); unset($cmd); break; } } }
/** * make sure backup file is local, download it and make it local if necessary */ function backup_restore_locate_file($id, $path) { global $amp_conf; $path = trim($path, '/'); $path = str_replace(array('..', ':'), '', trim($path, '/')); $path = escapeshellcmd($path); $s = backup_get_server($id); if (!$s) { return array('error_msg' => _('Backup Server not found!')); } //dest is where we gona put backup files pulled infrom other servers $dest = $amp_conf['ASTSPOOLDIR'] . '/tmp/' . 'backuptmp-s' . $id . '-' . time() . '-' . basename($path); switch ($s['type']) { case 'local': $s['path'] = backup__($s['path']); $path = $s['path'] . '/' . $path; break; case 'ftp': //subsitute variables if nesesary $s['host'] = backup__($s['host']); $s['port'] = backup__($s['port']); $s['user'] = backup__($s['user']); $s['password'] = backup__($s['password']); $s['path'] = backup__($s['path']); $path = ltrim($path, '/'); $connection = new Connection($s['host'], $s['user'], $s['password'], $s['port'], 90, $s['transfer'] == 'passive'); try { $connection->open(); } catch (\Exception $e) { $this->b['error'] = $e->getMessage(); backup_log($this->b['error']); return; } $wrapper = new FTPWrapper($connection); $permFactory = new PermissionsFactory(); $ftptype = $wrapper->systype(); if (strtolower($ftptype) == "unix") { $fsFactory = new FilesystemFactory($permFactory); } else { $fsFactory = new WindowsFilesystemFactory(); } $manager = new FTPFilesystemManager($wrapper, $fsFactory); $dlVoter = new DownloaderVoter(); $dlVoter->addDefaultFTPDownloaders($wrapper); $ulVoter = new UploaderVoter(); $ulVoter->addDefaultFTPUploaders($wrapper); $crVoter = new CreatorVoter(); $crVoter->addDefaultFTPCreators($wrapper, $manager); $deVoter = new DeleterVoter(); $deVoter->addDefaultFTPDeleters($wrapper, $manager); $ftp = new FTP($manager, $dlVoter, $ulVoter, $crVoter, $deVoter); if (!$ftp) { $this->b['error'] = _("Error creating the FTP object"); } $ftpdirs = $ftp->findFilesystems(new \Touki\FTP\Model\Directory($s['path'])); $file = null; foreach ($ftpdirs as $thisdir) { if ($ftp->fileExists(new \Touki\FTP\Model\File($thisdir->getRealPath() . '/' . $path))) { $file = $ftp->findFileByName($thisdir->getRealPath() . '/' . $path); } } try { $options = array(FTP::NON_BLOCKING => false, FTP::TRANSFER_MODE => FTP_BINARY); $ftp->download($dest, $file, $options); $path = $dest; } catch (\Exception $e) { return array('error_msg' => _('Failed to retrieve file from server!')); } break; case 'ssh': $s['path'] = backup__($s['path']); $s['user'] = backup__($s['user']); $s['host'] = backup__($s['host']); $cmd[] = fpbx_which('scp'); $cmd[] = '-o StrictHostKeyChecking=no -i'; $cmd[] = $s['key']; $cmd[] = '-P ' . $s['port']; $cmd[] = $s['user'] . '\\@' . $s['host'] . ':' . $s['path'] . '/' . $path; $cmd[] = $dest; exec(implode(' ', $cmd), $foo, $ret); unset($cmd); if ($ret === 0) { $path = $dest; } else { return array('error_msg' => _('Failed to retrieve file from server!')); } break; case 'awss3': $s['bucket'] = backup__($s['bucket']); $s['awsaccesskey'] = backup__($s['awsaccesskey']); $s['awssecret'] = backup__($s['awssecret']); $awss3 = new S3($s['awsaccesskey'], $s['awssecret']); dbug('S3 Path: ' . $path); dbug('S3 Dest: ' . $dest); if ($awss3->getObject($s['bucket'], $path, $dest) !== false) { $path = $dest; } else { return array('error_msg' => _('Failed to retrieve file from server!')); } break; } if (file_exists($path)) { return $path; } else { return array('error_msg' => _('File not found! ' . $path)); } }
function store_backup() { foreach ($this->b['storage_servers'] as $s) { $s = $this->s[$s]; switch ($s['type']) { case 'local': $path = backup__($s['path']) . '/' . $this->b['_dirname']; //ensure directory structure if (!is_dir($path)) { mkdir($path, 0755, true); } //would rather use the native copy() here, but by defualt //php doesnt support files > 2GB //see here for a posible solution: //http://ca3.php.net/manual/en/function.fopen.php#37791 $cmd[] = fpbx_which('cp'); $cmd[] = $this->b['_tmpfile']; $cmd[] = $path . '/' . $this->b['_file'] . '.tgz'; exec(implode(' ', $cmd), $error, $status); unset($cmd, $error); if ($status !== 0) { $this->b['error'] = 'Error copying ' . $this->b['_tmpfile'] . ' to ' . $path . '/' . $this->b['_file'] . '.tgz: ' . $error; backup_log($this->b['error']); } //run maintenance on the directory $this->maintenance($s['type'], $s); break; case 'email': //TODO: set agent to something informative, including fpbx & backup versions $email_options = array('useragent' => 'freepbx', 'protocol' => 'mail'); $email = new \CI_Email(); $from = $this->amp_conf['AMPBACKUPEMAILFROM'] ? $this->amp_conf['AMPBACKUPEMAILFROM'] : '*****@*****.**'; $msg[] = _('Name') . ': ' . $this->b['name']; $msg[] = _('Created') . ': ' . date('r', $this->b['_ctime']); $msg[] = _('Files') . ': ' . $this->manifest['file_count']; $msg[] = _('Mysql Db\'s') . ': ' . $this->manifest['mysql_count']; $msg[] = _('astDb\'s') . ': ' . $this->manifest['astdb_count']; $email->from($from); $email->to(backup__($s['addr'])); $email->subject(_('Backup') . ' ' . $this->b['name']); $body = implode("\n", $msg); // If the backup file is more than 25MB, yell $encodedsize = ceil(filesize($this->b['_tmpfile']) / 3) * 4; if ($encodedsize > 26214400) { $email->subject(_('Backup ERROR (exceeded SMTP limits)') . ' ' . $this->b['name']); $email->message(_('BACKUP NOT ATTACHED') . "\n" . _('The backup file exceeded the maximum SMTP limits of 25MB. It was not attempted to be sent. Please shrink your backup, or use a different method of transferring your backup.') . "\n{$body}\n"); } elseif ($encodedsize > $s['maxsize']) { $email->subject(_('Backup ERROR (exceeded soft limit)') . ' ' . $this->b['name']); $email->message(_('BACKUP NOT ATTACHED') . "\n" . _('The backup file exceeded the soft limit set in SMTP configuration (%s bytes). It was not attempted to be sent. Please shrink your backup, or use a different method of transferring your backup.') . "\n{$body}\n"); } else { $email->message($body); $email->attach($this->b['_tmpfile']); } $email->send(); unset($msg); break; case 'ftp': //subsitute variables if nesesary $s['host'] = backup__($s['host']); $s['port'] = backup__($s['port']); $s['user'] = backup__($s['user']); $s['password'] = backup__($s['password']); $s['path'] = backup__($s['path']); $ftp = @ftp_connect($s['host'], $s['port']); if ($ftp === false) { $this->b['error'] = _("Error connecting to the FTP Server... Check your host name or DNS"); backup_log($this->b['error']); return $ftp; } if (ftp_login($ftp, $s['user'], $s['password'])) { //chose pasive/active transfer mode ftp_pasv($ftp, $s['transfer'] == 'passive'); //switch to directory. If we fail, build directory structure and try again if (!@ftp_chdir($ftp, $s['path'] . '/' . $this->b['_dirname'])) { //ensure directory structure @ftp_mkdir($ftp, $s['path']); @ftp_mkdir($ftp, $s['path'] . '/' . $this->b['_dirname']); ftp_chdir($ftp, $s['path'] . '/' . $this->b['_dirname']); } //copy file ftp_put($ftp, $this->b['_file'] . '.tgz', $this->b['_tmpfile'], FTP_BINARY); //run maintenance on the directory $this->maintenance($s['type'], $s, $ftp); //release handel ftp_close($ftp); } else { $this->b['error'] = _("Error connecting to the FTP Server..."); backup_log($this->b['error']); } break; case 'awss3': //subsitute variables if nesesary $s['bucket'] = backup__($s['bucket']); $s['awsaccesskey'] = backup__($s['awsaccesskey']); $s['awssecret'] = backup__($s['awssecret']); $awss3 = new \S3($s['awsaccesskey'], $s['awssecret']); // Does this bucket already exist? $buckets = $awss3->listBuckets(); if (!in_array($s['bucket'], $buckets)) { // Create the bucket $awss3->putBucket($s['bucket'], \S3::ACL_PUBLIC_READ); } //copy file if ($awss3->putObjectFile($this->b['_tmpfile'], $s['bucket'], $this->b['name'] . "/" . $this->b['_file'] . '.tgz', \S3::ACL_PUBLIC_READ)) { dbug('S3 successfully uploaded your backup file.'); } else { dbug('S3 failed to accept your backup file'); } //run maintenance on the directory $this->maintenance($s['type'], $s, $awss3); break; case 'ssh': //subsitute variables if nesesary $s['path'] = backup__($s['path']); $s['user'] = backup__($s['user']); $s['host'] = backup__($s['host']); $destdir = $s['path'] . '/' . $this->b['_dirname']; //ensure directory structure $cmd = fpbx_which('ssh') . ' -o StrictHostKeyChecking=no -i '; $cmd .= $s['key'] . " -l " . $s['user'] . ' ' . $s['host'] . ' -p ' . $s['port']; $cmd .= " 'mkdir -p {$destdir}'"; exec($cmd, $output, $ret); if ($ret !== 0) { backup_log("SSH Error ({$ret}) - Received " . json_encode($output) . " from {$cmd}"); } $output = null; //put file // Note that SCP (*unlike SSH*) needs IPv6 addresses in ['s. Consistancy is awesome. if (filter_var($s['host'], \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) { $scphost = "[" . $s['host'] . "]"; } else { $scphost = $s['host']; } $cmd = fpbx_which('scp') . ' -o StrictHostKeyChecking=no -i ' . $s['key'] . ' -P ' . $s['port']; $cmd .= " " . $this->b['_tmpfile'] . " " . $s['user'] . "@{$scphost}:{$destdir}"; exec($cmd, $output, $ret); if ($ret !== 0) { backup_log("SCP Error ({$ret}) - Received " . json_encode($output) . " from {$cmd}"); } //run maintenance on the directory $this->maintenance($s['type'], $s); break; } } }