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 -577 10.11.1 → 11.1.1 View file →
@@ -1,577 +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 - $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 - acym_displayErrors();
142 -
143 - if ($timeLinechart === 'month') {
144 - $timeLinechart = acym_translation('ACYM_MONTHLY_STATS');
145 - } elseif ($timeLinechart === 'week') {
146 - $timeLinechart = acym_translation('ACYM_WEEKLY_STATS');
147 - } else {
148 - $timeLinechart = acym_translation('ACYM_DAILY_STATS');
149 - }
150 -
151 - $separator = '","';
152 -
153 - $csvLines = [];
154 - $csvLines[] = $this->before.$mailName.$this->after;
155 - $csvLines[] = $this->eol;
156 -
157 - $globalDonutsTitle = [
158 - acym_translation('ACYM_SUCCESSFULLY_SENT'),
159 - acym_translation('ACYM_OPEN_RATE'),
160 - acym_translation('ACYM_CLICK_RATE'),
161 - acym_translation('ACYM_BOUNCE_RATE'),
162 - acym_translation('ACYM_UNSUBSCRIBE_RATE'),
163 - ];
164 -
165 - $csvLines[] = $this->before.implode($separator, $globalDonutsTitle).$this->after;
166 - $csvLines[] = $this->before.implode($separator, $globalDonutsData).$this->after;
167 - $csvLines[] = $this->eol;
168 -
169 - $csvLines[] = $this->before.$timeLinechart.$separator.acym_translation('ACYM_OPEN').$separator.acym_translation('ACYM_CLICK').$this->after;
170 -
171 - foreach ($globaline as $date => $value) {
172 - $csvLines[] = $this->before.$date.$separator.$value['open'].$separator.$value['click'].$this->after;
173 - }
174 -
175 - $this->finishStatsExport($csvLines);
176 - }
177 -
178 - public function exportStatsFullCSV(string $query, array $columns, string $type = 'global'): void
179 - {
180 - $nbExport = $this->getExportLimit();
181 - $mailsStats = acym_loadObjectList($query.' LIMIT '.intval($nbExport));
182 - $mailClass = new MailClass();
183 - $mailClass->exceptKeysDecode = ['name'];
184 - $mailsStats = $mailClass->decode($mailsStats);
185 - acym_displayErrors();
186 -
187 - $csvSeparator = $this->config->get('csv_separator', ',');
188 - $separator = '"'.$csvSeparator.'"';
189 - $csvLines = [];
190 -
191 - $csvLines[] = $this->before.implode($separator, $columns).$this->after;
192 -
193 - $valueNeedNumber = ['click'];
194 -
195 - foreach ($mailsStats as $mailStat) {
196 - $oneLine = [];
197 - foreach ($columns as $key => $trad) {
198 - $key = strpos($key, '.') !== false ? explode('.', $key) : $key;
199 - if (is_array($key)) {
200 - $key = $key[1];
201 - }
202 -
203 - $line = in_array($key, $valueNeedNumber) && empty($mailStat->{$key}) ? 0 : $mailStat->{$key};
204 - if (is_null($line)) {
205 - $line = '';
206 - }
207 -
208 - if ($key === 'bounce_details' && !empty($line)) {
209 - $line = @unserialize($line);
210 - if ($line !== false) {
211 - $formattedLine = '';
212 - foreach ($line as $detailKey => $detailValue) {
213 - $formattedLine .= $detailKey.': '.$detailValue.'; ';
214 - }
215 - $line = rtrim($formattedLine, '; ');
216 - }
217 - }
218 -
219 - if (in_array($key, ['send_date', 'open_date', 'date_click']) && !empty($line)) {
220 - $line = acym_date(acym_getTimeFromUTCDate($line), 'Y-m-d H:i:s');
221 - }
222 -
223 - $oneLine[] = htmlspecialchars($line, ENT_QUOTES, 'UTF-8');
224 - }
225 - $csvLines[] = $this->before.implode($separator, $oneLine).$this->after;
226 - }
227 -
228 - $this->finishStatsExport($csvLines, $type);
229 - }
230 -
231 - private function finishStatsExport(array $csvLines, string $type = 'global'): void
232 - {
233 - $final = implode($this->eol, $csvLines);
234 -
235 - if (ACYM_CMS === 'wordpress') {
236 - @ob_get_clean();
237 - }
238 - $filename = 'export_stats_'.$type.'_'.date('Y-m-d');
239 - $this->setDownloadHeaders($filename);
240 - echo $final;
241 - }
242 -
243 - private function getLists(): array
244 - {
245 - static $lists = null;
246 - if (empty($lists)) {
247 - $listClass = new ListClass();
248 - $lists = $listClass->getAllWithIdName();
249 - }
250 -
251 - return $lists;
252 - }
253 -
254 - public function exportCSV(
255 - string $query,
256 - array $fieldsToExport,
257 - array $customFieldsToExport,
258 - array $specialFieldsToExport,
259 - string $separator = ',',
260 - string $charset = 'UTF-8',
261 - string $exportFile = '',
262 - int $flagToRemove = 0
263 - ): string {
264 - $nbExport = $this->getExportLimit();
265 - acym_displayErrors();
266 - $encodingClass = new EncodingHelper();
267 - $excelSecure = $this->config->get('export_excelsecurity', 0);
268 -
269 - if (!in_array($separator, [',', ';'])) $separator = ',';
270 - $separator = '"'.$separator.'"';
271 -
272 - $allFieldsToExport = array_merge($fieldsToExport, $customFieldsToExport);
273 -
274 - foreach ($allFieldsToExport as $key => $field) {
275 - $allFieldsToExport[$key] = $encodingClass->change($field, 'UTF-8', $charset);
276 - }
277 -
278 - if (in_array('subscribe_date', $specialFieldsToExport)) {
279 - $lists = $this->getLists();
280 - foreach ($lists as $oneList) {
281 - $allFieldsToExport[] = acym_translation('ACYM_SUBSCRIPTION_DATE').' '.acym_translation($oneList);
282 - }
283 - }
284 -
285 - if (in_array('unsubscribe_date', $specialFieldsToExport)) {
286 - $lists = $this->getLists();
287 - foreach ($lists as $oneList) {
288 - $allFieldsToExport[] = acym_translation('ACYM_UNSUBSCRIPTION_DATE').' '.acym_translation($oneList);
289 - }
290 - }
291 -
292 - $firstLine = $this->before.implode($separator, $allFieldsToExport).$this->after.$this->eol;
293 -
294 - if (empty($exportFile)) {
295 - @ob_get_clean();
296 - $filename = 'export_'.date('Y-m-d');
297 - $this->setDownloadHeaders($filename);
298 - echo $firstLine;
299 - } else {
300 - preg_match('#^(.+/)[^/]+$#', $exportFile, $folder);
301 - if (!empty($folder[1]) && !file_exists($folder[1])) acym_createDir($folder[1]);
302 -
303 - $fp = fopen($exportFile, 'w');
304 - if (false === $fp) {
305 - if ($flagToRemove !== 0) {
306 - $automationHelper = new AutomationHelper();
307 - $automationHelper->removeFlag($flagToRemove);
308 - }
309 -
310 - return acym_translationSprintf('ACYM_FAIL_SAVE_FILE', $exportFile);
311 - }
312 -
313 - $error = fwrite($fp, $firstLine);
314 - if (false === $error) {
315 - if ($flagToRemove !== 0) {
316 - $automationHelper = new AutomationHelper();
317 - $automationHelper->removeFlag($flagToRemove);
318 - }
319 -
320 - return acym_translationSprintf('ACYM_UNWRITABLE_FILE', $exportFile);
321 - }
322 - }
323 -
324 - $start = 0;
325 - do {
326 - try {
327 - $users = acym_loadObjectList($query.' LIMIT '.intval($start).', '.intval($nbExport), 'id');
328 - } catch (\Exception $e) {
329 - $users = false;
330 - }
331 - $start += $nbExport;
332 -
333 - if ($users === false) {
334 - $errorLine = $this->eol.$this->eol.'Error: '.(isset($e) ? $e->getMessage() : acym_getDBError());
335 -
336 - if (empty($exportFile)) {
337 - echo $errorLine;
338 - } else {
339 - $error = fwrite($fp, $errorLine);
340 - if (false === $error) {
341 - if ($flagToRemove !== 0) {
342 - $automationHelper = new AutomationHelper();
343 - $automationHelper->removeFlag($flagToRemove);
344 - }
345 -
346 - return acym_translationSprintf('ACYM_UNWRITABLE_FILE', $exportFile);
347 - }
348 - }
349 - }
350 -
351 - if (empty($users)) break;
352 -
353 - foreach ($users as $userID => $oneUser) {
354 - unset($oneUser->id);
355 -
356 - $data = get_object_vars($oneUser);
357 -
358 - if (!empty($customFieldsToExport)) {
359 - $fieldIDs = array_keys($customFieldsToExport);
360 - acym_arrayToInteger($fieldIDs);
361 -
362 - $userCustomFields = acym_loadObjectList(
363 - 'SELECT `field_id`, `value`
364 - FROM #__acym_user_has_field
365 - WHERE user_id = '.intval($userID).' AND field_id IN ('.implode(',', $fieldIDs).')',
366 - 'field_id'
367 - );
368 -
369 - foreach ($customFieldsToExport as $fieldID => $fieldName) {
370 - if (empty($userCustomFields[$fieldID])) {
371 - $data[] = '';
372 - } else {
373 - $data[] = acym_triggerCmsHook(
374 - 'onUserExportFieldData',
375 - [$userCustomFields[$fieldID]->value, $fieldID, $fieldName],
376 - false
377 - );
378 - }
379 - }
380 - unset($userCustomFields);
381 - }
382 -
383 - if (isset($lists)) {
384 - $userSubscriptions = acym_loadObjectList(
385 - 'SELECT `list_id`, `subscription_date`, `unsubscribe_date`
386 - FROM #__acym_user_has_list
387 - WHERE user_id = '.intval($userID),
388 - 'list_id'
389 - );
390 -
391 - if (in_array('subscribe_date', $specialFieldsToExport)) {
392 - foreach ($lists as $listId => $oneList) {
393 - $data[] = $userSubscriptions[$listId]->subscription_date ?? '';
394 - }
395 - }
396 -
397 - if (in_array('unsubscribe_date', $specialFieldsToExport)) {
398 - foreach ($lists as $listId => $oneList) {
399 - $data[] = $userSubscriptions[$listId]->unsubscribe_date ?? '';
400 - }
401 - }
402 -
403 - unset($userSubscriptions);
404 - }
405 -
406 - foreach ($data as &$oneData) {
407 - if (is_null($oneData)) {
408 - continue;
409 - }
410 -
411 - if ($excelSecure == 1) {
412 - $firstCharacter = substr($oneData, 0, 1);
413 - if (in_array($firstCharacter, ['=', '+', '-', '@'])) {
414 - $oneData = ' '.$oneData;
415 - }
416 - }
417 -
418 - $oneData = htmlspecialchars($oneData);
419 - }
420 -
421 - $dataexport = implode($separator, $data);
422 - unset($data);
423 -
424 - $oneLine = $this->before.$encodingClass->change($dataexport, 'UTF-8', $charset).$this->after.$this->eol;
425 - if (empty($exportFile)) {
426 - echo $oneLine;
427 - } else {
428 - $error = fwrite($fp, $oneLine);
429 - if (false === $error) {
430 - if ($flagToRemove !== 0) {
431 - $automationHelper = new AutomationHelper();
432 - $automationHelper->removeFlag($flagToRemove);
433 - }
434 -
435 - return acym_translationSprintf('ACYM_UNWRITABLE_FILE', $exportFile);
436 - }
437 - }
438 - }
439 -
440 - unset($users);
441 - } while (true);
442 -
443 - if ($flagToRemove !== 0) {
444 - $automationHelper = new AutomationHelper();
445 - $automationHelper->removeFlag($flagToRemove);
446 - }
447 -
448 - if (!empty($exportFile)) fclose($fp);
449 -
450 - return '';
451 - }
452 -
453 - private function getExportLimit(): int
454 - {
455 - $serverLimit = acym_bytes(ini_get('memory_limit'));
456 - if ($serverLimit > 500000000) {
457 - return 250000;
458 - } elseif ($serverLimit > 150000000) {
459 - return 50000;
460 - } elseif ($serverLimit > 80000000) {
461 - return 15000;
462 - } else {
463 - return 5000;
464 - }
465 - }
466 -
467 - public function getExportChangesFileName(string $year, string $month, bool $extension = true): string
468 - {
469 - $filename = 'export_changes_'.$year.'_'.$month;
470 -
471 - if ($extension) {
472 - $filename .= '.csv';
473 - }
474 -
475 - return $filename;
476 - }
477 -
478 - public function getExportChangesFilePath(): string
479 - {
480 - $filename = $this->getExportChangesFileName(acym_date('now', 'Y'), acym_date('now', 'm'));
481 -
482 - return acym_getLogPath($filename);
483 - }
484 -
485 - public function generateExportChangesFilePathConfigChanges(): string
486 - {
487 - $filename = $this->getExportChangesFileName(acym_date('now', 'Y'), acym_date('now', 'm'), false);
488 -
489 - $i = 1;
490 -
491 - $newFilename = $filename.'_'.$i.'.csv';
492 -
493 - while (file_exists(acym_getLogPath($newFilename))) {
494 - $i++;
495 - $newFilename = $filename.'_'.$i.'.csv';
496 - }
497 -
498 - return acym_getLogPath($newFilename);
499 - }
500 -
501 - public function exportChanges(array $user, array $fieldsToExport, string $fieldName, $newValue, $oldValue): void
502 - {
503 - if (empty($user) || empty($fieldName)) {
504 - return;
505 - }
506 -
507 - $exportFullPath = $this->getExportChangesFilePath();
508 -
509 - $separator = '","';
510 - $content = '';
511 -
512 - if (!file_exists($exportFullPath)) {
513 - $columnsHeader = [];
514 - foreach ($fieldsToExport as $field) {
515 - $columnsHeader[] = $field;
516 - }
517 - $columnsHeader = array_merge(
518 - $columnsHeader,
519 - [
520 - acym_translation('ACYM_FIELD_MODIFIED'),
521 - acym_translation('ACYM_NEW_VALUE'),
522 - acym_translation('ACYM_OLD_VALUE'),
523 - acym_translation('ACYM_DATE'),
524 - ]
525 - );
526 - $content .= $this->before.implode($separator, $columnsHeader).$this->after;
527 - }
528 -
529 -
530 - $columns = [];
531 -
532 - foreach ($fieldsToExport as $field) {
533 - $columns[] = empty($user[$field]) ? '' : $user[$field];
534 - }
535 -
536 - $columns = array_merge(
537 - $columns,
538 - [
539 - $fieldName,
540 - $newValue,
541 - $oldValue,
542 - acym_date(),
543 - ]
544 - );
545 -
546 - $content .= $this->eol;
547 - $content .= $this->before.implode($separator, $columns).$this->after;
548 -
549 - file_put_contents(
550 - $exportFullPath,
551 - $content,
552 - FILE_APPEND
553 - );
554 - }
555 -
556 - public function cleanExportChangesFile(): void
557 - {
558 - $exportFolder = acym_getLogPath();
559 - if (!file_exists($exportFolder)) {
560 - return;
561 - }
562 -
563 - $files = scandir($exportFolder);
564 - if (empty($files)) {
565 - return;
566 - }
567 -
568 - $filenameToSearch = $this->getExportChangesFileName(acym_date('2 month ago', 'Y'), acym_date('2 month ago', 'm'), false);
569 - foreach ($files as $file) {
570 - if (strpos($file, $filenameToSearch) === false) {
571 - continue;
572 - }
573 -
574 - @unlink(acym_getLogPath($file));
575 - }
576 - }
577 -}