<?php
// namespace administrator\components\com_gdpr\framework\files;
/**
 * @package GDPR::FRAMEWORK::administrator::components::com_gdpr
 * @subpackage framework
 * @subpackage file
 * @author Joomla! Extensions Store
 * @copyright (C) 2015 - Joomla! Extensions Store
 * @license GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html
 */
defined('_JEXEC') or die('Restricted access');

// CSV import fields
define ('COM_GDPR_COOKIE', 0);
define ('COM_GDPR_CATEGORY', 1);
define ('COM_GDPR_DESCRIPTIONHTML', 2);
define ('COM_GDPR_PUBLISHED', 3);
define ('COM_GDPR_FIELDS_NUM', 4);

jimport('joomla.filesystem.file');
jimport('joomla.filesystem.folder');
jimport('joomla.filesystem.archive');

/**
 * Manager of the import/export configuration and migration of settings JSON encoded
 * 
 * @package GDPR::FRAMEWORK::administrator::components::com_gdpr
 * @subpackage framework
 * @subpackage file
 * @since 4.5
 */
class GdprHelpersConfig extends JObject {
	/**
	 * Database connector
	 * 
	 * @access private
	 * @var Object
	 */
	private $dbo;
	
	/**
	 * Application object
	 *
	 * @access private
	 * @var Object
	 */
	private $app;
	
	/**
	 * Clean the cache
	 * @param   string   $group      The cache group
	 * @param   integer  $client_id  The ID of the client
	 * @return  void
	 * @since   11.1
	 */
	private function cleanComponentCache($group = null, $client_id = 0) {
		// Initialise variables;
		$conf = JFactory::getConfig();
		$dispatcher = JDispatcher::getInstance();
		
		$options = array(
				'defaultgroup' => ($group) ? $group : $this->app->input->get('option'),
				'cachebase' => ($client_id) ? JPATH_ADMINISTRATOR . '/cache' : $conf->get('cache_path', JPATH_SITE . '/cache'));
		
		$cache = JCache::getInstance('callback', $options);
		$cache->clean();
		
		// Trigger the onContentCleanCache event.
		$dispatcher->trigger('onContentCleanCache', $options);
	}
	
	/**
	 * Store uploaded file to cache folder,
	 * fully manage error messages and ask for database insert
	 * 
	 * @access public
	 * @return boolean 
	 */
	public function import() {
		// Get file info
		$file = $this->app->input->files->get('configurationimport', null, 'raw');
		$tmpFile = $file['tmp_name'];
		$tmpFileName = $file['name'];
		try {
			if(!$tmpFile || !$tmpFileName) {
				throw new GdprException(JText::_('COM_GDPR_NOFILE_SELECTED'), 'error');
			}
			
			$tmpFileSize = $file['size'];
			$allowedFileSize = 2 * 1024 * 1024; // MB->Bytes
			if($tmpFileSize > $allowedFileSize) {
				throw new GdprException(JText::_('COM_GDPR_SIZE_ERROR') .' Max 2MB.', 'error');
			}
			
			$tmpFileExtension = @array_pop(explode('.', $tmpFileName));
			if($tmpFileExtension != 'json') {
				throw new GdprException(JText::_('COM_GDPR_EXT_ERROR'), 'error');
			}

			// Deserialize contents
			$fileContents = file_get_contents($tmpFile);
			if($fileContents) {
				$objectToRestore = json_decode($fileContents);
			}
			
			if(!is_object($objectToRestore)) {
				throw new GdprException(JText::_('COM_GDPR_INVALID_IMPORT_DATA'), 'error');
			}
			
			$queryImport = 	"UPDATE " . $this->dbo->quoteName('#__extensions') .
						   	"\n SET " . $this->dbo->quoteName('params') . " = " . $this->dbo->quote($fileContents) .
						   	"\n WHERE " . $this->dbo->quoteName('type') . " = " . $this->dbo->quote('component') .
							"\n AND " . $this->dbo->quoteName('element') . " = " . $this->dbo->quote('com_gdpr') .
							"\n AND " . $this->dbo->quoteName('client_id') . " = 1";
			$this->dbo->setQuery($queryImport);
			$this->dbo->execute();
			if($this->dbo->getErrorNum()) {
				throw new GdprException(JText::sprintf('COM_GDPR_DBERROR_IMPORT_DATA', $this->dbo->getErrorMsg()), 'error');
			}
			
			// Clean the cache.
			$this->cleanComponentCache('_system', 0);
			$this->cleanComponentCache('_system', 1);
		}
		catch(GdprException $e) {
			$this->setError($e);
			return false;
		} catch (Exception $e) {
			$gdprException = new GdprException($e->getMessage(), 'error');
			$this->setError($gdprException);
			return false;
		}
		
		return true;
	}

	/**
	 * Download uploaded file message
	 * 
	 * @access public
	 * @return boolean
	 */
	public function export($ids = null) { 
		// Load data from DB 
		try {
			$query = "SELECT" . $this->dbo->quoteName('params') .
					 "\n FROM " . $this->dbo->quoteName('#__extensions') .
					 "\n WHERE " . $this->dbo->quoteName('type') . " = " . $this->dbo->quote('component') .
					 "\n AND " . $this->dbo->quoteName('element') . " = " . $this->dbo->quote('com_gdpr') .
					 "\n AND " . $this->dbo->quoteName('client_id') . " = 1";
			$this->dbo->setQuery($query);
			$resultInfo = $this->dbo->loadResult();
			if(!$resultInfo) {
				throw new GdprException(JText::_('COM_GDPR_ERROR_NODATA_TOEXPORT'), 'error');
			}
		} catch(GdprException $e) {
			$this->setError($e);
			return false;
		} catch (Exception $e) {
			$gdprException = new GdprException($e->getMessage(), 'error');
			$this->setError($gdprException);
			return false;
		}
		
		$fsize = JString::strlen($resultInfo);
		$cont_dis = 'attachment';
		$mimeType = 'application/json';
		
		// required for IE, otherwise Content-disposition is ignored
		if (ini_get ( 'zlib.output_compression' )) {
			ini_set ( 'zlib.output_compression', 'Off' );
		}
		header ( "Pragma: public" );
		header ( "Cache-Control: must-revalidate, post-check=0, pre-check=0" );
		header ( "Expires: 0" );
		header ( "Content-Transfer-Encoding: binary" );
		header ( 'Content-Disposition:' . $cont_dis . ';' . ' filename="gdpr_configuration.json";' . ' size=' . $fsize . ';' ); //RFC2183
		header ( "Content-Type: " . $mimeType ); // MIME type
		header ( "Content-Length: " . $fsize );
		if (! ini_get ( 'safe_mode' )) { // set_time_limit doesn't work in safe mode
			@set_time_limit ( 0 );
		}
		// No encoding - we aren't using compression... (RFC1945)
		//header("Content-Encoding: none");
		//header("Vary: none");
		echo $resultInfo;
		
		exit();
	}

	/**
	 * Store uploaded file to cache folder,
	 * fully manage error messages and ask for database insert
	 *
	 * @access public
	 * @param Object $componentConfig
	 * @param boolean $defaultFile
	 * @return boolean
	 */
	public function importCookieDescriptions($componentConfig, $defaultFile = false) {
		// Setup the default file import
		if($defaultFile) {
			$tmpFile = JPATH_ROOT . '/administrator/components/com_gdpr/framework/helpers/cookie_descriptions.csv';
			$tmpFileName = 'cookie_descriptions.csv';
		} else {
			// Get file info
			$file = $this->app->input->files->get('configurationimport', null, 'raw');
			$tmpFile = $file['tmp_name'];
			$tmpFileName = $file['name'];
		}
		
		$delimiter = $componentConfig->get('csv_delimiter', ';');
		$enclosure = $componentConfig->get('csv_enclosure', '"');
		
		try {
			if(!$tmpFile || !$tmpFileName) {
				throw new GdprException(JText::_('COM_GDPR_NOFILE_SELECTED'), 'error');
			}
			
			$tmpFileExtension = @array_pop(explode('.', $tmpFileName));
			if($tmpFileExtension != 'csv') {
				throw new GdprException(JText::_('COM_GDPR_COOKIEDESCRIPTIONS_EXT_ERROR'), 'error');
			}
			
			// Deserialize contents
			$fileHandle = fopen($tmpFile, "r");
			if(!is_resource($fileHandle)) {
				throw new GdprException(JText::_('COM_GDPR_DATA_FILE_NOT_READABLE'), 'error');
			}
			
			// Parse the CSV files dataset into an importable array
			$skip = true;
			$dbQueryArray = array();
			while ( $csvRecord = fgetcsv ( $fileHandle, 0, $delimiter, $enclosure ) ) {
				// Skip prima riga intestazioni
				if($skip) {
					$skip = false;
					continue;
				}
				//Insert
				array_push ( $dbQueryArray, $csvRecord );
			}
			
			// Check if some valid data to import are available
			if(!count($dbQueryArray)) {
				throw new GdprException(JText::_('COM_GDPR_NO_IMPORT_DATA_FOUND'), 'warning');
			}
			
			// Prepare the values array
			foreach ($dbQueryArray as $dbRecord) {
				// Ensure at least that the number of csv fields are correct
				if(count($dbRecord) != COM_GDPR_FIELDS_NUM) {
					continue;
				}
				
				// Check if the link as primary key already exists in this table
				$selectQuery = 	"SELECT" . $this->dbo->quoteName('id') .
								"\n FROM " . $this->dbo->quoteName('#__gdpr_cookie_descriptions') .
								"\n WHERE" .
								$this->dbo->quoteName('cookie') . " = " . $this->dbo->quote($dbRecord[COM_GDPR_COOKIE]) .
								"\n AND " . $this->dbo->quoteName('category') . " = " . $this->dbo->quote($dbRecord[COM_GDPR_CATEGORY]);
				$recordExists = $this->dbo->setQuery ( $selectQuery )->loadResult();

				// Sanitize the imported HTML field to avoid cross site scripting
				$dbRecord[COM_GDPR_DESCRIPTIONHTML] = preg_replace('#<script(.*?)>(.*?)</script>#is', '$2', $dbRecord[COM_GDPR_DESCRIPTIONHTML]);
				
				// If the link exists just update it, otherwise insert a new one
				if($recordExists) {
					$query = "UPDATE" .
							 "\n " . $this->dbo->quoteName('#__gdpr_cookie_descriptions') .
							 "\n SET " .
							 "\n " . $this->dbo->quoteName('cookie') . " = " . $this->dbo->quote($dbRecord[COM_GDPR_COOKIE]) . "," .
							 "\n " . $this->dbo->quoteName('category') . " = " . $this->dbo->quote($dbRecord[COM_GDPR_CATEGORY]) . "," .
							 "\n " . $this->dbo->quoteName('descriptionhtml') . " = " . $this->dbo->quote($dbRecord[COM_GDPR_DESCRIPTIONHTML]) . "," .
							 "\n " . $this->dbo->quoteName('published') . " = " . (int)($dbRecord[COM_GDPR_PUBLISHED]) .
							 "\n WHERE " .
							 "\n " . $this->dbo->quoteName('id') . " = " . (int)$recordExists;
					$this->dbo->setQuery ( $query );
				} else {
					$query = "INSERT INTO" .
							 "\n " . $this->dbo->quoteName('#__gdpr_cookie_descriptions') . "(" .
							 $this->dbo->quoteName('cookie') . "," .
							 $this->dbo->quoteName('category') . "," .
							 $this->dbo->quoteName('descriptionhtml') . "," .
							 $this->dbo->quoteName('published') . ") VALUES (" .
							 $this->dbo->quote($dbRecord[COM_GDPR_COOKIE]) . "," .
							 $this->dbo->quote($dbRecord[COM_GDPR_CATEGORY]) . "," .
							 $this->dbo->quote($dbRecord[COM_GDPR_DESCRIPTIONHTML]) . "," .
							 (int)$dbRecord[COM_GDPR_PUBLISHED] . ")";
					$this->dbo->setQuery ( $query );
				}
				$this->dbo->execute ();
				if ($this->dbo->getErrorNum ()) {
					throw new GdprException(JText::sprintf('COM_GDPR_ERROR_STORING_DATA', $this->dbo->getErrorMsg()), 'error');
				}
			}
		}
		catch(GdprException $e) {
			$this->setError($e);
			return false;
		} catch (Exception $e) {
			$gdprException = new GdprException(JText::sprintf('COM_GDPR_ERROR_STORING_DATA', $e->getMessage()), 'error');
			$this->setError($gdprException);
			return false;
		}
		
		return true;
	}

	/**
	 * Class constructor
	 * 
	 * @access public
	 * @param Object $dbo
	 * @param Object $app
	 * @return Object &
	 */
	public function __construct($dbo, $app) {
		// DB connector
		$this->dbo = $dbo;
		
		// Application
		$this->app = $app;
	}
}