<?php /** * @package RSForm! Pro * @copyright (C) 2007-2019 www.rsjoomla.com * @license GPL, http://www.gnu.org/copyleft/gpl.html */ defined('_JEXEC') or die; use Joomla\CMS\Factory; use Joomla\CMS\Filesystem\Folder; use Joomla\CMS\Uri\Uri; use Joomla\CMS\HTML\HTMLHelper; require_once __DIR__.'/helper.php'; require_once __DIR__.'/xml.php'; require_once __DIR__.'/tar.php'; class RSFormProBackup { // Database instance protected $db; // Path to the Joomla! temporary folder protected $tmp; // Path to the backup protected $path; // Path to metadata file protected $metadata; // Holds an array of form IDs. protected $formIds; // Holds an array of forms. protected $forms; // True to export submissions as well. protected $submissions; // This is the MD5 key that's used to identify the backup. protected $key; // set the desired name for the archive protected $name; public function __construct($options = array()) { $this->db = Factory::getDbo(); $this->tmp = isset($options['tmp']) ? $options['tmp'] : Factory::getApplication()->get('tmp_path'); $this->formIds = isset($options['forms']) ? $options['forms'] : array(); $this->submissions = isset($options['submissions']) ? $options['submissions'] : 0; $this->key = isset($options['key']) ? $options['key'] : null; $this->name = isset($options['name']) ? $options['name'] : null; // Check if the temporary folder is writable. if (!is_writable($this->tmp)) { throw new Exception(sprintf('The temporary folder "%s" is not writable!', $this->tmp)); } // Generate a path where we will store the backup contents. $this->path = $this->tmp.'/rsform_backup_'.$this->getKey(); // Let's create our folder if it doesn't exist. if (!is_dir($this->path) && !Folder::create($this->path)) { throw new Exception(sprintf('Could not create temporary path "%s"!', $this->path)); } // Check if the newly created path (or supplied one) is writable. if (!is_writable($this->path)) { throw new Exception(sprintf('Path "%s" is not writable!', $this->path)); } } // Store metadata.xml public function storeMetaData() { // Load forms from the database $db = &$this->db; $query = $db->getQuery(true); $query->select('*') ->from($db->qn('#__rsform_forms')) ->where($db->qn('FormId').' IN ('.RSFormProBackupHelper::qi($this->formIds).')'); $db->setQuery($query); $this->forms = $db->loadObjectList('FormId'); // Count the number of submissions as well, if requested. if ($this->submissions) { $query->clear() ->select('COUNT('.$db->qn('SubmissionId').') AS '.$db->qn('count')) ->select($db->qn('FormId')) ->from($db->qn('#__rsform_submissions')) ->where($db->qn('FormId').' IN ('.RSFormProBackupHelper::qi($this->formIds).')') ->group($db->qn('FormId')); $db->setQuery($query); if ($submissions = $db->loadObjectList()) { foreach ($submissions as $submission) { if (isset($this->forms[$submission->FormId])) { $this->forms[$submission->FormId]->SubmissionsCount = $submission->count; } } } } // Initialize XML writer. $xml = new RSFormProBackupXML; $xml->addHeader() ->add('rsform') // Software environment ->add('version', (string) new RSFormProVersion) ->add('cms', JVERSION) ->add('php', phpversion()) ->add('os', PHP_OS) // Website information ->add('url', Factory::getApplication()->isClient('cli') ? 'cli' : Uri::root()) ->add('root', JPATH_ROOT) ->add('author', Factory::getUser()->get('email')) ->add('date', Factory::getDate()->toSql()); // Start adding form information if ($this->forms) { $xml->add('forms'); foreach ($this->forms as $form) { $xml->add('form') ->add('id', RSFormProBackupHelper::getHash($form->FormId)) ->add('name', $form->FormName) ->add('title', $form->FormTitle) ->add('submissions', !empty($form->SubmissionsCount) ? $form->SubmissionsCount : 0) ->add('/form'); } $xml->add('/forms'); } // Finishup $xml->add('/rsform'); $archive = new RSFormProTar($this->getPath()); $buffer = (string) $xml; $size = strlen($buffer); $archive->addHeader($size, 'metadata.xml'); $archive->add($buffer); $archive->addPadding($size); $archive->close(); } // Store form structure public function storeForms($symfonyStyle = false) { require_once __DIR__.'/form.php'; foreach ($this->formIds as $form) { $part = new RSFormProBackupForm(array( 'path' => $this->getPath(), 'form' => $form )); $part->store(); if ($symfonyStyle && is_callable($symfonyStyle, 'progressAdvance')) { $symfonyStyle->progressAdvance(); } } } // Store submissions public function storeSubmissions($start = 0, $limit = 100, $header = 0) { require_once __DIR__.'/submissions.php'; $backupSubmission = new RSFormProBackupSubmissions(array( 'path' => $this->getPath(), 'form' => reset($this->formIds), 'start' => $start, 'limit' => $limit, 'header' => $header )); return $backupSubmission->store(); } public function clean() { $tar = $this->getPath(); if (file_exists($tar)) { @unlink($tar); } } // Download backup contents. public function download($clean = true) { $tar = $this->getPath(); $gzip = substr($tar, 0, -3).'tgz'; // If there's a .TAR archive, we no longer need it, remove it. if ($clean) { $this->clean(); } if (!file_exists($gzip)) { throw new Exception(sprintf('File %s does not exist!', $gzip)); } if (!is_readable($gzip)) { throw new Exception(sprintf('File %s is not readable!', $gzip)); } if (!is_null($this->name)) { $name = $this->prepareName($this->name); } else { $name = 'backup'; } RSFormProHelper::readFile($gzip, $name.'.tgz', false); unlink($gzip); if (is_dir($this->path)) { Folder::delete($this->path); } exit(); } public function getPath() { return $this->path.'/backup.tar'; } protected function prepareName($name) { $domain = Uri::getInstance()->getHost(); $date = HTMLHelper::_('date', 'now', 'Y-m-d_H-i'); return str_replace(array('{domain}', '{date}'), array($domain, $date), $name); } public function getKey() { if (empty($this->key)) { $this->key = md5(mt_rand() . uniqid('rsform_backup', true)); } return $this->key; } }