PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.1.1
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.1.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
← All changes | back/Helpers/ExportHelper.php +0 -574 10.2.2 → 11.1.1 View file →
@@ -1,574 +1,0 @@
1 -<?php
2 -
3 -namespace AcyMailing\Helpers;
4 -
5 -use AcyMailing\Classes\ListClass;
6 -use AcyMailing\Classes\MailClass;
7 -use AcyMailing\Core\AcymObject;
8 -
9 -class ExportHelper extends AcymObject
10 -{
11 - private string $eol = "\r\n";
12 - private string $before = '"';
13 - private string $after = '"';
14 -
15 - public function setDownloadHeaders(string $filename = 'export', string $extension = 'csv'): void
16 - {
17 - acym_header('Pragma: public');
18 - acym_header('Expires: 0');
19 - acym_header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
20 -
21 - acym_header('Content-Type: application/force-download');
22 - acym_header('Content-Type: application/octet-stream');
23 - acym_header('Content-Type: application/download');
24 -
25 - acym_header('Content-Disposition: attachment; filename='.$filename.'.'.$extension);
26 - acym_header('Content-Transfer-Encoding: binary');
27 - }
28 -
29 - public function exportTemplate(object $template): void
30 - {
31 - $name = preg_replace('#[^a-z0-9]#Uis', '_', $template->name);
32 - $name = preg_replace('#_+#s', '_', $name);
33 - $exportFolder = ACYM_ROOT.ACYM_MEDIA_FOLDER.'tmp'.DS.$name;
34 - acym_createFolder($exportFolder);
35 -
36 - $template->body = acym_absoluteURL($template->body);
37 - $images = [];
38 - preg_match_all('#<img[^>]* src="([^"]+)"#Uis', $template->body, $images);
39 -
40 - if (!empty($images[1])) {
41 - $imagesFolder = $exportFolder.DS.'images';
42 - acym_createFolder($imagesFolder);
43 -
44 - $replace = [];
45 - foreach ($images[1] as $oneImage) {
46 - if (isset($replace[$oneImage])) continue;
47 -
48 - $location = str_replace(
49 - [ACYM_LIVE, '/'],
50 - [ACYM_ROOT, DS],
51 - $oneImage
52 - );
53 - if (strpos($location, 'http') === 0) continue;
54 -
55 - if (!file_exists($location)) continue;
56 -
57 - $filename = basename($location);
58 - while (file_exists($imagesFolder.DS.$filename)) {
59 - $filename = rand(0, 99).$filename;
60 - }
61 -
62 - acym_copyFile($location, $imagesFolder.DS.$filename);
63 - $replace[$oneImage] = 'images/'.$filename;
64 - }
65 -
66 - $template->body = str_replace(array_keys($replace), $replace, $template->body);
67 - }
68 -
69 - $structure = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
70 -<html xmlns="http://www.w3.org/1999/xhtml">
71 -<head>
72 -<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
73 -
74 - $dataToCopy = [
75 - 'fromname',
76 - 'fromemail',
77 - 'replyname',
78 - 'replyemail',
79 - 'subject',
80 - 'settings',
81 - ];
82 - foreach ($dataToCopy as $oneData) {
83 - if (empty($template->$oneData)) continue;
84 - $structure .= "\n".'<meta name="'.$oneData.'" content="'.acym_escape($template->$oneData).'" />';
85 - }
86 -
87 - $structure .= "\n".'<title>'.$template->name.'</title>
88 -</head>
89 -<body>
90 -'.$template->body.'
91 -</body>
92 -</html>';
93 -
94 - acym_writeFile($exportFolder.DS.'template.html', $structure);
95 -
96 - $thumbnail = acym_getMailThumbnail($template->thumbnail);
97 - $thumbnail = str_replace(ACYM_LIVE, ACYM_ROOT, $thumbnail);
98 - acym_copyFile($thumbnail, $exportFolder.DS.'thumbnail.png');
99 -
100 - if (!empty($template->stylesheet)) {
101 - acym_createFolder($exportFolder.DS.'css');
102 - acym_writeFile($exportFolder.DS.'css'.DS.'custom.css', $template->stylesheet);
103 - }
104 -
105 - $zipFiles = [];
106 - $folders = acym_getFolders($exportFolder, '.', true, true);
107 - array_push($folders, $exportFolder);
108 - foreach ($folders as $folder) {
109 - $files = acym_getFiles($folder, '.', false, true);
110 - foreach ($files as $file) {
111 - $posSlash = strrpos($file, '/');
112 - $posASlash = strrpos($file, '\\');
113 - $pos = ($posSlash < $posASlash) ? $posASlash : $posSlash;
114 - if (!empty($pos)) $file = substr_replace($file, DS, $pos, 1);
115 -
116 - $data = acym_fileGetContent($file);
117 - $zipFiles[] = [
118 - 'name' => str_replace(
119 - $exportFolder.DS,
120 - '',
121 - $file
122 - ),
123 - 'data' => $data,
124 - ];
125 - }
126 - }
127 -
128 - acym_createArchive($exportFolder, $zipFiles);
129 -
130 - acym_deleteFolder($exportFolder);
131 -
132 - $this->setDownloadHeaders($name, 'zip');
133 - echo acym_fileGetContent($exportFolder.'.zip');
134 - acym_deleteFile($exportFolder.'.zip');
135 -
136 - exit;
137 - }
138 -
139 - public function exportStatsFormattedCSV(string $mailName, array $globalDonutsData, array $globaline, string $timeLinechart): void
140 - {
141 - $nbExport = $this->getExportLimit();
142 - acym_displayErrors();
143 -
144 - if ($timeLinechart === 'month') {
145 - $timeLinechart = acym_translation('ACYM_MONTHLY_STATS');
146 - } elseif ($timeLinechart === 'week') {
147 - $timeLinechart = acym_translation('ACYM_WEEKLY_STATS');
148 - } else {
149 - $timeLinechart = acym_translation('ACYM_DAILY_STATS');
150 - }
151 -
152 - $separator = '","';
153 -
154 - $csvLines = [];
155 - $csvLines[] = $this->before.$mailName.$this->after;
156 -
157 - $csvLines[] = $this->eol;
158 -
159 - $globalDonutsTitle = [
160 - acym_translation('ACYM_SUCCESSFULLY_SENT'),
161 - acym_translation('ACYM_OPEN_RATE'),
162 - acym_translation('ACYM_CLICK_RATE'),
163 - acym_translation('ACYM_BOUNCE_RATE'),
164 - acym_translation('ACYM_UNSUBSCRIBE_RATE'),
165 - ];
166 -
167 - $csvLines[] = $this->before.implode($separator, $globalDonutsTitle).$this->after;
168 - $csvLines[] = $this->before.implode($separator, $globalDonutsData).$this->after;
169 -
170 - $csvLines[] = $this->eol;
171 -
172 - $csvLines[] = $this->before.$timeLinechart.$separator.acym_translation('ACYM_OPEN').$separator.acym_translation('ACYM_CLICK').$this->after;
173 -
174 - $i = 0;
175 - foreach ($globaline as $date => $value) {
176 - if ($i > $nbExport) break;
177 - $csvLines[] = $this->before.$date.$separator.$value['open'].$separator.$value['click'].$this->after;
178 - $i++;
179 - }
180 -
181 - $this->finishStatsExport($csvLines);
182 - }
183 -
184 - public function exportStatsFullCSV(string $query, array $columns, string $type = 'global'): void
185 - {
186 - $mailsStats = acym_loadObjectList($query);
187 - $mailClass = new MailClass();
188 - $mailClass->exceptKeysDecode = ['name'];
189 - $mailsStats = $mailClass->decode($mailsStats);
190 - $nbExport = $this->getExportLimit();
191 - acym_displayErrors();
192 -
193 - $separator = '","';
194 - $csvLines = [];
195 -
196 - $csvLines[] = $this->before.implode($separator, $columns).$this->after;
197 -
198 - $valueNeedNumber = ['click'];
199 -
200 - $i = 0;
201 - foreach ($mailsStats as $mailStat) {
202 - if ($i > $nbExport) break;
203 - $oneLine = [];
204 - foreach ($columns as $key => $trad) {
205 - $key = strpos($key, '.') !== false ? explode('.', $key) : $key;
206 - if (is_array($key)) $key = $key[1];
207 - $line = in_array($key, $valueNeedNumber) && empty($mailStat->{$key}) ? 0 : $mailStat->{$key};
208 - if (is_null($line)) {
209 - $line = '';
210 - }
211 - if ($key === 'bounce_details' && !empty($line)) {
212 - $line = @unserialize($line);
213 - if ($line !== false) {
214 - $formattedLine = '';
215 - foreach ($line as $detailKey => $detailValue) {
216 - $formattedLine .= $detailKey.': '.$detailValue.'; ';
217 - }
218 - $line = rtrim($formattedLine, '; ');
219 - }
220 - }
221 - $oneLine[] = htmlspecialchars($line, ENT_QUOTES, 'UTF-8');
222 - }
223 - $csvLines[] = $this->before.implode($separator, $oneLine).$this->after;
224 - $i++;
225 - }
226 -
227 - $this->finishStatsExport($csvLines, $type);
228 - }
229 -
230 - private function finishStatsExport(array $csvLines, string $type = 'global'): void
231 - {
232 - $final = implode($this->eol, $csvLines);
233 -
234 - if (ACYM_CMS === 'wordpress') {
235 - @ob_get_clean();
236 - }
237 - $filename = 'export_stats_'.$type.'_'.date('Y-m-d');
238 - $this->setDownloadHeaders($filename);
239 - echo $final;
240 - }
241 -
242 - private function getLists(): array
243 - {
244 - static $lists = null;
245 - if (empty($lists)) {
246 - $listClass = new ListClass();
247 - $lists = $listClass->getAllWithIdName();
248 - }
249 -
250 - return $lists;
251 - }
252 -
253 - public function exportCSV(
254 - string $query,
255 - array $fieldsToExport,
256 - array $customFieldsToExport,
257 - array $specialFieldsToExport,
258 - string $separator = ',',
259 - string $charset = 'UTF-8',
260 - string $exportFile = '',
261 - int $flagToRemove = 0
262 - ): string {
263 - $nbExport = $this->getExportLimit();
264 - acym_displayErrors();
265 - $encodingClass = new EncodingHelper();
266 - $excelSecure = $this->config->get('export_excelsecurity', 0);
267 -
268 - if (!in_array($separator, [',', ';'])) $separator = ',';
269 - $separator = '"'.$separator.'"';
270 -
271 - $allFieldsToExport = array_merge($fieldsToExport, $customFieldsToExport);
272 -
273 - foreach ($allFieldsToExport as $key => $field) {
274 - $allFieldsToExport[$key] = $encodingClass->change($field, 'UTF-8', $charset);
275 - }
276 -
277 - if (in_array('subscribe_date', $specialFieldsToExport)) {
278 - $lists = $this->getLists();
279 - foreach ($lists as $oneList) {
280 - $allFieldsToExport[] = acym_translation('ACYM_SUBSCRIPTION_DATE').' '.acym_translation($oneList);
281 - }
282 - }
283 -
284 - if (in_array('unsubscribe_date', $specialFieldsToExport)) {
285 - $lists = $this->getLists();
286 - foreach ($lists as $oneList) {
287 - $allFieldsToExport[] = acym_translation('ACYM_UNSUBSCRIPTION_DATE').' '.acym_translation($oneList);
288 - }
289 - }
290 -
291 - $firstLine = $this->before.implode($separator, $allFieldsToExport).$this->after.$this->eol;
292 -
293 - if (empty($exportFile)) {
294 - @ob_get_clean();
295 - $filename = 'export_'.date('Y-m-d');
296 - $this->setDownloadHeaders($filename);
297 - echo $firstLine;
298 - } else {
299 - preg_match('#^(.+/)[^/]+$#', $exportFile, $folder);
300 - if (!empty($folder[1]) && !file_exists($folder[1])) acym_createDir($folder[1]);
301 -
302 - $fp = fopen($exportFile, 'w');
303 - if (false === $fp) {
304 - if ($flagToRemove !== 0) {
305 - $automationHelper = new AutomationHelper();
306 - $automationHelper->removeFlag($flagToRemove);
307 - }
308 -
309 - return acym_translationSprintf('ACYM_FAIL_SAVE_FILE', $exportFile);
310 - }
311 -
312 - $error = fwrite($fp, $firstLine);
313 - if (false === $error) {
314 - if ($flagToRemove !== 0) {
315 - $automationHelper = new AutomationHelper();
316 - $automationHelper->removeFlag($flagToRemove);
317 - }
318 -
319 - return acym_translationSprintf('ACYM_UNWRITABLE_FILE', $exportFile);
320 - }
321 - }
322 -
323 - $start = 0;
324 - do {
325 - try {
326 - $users = acym_loadObjectList($query.' LIMIT '.intval($start).', '.intval($nbExport), 'id');
327 - } catch (\Exception $e) {
328 - $users = false;
329 - }
330 - $start += $nbExport;
331 -
332 - if ($users === false) {
333 - $errorLine = $this->eol.$this->eol.'Error: '.(isset($e) ? $e->getMessage() : acym_getDBError());
334 -
335 - if (empty($exportFile)) {
336 - echo $errorLine;
337 - } else {
338 - $error = fwrite($fp, $errorLine);
339 - if (false === $error) {
340 - if ($flagToRemove !== 0) {
341 - $automationHelper = new AutomationHelper();
342 - $automationHelper->removeFlag($flagToRemove);
343 - }
344 -
345 - return acym_translationSprintf('ACYM_UNWRITABLE_FILE', $exportFile);
346 - }
347 - }
348 - }
349 -
350 - if (empty($users)) break;
351 -
352 - foreach ($users as $userID => $oneUser) {
353 - unset($oneUser->id);
354 -
355 - $data = get_object_vars($oneUser);
356 -
357 - if (!empty($customFieldsToExport)) {
358 - $fieldIDs = array_keys($customFieldsToExport);
359 - acym_arrayToInteger($fieldIDs);
360 -
361 - $userCustomFields = acym_loadObjectList(
362 - 'SELECT `field_id`, `value`
363 - FROM #__acym_user_has_field
364 - WHERE user_id = '.intval($userID).' AND field_id IN ('.implode(',', $fieldIDs).')',
365 - 'field_id'
366 - );
367 -
368 - foreach ($customFieldsToExport as $fieldID => $fieldName) {
369 - if (empty($userCustomFields[$fieldID])) {
370 - $data[] = '';
371 - } else {
372 - $data[] = acym_triggerCmsHook(
373 - 'onUserExportFieldData',
374 - [$userCustomFields[$fieldID]->value, $fieldID, $fieldName],
375 - false
376 - );
377 - }
378 - }
379 - unset($userCustomFields);
380 - }
381 -
382 - if (isset($lists)) {
383 - $userSubscriptions = acym_loadObjectList(
384 - 'SELECT `list_id`, `subscription_date`, `unsubscribe_date`
385 - FROM #__acym_user_has_list
386 - WHERE user_id = '.intval($userID),
387 - 'list_id'
388 - );
389 -
390 - if (in_array('subscribe_date', $specialFieldsToExport)) {
391 - foreach ($lists as $listId => $oneList) {
392 - $data[] = $userSubscriptions[$listId]->subscription_date ?? '';
393 - }
394 - }
395 -
396 - if (in_array('unsubscribe_date', $specialFieldsToExport)) {
397 - foreach ($lists as $listId => $oneList) {
398 - $data[] = $userSubscriptions[$listId]->unsubscribe_date ?? '';
399 - }
400 - }
401 -
402 - unset($userSubscriptions);
403 - }
404 -
405 - foreach ($data as &$oneData) {
406 - if (is_null($oneData)) {
407 - continue;
408 - }
409 -
410 - if ($excelSecure == 1) {
411 - $firstCharacter = substr($oneData, 0, 1);
412 - if (in_array($firstCharacter, ['=', '+', '-', '@'])) {
413 - $oneData = ' '.$oneData;
414 - }
415 - }
416 -
417 - $oneData = htmlspecialchars($oneData);
418 - }
419 -
420 - $dataexport = implode($separator, $data);
421 - unset($data);
422 -
423 - $oneLine = $this->before.$encodingClass->change($dataexport, 'UTF-8', $charset).$this->after.$this->eol;
424 - if (empty($exportFile)) {
425 - echo $oneLine;
426 - } else {
427 - $error = fwrite($fp, $oneLine);
428 - if (false === $error) {
429 - if ($flagToRemove !== 0) {
430 - $automationHelper = new AutomationHelper();
431 - $automationHelper->removeFlag($flagToRemove);
432 - }
433 -
434 - return acym_translationSprintf('ACYM_UNWRITABLE_FILE', $exportFile);
435 - }
436 - }
437 - }
438 -
439 - unset($users);
440 - } while (true);
441 -
442 - if ($flagToRemove !== 0) {
443 - $automationHelper = new AutomationHelper();
444 - $automationHelper->removeFlag($flagToRemove);
445 - }
446 -
447 - if (!empty($exportFile)) fclose($fp);
448 -
449 - return '';
450 - }
451 -
452 - private function getExportLimit(): int
453 - {
454 - $serverLimit = acym_bytes(ini_get('memory_limit'));
455 - if ($serverLimit > 150000000) {
456 - return 50000;
457 - } elseif ($serverLimit > 80000000) {
458 - return 15000;
459 - } else {
460 - return 5000;
461 - }
462 - }
463 -
464 - public function getExportChangesFileName(string $year, string $month, bool $extension = true): string
465 - {
466 - $filename = 'export_changes_'.$year.'_'.$month;
467 -
468 - if ($extension) {
469 - $filename .= '.csv';
470 - }
471 -
472 - return $filename;
473 - }
474 -
475 - public function getExportChangesFilePath(): string
476 - {
477 - $filename = $this->getExportChangesFileName(acym_date('now', 'Y'), acym_date('now', 'm'));
478 -
479 - return acym_getLogPath($filename);
480 - }
481 -
482 - public function generateExportChangesFilePathConfigChanges(): string
483 - {
484 - $filename = $this->getExportChangesFileName(acym_date('now', 'Y'), acym_date('now', 'm'), false);
485 -
486 - $i = 1;
487 -
488 - $newFilename = $filename.'_'.$i.'.csv';
489 -
490 - while (file_exists(acym_getLogPath($newFilename))) {
491 - $i++;
492 - $newFilename = $filename.'_'.$i.'.csv';
493 - }
494 -
495 - return acym_getLogPath($newFilename);
496 - }
497 -
498 - public function exportChanges(array $user, array $fieldsToExport, string $fieldName, $newValue, $oldValue): void
499 - {
500 - if (empty($user) || empty($fieldName)) {
501 - return;
502 - }
503 -
504 - $exportFullPath = $this->getExportChangesFilePath();
505 -
506 - $separator = '","';
507 - $content = '';
508 -
509 - if (!file_exists($exportFullPath)) {
510 - $columnsHeader = [];
511 - foreach ($fieldsToExport as $field) {
512 - $columnsHeader[] = $field;
513 - }
514 - $columnsHeader = array_merge(
515 - $columnsHeader,
516 - [
517 - acym_translation('ACYM_FIELD_MODIFIED'),
518 - acym_translation('ACYM_NEW_VALUE'),
519 - acym_translation('ACYM_OLD_VALUE'),
520 - acym_translation('ACYM_DATE'),
521 - ]
522 - );
523 - $content .= $this->before.implode($separator, $columnsHeader).$this->after;
524 - }
525 -
526 -
527 - $columns = [];
528 -
529 - foreach ($fieldsToExport as $field) {
530 - $columns[] = empty($user[$field]) ? '' : $user[$field];
531 - }
532 -
533 - $columns = array_merge(
534 - $columns,
535 - [
536 - $fieldName,
537 - $newValue,
538 - $oldValue,
539 - acym_date(),
540 - ]
541 - );
542 -
543 - $content .= $this->eol;
544 - $content .= $this->before.implode($separator, $columns).$this->after;
545 -
546 - file_put_contents(
547 - $exportFullPath,
548 - $content,
549 - FILE_APPEND
550 - );
551 - }
552 -
553 - public function cleanExportChangesFile(): void
554 - {
555 - $exportFolder = acym_getLogPath();
556 - if (!file_exists($exportFolder)) {
557 - return;
558 - }
559 -
560 - $files = scandir($exportFolder);
561 - if (empty($files)) {
562 - return;
563 - }
564 -
565 - $filenameToSearch = $this->getExportChangesFileName(acym_date('2 month ago', 'Y'), acym_date('2 month ago', 'm'), false);
566 - foreach ($files as $file) {
567 - if (strpos($file, $filenameToSearch) === false) {
568 - continue;
569 - }
570 -
571 - @unlink(acym_getLogPath($file));
572 - }
573 - }
574 -}