Server : LiteSpeed System : Linux server 3.10.0-1160.90.1.el7.x86_64 #1 SMP Thu May 4 15:21:22 UTC 2023 x86_64 User : alsaif ( 1057) PHP Version : 7.4.33 Disable Function : show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/alsaif/public_html/administrator/components/com_convertforms/ConvertForms/ |
<?php
/**
* @package Convert Forms
* @version 4.3.3 Pro
*
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2023 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace ConvertForms;
use Joomla\Registry\Registry;
use ConvertForms\Helper;
use NRFramework\File;
defined('_JEXEC') or die('Restricted access');
/**
* Export submissions to CSV and JSON
*/
class Export
{
/**
* Export submissions to CSV or JSON file
*
* @param array $options The export options
*
* @return array
*/
public static function export($options)
{
// Increase memory size and execution time to prevent PHP errors on datasets > 20K
set_time_limit(300); // 5 Minutes
ini_set('memory_limit', '-1');
$options = new Registry($options);
// Load submissions model
\JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_convertforms/models');
$model = \JModelLegacy::getInstance('Conversions', 'ConvertFormsModel', ['ignore_request' => true]);
// When we're exporting certain IDs, there's no need to check the state.
if (strpos($options->get('filter_search', ''), 'id:') !== false || $options->get('filter_state') == '*')
{
$filter_state = 'skip';
} else
{
$filter_state = $options->get('filter_state');
}
$model->setState('filter.state', $filter_state);
$model->setState('filter.join_campaigns', 'skip');
$model->setState('filter.join_forms', 'skip');
$model->setState('list.limit', $options->get('limit', 0));
$model->setState('list.start', $options->get('offset', 0));
$model->setState('list.direction', 'asc');
$model->setState('filter.search', $options->get('filter_search'));
$model->setState('filter.form_id', $options->get('filter_form_id'));
$model->setState('filter.period', $options->get('filter_period', ''));
$model->setState('filter.created_from', $options->get('filter_created_from', ''));
$model->setState('filter.created_to', $options->get('filter_created_to', ''));
// Proceed only if we have submissions
if (!$submissions = $model->getItems())
{
$error = \JText::sprintf('COM_CONVERTFORMS_NO_RESULTS_FOUND', strtolower(\JText::_('COM_CONVERTFORMS_SUBMISSIONS')));
throw new \Exception($error);
}
foreach ($submissions as $key => &$submission)
{
self::prepareSubmission($submission);
}
$export_type = $options->get('export_type', 'csv');
$pagination = $model->getPagination();
$firstRun = $pagination->pagesCurrent == 1;
$append = !$firstRun || $options->get('export_append', false);
// Check whether the path does exist. If not, attemp to create it.
$export_path = $options->get('export_path', File::getTempFolder());
if (!File::createDirs($export_path, false))
{
throw new \Exception('Export path does not exist');
}
$filename = \JPath::clean($export_path . DIRECTORY_SEPARATOR) . $options->get('filename', 'convertforms_submissions.' . $export_type);
switch ($export_type)
{
case 'json':
self::toJSON($submissions, $filename, $append);
break;
default:
$excel_security = (bool) Helper::getComponentParams()->get('excel_security', true);
self::toCSV($submissions, $filename, $append, $excel_security);
break;
}
return [
'options' => $options,
'pagination' => $pagination
];
}
/**
* Get a key value array with submission's submitted data
*
* @param object $submission The submission object
*
* @return array
*/
private static function prepareSubmission(&$submission)
{
$result = [
'id' => $submission->id,
'created' => $submission->created,
'state' => $submission->state
];
foreach ($submission->prepared_fields as $field_name => $field)
{
// Always return the raw value and let the export type decide how the value should be displayed.
$result[$field_name] = $field->value_raw;
}
$submission = $result;
}
/**
* Create a JSON file with given data
*
* @param array $data The data to populate the file
* @param string $destination The path where the store the JSON file
* @param bool $append If true, given data will be appended to the end of the file.
*
* @return void
*/
private static function toJSON($data, $destination, $append = false, $check_for_duplicates = true)
{
$content = \JFile::exists($destination) ? (array) json_decode(file_get_contents($destination), true) : [];
$content = $append ? array_merge($content, $data) : $data;
if ($content && $append && $check_for_duplicates)
{
$newArr = [];
foreach ($content as $row)
{
$newArr[$row['id']] = $row;
}
$content = $newArr;
}
$content = json_encode(array_values($content), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
// Save the file
\JFile::write($destination, $content);
}
/**
* Create a CSV file with given data
*
* @param array $data The data to populate the file
* @param string $destination The path where the store the CSV file
* @param bool $append If true, given data will be appended to the end of the file.
* @param boolean $excel_security If enabled, certain row values will be prefixed by a tab to avoid any CSV injection.
*
* @return void
*/
private static function toCSV($data, $destination, $append = false, $excel_security = true, $check_for_duplicates = true)
{
$resource = fopen($destination, $append ? 'a+' : 'w');
if (!$append)
{
// Support UTF-8 on Microsoft Excel
fputs($resource, "\xEF\xBB\xBF");
// Add column names in the first line
fputcsv($resource, array_keys($data[0]));
}
// Get CSV content
$existingRows = [];
if ($append && $check_for_duplicates)
{
while (($existingData = fgetcsv($resource)) !== false)
{
$existingRows[(int) $existingData[0]] = $existingData;
}
}
foreach ($data as $row)
{
if (!empty($existingRows) && isset($row['id']) && array_key_exists($row['id'], $existingRows))
{
continue;
}
// Prevent CSV Injection: https://vel.joomla.org/articles/2140-introducing-csv-injection
if ($excel_security)
{
foreach ($row as &$value)
{
$value = is_array($value) ? implode(', ', $value) : $value;
$firstChar = substr($value, 0, 1);
// Prefixe values starting with a =, +, - or @ by a tab character
if (in_array($firstChar, array('=', '+', '-', '@')))
{
$value = ' ' . $value;
}
}
}
fputcsv($resource, $row);
}
fclose($resource);
}
/**
* Redirects to the error layout and displays the given error message
*
* @param string $error_message
*
* @return void
*/
public static function error($error_message)
{
$app = \JFactory::getApplication();
$optionsQuery = http_build_query(array_filter([
'option' => 'com_convertforms',
'view' => 'export',
'layout' => 'error',
'error' => $error_message,
'tmpl' => $app->input->get('tmpl')
]));
$app->redirect('index.php?' . $optionsQuery);
}
/**
* Verifies the export file does exist
*
* @param string $filename
*
* @return bool
*/
public static function exportFileExists($filename)
{
return \JFile::exists(File::getTempFolder() . $filename);
}
/**
* Adds the Export popup to the page which can be triggered by toolbar buttons.
*
* @return void
*/
public static function renderModal()
{
\JHtml::script('com_convertforms/export.js', ['relative' => true, 'version' => 'auto']);
\JFactory::getDocument()->addScriptDeclaration('
document.addEventListener("DOMContentLoaded", function() {
new exportModal("'.\JFactory::getApplication()->input->get('view') . '");
});
');
$html = \JHtml::_('bootstrap.renderModal', 'cfExportSubmissions', [
'backdrop' => 'static'
]);
// This is the only way to add a custom CSS class to the popup container
echo str_replace('modal hide', 'modal hide transparent', $html);
}
}