PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 10.0.1
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v10.0.1
11.1.1 11.1.0 11.0.5 11.0.4 11.0.3 11.0.2 11.0.1 11.0.0 10.11.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 trunk 10.0.0 10.0.1 10.1.0 10.1.1 10.1.2 10.1.3 10.1.4 10.2.0 10.2.1 10.2.2 All 62 releases
acymailing / back / Helpers / ImportHelper.php

ImportHelper.php in AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress 10.0.1, at back/Helpers/ImportHelper.php

1,124 lines 43.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace AcyMailing\Helpers;
4
5 use AcyMailing\Classes\ListClass;
6 use AcyMailing\Classes\UserClass;
7 use AcyMailing\Core\AcymObject;
8
9 class ImportHelper extends AcymObject
10 {
11 var $importUserInLists = [];
12 var $totalInserted = 0;
13 var $totalTry = 0;
14 var $totalValid = 0;
15 var $allSubid = [];
16 var $forceconfirm = false;
17 var $generatename = true;
18 var $overwrite = false;
19 var $importblocked = false;
20 var $removeSep = 0;
21 var $dispresults = true;
22
23 public $tableName = '';
24 public $dbWhere = [];
25 public $fieldsMap = [];
26
27 var $subscribedUsers = [];
28
29 public $header;
30 public $separator;
31 public $columns;
32
33 public function __construct()
34 {
35 parent::__construct();
36 acym_increasePerf();
37 }
38
39
40 public function file()
41 {
42 $importFile = acym_getVar('array', 'import_file', [], 'files');
43
44 if (empty($importFile['name'])) {
45 acym_enqueueMessage(acym_translation('ACYM_PLEASE_BROWSE_FILE_IMPORT'), 'error');
46
47 return false;
48 }
49
50 $extension = strtolower(acym_fileGetExt($importFile['name']));
51
52 if (!preg_match('#^(csv)$#Ui', $extension) || preg_match('#\.(php.?|.?htm.?|pl|py|jsp|asp|sh|cgi)$#Ui', $importFile['name'])) {
53 acym_enqueueMessage(acym_translationSprintf('ACYM_ACCEPTED_TYPE', acym_escape($extension), $this->config->get('allowed_files')), 'error');
54
55 return false;
56 }
57
58 $fileError = $importFile['error'];
59 if ($fileError > 0) {
60 switch ($fileError) {
61 case 1:
62 case 2:
63 acym_enqueueMessage(acym_translation('ACYM_UPLOADED_FILE_EXCEED_MAX_FILESIZE_PHP'), 'error');
64
65 return false;
66 case 3:
67 acym_enqueueMessage(acym_translation('ACYM_FILE_UPLOADED_PARTIALLY'), 'error');
68
69 return false;
70 case 4:
71 acym_enqueueMessage(acym_translation('ACYM_NO_FILE_WAS_UPLOADED'), 'error');
72
73 return false;
74 default:
75 acym_enqueueMessage(acym_translationSprintf('ACYM_UNKNOWN_ERROR_UPLOADING_FILE', $fileError), 'error');
76
77 return false;
78 }
79 }
80
81 $uploadPath = $this->_createUploadFolder();
82
83 $attachment = new \stdClass();
84 $attachment->filename = uniqid('import_').'.csv';
85 acym_setVar('acym_import_filename', $attachment->filename);
86
87 $attachment->size = $importFile['size'];
88
89 if (!acym_uploadFile($importFile['tmp_name'], $uploadPath.$attachment->filename)) {
90 if (!move_uploaded_file($importFile['tmp_name'], $uploadPath.$attachment->filename)) {
91 acym_enqueueMessage(
92 acym_translationSprintf(
93 'ACYM_FAIL_UPLOAD',
94 '<b><i>'.acym_escape($importFile['tmp_name']).'</i></b>',
95 '<b><i>'.acym_escape($uploadPath.$attachment->filename).'</i></b>'
96 ),
97 'error'
98 );
99 }
100 }
101
102 return true;
103 }
104
105 public function textarea()
106 {
107 $content = acym_getVar('string', 'acym__users__import__from_text__textarea');
108 $path = $this->_createUploadFolder();
109 $filename = uniqid('import_').'.csv';
110
111 acym_writeFile($path.$filename, $content);
112 acym_setVar('acym_import_filename', $filename);
113
114 return true;
115 }
116
117 public function cms()
118 {
119 global $acymCmsUserVars;
120
121 $query = 'UPDATE IGNORE '.$acymCmsUserVars->table.' as b, #__acym_user as a SET a.email = b.'.$acymCmsUserVars->email.', a.name = b.'.$acymCmsUserVars->name.', a.active = 1 - b.'.$acymCmsUserVars->blocked.' WHERE a.cms_id = b.'.$acymCmsUserVars->id.' AND a.cms_id IS NOT NULL';
122 $nbUpdated = acym_query($query);
123
124 $query = 'UPDATE IGNORE '.$acymCmsUserVars->table.' as b, #__acym_user as a SET a.cms_id = b.'.$acymCmsUserVars->id.' WHERE a.email = b.'.$acymCmsUserVars->email;
125 $affected = acym_query($query);
126 $nbUpdated += intval($affected);
127
128 acym_enqueueMessage(acym_translationSprintf('ACYM_IMPORT_UPDATE', $nbUpdated), 'success');
129
130 $query = 'SELECT a.id FROM #__acym_user as a LEFT JOIN '.$acymCmsUserVars->table.' as b on a.cms_id = b.'.$acymCmsUserVars->id.' WHERE b.'.$acymCmsUserVars->id.' IS NULL AND a.cms_id > 0';
131 $deletedSubid = acym_loadResultArray($query);
132
133 $query = 'SELECT a.id FROM #__acym_user as a LEFT JOIN '.$acymCmsUserVars->table.' as b on a.email = b.'.$acymCmsUserVars->email.' WHERE b.'.$acymCmsUserVars->id.' IS NULL AND a.cms_id > 0';
134 $deletedSubid = array_merge(acym_loadResultArray($query), $deletedSubid);
135
136 if (!empty($deletedSubid)) {
137 $userClass = new UserClass();
138 $deletedUsers = $userClass->delete($deletedSubid);
139 acym_enqueueMessage(acym_translationSprintf('ACYM_IMPORT_DELETE', $deletedUsers), 'success');
140 }
141
142 $time = time();
143 $formattedTime = acym_date($time, 'Y-m-d H:i:s');
144 $sourceImport = 'Import on '.$formattedTime;
145 $query = 'INSERT IGNORE INTO #__acym_user (`name`,`email`,`creation_date`,`active`,`cms_id`, `source`) SELECT `user`.`'.$acymCmsUserVars->name.'`,`user`.`'.$acymCmsUserVars->email.'`,`user`.`'.$acymCmsUserVars->registered.'`,1 - `user`.'.$acymCmsUserVars->blocked.',`user`.`'.$acymCmsUserVars->id.'`,\''.$sourceImport.'\' FROM '.$acymCmsUserVars->table.' AS `user` ';
146 $groups = acym_getVar('array', 'groups', []);
147 $this->config->save(['import_groups' => implode(',', $groups)]);
148 if (!empty($groups)) {
149 if (ACYM_CMS === 'joomla') {
150 acym_arrayToInteger($groups);
151 $query .= ' JOIN #__user_usergroup_map AS `map` ON map.user_id = `user`.`'.$acymCmsUserVars->id.'` WHERE `map`.`group_id` IN ('.implode(', ', $groups).')';
152 } else {
153 $query .= ' JOIN #__usermeta AS `meta` ON meta.user_id = `user`.`'.$acymCmsUserVars->id.'` AND `meta`.`meta_key` = "#__capabilities"';
154 foreach ($groups as $i => $oneGroup) {
155 $groups[$i] = acym_escapeDB('%'.strlen($oneGroup).':"'.$oneGroup.'"%');
156 }
157 $query .= ' WHERE `meta`.`meta_value` LIKE '.implode(' OR `meta`.`meta_value` LIKE ', $groups);
158 }
159 }
160
161 $insertedUsers = acym_query($query);
162
163 acym_query('UPDATE #__acym_configuration SET `value` = '.intval($time).' WHERE `name` = \'last_import\'');
164
165 acym_trigger('onAcymAfterCMSUserImport', [$sourceImport]);
166
167 acym_enqueueMessage(acym_translationSprintf('ACYM_IMPORT_NEW_SUBS', $insertedUsers), 'info');
168
169 $lists = $this->getImportedLists();
170 $listsSubscribe = [];
171 if (!empty($lists)) {
172 foreach ($lists as $listid => $val) {
173 if (!empty($val)) {
174 $listsSubscribe[] = intval($listid);
175 }
176 }
177 }
178
179 if (empty($listsSubscribe)) {
180 return true;
181 }
182
183 $query = 'INSERT IGNORE INTO #__acym_user_has_list (`user_id`,`list_id`,`status`,`subscription_date`) ';
184 $query .= 'SELECT user.`id`, list.`id`, 1, '.acym_escapeDB(date('Y-m-d H:i:s', time() - date('Z'))).'
185 FROM #__acym_list AS list, #__acym_user AS user ';
186 $conditions = [];
187 $conditions[] = 'list.`id` IN ('.implode(',', $listsSubscribe).')';
188 $conditions[] = 'user.`cms_id` > 0';
189
190 if (!empty($groups)) {
191 if (ACYM_CMS === 'joomla') {
192 $query .= ' JOIN #__user_usergroup_map AS `map` ON map.user_id = `user`.`cms_id`';
193 $conditions[] = '`map`.`group_id` IN ('.implode(', ', $groups).')';
194 } else {
195 $query .= ' JOIN #__usermeta AS `meta` ON meta.user_id = `user`.`cms_id` AND `meta`.`meta_key` = "#__capabilities"';
196 $conditions[] = '`meta`.`meta_value` LIKE ('.implode(' OR `meta`.`meta_value` LIKE ', $groups).')';
197 }
198 }
199
200 $query .= ' WHERE '.implode(' AND ', $conditions);
201 $nbsubscribed = acym_query($query);
202 acym_enqueueMessage(acym_translationSprintf('ACYM_IMPORT_SUBSCRIPTION', $nbsubscribed));
203
204 return true;
205 }
206
207
208 public function database($onlyImport = false)
209 {
210 $this->forceconfirm = acym_getVar('int', 'import_confirmed_database');
211
212
213 $table = empty($this->tableName) ? trim(acym_getVar('string', 'tablename')) : $this->tableName;
214 $time = time();
215 $formattedTime = acym_date($time, 'Y-m-d H:i:s');
216
217 if (empty($table)) {
218 acym_enqueueMessage(acym_translation('ACYM_SPECIFYTABLE'), 'warning');
219
220 return false;
221 }
222
223 $fields = acym_getColumns($table, false, false);
224 if (empty($fields)) {
225 acym_enqueueMessage(acym_translation('ACYM_SPECIFYTABLE'), 'warning');
226
227 return false;
228 }
229
230 $equivalentFields = empty($this->fieldsMap) ? acym_getVar('array', 'fields', []) : $this->fieldsMap;
231
232 if (empty($equivalentFields['email'])) {
233 acym_enqueueMessage(acym_translation('ACYM_SPECIFYFIELDEMAIL'), 'warning');
234
235 return false;
236 }
237
238 $select = [];
239 foreach ($equivalentFields as $acyField => $tableField) {
240 $tableField = trim($tableField);
241 if (empty($tableField)) {
242 continue;
243 }
244 if (!in_array($tableField, $fields)) {
245 acym_enqueueMessage(acym_translationSprintf('ACYM_SPECIFYFIELD', $tableField, implode(' <br> ', $fields)), 'warning');
246
247 return false;
248 }
249 $select['`'.acym_secureDBColumn($acyField).'`'] = acym_secureDBColumn($tableField);
250 }
251
252 if (empty($select['`creation_date`'])) {
253 $select['`creation_date`'] = acym_escapeDB(acym_date('now', 'Y-m-d H:i:s'));
254 }
255
256 if ($this->forceconfirm && empty($select['`confirmed`'])) {
257 $select['`confirmed`'] = 1;
258 }
259
260 $sourceTxt = 'Import on '.$formattedTime;
261 $select['`source`'] = acym_escapeDB($sourceTxt);
262
263 $query = 'INSERT IGNORE INTO #__acym_user ('.implode(' , ', array_keys($select)).') SELECT '.implode(' , ', $select);
264 $query .= ' FROM '.acym_secureDBColumn($table).' WHERE '.acym_secureDBColumn($select['`email`']).' LIKE "%@%"';
265 if (!empty($this->dbWhere)) {
266 $query .= ' AND ( '.implode(' ) AND (', $this->dbWhere).' )';
267 }
268
269 $affectedRows = acym_query($query);
270
271 acym_query('UPDATE #__acym_configuration SET `value` = '.intval($time).' WHERE `name` = "last_import"');
272
273 acym_trigger('onAcymAfterDatabaseUserImport', [$sourceTxt]);
274
275 if ($onlyImport) return true;
276
277 acym_enqueueMessage(acym_translationSprintf('ACYM_IMPORT_NEW_SUBS', $affectedRows), 'info');
278
279
280 $lists = $this->getImportedLists();
281 $listsSubscribe = [];
282 if (!empty($lists)) {
283 foreach ($lists as $listid => $val) {
284 if (!empty($val)) {
285 $listsSubscribe[] = intval($listid);
286 }
287 }
288 }
289
290 if (empty($listsSubscribe)) {
291 return true;
292 }
293
294 $query = 'INSERT IGNORE INTO #__acym_user_has_list (`user_id`,`list_id`,`status`,`subscription_date`) ';
295 $query .= 'SELECT user.`id`, list.`id`, 1, '.acym_escapeDB(date('Y-m-d H:i:s', time() - date('Z'))).'
296 FROM #__acym_list AS list, #__acym_user AS user
297 WHERE list.`id` IN ('.implode(',', $listsSubscribe).')
298 AND user.`email` IN (SELECT '.acym_secureDBColumn($select['`email`']).' FROM '.acym_secureDBColumn($table).')';
299
300 $nbsubscribed = acym_query($query);
301 acym_enqueueMessage(acym_translationSprintf('ACYM_IMPORT_SUBSCRIPTION', $nbsubscribed));
302
303 return true;
304 }
305
306 public function mailpoet()
307 {
308 $time = time();
309 $formattedTime = acym_date($time, 'Y-m-d H:i:s');
310 $sourceImport = 'import_on_'.$formattedTime.'_mailpoet';
311
312 $query = 'INSERT IGNORE INTO #__acym_user (`name`,`email`,`creation_date`,`active`, `confirmed`,`cms_id`, `source`)
313 SELECT CONCAT(`subscriber`.`first_name`, `subscriber`.`last_name`),
314 `subscriber`.`email`,
315 `subscriber`.`created_at`,
316 IF(`subscriber`.`status` = "inactive", 0, 1),
317 IF(`subscriber`.`status` = "subscribed", 1, 0),
318 `subscriber`.`wp_user_id`,
319 \''.$sourceImport.'\'
320 FROM #__mailpoet_subscribers AS `subscriber` ';
321 $listsMailpoet = acym_getVar('array', 'mailpoet_lists', []);
322 if (!empty($listsMailpoet)) {
323 acym_arrayToInteger($listsMailpoet);
324 $query .= ' JOIN #__mailpoet_subscriber_segment AS sub_segment ON `subscriber`.`id` = `sub_segment`.`subscriber_id` AND `sub_segment`.`segment_id` IN ('.implode(
325 ',',
326 $listsMailpoet
327 ).')';
328 }
329 $query .= ' WHERE `subscriber`.`deleted_at` IS NULL ON DUPLICATE KEY UPDATE `source`='.acym_escapeDB($sourceImport);
330
331 $insertedUsers = acym_query($query);
332
333 acym_query('UPDATE #__acym_configuration SET `value` = '.intval($time).' WHERE `name` = \'last_import\'');
334
335 acym_enqueueMessage(acym_translationSprintf('ACYM_IMPORT_NEW_SUBS', $insertedUsers), 'info');
336
337 $lists = $this->getImportedLists();
338 $listsSubscribe = [];
339 if (!empty($lists)) {
340 foreach ($lists as $listid => $val) {
341 if (!empty($val)) {
342 $listsSubscribe[] = intval($listid);
343 }
344 }
345 }
346
347 if (empty($listsSubscribe)) {
348 return true;
349 }
350
351 $query = 'INSERT IGNORE INTO #__acym_user_has_list (`user_id`,`list_id`,`status`,`subscription_date`) ';
352 $query .= 'SELECT user.`id`, list.`id`, 1, '.acym_escapeDB(date('Y-m-d H:i:s', time() - date('Z'))).'
353 FROM #__acym_list AS list, #__acym_user AS user ';
354 $conditions = [];
355 $conditions[] = 'list.`id` IN ('.implode(',', $listsSubscribe).')';
356 $conditions[] = 'user.`source` = '.acym_escapeDB($sourceImport);
357
358 if (!empty($listsMailpoet)) {
359 $query .= ' JOIN #__mailpoet_subscribers AS subscriber ON subscriber.email = user.email';
360 $query .= ' JOIN #__mailpoet_subscriber_segment AS subscriber_segment ON subscriber.id = subscriber_segment.subscriber_id AND subscriber_segment.segment_id IN ('.implode(
361 ',',
362 $listsMailpoet
363 ).')';
364 }
365
366 $query .= ' WHERE '.implode(' AND ', $conditions);
367 $nbsubscribed = acym_query($query);
368 acym_enqueueMessage(acym_translationSprintf('ACYM_IMPORT_SUBSCRIPTION', $nbsubscribed));
369
370 return true;
371 }
372
373 private function _createUploadFolder()
374 {
375 $folderPath = acym_cleanPath(ACYM_ROOT.trim(html_entity_decode(ACYM_MEDIA_FOLDER.'import'))).DS;
376 if ('wordpress' === ACYM_CMS) {
377 $folderPath = acym_cleanPath(WP_PLUGIN_DIR.DS.ACYM_COMPONENT.DS.'media'.DS.'import').DS;
378 }
379 if (!is_dir($folderPath)) {
380 acym_createDir($folderPath, true, true);
381 }
382
383 if (!is_writable($folderPath)) {
384 @chmod($folderPath, '0755');
385 if (!is_writable($folderPath)) {
386 acym_enqueueMessage(acym_translationSprintf('ACYM_WRITABLE_FOLDER', $folderPath), 'warning');
387 }
388 }
389
390 return $folderPath;
391 }
392
393 public function finalizeImport()
394 {
395 $filename = strtolower(acym_getVar('cmd', 'acym_import_filename'));
396 $extension = '.'.acym_fileGetExt($filename);
397 $this->forceconfirm = acym_getVar('int', 'import_confirmed_generic', 1);
398 $this->generatename = acym_getVar('int', 'import_generate_generic', 1);
399 $this->overwrite = acym_getVar('int', 'import_overwrite_generic', 1);
400
401 $newConfig = new \stdClass();
402 $newConfig->import_confirmed = $this->forceconfirm;
403 $newConfig->import_generate = $this->generatename;
404 $newConfig->import_overwrite = $this->overwrite;
405 $this->config->save($newConfig);
406
407 $filename = str_replace(['.', ' '], '_', substr($filename, 0, strpos($filename, $extension))).$extension;
408 $uploadPath = ACYM_MEDIA.'import'.DS.$filename;
409
410 if (!file_exists($uploadPath) || !is_file($uploadPath)) {
411 acym_enqueueMessage(acym_translation('ACYM_UPLOADED_FILE_NOT_FOUND').' '.$uploadPath, 'error');
412
413 return false;
414 }
415
416 $importColumns = acym_getVar('string', 'import_columns');
417 if (empty($importColumns)) {
418 acym_enqueueMessage(acym_translation('ACYM_COLUMNS_NOT_FOUND'), 'error');
419
420 return false;
421 }
422
423 $contentFile = file_get_contents($uploadPath);
424
425 if (acym_getVar('cmd', 'acyencoding', '') != '') {
426 $encodingHelper = new EncodingHelper();
427 $contentFile = $encodingHelper->change($contentFile, acym_getVar('cmd', 'acyencoding'), 'UTF-8');
428 }
429
430 $cutContent = str_replace(["\r\n", "\r"], "\n", $contentFile);
431 $allLines = explode("\n", $cutContent);
432
433 $listSeparators = ["\t", ';', ','];
434 $separator = ',';
435 foreach ($listSeparators as $sep) {
436 if (strpos($allLines[0], $sep) !== false) {
437 $separator = $sep;
438 break;
439 }
440 }
441
442 if (!empty($listsId)) {
443 $allLines[0] .= $sep;
444 }
445
446 $importColumns = str_replace(',', $separator, $importColumns);
447
448 if (strpos($allLines[0], '@')) {
449 $contentFile = $importColumns."\n".$contentFile;
450 } else {
451 $allLines[0] = $importColumns;
452 $contentFile = implode("\n", $allLines);
453 }
454
455 $this->_handleContent($contentFile);
456
457 unlink($uploadPath);
458 $this->_cleanImportFolder();
459 }
460
461 public function _handleContent(&$contentFile)
462 {
463 $success = true;
464 $timestamp = time();
465
466 $contentFile = str_replace(["\r\n", "\r"], "\n", $contentFile);
467 $importLines = explode("\n", $contentFile);
468
469 $i = 0;
470 $this->header = '';
471 $this->allSubid = [];
472 while (empty($this->header) && $i < 10) {
473 $this->header = trim($importLines[$i]);
474 $i++;
475 }
476
477 if (strpos($this->header, '@') && !strpos($this->header, ',') && !strpos($this->header, ';') && !strpos($this->header, "\t")) {
478 $this->header = 'email';
479 $i--;
480 }
481
482 if (!$this->_autoDetectHeader()) {
483 acym_enqueueMessage(acym_translationSprintf('ACYM_IMPORT_HEADER', acym_escape($this->header)), 'error');
484 acym_enqueueMessage(acym_translation('ACYM_IMPORT_EMAIL'), 'error');
485
486 return false;
487 }
488
489 $numberColumns = count($this->columns);
490
491 $encodingHelper = new EncodingHelper();
492
493 $importUsers = [];
494
495 $errorLines = [];
496
497 $errorMessageInvalidEmails = "";
498
499 $userClass = new UserClass();
500
501 $countUsersBeforeImport = $userClass->getCountTotalUsers();
502
503 $listClass = new ListClass();
504 $allLists = $listClass->getAll('name');
505
506 while (isset($importLines[$i])) {
507 if (strpos($importLines[$i], '"') !== false) {
508 $data = [];
509 $j = $i + 1;
510 $position = -1;
511
512 while ($j < ($i + 30)) {
513
514 $quoteOpened = substr($importLines[$i], $position + 1, 1) == '"';
515
516 if ($quoteOpened) {
517 $nextQuotePosition = strpos($importLines[$i], '"', $position + 2);
518 while ($nextQuotePosition !== false && $nextQuotePosition + 1 != strlen($importLines[$i]) && substr(
519 $importLines[$i],
520 $nextQuotePosition + 1,
521 1
522 ) != $this->separator) {
523 $nextQuotePosition = strpos($importLines[$i], '"', $nextQuotePosition + 1);
524 }
525 if ($nextQuotePosition === false) {
526 if (!isset($importLines[$j])) {
527 break;
528 }
529
530 $importLines[$i] .= "\n".$importLines[$j];
531 $importLines[$i] = rtrim($importLines[$i], $this->separator);
532 unset($importLines[$j]);
533 $j++;
534 continue;
535 } else {
536
537 if (strlen($importLines[$i]) - 1 == $nextQuotePosition) {
538 $data[] = substr($importLines[$i], $position + 1);
539 break;
540 }
541 $data[] = substr($importLines[$i], $position + 1, $nextQuotePosition + 1 - ($position + 1));
542 $position = $nextQuotePosition + 1;
543 }
544 } else {
545 $nextSeparatorPosition = strpos($importLines[$i], $this->separator, $position + 1);
546 if ($nextSeparatorPosition === false) {
547 $data[] = substr($importLines[$i], $position + 1);
548 break;
549 } else { // If found the next separator, add the value in $data and change the position
550 $data[] = substr($importLines[$i], $position + 1, $nextSeparatorPosition - ($position + 1));
551 $position = $nextSeparatorPosition;
552 }
553 }
554 }
555
556 $importLines = array_merge($importLines);
557 } else {
558 $data = explode($this->separator, rtrim(trim($importLines[$i]), $this->separator));
559 }
560
561 if (!empty($this->removeSep)) {
562 for ($b = $numberColumns + $this->removeSep - 1 ; $b >= $numberColumns ; $b--) {
563 if (isset($data[$b]) && (strlen($data[$b]) == 0 || $data[$b] == ' ')) {
564 unset($data[$b]);
565 }
566 }
567 }
568
569 $i++;
570 if (empty($importLines[$i - 1])) {
571 continue;
572 }
573
574 $this->totalTry++;
575 if (count($data) > $numberColumns) {
576 $copy = $data;
577 foreach ($copy as $oneelem => $oneval) {
578 if (!empty($oneval[0]) && $oneval[0] == '"' && $oneval[strlen($oneval) - 1] != '"' && isset($copy[$oneelem + 1]) && $copy[$oneelem + 1][strlen(
579 $copy[$oneelem + 1]
580 ) - 1] == '"') {
581 $data[$oneelem] = $copy[$oneelem].$this->separator.$copy[$oneelem + 1];
582 unset($data[$oneelem + 1]);
583 }
584 }
585 $data = array_values($data);
586 }
587
588 if (count($data) < $numberColumns) {
589 for ($a = count($data) ; $a < $numberColumns ; $a++) {
590 $data[$a] = '';
591 }
592 }
593
594 if (count($data) != $numberColumns) {
595 $success = false;
596 static $errorcount = 0;
597 if (empty($errorcount)) {
598 acym_enqueueMessage(acym_translationSprintf('ACYM_IMPORT_ARGUMENTS', $numberColumns), 'warning');
599 }
600 $errorcount++;
601
602 if ($this->totalTry == 1) {
603 return false;
604 }
605 if (empty($errorLines)) {
606 $errorLines[] = 'error,'.$importLines[0];
607 }
608 $errorLines[] = acym_translation('ACYM_IMPORT_ERROR_WRONG_NUMBER_ARGUMENTS').','.$importLines[$i - 1];
609 continue;
610 }
611
612 $newUser = new \stdClass();
613 $newUser->customfields = [];
614
615 $emailKey = array_search('email', $this->columns);
616 $newUser->email = trim(strip_tags($data[$emailKey]), '\'" ');
617 $newUser->email = preg_replace("/\s+/u", '', $newUser->email);
618 if (!empty($newUser->email)) {
619 $newUser->email = acym_punycode($newUser->email);
620 }
621 $newUser->email = trim(str_replace([' ', "\t"], '', $encodingHelper->change($newUser->email, 'UTF-8', 'ISO-8859-1')));
622
623
624 if (!acym_isValidEmail($newUser->email)) {
625 $success = false;
626 static $errorcountfail = 0;
627 if ($errorcountfail == 0) {
628 acym_enqueueMessage(acym_translation('ACYM_ADDRESSES_INVALID'), 'warning');
629 }
630 $errorcountfail++;
631 if (empty($errorLines)) {
632 $errorLines[] = 'error,'.$importLines[0];
633 }
634 $errorLines[] = acym_translation('ACYM_INVALID_EMAIL_ADDRESS').','.$importLines[$i - 1];
635 continue;
636 }
637
638 foreach ($data as $num => $value) {
639 if ($num == $emailKey) continue;
640
641 $field = $this->columns[$num];
642
643 if ($field == 1) continue;
644
645 if ($field == 'listids') {
646 $liststosub = explode('-', trim($value, '\'" '));
647 foreach ($liststosub as $onelistid) {
648 $this->importUserInLists[intval(trim($onelistid))][] = acym_escapeDB($newUser->email);
649 }
650 continue;
651 }
652
653 if ($field == 'listname') {
654 $liststosub = explode('-', trim($value, '\'" '));
655 foreach ($liststosub as $onelistName) {
656 if (empty($onelistName)) {
657 continue;
658 }
659 $onelistName = trim($onelistName);
660 if (empty($allLists[$onelistName])) {
661 $newList = new \stdClass();
662 $newList->name = $onelistName;
663 $newList->active = 1;
664 $colors = ['#3366ff', '#7240A4', '#7A157D', '#157D69', '#ECE649'];
665 $newList->color = $colors[rand(0, count($colors) - 1)];
666 $listid = $listClass->save($newList);
667 $newList->id = $listid;
668 $allLists[$onelistName] = $newList;
669 }
670 $this->importUserInLists[intval($allLists[$onelistName]->id)][] = acym_escapeDB($newUser->email);
671 }
672 continue;
673 }
674
675 if (strpos($field, 'cf_') === 0) {
676 $newUser->customfields[substr($field, 3)] = trim(strip_tags($value), '\'" ');
677 continue;
678 }
679
680 if ($value == 'null') {
681 $newUser->$field = '';
682 } else {
683 $newUser->$field = trim(strip_tags($value), '\'" ');
684 }
685 }
686
687 if (acym_isMultilingual() && empty($newUser->language)) {
688 $newUser->language = $this->config->get('multilingual_default', '');
689 }
690
691 $importUsers[] = $newUser;
692 $this->totalValid++;
693
694 if ($this->totalValid % 50 == 0) {
695 $this->_insertUsers($importUsers, $timestamp);
696 $importUsers = [];
697 }
698 }
699
700 if (!empty($errorLines)) {
701 $filename = strtolower(acym_getVar('cmd', 'acym_import_filename', ''));
702 if (!empty($filename)) {
703 $extension = '.'.acym_fileGetExt($filename);
704 $filename = str_replace(['.', ' '], '_', substr($filename, 0, strpos($filename, $extension))).$extension;
705 $errorFile = implode("\n", $errorLines);
706 acym_writeFile(ACYM_MEDIA.'import'.DS.'error_'.$filename, $errorFile);
707 acym_enqueueMessage(
708 '<a target="_blank" href="'.acym_prepareAjaxURL((acym_isAdmin() ? '' : 'front').'users&task=downloadImport').'&filename=error_'.preg_replace(
709 '#\.[^.]*$#',
710 '',
711 $filename
712 ).'&'.acym_noTemplate().'" >'.acym_translation('ACYM_DOWNLOAD_IMPORT_ERRORS').'</a>',
713 'notice'
714 );
715 }
716 }
717
718 $this->_insertUsers($importUsers, $timestamp);
719
720 acym_query('UPDATE #__acym_configuration SET `value` = '.intval($timestamp).' WHERE `name` = \'last_import\'');
721
722 acym_query('DELETE FROM #__acym_user_has_field WHERE `value` = ""');
723
724 $countUsersAfterImport = $userClass->getCountTotalUsers();
725 $this->totalInserted = $countUsersAfterImport - $countUsersBeforeImport;
726
727 if ($this->dispresults) {
728 $maybeUpdated = acym_translation('ACYM_NOT_UPDATED');
729 if ($this->overwrite) {
730 $maybeUpdated = acym_translation('ACYM_UPDATED');
731 }
732 $reportMsg = acym_translationSprintf(
733 'ACYM_IMPORT_REPORTING_UPDATED',
734 $this->totalTry,
735 $this->totalInserted,
736 $this->totalTry - $this->totalValid,
737 $this->totalValid - $this->totalInserted,
738 $maybeUpdated
739 );
740 acym_enqueueMessage($reportMsg, 'info');
741 }
742
743 $this->_subscribeUsers();
744
745 return $success;
746 }
747
748 public function _insertUsers($users, $timestamp)
749 {
750 if (empty($users)) return true;
751
752 $importedCols = array_keys(get_object_vars($users[0]));
753 unset($importedCols[array_search('customfields', $importedCols)]);
754 if ($this->forceconfirm) $importedCols[] = 'confirmed';
755
756 foreach ($users as $a => $oneUser) {
757 $this->_checkData($users[$a], $timestamp);
758 }
759
760 $columns = reset($users);
761 $colNames = array_keys(get_object_vars($columns));
762 unset($colNames[array_search('customfields', $colNames)]);
763
764 if (!in_array('key', $colNames)) $colNames[] = 'key';
765
766 foreach ($colNames as $oneColumn) {
767 acym_secureDBColumn($oneColumn);
768 }
769
770 $queryInsertUsers = 'INSERT'.($this->overwrite ? '' : ' IGNORE').' INTO #__acym_user (`'.implode('`,`', $colNames).'`) VALUES (';
771 $values = [];
772 $customFieldsvalues = [];
773 $allemails = [];
774 foreach ($users as $oneUser) {
775 $value = [];
776 acym_trigger('onAcymBeforeUserImport', [&$oneUser]);
777
778 foreach ($oneUser as $map => $oneValue) {
779 if ($map === 'customfields') continue;
780
781 $oneValue = htmlspecialchars_decode($oneValue, ENT_QUOTES);
782
783 if ($map === 'active' && $this->importblocked) {
784 $value[] = 0;
785 } else {
786 if ($map !== 'id') {
787 $oneValue = acym_escapeDB($oneValue);
788 if ($map === 'email') $allemails[] = $oneValue;
789 } else {
790 $oneValue = intval($oneValue);
791 }
792
793 $value[] = $oneValue;
794 }
795 }
796
797 if (!isset($oneUser->key)) $value[] = acym_escapeDB(acym_generateKey(14));
798 $values[] = implode(',', $value);
799
800 if (!empty($oneUser->customfields)) $customFieldsvalues[$oneUser->email] = $oneUser->customfields;
801 }
802 acym_trigger('onAcymUserImport', [&$users]);
803
804 $queryInsertUsers .= implode('),(', $values).')';
805
806 if ($this->overwrite) {
807 $queryInsertUsers .= ' ON DUPLICATE KEY UPDATE ';
808 foreach ($importedCols as &$oneColumn) {
809 acym_secureDBColumn($oneColumn);
810 if ($oneColumn == 'key') {
811 $oneColumn = '`'.$oneColumn.'` = `'.$oneColumn.'`';
812 } else {
813 $oneColumn = '`'.$oneColumn.'` = VALUES(`'.$oneColumn.'`)';
814 }
815 }
816 $queryInsertUsers .= implode(',', $importedCols);
817 }
818
819 acym_query($queryInsertUsers);
820
821 $importedUsers = acym_loadObjectList('SELECT id, email FROM #__acym_user WHERE email IN ('.implode(',', $allemails).')', 'id');
822
823 if (!empty($customFieldsvalues)) {
824 $insertValues = [];
825 foreach ($importedUsers as $one) {
826 if (empty($customFieldsvalues[$one->email])) continue;
827
828 foreach ($customFieldsvalues[$one->email] as $fieldId => $value) {
829 $value = htmlspecialchars_decode($value, ENT_QUOTES);
830 $insertValues[] = '('.intval($one->id).','.intval($fieldId).','.acym_escapeDB($value).')';
831 }
832 }
833
834 if (!empty($insertValues)) {
835 $queryInsertCustomFields = 'INSERT'.($this->overwrite ? '' : ' IGNORE').' INTO #__acym_user_has_field (`user_id`, `field_id`, `value`) VALUES '.implode(
836 ',',
837 $insertValues
838 );
839 if ($this->overwrite) {
840 $queryInsertCustomFields .= ' ON DUPLICATE KEY UPDATE `value` = VALUES(`value`)';
841 }
842 acym_query($queryInsertCustomFields);
843 }
844 }
845
846
847 $this->allSubid = array_merge($this->allSubid, array_keys($importedUsers));
848
849 return true;
850 }
851
852 public function _checkData(&$user, $timestamp)
853 {
854 if (empty($user->creation_date)) {
855 $user->creation_date = time();
856 }
857
858 if (is_numeric($user->creation_date)) {
859 $user->creation_date = date('Y-m-d H:i:s', $user->creation_date);
860 }
861
862 if (!isset($user->active) || strlen($user->active) == 0) {
863 $user->active = 1;
864 }
865
866 if ((!isset($user->confirmed) || strlen($user->confirmed) == 0) && $this->forceconfirm) {
867 $user->confirmed = 1;
868 }
869
870 if (empty($user->source)) {
871 $user->source = 'Import on '.acym_date($timestamp, 'Y-m-d H:i:s');
872 }
873
874 if (empty($user->name) && $this->generatename) {
875 $user->name = ucwords(trim(str_replace(['.', '_', '-', 1, 2, 3, 4, 5, 6, 7, 8, 9, 0], ' ', substr($user->email, 0, strpos($user->email, '@')))));
876 }
877 }
878
879 public function _autoDetectHeader()
880 {
881 $this->separator = ',';
882
883 $this->header = str_replace("\xEF\xBB\xBF", "", $this->header);
884
885 $listSeparators = ["\t", ';', ','];
886 foreach ($listSeparators as $sep) {
887 if (strpos($this->header, $sep) !== false) {
888 $this->separator = $sep;
889 break;
890 }
891 }
892
893
894 $this->columns = explode($this->separator, $this->header);
895
896 for ($i = count($this->columns) - 1 ; $i >= 0 ; $i--) {
897 if (strlen($this->columns[$i]) == 0) {
898 unset($this->columns[$i]);
899 $this->removeSep++;
900 }
901 }
902
903 $columns = acym_getColumns('user');
904 foreach ($columns as $i => $oneColumn) {
905 $columns[$i] = strtolower($oneColumn);
906 }
907
908 foreach ($this->columns as $i => $oneColumn) {
909 $this->columns[$i] = strtolower(trim($oneColumn, '\'" '));
910 if (in_array($this->columns[$i], ['listids', 'listname'])) continue;
911 if (strpos($this->columns[$i], 'cf_') === 0) continue;
912
913 if (!in_array($this->columns[$i], $columns) && $this->columns[$i] != 1) {
914 acym_enqueueMessage(
915 acym_translationSprintf(
916 'ACYM_IMPORT_ERROR_FIELD',
917 '<b>'.acym_escape($this->columns[$i]).'</b>',
918 '<b>'.implode('</b> | <b>', array_diff($columns, ['id', 'cms_id'])).'</b>'
919 ),
920 'error'
921 );
922
923 return false;
924 }
925 }
926
927 if (!in_array('email', $this->columns)) {
928 return false;
929 }
930
931 return true;
932 }
933
934 public function _cleanImportFolder()
935 {
936
937 $files = acym_getFiles(ACYM_MEDIA.'import', '.', false, true, []);
938 foreach ($files as $oneFile) {
939 if (acym_fileGetExt($oneFile) != 'csv') {
940 continue;
941 }
942 if (filectime($oneFile) < time() - 86400) {
943 unlink($oneFile);
944 }
945 }
946 }
947
948 public function getImportedLists()
949 {
950 $listClass = new ListClass();
951 $listsId = json_decode(acym_getVar('string', 'acym__entity_select__selected'));
952 $newListName = acym_getVar('string', 'new_list');
953
954 if (empty($listsId) && empty($newListName)) {
955 return false;
956 }
957
958 $lists = [];
959
960 if (!empty($newListName)) {
961 $newList = new \stdClass();
962 $newList->name = $newListName;
963 $newList->active = 1;
964 $colors = '#'.substr(str_shuffle('ABCDEF0123456789'), 0, 6);
965 $newList->color = $colors;
966 $listid = $listClass->save($newList);
967 $lists[$listid] = 1;
968 }
969
970 if (!empty($listsId)) {
971 foreach ($listsId as $id) {
972 $lists[$id] = 1;
973 }
974 }
975
976 if (!empty($lists)) {
977 return $lists;
978 } else {
979 return false;
980 }
981 }
982
983 public function _subscribeUsers()
984 {
985 if (empty($this->allSubid)) return true;
986
987 $subdate = date('Y-m-d H:i:s', time() - date('Z'));
988
989 $listClass = new ListClass();
990 $lists = $this->getImportedLists();
991
992 if (!acym_isAdmin() && 'joomla' === ACYM_CMS) {
993 $listClass = new ListClass();
994 $listManagementId = $listClass->getfrontManagementList();
995 if (empty($listManagementId)) {
996 acym_redirect(acym_rootURI(), 'ACYM_UNABLE_TO_CREATE_MANAGEMENT_LIST', 'error');
997 }
998
999 if (empty($lists)) {
1000 $lists = [$listManagementId => 1];
1001 } else {
1002 $lists[$listManagementId] = 1;
1003 }
1004 }
1005
1006 if (!empty($this->importUserInLists)) {
1007 foreach ($this->importUserInLists as $listid => $arrayEmails) {
1008 if (empty($listid)) continue;
1009
1010 $listid = (int)$listid;
1011 $query = 'INSERT IGNORE INTO #__acym_user_has_list (`list_id`,`user_id`,`subscription_date`,`status`) ';
1012 $query .= 'SELECT '.intval($listid).',`id`,'.acym_escapeDB($subdate).',1 FROM #__acym_user WHERE `email` IN (';
1013 $query .= implode(',', $arrayEmails).')';
1014 $nbsubscribed = acym_query($query);
1015 $nbsubscribed = intval($nbsubscribed);
1016
1017 if (isset($this->subscribedUsers[$listid])) {
1018 $this->subscribedUsers[$listid]->nbusers += $nbsubscribed;
1019 } else {
1020 $myList = $listClass->getOneById($listid);
1021 $this->subscribedUsers[$listid] = $myList;
1022 $this->subscribedUsers[$listid]->nbusers = $nbsubscribed;
1023 }
1024 }
1025 }
1026
1027 if (!empty($lists)) {
1028
1029 foreach ($lists as $listid => $val) {
1030 if (empty($val)) {
1031 continue;
1032 }
1033
1034 if ($val == -1) {
1035 $dateColumn = 'unsubscribe_date';
1036 $status = -1;
1037 } else {
1038 $dateColumn = 'subscription_date';
1039 $status = 1;
1040 }
1041
1042 $nbsubscribed = 0;
1043 $listid = intval($listid);
1044 $query = 'INSERT IGNORE INTO #__acym_user_has_list (`list_id`,`user_id`,`'.$dateColumn.'`,`status`) VALUES ';
1045 $b = 0;
1046 $currentSubids = [];
1047 foreach ($this->allSubid as $subid) {
1048 $subid = intval($subid);
1049 $currentSubids[] = $subid;
1050 $b++;
1051
1052 if ($b > 200) {
1053 $query = rtrim($query, ',');
1054 if ($val == -1) {
1055 $query .= ' ON DUPLICATE KEY UPDATE status = -1';
1056 $nbsubscribed = -acym_loadResult(
1057 'SELECT COUNT(*) FROM #__acym_listsub WHERE `list_id` = '.intval($listid).' AND status != -1 AND `user_id` IN ('.implode(',', $currentSubids).')'
1058 );
1059 }
1060 $affected = acym_query($query);
1061 $nbsubscribed += intval($affected);
1062 $b = 0;
1063 $currentSubids = [];
1064 $query = 'INSERT IGNORE INTO #__acym_user_has_list (`list_id`,`user_id`,`'.$dateColumn.'`,`status`) VALUES ';
1065 }
1066
1067 $query .= '('.intval($listid).','.intval($subid).','.acym_escapeDB($subdate).','.$status.'),';
1068 }
1069 $query = rtrim($query, ',');
1070 if ($val == -1) {
1071 $query .= ' ON DUPLICATE KEY UPDATE status = -1';
1072 if (!empty($currentSubids)) {
1073 $nbsubscribed = -acym_loadResult(
1074 'SELECT COUNT(*) FROM #__acym_listsub WHERE `list_id` = '.intval($listid).' AND status != -1 AND `user_id` IN ('.implode(',', $currentSubids).')'
1075 );
1076 }
1077 }
1078
1079 $affected = acym_query($query);
1080 $nbsubscribed += intval($affected);
1081
1082 if (isset($this->subscribedUsers[$listid])) {
1083 $this->subscribedUsers[$listid]->nbusers += $nbsubscribed;
1084 } else {
1085 $myList = $listClass->getOneById($listid);
1086 $myList->status = $val;
1087 $this->subscribedUsers[$listid] = $myList;
1088 $this->subscribedUsers[$listid]->nbusers = $nbsubscribed;
1089 }
1090 }
1091 }
1092
1093 return true;
1094 }
1095
1096 public function additionalDataUsersImport($isGeneric)
1097 {
1098 $buttonAddListId = $isGeneric ? 'acym__users__generic__import__create-list__button' : 'acym__users__import__create-list__button';
1099 $buttonImportClass = $isGeneric ? 'acym__users__import__generic__import__button' : 'acym__users__import__button';
1100 $buttonSkipId = $isGeneric ? 'acym__users__generic__import__skip__button' : 'acym__users__import__skip__button';
1101 $buttonImportDataTask = $isGeneric ? 'listing' : '';
1102
1103 return '<div class="cell align-right grid-x margin-bottom-2">
1104 <div id="acym__users__import__create-list" class="grid-x" style="display: none;">
1105 <label for="acym__users__import__create-list__field" class="margin-right-1 acym_vcenter">'.acym_translation('ACYM_LIST_NAME').' : </label>
1106 <div>
1107 <input id="acym__users__import__create-list__field" type="text">
1108 </div>
1109 </div>
1110 <button type="button" class="button button-secondary margin-left-1 acym_vcenter margin-right-2" id="'.$buttonAddListId.'">'.acym_translation(
1111 'ACYM_CREATE_NEW_LIST'
1112 ).'</button>
1113 <i style="display: none;" class="acym_vcenter acymicon-circle-o-notch acymicon-spin" id="acym__users__import__create-list__loading-logo"></i>
1114 </div>
1115 <div class="cell align-right grid-x">
1116 <button type="button" class="button-secondary button cell shrink margin-right-1" id="'.$buttonSkipId.'">'.acym_translation('ACYM_SKIP').'</button>
1117 <button
1118 type="button"
1119 class="button-primary button acy_button_submit cell shrink margin-right-2 '.$buttonImportClass.'"
1120 id="acym__entity_select__button__submit" data-task="'.$buttonImportDataTask.'">'.acym_translation('ACYM_SUBSCRIBE_USERS_TO_THESE_LISTS').'</button>
1121 </div>';
1122 }
1123 }
1124