386 lines
12 KiB
PHP
386 lines
12 KiB
PHP
<?php
|
|
/**
|
|
* @package JEM
|
|
* @copyright (C) 2013-2024 joomlaeventmanager.net
|
|
* @copyright (C) 2005-2009 Christoph Lukes
|
|
* @license https://www.gnu.org/licenses/gpl-3.0 GNU/GPL
|
|
*/
|
|
|
|
defined('_JEXEC') or die;
|
|
|
|
use Joomla\CMS\Factory;
|
|
use Joomla\CMS\Table\Table;
|
|
use Joomla\CMS\Language\Text;
|
|
use Joomla\CMS\MVC\Controller\BaseController;
|
|
use Joomla\CMS\Session\Session;
|
|
|
|
// helper callback function to convert all elements of an array
|
|
function jem_convert_ansi2utf8(&$value, $key)
|
|
{
|
|
$value = iconv('windows-1252', 'utf-8', $value);
|
|
}
|
|
|
|
/**
|
|
* JEM Component Import Controller
|
|
*
|
|
* @package JEM
|
|
*
|
|
*/
|
|
class JemControllerImport extends BaseController
|
|
{
|
|
/**
|
|
* Constructor
|
|
*/
|
|
public function __construct()
|
|
{
|
|
parent::__construct();
|
|
}
|
|
|
|
public function csveventimport()
|
|
{
|
|
$this->CsvImport('events', 'events');
|
|
}
|
|
|
|
public function csvcategoriesimport()
|
|
{
|
|
$this->CsvImport('categories', 'categories');
|
|
}
|
|
|
|
public function csvvenuesimport()
|
|
{
|
|
$this->CsvImport('venues', 'venues');
|
|
}
|
|
|
|
public function csvcateventsimport()
|
|
{
|
|
$this->CsvImport('catevents', 'cats_event_relations');
|
|
}
|
|
|
|
private function CsvImport($type, $dbname)
|
|
{
|
|
// Check for request forgeries
|
|
Session::checkToken() or jexit('Invalid Token');
|
|
|
|
$replace = Factory::getApplication()->input->post->getInt('replace_'.$type, 0);
|
|
$object = Table::getInstance('jem_'.$dbname, '');
|
|
$object_fields = get_object_vars($object);
|
|
$jemconfig = JemConfig::getInstance()->toRegistry();
|
|
$separator = $jemconfig->get('csv_separator', ';');
|
|
$delimiter = $jemconfig->get('csv_delimiter', '"');
|
|
|
|
if ($type === 'events') {
|
|
// add additional fields
|
|
$object_fields['categories'] = '';
|
|
}
|
|
|
|
$msg = '';
|
|
$file = Factory::getApplication()->input->files->get('File'.$type, array(), 'array');
|
|
|
|
if (empty($file['name']))
|
|
{
|
|
$msg = Text::_('COM_JEM_IMPORT_SELECT_FILE');
|
|
$this->setRedirect('index.php?option=com_jem&view=import', $msg, 'error');
|
|
return;
|
|
}
|
|
|
|
if ($file['name']) {
|
|
$handle = fopen($file['tmp_name'], 'r');
|
|
if (!$handle) {
|
|
$msg = Text::_('COM_JEM_IMPORT_OPEN_FILE_ERROR');
|
|
$this->setRedirect('index.php?option=com_jem&view=import', $msg, 'error');
|
|
return;
|
|
}
|
|
|
|
// search for bom - then it is utf-8
|
|
$bom = pack('CCC', 0xEF, 0xBB, 0xBF);
|
|
$fc = fread($handle, 3);
|
|
$convert = strncmp($fc, $bom, 3) !== 0;
|
|
if ($convert) {
|
|
// no bom - rewind file
|
|
fseek($handle, 0);
|
|
}
|
|
|
|
// get fields, on first row of the file
|
|
$fields = array();
|
|
if (($data = fgetcsv($handle, 1000, $separator, $delimiter)) !== false) {
|
|
$numfields = count($data);
|
|
|
|
// convert from ansi to utf-8 if required
|
|
if ($convert) {
|
|
$msg .= "<p>".Text::_('COM_JEM_IMPORT_BOM_NOT_FOUND')."</p>\n";
|
|
array_walk($data, 'jem_convert_ansi2utf8');
|
|
}
|
|
|
|
for ($c = 0; $c < $numfields; $c++) {
|
|
// here, we make sure that the field match one of the fields of jem_venues table or special fields,
|
|
// otherwise, we don't add it
|
|
if (array_key_exists($data[$c], $object_fields)) {
|
|
$fields[$c] = $data[$c];
|
|
}
|
|
}
|
|
}
|
|
|
|
// If there is no validated fields, there is a problem...
|
|
if (!count($fields)) {
|
|
$msg .= "<p>".Text::_('COM_JEM_IMPORT_PARSE_ERROR')."</p>\n";
|
|
$msg .= "<p>".Text::_('COM_JEM_IMPORT_PARSE_ERROR_INFOTEXT')."</p>\n";
|
|
|
|
$this->setRedirect('index.php?option=com_jem&view=import', $msg, 'error');
|
|
return;
|
|
} else {
|
|
$msg .= "<p>".Text::sprintf('COM_JEM_IMPORT_NUMBER_OF_FIELDS', $numfields)."</p>\n";
|
|
$msg .= "<p>".Text::sprintf('COM_JEM_IMPORT_NUMBER_OF_FIELDS_USEABLE', count($fields))."</p>\n";
|
|
}
|
|
|
|
// Now get the records, meaning the rest of the rows.
|
|
$records = array();
|
|
$row = 1;
|
|
|
|
while (($data = fgetcsv($handle, 10000, $separator, $delimiter)) !== FALSE) {
|
|
$num = count($data);
|
|
|
|
if ($numfields != $num) {
|
|
$msg .= "<p>".Text::sprintf('COM_JEM_IMPORT_NUMBER_OF_FIELDS_COUNT_ERROR', $num, $row)."</p>\n";
|
|
} else {
|
|
// convert from ansi to utf-8 if required
|
|
if ($convert) {
|
|
array_walk($data, 'jem_convert_ansi2utf8');
|
|
}
|
|
|
|
$r = array();
|
|
// only extract columns with validated header, from previous step.
|
|
foreach ($fields as $k => $v) {
|
|
$r[$k] = $this->_formatcsvfield($v, $data[$k]);
|
|
}
|
|
$records[] = $r;
|
|
}
|
|
$row++;
|
|
}
|
|
|
|
fclose($handle);
|
|
$msg .= "<p>".Text::sprintf('COM_JEM_IMPORT_NUMBER_OF_ROWS_FOUND', count($records))."</p>\n";
|
|
|
|
// database update
|
|
if (count($records)) {
|
|
$model = $this->getModel('import');
|
|
$result = $model->{$type.'import'}($fields, $records, $replace);
|
|
if ($result['added']) {
|
|
$msg .= "<p>" . Text::sprintf('COM_JEM_IMPORT_NUMBER_OF_ROWS_ADDED', $result['added']) . "</p>\n";
|
|
}
|
|
if ($result['updated']){
|
|
$msg .= "<p>" . Text::sprintf('COM_JEM_IMPORT_NUMBER_OF_ROWS_UPDATED', $result['updated']) . "</p>\n";
|
|
}
|
|
if ($result['duplicated']){
|
|
$msg .= "<p>" . Text::sprintf('COM_JEM_IMPORT_NUMBER_OF_ROWS_DUPLICATED', $result['duplicated']) . " [Id events: " . $result['duplicatedids'] . "]</p>\n";
|
|
}
|
|
if ($result['replaced']){
|
|
$msg .= "<p>" . Text::sprintf('COM_JEM_IMPORT_NUMBER_OF_ROWS_REPLACED', $result['replaced']) . " [Id events: " . $result['replacedids'] . "]</p>\n";
|
|
}
|
|
if ($result['ignored']){
|
|
$msg .= "<p>" . Text::sprintf('COM_JEM_IMPORT_NUMBER_OF_ROWS_IGNORED', $result['ignored']) . " [Id events: " . $result['ignoredids'] . "]</p>\n";
|
|
}
|
|
if ($result['error']){
|
|
$msg .= "<p>" . Text::sprintf('COM_JEM_IMPORT_NUMBER_OF_ROWS_ERROR', $result['error']) . " [Id events: " . $result['errorids'] . "]</p>\n";
|
|
}
|
|
}
|
|
$this->setRedirect('index.php?option=com_jem&view=import', $msg);
|
|
} else {
|
|
parent::display();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* handle specific fields conversion if needed
|
|
*
|
|
* @param string column name
|
|
* @param string $value
|
|
* @return string
|
|
*/
|
|
protected function _formatcsvfield($type, $value)
|
|
{
|
|
switch($type) {
|
|
case 'times':
|
|
case 'endtimes':
|
|
if ($value !== '' && strtoupper($value) !== 'NULL') {
|
|
$time = strtotime($value);
|
|
$field = date('H:i:s',$time);
|
|
} else {
|
|
$field = null;
|
|
}
|
|
break;
|
|
case 'dates':
|
|
case 'enddates':
|
|
case 'recurrence_limit_date':
|
|
if ($value !== '' && strtoupper($value) !== 'NULL' && $value != '0000-00-00') {
|
|
$date = strtotime($value);
|
|
$field = date('Y-m-d', $date);
|
|
} else {
|
|
$field = null;
|
|
}
|
|
break;
|
|
default:
|
|
$field = $value;
|
|
break;
|
|
}
|
|
return $field;
|
|
}
|
|
|
|
/**
|
|
* Imports data from an old Eventlist installation
|
|
*/
|
|
public function eventlistImport()
|
|
{
|
|
// Check for request forgeries
|
|
Session::checkToken() or jexit('Invalid Token');
|
|
|
|
$model = $this->getModel('import');
|
|
$size = 5000;
|
|
|
|
// Handling the different names for all classes and db table names (possibly substrings)
|
|
// EL 1.0.2 doesn't have tables attachments and cats_event_descriptions
|
|
// EL 1.1 has both tables but events doesn't contain field catsid
|
|
// also the recurrence fields are different
|
|
// And EL 1.1 runs on J! 1.5 only - which has different access level ids (fixed (0, 1, 2) instead of (1, 2, 3, ...))
|
|
$tables = new stdClass();
|
|
// Note: 'attachments' MUST be last entry!
|
|
$tables->eltables = array("categories", "events", "cats_event_relations", "groupmembers", "groups", "register", "venues", "attachments");
|
|
$tables->jemtables = array("categories", "events", "cats_event_relations", "groupmembers", "groups", "register", "venues", "attachments");
|
|
|
|
$app = Factory::getApplication();
|
|
$jinput = $app->input;
|
|
$step = $jinput->get('step', 0, 'INT');
|
|
$current = $jinput->get->get('current', 0, 'INT');
|
|
$total = $jinput->get->get('total', 0, 'INT');
|
|
$table = $jinput->get->get('table', 0, 'INT');
|
|
$prefix = $app->getUserStateFromRequest('com_jem.import.elimport.prefix', 'prefix', '#__', 'cmd');
|
|
$copyImages = $app->getUserStateFromRequest('com_jem.import.elimport.copyImages', 'copyImages', 0, 'int');
|
|
$copyAttachments = $app->getUserStateFromRequest('com_jem.import.elimport.copyAttachments', 'copyAttachments', 0, 'int');
|
|
$fromJ15 = $app->getUserStateFromRequest('com_jem.import.elimport.fromJ15', 'fromJ15', '0', 'int'); // import from Joomla! 1.5 site?
|
|
|
|
$link = 'index.php?option=com_jem&view=import';
|
|
$msg = Text::_('COM_JEM_IMPORT_EL_IMPORT_WORK_IN_PROGRESS')." ";
|
|
|
|
if ($jinput->get('startToken', 0, 'INT') || ($step === 1)) {
|
|
// Are the JEM tables empty at start? If no, stop import
|
|
if ($model->getExistingJemData()) {
|
|
$this->setRedirect($link);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ($step <= 1) {
|
|
$app->setUserState('com_jem.import.elimport.copyImages', '0');
|
|
$app->setUserState('com_jem.import.elimport.copyAttachments', '0');
|
|
$app->setUserState('com_jem.import.elimport.fromJ15', '0');
|
|
|
|
if ($step === 1) {
|
|
$attachments = $model->getEventlistTableCount("eventlist_attachments") !== null;
|
|
$app->setUserState('com_jem.import.elimport.attachmentsPossible', $attachments);
|
|
}
|
|
|
|
parent::display();
|
|
return;
|
|
} elseif ($step === 2) {
|
|
// Special handling of cats_event_relations table which only exists on EL 1.1
|
|
if (($tables->eltables[$table] == 'cats_event_relations')) {
|
|
$tot = $model->getEventlistTableCount("eventlist_".$tables->eltables[$table]);
|
|
if (!empty($tot)) {
|
|
$total = $tot;
|
|
} else {
|
|
$tables->eltables[$table] = 'events';
|
|
}
|
|
}
|
|
|
|
// Get number of rows if it is still 0 or we have moved to the next table
|
|
if ($total == 0 || $current == 0) {
|
|
$total = $model->getEventlistTableCount("eventlist_".$tables->eltables[$table]);
|
|
}
|
|
|
|
// If $total is null, the table does not exist, so we skip import for this table.
|
|
if ($total === null) {
|
|
// This helps to prevent special cases in the following code
|
|
$total = 0;
|
|
} else {
|
|
// The real work is done here:
|
|
// Loading from EL tables, changing data, storing in JEM tables
|
|
$data = $model->getEventlistData("eventlist_".$tables->eltables[$table], $current, $size);
|
|
$data = $model->transformEventlistData($tables->jemtables[$table], $data, $fromJ15);
|
|
$model->storeJemData("jem_".$tables->jemtables[$table], $data);
|
|
}
|
|
|
|
// Proceed with next bunch of data
|
|
$current += $size;
|
|
|
|
// Current table is imported completely, proceed with next table
|
|
if ($current > $total) {
|
|
$table++;
|
|
$current = 0;
|
|
}
|
|
|
|
// Check if table import is complete
|
|
if ($current <= $total && $table < count($tables->eltables)) {
|
|
// Don't add default prefix to link because of special character #
|
|
if ($prefix == "#__") {
|
|
$prefix = "";
|
|
}
|
|
|
|
$link .= '&step='.$step.'&table='.$table.'¤t='.$current.'&total='.$total;
|
|
//todo: we say "importing..." so we must show table of next step - but we don't know their entry count ($total).
|
|
$msg .= Text::sprintf('COM_JEM_IMPORT_EL_IMPORT_WORKING_STEP_COPY_DB', $tables->jemtables[$table], $current, '?');
|
|
} else {
|
|
$step++;
|
|
$link .= '&step='.$step;
|
|
$msg .= Text::_('COM_JEM_IMPORT_EL_IMPORT_WORKING_STEP_REBUILD');
|
|
}
|
|
} elseif ($step === 3) {
|
|
// We have to rebuild the hierarchy of the categories due to the plain database insertion
|
|
Table::addIncludePath(JPATH_COMPONENT_ADMINISTRATOR.'/tables');
|
|
$categoryTable = Table::getInstance('Category', 'JemTable');
|
|
$categoryTable->rebuild();
|
|
$step++;
|
|
$link .= '&step='.$step;
|
|
if ($copyImages) {
|
|
$msg .= Text::_('COM_JEM_IMPORT_EL_IMPORT_WORKING_STEP_COPY_IMAGES');
|
|
} else {
|
|
$msg .= Text::_('COM_JEM_IMPORT_EL_IMPORT_WORKING_STEP_COPY_IMAGES_SKIPPED');
|
|
}
|
|
} elseif ($step === 4) {
|
|
// Copy EL images to JEM image destination?
|
|
if ($copyImages) {
|
|
$model->copyImages();
|
|
}
|
|
$step++;
|
|
$link .= '&step='.$step;
|
|
if ($copyAttachments) {
|
|
$msg .= Text::_('COM_JEM_IMPORT_EL_IMPORT_WORKING_STEP_COPY_ATTACHMENTS');
|
|
} else {
|
|
$msg .= Text::_('COM_JEM_IMPORT_EL_IMPORT_WORKING_STEP_COPY_ATTACHMENTS_SKIPPED');
|
|
}
|
|
} elseif ($step === 5) {
|
|
// Copy EL images to JEM image destination?
|
|
if ($copyAttachments) {
|
|
$model->copyAttachments();
|
|
}
|
|
$step++;
|
|
$link .= '&step='.$step;
|
|
$msg = Text::_('COM_JEM_IMPORT_EL_IMPORT_FINISHED');
|
|
} else {
|
|
// cleanup stored fields for users importing multiple time ;-)
|
|
$app->setUserState('com_jem.import.elimport.prefix', null);
|
|
$app->setUserState('com_jem.import.elimport.copyImages', null);
|
|
$app->setUserState('com_jem.import.elimport.copyAttachments', null);
|
|
$app->setUserState('com_jem.import.elimport.fromJ15', null);
|
|
$app->setUserState('com_jem.import.elimport.attachmentsPossible', null);
|
|
|
|
// perform forced cleanup (archive, delete, recurrence)
|
|
JemHelper::cleanup(true);
|
|
|
|
$msg = Text::_('COM_JEM_IMPORT_EL_IMPORT_FINISHED');
|
|
}
|
|
|
|
$app->enqueueMessage($msg);
|
|
$this->setRedirect($link);
|
|
}
|
|
}
|
|
?>
|