%PDF- %PDF-
| Direktori : /home/lightco1/www/quoizel.com.au/plugins/system/jsnframework/libraries/joomlashine/data/ |
| Current File : /home/lightco1/www/quoizel.com.au/plugins/system/jsnframework/libraries/joomlashine/data/model.php |
<?php
/**
* @version $Id$
* @package JSN_Framework
* @author JoomlaShine Team <support@joomlashine.com>
* @copyright Copyright (C) 2012 JoomlaShine.com. All Rights Reserved.
* @license GNU/GPL v2 or later http://www.gnu.org/licenses/gpl-2.0.html
*
* Websites: http://www.joomlashine.com
* Technical Support: Feedback - http://www.joomlashine.com/contact-us/get-support.html
*/
// No direct access to this file
defined('_JEXEC') or die('Restricted access');
// Import necessary Joomla libraries
jimport('joomla.filesystem.file');
jimport('joomla.filesystem.folder');
jimport('joomla.installer.helper');
if (JSNVersion::isJoomlaCompatible('3.0'))
{
jimport('joomla.archive.archive');
}
else
{
jimport('joomla.filesystem.archive');
}
/**
* Model class of JSN Data library.
*
* To implement <b>JSNDataModel</b> class, create a model file in
* <b>administrator/components/com_YourComponentName/models</b> folder
* then put following code into that file:
*
* <code>class YourComponentPrefixModelData extends JSNDataModel
* {
* }</code>
*
* The <b>JSNDataModel</b> class pre-defines <b>backup</b>, <b>restore</b>
* and <b>installSample</b> method to handle data backup/restore and sample data
* installation task. So, you <b>DO NOT NEED</b> to re-define those methods in
* your model class.
*
* <b>JSNDataModel</b> class has following protected methods that you can
* overwrite in your model class to customize data backup/restore task:
*
* <ul>
* <li>beforeBackup(&$options, &$name)</li>
* <li>afterBackup(&$options, &$name)</li>
* <li>beforeRestore(&$backup)</li>
* <li>afterRestore(&$backup)</li>
* </ul>
*
* If you overwrite any of 4 methods above, remember to call parent method
* either before or after your customization in order to make JSN Data library
* working properly. See example below:
*
* <code>class YourComponentPrefixModelData extends JSNDataModel
* {
* protected function beforeBackup(&$options, &$name)
* {
* parent::beforeBackup(&$options, &$name);
*
* // Do some additional preparation...
* }
*
* protected function afterRestore(&$backup)
* {
* // Do some additional finalization...
*
* parent::afterRestore(&$backup);
* }
* }</code>
*
* @package JSN_Framework
* @since 1.0.0
*/
class JSNDataModel extends JSNBaseModel
{
/**
* Variable for holding backed up data.
*
* @var SimpleXMLElement
*/
protected $data;
/**
* Variable for holding backed up files.
*
* @var array
*/
protected $files;
/**
* Backup selected database tables and/or files.
*
* @param array $options Backup options.
*
* @return void
*/
public function backup($options = array())
{
// Get Joomla config and version object
$config = JFactory::getConfig();
$jVer = new JVersion;
// Initialize variables
$tag = isset($options['xmlRoot']) ? $options['xmlRoot'] : 'backup';
$com = preg_replace('/^com_/i', '', JFactory::getApplication()->input->getCmd('option'));
$info = JSNUtilsXml::loadManifestCache();
$name = (isset($options['name']) AND ! empty($options['name']))
? ($options['name'] . (@$options['timestamp'] ? '_' . date('YmdHis') : ''))
: date('YmdHis');
$name = array(
'zip' => "{$name}.zip",
'xml' => "jsn_{$com}_backup_db.xml"
);
// Preset XML object for holding backed up data
$this->data = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8" ?><' . $tag . '></' . $tag . '>');
$this->data->addAttribute('extension-name', 'JSN ' . preg_replace('/JSN\s*/i', '', JText::_($info->name)));
if ($const = JSNUtilsText::getConstant('EDITION'))
{
$this->data->addAttribute('extension-edition', $const);
}
$this->data->addAttribute('extension-version', $info->version);
$this->data->addAttribute('joomla-version', $jVer->getShortVersion());
// Do any preparation needed before doing real data backup
try
{
$this->beforeBackup($options, $name);
}
catch (Exception $e)
{
throw $e;
}
// Backup data from selected tables
$this->backupTables($options['tables']);
// Backup files from selected folders
$this->backupFiles($options['files']);
// Do any extra work needed after doing real data backup
try
{
$this->afterBackup($options, $name);
}
catch (Exception $e)
{
throw $e;
}
// Force client to download backup file
if (isset($this->zippedBackup))
{
if ( ! isset($options['no-download']) OR ! $options['no-download'])
{
JSNUtilsFile::forceDownload($name['zip'], $this->zippedBackup, 'application/zip', true);
}
else
{
// Store zipped backup to file system
JFile::write($config->get('tmp_path') . '/' . $name['zip'], $this->zippedBackup);
return $config->get('tmp_path') . '/' . $name['zip'];
}
}
throw new Exception(JText::_('JSN_EXTFW_DATA_BACKUP_FAIL'));
}
/**
* Do any preparation needed before doing real data backup.
*
* @param array &$options Backup options.
* @param array &$name array('zip' => 'zip_backup_file_name', 'xml' => 'xml_backup_file_name')
*
* @return void
*/
protected function beforeBackup(&$options, &$name)
{
// Preset variables
isset($options['tables']) OR $options['tables'] = array();
isset($options['files']) OR $options['files'] = array();
// Decode variables
$tables = array();
foreach ($options['tables'] AS $value)
{
$tables = array_merge($tables, json_decode(html_entity_decode($value, ENT_QUOTES, 'UTF-8')));
}
$options['tables'] = array_unique($tables);
$files = array();
foreach ($options['files'] AS $value)
{
$files = array_merge($files, (array) json_decode(html_entity_decode($value, ENT_QUOTES, 'UTF-8')));
}
$options['files'] = array_unique($files, SORT_REGULAR);
}
/**
* Backup data from selected database tables.
*
* @param array $tables Array of table to dump data from.
*
* @return void
*/
protected function backupTables($tables)
{
// Create parent node for storing dumped data
$this->data->addChild('tables');
// Get database object
$db = JFactory::getDbo();
foreach ($tables AS $table)
{
$query = $db->getQuery(true);
$query->select('*');
$query->from($table);
$db->setQuery($query);
try
{
if ($rows = $db->loadAssocList())
{
$this->storeTableData($table, $rows);
}
}
catch (Exception $e)
{
throw $e;
}
}
}
/**
* Store backed up table data to XML object.
*
* @param array $table Name of data table.
* @param array $rows Dumped data from the table.
*
* @return void
*/
protected function storeTableData($table, $rows)
{
// Create new node for storing backed up table data
$node = $this->data->tables->addChild('table');
$node->addAttribute('name', $table);
// Store backed up table data to table node
$node = $node->addChild('rows');
foreach ($rows AS $row)
{
// Create new node for storing current row of data
$rowNode = $node->addChild('row');
foreach ($row AS $name => $value)
{
$rowNode->addChild($name, htmlspecialchars($value, ENT_QUOTES, 'UTF-8', false));
}
}
}
/**
* Backup files from selected folders.
*
* @param array $folders Array of folder to backup file.
*
* @return void
*/
protected function backupFiles($folders)
{
// Preset files array
$this->files = array();
foreach ($folders AS $folder => $filter)
{
// Get list of file need to backup
if ($files = JFolder::files(JPATH_ROOT . '/' . $folder, $filter, true, true))
{
foreach ($files AS $file)
{
// Append to files array
$this->files[] = $file;
}
}
}
}
/**
* Do any extra work needed after doing real data backup.
*
* @param array &$options Backup options.
* @param array &$name array('zip' => 'zip_backup_file_name', 'xml' => 'xml_backup_file_name')
*
* @return void
*/
protected function afterBackup(&$options, &$name)
{
// Create zip file containing all backed up data and/or files
try
{
$this->finalizeBackup($name);
}
catch (Exception $e)
{
throw $e;
}
}
/**
* Create downloadable zip-archived backup file.
*
* @param array $name array('zip' => 'zip_backup_file_name', 'xml' => 'xml_backup_file_name')
*
* @return void
*/
protected function finalizeBackup($name)
{
// Get XML data from XML object
if (($data = $this->data->asXML()) === false)
{
throw new Exception(JText::_('JSN_EXTFW_DATA_XML_GENERATION_FAIL'));
}
// Prepend XML file to the array of backed up files
array_unshift($this->files, array($name['xml'] => $data));
// Create zip file containing all backed up data and/or files
if ( ! ($this->zippedBackup = JSNUtilsArchive::createZip($this->files)))
{
throw new Exception(JText::_('JSN_EXTFW_DATA_ARCHIVE_CREATION_FAIL'));
}
}
/**
* Restore database table data and/or files from backup.
*
* @param mixed $backup Either path to an existing file or a variable of $_FILES.
* @param boolean $checkEdition Check for matching edition before restore?
*
* @return void
*/
public function restore($backup, $checkEdition = true)
{
// Get Joomla config
$config = JFactory::getConfig();
// Initialize backup file
if (is_array($backup))
{
if ( ! JFile::upload($backup['tmp_name'], $config->get('tmp_path') . '/' . $backup['name']))
{
throw new Exception(JText::_('JSN_EXTFW_GENERAL_MOVE_UPLOAD_FILE_FAIL'));
}
$backup = $config->get('tmp_path') . '/' . $backup['name'];
}
elseif ( ! preg_match('/^(\/|[a-z]:)/i', $backup))
{
$backup = JPATH_ROOT . '/' . $backup;
}
// Do any preparation needed before doing real data restore
try
{
$this->beforeRestore($backup, $checkEdition);
}
catch (Exception $e)
{
throw $e;
}
// Backup data from selected tables
$this->restoreTables();
// Backup files from selected folders
$this->restoreFiles($backup);
// Do any extra work needed after doing real data restore
try
{
$this->afterRestore($backup);
}
catch (Exception $e)
{
throw $e;
}
}
/**
* Do any preparation needed before doing real data restore.
*
* @param string &$backup Path to folder containing extracted backup files.
* @param boolean $checkEdition Check for matching edition before restore?
*
* @return void
*/
protected function beforeRestore(&$backup, $checkEdition = true)
{
// Initialize variables
$com = preg_replace('/^com_/i', '', JFactory::getApplication()->input->getCmd('option'));
$info = JSNUtilsXml::loadManifestCache();
$jVer = new JVersion;
// Extract backup file
if ( ! JArchive::extract($backup, substr($backup, 0, -4)))
{
throw new Exception(JText::_('JSN_EXTFW_DATA_EXTRACT_UPLOAD_FILE_FAIL'));
}
$backup = substr($backup, 0, -4);
// Auto-detect backup XML file
$files = glob("{$backup}/*.xml");
foreach ($files AS $file)
{
$this->data = JSNUtilsXml::load($file);
// Check if this XML file contain backup data for our product
if (strcasecmp($this->data->getName(), 'backup') == 0 AND isset($this->data['extension-name']) AND isset($this->data['extension-version']) AND isset($this->data['joomla-version']))
{
// Store backup XML file name
$this->xml = basename($file);
// Simply break the loop if we found backup file
break;
}
unset($this->data);
}
if (isset($this->data))
{
// Check if Joomla series match
if ( ! $jVer->isCompatible((string) $this->data['joomla-version']))
{
throw new Exception(JText::_('JSN_EXTFW_DATA_JOOMLA_VERSION_NOT_MATCH'));
}
// Check if extension match
if ( (string) $this->data['extension-name'] != 'JSN ' . preg_replace('/JSN\s*/i', '', JText::_($info->name)))
{
throw new Exception(JText::_('JSN_EXTFW_DATA_INVALID_PRODUCT'));
}
elseif (isset($this->data['extension-edition']) AND $checkEdition
AND ( ! ($const = JSNUtilsText::getConstant('EDITION')) OR (string) $this->data['extension-edition'] != $const))
{
throw new Exception(JText::_('JSN_EXTFW_DATA_INVALID_PRODUCT_EDITION'));
}
elseif ( ! version_compare($info->version, (string) $this->data['extension-version'], 'ge'))
{
// Get update link for out-of-date product
$ulink = $info->authorUrl;
if (isset($this->data['update-url']))
{
$ulink = (string) $this->data['update-url'];
}
elseif ($const = JSNUtilsText::getConstant('UPDATE_LINK'))
{
$ulink = $const;
}
throw new Exception(
JText::_('JSN_EXTFW_DATA_PRODUCT_VERSION_OUTDATE')
. ' <a href="' . $ulink . '" class="jsn-link-action">' . JText::_('JSN_EXTFW_GENERAL_UPDATE_NOW') . '</a>'
);
}
}
else
{
throw new Exception(JText::_('JSN_EXTFW_DATA_BACKUP_XML_NOT_FOUND'));
}
}
/**
* Restore database table data from backup.
*
* @return void
*/
protected function restoreTables()
{
// Get database object
$db = JFactory::getDbo();
foreach ($this->data->tables->table AS $table)
{
// Truncate current table data
$query = $db->getQuery(true);
$query->delete((string) $table['name']);
$query->where('1');
$db->setQuery($query);
try
{
$db->execute();
}
catch (Exception $e)
{
throw $e;
}
// Get table columns
$columns = array();
foreach ($table->rows->row[0]->children() AS $column)
{
$columns[] = $column->getName();
}
// Restore database table data from backup
$query = $db->getQuery(true);
$query->insert((string) $table['name']);
$query->columns(implode(', ', $columns));
foreach ($table->rows->row AS $row)
{
$columns = array();
foreach ($row->children() AS $column)
{
// Initialize column value
$column = html_entity_decode((string) $column, ENT_QUOTES, 'UTF-8');
$column = ! is_numeric($column) ? $db->quote($column) : $column;
$columns[] = $column;
}
$query->values(implode(', ', $columns));
}
$db->setQuery($query);
try
{
$db->execute();
}
catch (Exception $e)
{
throw $e;
}
}
}
/**
* Restore files from backup.
*
* @param string &$backup Path to folder containing extracted backup files.
*
* @return void
*/
protected function restoreFiles(&$backup)
{
// Initialize variables
$config = JFactory::getConfig();
$tmp = str_replace('\\', '/', $config->get('tmp_path'));
$root = str_replace('\\', '/', JPATH_ROOT);
$backup = str_replace('\\', '/', $backup);
// Get list of backed up files
if ($this->files = JFolder::files($backup, '.', true, true))
{
foreach ($this->files as $file)
{
// Initialize file path
$file = str_replace('\\', '/', $file);
if (basename($file) != $this->xml)
{
// Generate destination path
if (strpos($file, $tmp) !== false)
{
$path = $root . '/' . trim(str_replace($backup, '', dirname($file)), '/');
}
elseif (strpos($file, $root) !== false)
{
$path = str_replace($backup, $root, dirname($file));
}
// Create folder if necessary
is_dir($path) OR JFolder::create($path);
// Copy file now
JFile::copy($file, $path . '/' . basename($file));
}
}
}
}
/**
* Do any extra work needed after doing real data restore.
*
* @param array &$backup Uploaded backup file.
*
* @return void
*/
protected function afterRestore(&$backup)
{
// Clean temporary files
JFolder::delete($backup);
JFile::delete("{$backup}.zip");
}
/**
* Install sample data.
*
* @param integer $step Installation step.
*
* @return void
*/
public function installSample($step)
{
// Check if method exists for current installation step
$method = "installSampleStep{$step}";
if (method_exists($this, $method))
{
try
{
$this->$method();
}
catch (Exception $e)
{
$msg = $e->getMessage();
if ( ! preg_match('/[A-Z]+:\s*/', $msg))
{
$msg = 'FAIL: ' . $msg;
}
jexit($msg);
}
}
}
/**
* Install sample data (step 1).
*
* @return boolean
*/
protected function installSampleStep1()
{
// Get Joomla config
$config = JFactory::getConfig();
// Get URL to download sample data package
$url = JFactory::getApplication()->input->getVar('sampleDownloadUrl');
// Set maximum execution time
ini_set('max_execution_time', 300);
// Try to download the sample data package
try
{
$path = $config->get('tmp_path') . '/' . basename($url);
if ( ! JSNUtilsHttp::get($url, $path, true))
{
jexit('DOWNLOAD FAIL');
}
}
catch (Exception $e)
{
jexit('DOWNLOAD FAIL');
}
// Complete AJAX based download task
jexit('DONE: ' . trim(str_replace(JPATH_ROOT, '', $path), '/\\'));
}
/**
* Install sample data (step 2).
*
* @return boolean
*/
protected function installSampleStep2()
{
// Get Joomla config
$config = JFactory::getConfig();
// Get path to downloaded sample data package
if (isset($_FILES['sampleDataPackage']))
{
if ( ! JFile::upload($_FILES['sampleDataPackage']['tmp_name'], $config->get('tmp_path') . '/' . $_FILES['sampleDataPackage']['name']))
{
throw new Exception(JText::_('JSN_EXTFW_GENERAL_MOVE_UPLOAD_FILE_FAIL'));
}
$path = $config->get('tmp_path') . '/' . $_FILES['sampleDataPackage']['name'];
}
else
{
$path = JFactory::getApplication()->input->getVar('sampleDownloadUrl');
}
// Try to install the sample data package
try
{
$this->restore($path, false);
}
catch (Exception $e)
{
throw $e;
}
// Complete AJAX based sample data installation task
jexit('DONE');
}
}