PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.34.2
MailPoet – Newsletters, Email Marketing, and Automation v5.34.2
5.34.2 5.34.1 5.34.0 5.33.1 5.33.0 5.32.0 5.31.0 5.30.0 5.29.0 5.28.1 5.28.0 5.27.0 5.26.0 5.26.1 5.25.0 5.24.0 4.43.0 4.43.1 4.44.0 4.44.1 4.45.0 4.46.0 4.47.0 4.48.0 4.48.1 4.48.2 4.49.0 4.49.1 4.5.0 4.5.1 4.5.2 4.50.0 4.50.1 4.51.0 4.51.1 4.51.2 4.52.0 4.53.0 4.54.0 4.55.0 4.56.0 4.57.0 4.58.0 4.58.1 4.58.2 4.6.0 4.6.1 4.6.2 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 5.0.0 5.0.1 5.0.2 5.1.0 5.1.1 5.10.0 5.10.1 5.11.0 5.12.0 5.12.1 5.12.10 5.12.11 5.12.12 5.12.13 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13.0 5.13.1 5.13.2 5.14.0 5.14.1 5.14.2 5.14.3 5.15.0 5.15.1 5.16.0 5.16.1 5.16.2 5.16.3 5.16.4 5.17.0 5.17.1 5.17.2 5.17.3 5.17.4 5.17.5 5.17.6 5.18.0 5.19.0 5.2.0 5.2.1 5.2.2 5.2.3 5.20.0 5.21.0 5.21.1 5.21.2 5.21.3 5.22.0 5.22.1 5.22.2 5.22.3 5.22.4 5.23.0 5.23.1 5.23.2 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.6.3 5.6.4 5.7.0 5.7.1 5.8.0 5.8.1 5.9.0 3.0.0-beta.15 3.7.1 3.0.0-beta.16 3.7.2 3.0.0-beta.17 3.7.3 3.0.0-beta.18 3.7.4 3.0.0-beta.19 3.7.5 3.0.0-beta.2 3.7.6 3.0.0-beta.20 3.7.8 3.0.0-beta.21 3.70.0 3.0.0-beta.22 3.71.0 3.0.0-beta.23 3.71.1 3.0.0-beta.23.1 3.71.2 3.0.0-beta.23.2 3.71.3 3.0.0-beta.24 3.72.0 3.0.0-beta.25 3.73.0 3.0.0-beta.26 3.73.1 3.0.0-beta.27 3.73.2 3.0.0-beta.28 3.74.0 3.0.0-beta.29 3.74.1 3.0.0-beta.3 3.74.2 3.0.0-beta.30 3.74.3 3.0.0-beta.31 3.75.0 3.0.0-beta.32 3.75.1 3.0.0-beta.33 3.76.0 3.0.0-beta.33.1 3.77.0 3.0.0-beta.34.0.0 3.77.1 3.0.0-beta.36.0.0 3.78.0 3.0.0-beta.36.0.1 3.79.0 3.0.0-beta.36.2.0 3.8 3.0.0-beta.36.3.0 3.8.1 3.0.0-beta.36.3.1 3.8.2 3.0.0-beta.37.0.0 3.8.3 3.0.0-beta.4 3.8.4 3.0.0-beta.5 3.8.5 3.0.0-beta.6 3.8.6 3.0.0-beta.7 3.80.0 3.0.0-beta.7.1 3.81.0 3.0.0-beta.8 3.82.0 3.0.0-beta.9 3.83.0 3.0.0-rc.1.0.0 3.84.0 3.0.0-rc.1.0.1 3.84.1 3.0.0-rc.1.0.2 3.85.0 3.0.0-rc.1.0.3 3.85.1 3.0.0-rc.1.0.4 3.86.0 3.0.0-rc.2.0.0 3.87.0 3.0.0-rc.2.0.1 3.87.1 3.0.0-rc.2.0.2 3.87.2 3.0.0-rc.2.0.3 3.88.0 3.0.1 3.88.1 3.0.2 3.88.2 3.0.3 3.89.0 3.0.4 3.89.1 3.0.5 3.89.2 3.0.6 3.89.3 3.0.7 3.89.4 3.0.8 3.9.0 3.0.9 3.9.1 3.1.0 3.90.0 3.10 3.90.1 3.10.1 3.90.2 3.100.0 3.91.0 3.100.1 3.91.1 3.100.2 3.92.0 3.101.0 3.92.1 3.101.1 3.93.0 3.102.0 3.93.1 3.102.1 3.94.0 3.103.0 3.95.0 3.103.1 3.95.1 3.11.0 3.96.0 3.11.1 3.96.1 3.11.2 3.97.0 3.11.3 3.98.0 3.11.4 3.98.1 3.11.5 3.99.0 3.12.0 3.99.1 3.12.1 4.0.0 3.13.0 4.0.1 3.14.0 4.1.0 3.14.1 4.1.1 3.15.0 4.10.0 3.16.0 4.11.0 3.16.1 4.11.1 3.16.2 4.12.0 3.16.3 4.12.1 3.17.0 4.12.2 3.17.1 4.13.0 3.17.2 4.14.0 3.18.0 4.15.0 3.18.1 4.16.0 3.18.2 4.17.0 3.19.0 4.17.1 3.19.1 4.18.0 3.19.2 4.18.1 3.19.3 4.19.0 3.2.0 4.2.0 3.2.1 4.20.0 3.2.2 4.20.1 3.2.3 4.20.2 3.2.4 4.21.0 3.2.5 4.22.0 3.20.0 4.22.1 3.21.0 4.22.2 3.21.1 4.23.0 3.22.0 4.24.0 3.23.0 4.25.0 3.23.1 4.26.0 3.23.2 4.26.1 3.24.0 4.27.0 3.25.0 4.28.0 3.25.1 4.29.0 3.26.0 4.3.0 3.26.1 4.3.1 3.27.0 4.30.0 3.28.0 4.31.0 3.29.0 4.31.1 3.3.0 4.32.0 3.3.1 4.33.0 3.3.2 4.34.0 3.3.3 4.35.0 3.3.4 4.35.1 3.3.5 4.36.0 3.3.6 4.37.0 3.30.0 4.38.0 3.31.0 4.39.0 3.31.1 4.4.0 3.32.0 4.40.0 3.32.1 4.41.0 3.32.2 4.41.1 3.33.0 4.41.2 3.34.0 4.41.3 3.34.1 4.42.0 3.34.2 4.42.1 3.34.3 3.34.4 3.35.0 3.35.1 3.35.3 3.35.4 3.36.0 3.37.0 3.37.1 3.37.2 3.37.3 3.38.0 3.38.1 3.39.0 3.39.1 3.39.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.40.0 3.40.1 3.41.0 3.41.1 3.41.2 3.42.0 3.42.1 3.42.2 3.42.3 3.43.0 3.43.1 3.44.0 3.45.0 3.45.1 3.46.0 3.46.1 3.46.10 3.46.11 3.46.12 3.46.13 3.46.14 3.46.2 3.46.3 3.46.4 3.46.5 3.46.6 3.46.7 3.46.8 3.46.9 3.47.0 3.47.1 3.47.10 3.47.11 3.47.2 3.47.3 3.47.5 3.47.6 3.47.7 3.47.9 3.48.0 3.48.1 3.49.0 3.49.1 3.5.0 3.5.1 3.50.0 3.51.0 3.51.1 3.51.2 3.52.0 3.53.0 3.54.0 3.54.1 3.54.2 3.54.3 3.55.0 3.55.1 3.56.0 3.56.1 3.56.2 3.57.0 3.57.1 3.58.0 3.59.0 3.59.1 3.59.2 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.60.0 3.60.1 3.60.10 3.60.11 3.60.12 3.60.2 3.60.3 3.60.4 3.60.6 3.60.7 3.60.8 3.60.9 3.61.0 3.62.0 3.62.1 3.63.0 3.64.0 3.64.1 3.64.2 3.64.3 3.65.0 trunk 3.65.1 3.0.0 3.66.0 3.0.0-beta.1 3.67.0 3.0.0-beta.10 3.67.1 3.0.0-beta.11 3.68.0 3.0.0-beta.12 3.69.0 3.0.0-beta.13 3.69.1 3.0.0-beta.14 3.7.0
mailpoet / lib / Logging / LogsDownload.php
mailpoet / lib / Logging Last commit date
RestApi 1 month ago LogHandler.php 10 months ago LogListingRepository.php 1 month ago LogRepository.php 2 weeks ago LoggerFactory.php 10 months ago LogsDownload.php 2 weeks ago PluginVersionProcessor.php 3 years ago index.php 3 years ago
LogsDownload.php
157 lines
1 <?php declare(strict_types = 1);
2
3 namespace MailPoet\Logging;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use MailPoet\Config\AccessControl;
9 use MailPoet\WP\Functions as WPFunctions;
10
11 class LogsDownload {
12 private const ACTION = 'mailpoet_download_logs';
13 private const NONCE_ACTION = 'mailpoet_download_logs_nonce';
14 private const MAX_LOGS = 50000;
15
16 /** @var LogRepository */
17 private $logRepository;
18
19 /** @var WPFunctions */
20 private $wp;
21
22 public function __construct(
23 LogRepository $logRepository,
24 WPFunctions $wp
25 ) {
26 $this->logRepository = $logRepository;
27 $this->wp = $wp;
28 }
29
30 public function initialize(): void {
31 $this->wp->addAction('admin_post_' . self::ACTION, [$this, 'handle']);
32 }
33
34 public function handle(): void {
35 if (!$this->wp->currentUserCan(AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN)) {
36 $this->wp->wpDie(esc_html__('You do not have permission to download logs.', 'mailpoet'), '', ['response' => 403]);
37 }
38
39 $nonce = $this->getStringParam('_wpnonce') ?? '';
40 if (!$this->wp->wpVerifyNonce($nonce, self::NONCE_ACTION)) {
41 $this->wp->wpDie(esc_html__('Security check failed.', 'mailpoet'), '', ['response' => 403]);
42 }
43
44 $from = $this->getStringParam('from');
45 $to = $this->getStringParam('to');
46 $search = $this->getStringParam('search');
47
48 $filter = [];
49 $dateFrom = $this->parseDateParam($from);
50 if ($dateFrom instanceof \DateTimeImmutable) {
51 $filter['from'] = $dateFrom->format('Y-m-d');
52 }
53 $dateTo = $this->parseDateParam($to);
54 if ($dateTo instanceof \DateTimeImmutable) {
55 $filter['to'] = $dateTo->format('Y-m-d');
56 }
57 $names = $this->parseStringArrayParam('name');
58 if ($names) {
59 $filter['name'] = $names;
60 }
61 $levels = $this->parseIntArrayParam('level');
62 if ($levels) {
63 $filter['level'] = $levels;
64 }
65 if ($search === '') {
66 $search = null;
67 }
68
69 $logs = $this->logRepository->getLogsForExport($filter, $search, self::MAX_LOGS);
70
71 $filename = 'mailpoet-logs';
72 if (isset($filter['from'])) {
73 $filename .= '-from-' . $filter['from'];
74 }
75 if (isset($filter['to'])) {
76 $filename .= '-to-' . $filter['to'];
77 }
78 $filename .= '.txt';
79
80 header('Content-Type: text/plain; charset=utf-8');
81 header('Content-Disposition: attachment; filename="' . $filename . '"');
82 header('Cache-Control: no-cache, no-store, must-revalidate');
83 header('Pragma: no-cache');
84 header('Expires: 0');
85
86 $count = 0;
87 foreach ($logs as $log) {
88 $createdAt = $log['created_at'] ?? 'N/A';
89 $name = $log['name'] ?? '';
90 $message = $log['message'] ?? '';
91 // Output is a text/plain attachment download, not HTML; HTML-escaping would corrupt the log content.
92 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
93 echo '[' . $createdAt . '] [' . $name . '] ' . $message . "\n";
94 // Stream to the client as we go so the output buffer doesn't accumulate
95 // the whole file in memory; the repository already pages the DB rows.
96 $count++;
97 if (($count % 1000) === 0) {
98 flush();
99 }
100 }
101 exit;
102 }
103
104 private function getStringParam(string $key): ?string {
105 if (!isset($_GET[$key]) || !is_string($_GET[$key])) {
106 return null;
107 }
108 return sanitize_text_field(wp_unslash($_GET[$key]));
109 }
110
111 /**
112 * @return string[]
113 */
114 private function parseStringArrayParam(string $key): array {
115 if (!isset($_GET[$key]) || !is_array($_GET[$key])) {
116 return [];
117 }
118 $values = array_filter(
119 array_map('sanitize_text_field', wp_unslash($_GET[$key])),
120 static function (string $value): bool {
121 return $value !== '';
122 }
123 );
124 return array_values(array_unique($values));
125 }
126
127 /**
128 * @return int[]
129 */
130 private function parseIntArrayParam(string $key): array {
131 if (!isset($_GET[$key]) || !is_array($_GET[$key])) {
132 return [];
133 }
134 $values = array_map('intval', wp_unslash($_GET[$key]));
135 return array_values(array_unique($values));
136 }
137
138 public static function createNonce(WPFunctions $wp): string {
139 return $wp->wpCreateNonce(self::NONCE_ACTION);
140 }
141
142 private function parseDateParam(?string $value): ?\DateTimeImmutable {
143 if ($value === null || $value === '') {
144 return null;
145 }
146 $date = \DateTimeImmutable::createFromFormat('!Y-m-d', $value);
147 if (!$date) {
148 return null;
149 }
150 $errors = \DateTimeImmutable::getLastErrors();
151 if (is_array($errors) && ($errors['warning_count'] > 0 || $errors['error_count'] > 0)) {
152 return null;
153 }
154 return $date;
155 }
156 }
157