Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
53.23% |
66 / 124 |
|
36.36% |
4 / 11 |
CRAP | |
0.00% |
0 / 1 |
base | |
53.23% |
66 / 124 |
|
36.36% |
4 / 11 |
152.30 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
15 / 15 |
|
100.00% |
1 / 1 |
1 | |||
get_id | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
is_enabled | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
set_use_queue | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
init | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
set_addresses | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
get_queue_object_name | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
subject | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
send | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
process_queue | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
template | |
56.10% |
23 / 41 |
|
0.00% |
0 / 1 |
21.24 | |||
assign_vars | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
assign_block_vars | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
prepare_message | |
0.00% |
0 / 27 |
|
0.00% |
0 / 1 |
56 | |||
error | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
20 | |||
save_queue | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
12 | |||
setup_template | |
100.00% |
24 / 24 |
|
100.00% |
1 / 1 |
3 | |||
set_template_paths | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | /** |
3 | * |
4 | * This file is part of the phpBB Forum Software package. |
5 | * |
6 | * @copyright (c) phpBB Limited <https://www.phpbb.com> |
7 | * @license GNU General Public License, version 2 (GPL-2.0) |
8 | * |
9 | * For full copyright and license information, please see |
10 | * the docs/CREDITS.txt file. |
11 | * |
12 | */ |
13 | |
14 | namespace phpbb\messenger\method; |
15 | |
16 | use phpbb\config\config; |
17 | use phpbb\di\service_collection; |
18 | use phpbb\event\dispatcher; |
19 | use phpbb\extension\manager; |
20 | use phpbb\language\language; |
21 | use phpbb\log\log_interface; |
22 | use phpbb\path_helper; |
23 | use phpbb\request\request; |
24 | use phpbb\messenger\queue; |
25 | use phpbb\template\assets_bag; |
26 | use phpbb\template\twig\lexer; |
27 | use phpbb\user; |
28 | |
29 | /** |
30 | * Messenger base class |
31 | */ |
32 | abstract class base implements messenger_interface |
33 | { |
34 | /** @var array */ |
35 | protected $additional_headers = []; |
36 | |
37 | /** @var assets_bag */ |
38 | protected $assets_bag; |
39 | |
40 | /** @var config */ |
41 | protected $config; |
42 | |
43 | /** @var dispatcher */ |
44 | protected $dispatcher; |
45 | |
46 | /** @var manager */ |
47 | protected $ext_manager; |
48 | |
49 | /** @var language */ |
50 | protected $language; |
51 | |
52 | /** @var log_interface */ |
53 | protected $log; |
54 | |
55 | /** @var string */ |
56 | protected $msg = ''; |
57 | |
58 | /** @var queue */ |
59 | protected $queue; |
60 | |
61 | /** @var path_helper */ |
62 | protected $path_helper; |
63 | |
64 | /** @var request */ |
65 | protected $request; |
66 | |
67 | /** @var string */ |
68 | protected $root_path; |
69 | |
70 | /** @var string */ |
71 | protected $subject = ''; |
72 | |
73 | /** @var \phpbb\template\template */ |
74 | protected $template; |
75 | |
76 | /** @var string */ |
77 | protected $template_cache_path; |
78 | |
79 | /** @var service_collection */ |
80 | protected $twig_extensions_collection; |
81 | |
82 | /** @var lexer */ |
83 | protected $twig_lexer; |
84 | |
85 | /** @var bool */ |
86 | protected $use_queue = true; |
87 | |
88 | /** @var user */ |
89 | protected $user; |
90 | |
91 | /** |
92 | * Messenger base class constructor |
93 | * |
94 | * @param assets_bag $assets_bag |
95 | * @param config $config |
96 | * @param dispatcher $dispatcher |
97 | * @param language $language |
98 | * @param queue $queue |
99 | * @param path_helper $path_helper |
100 | * @param request $request |
101 | * @param service_collection $twig_extensions_collection |
102 | * @param lexer $twig_lexer |
103 | * @param user $user |
104 | * @param string $phpbb_root_path |
105 | * @param string $template_cache_path |
106 | * @param manager $ext_manager |
107 | * @param log_interface $log |
108 | */ |
109 | public function __construct( |
110 | assets_bag $assets_bag, |
111 | config $config, |
112 | dispatcher $dispatcher, |
113 | language $language, |
114 | queue $queue, |
115 | path_helper $path_helper, |
116 | request $request, |
117 | service_collection $twig_extensions_collection, |
118 | lexer $twig_lexer, |
119 | user $user, |
120 | string $phpbb_root_path, |
121 | string $template_cache_path, |
122 | ?manager $ext_manager = null, |
123 | ?log_interface $log = null |
124 | ) |
125 | { |
126 | $this->assets_bag = $assets_bag; |
127 | $this->config = $config; |
128 | $this->dispatcher = $dispatcher; |
129 | $this->ext_manager = $ext_manager; |
130 | $this->language = $language; |
131 | $this->log = $log; |
132 | $this->queue = $queue; |
133 | $this->path_helper = $path_helper; |
134 | $this->request = $request; |
135 | $this->twig_extensions_collection = $twig_extensions_collection; |
136 | $this->twig_lexer = $twig_lexer; |
137 | $this->user = $user; |
138 | $this->root_path = $phpbb_root_path; |
139 | $this->template_cache_path = $template_cache_path; |
140 | |
141 | $this->set_use_queue(); |
142 | } |
143 | |
144 | /** |
145 | * {@inheritdoc} |
146 | */ |
147 | abstract public function get_id(): int; |
148 | |
149 | /** |
150 | * {@inheritdoc} |
151 | */ |
152 | abstract public function is_enabled(): bool; |
153 | |
154 | /** |
155 | * Sets the use of messenger queue flag |
156 | * |
157 | * @param bool $use_queue Flag indicating if cached queue to be used |
158 | * |
159 | * @return void |
160 | */ |
161 | public function set_use_queue(bool $use_queue = true): void |
162 | { |
163 | $this->use_queue = $use_queue; |
164 | } |
165 | |
166 | /** |
167 | * Initializes all the data (address, template file, etc) or resets to default |
168 | * |
169 | * @return void |
170 | */ |
171 | abstract public function init(): void; |
172 | |
173 | /** |
174 | * Set addresses for to/im as available |
175 | * |
176 | * @param array $user_row User row |
177 | * |
178 | * @return void |
179 | */ |
180 | abstract public function set_addresses(array $user_row): void; |
181 | |
182 | /** |
183 | * Get messenger method fie queue object name |
184 | * |
185 | * @return string |
186 | */ |
187 | abstract public function get_queue_object_name(): string; |
188 | |
189 | /** |
190 | * {@inheritdoc} |
191 | */ |
192 | public function subject(string $subject = ''): void |
193 | { |
194 | $this->subject = $subject; |
195 | } |
196 | |
197 | /** |
198 | * {@inheritdoc} |
199 | */ |
200 | abstract public function send(): bool; |
201 | |
202 | /** |
203 | * Send messages from the queue |
204 | * |
205 | * @param array $queue_data Queue data array |
206 | * |
207 | * @return void |
208 | */ |
209 | abstract public function process_queue(array &$queue_data): void; |
210 | |
211 | /** |
212 | * Set email template to use |
213 | * |
214 | * @param string $template_file Email template file name |
215 | * @param string $template_lang Email template language |
216 | * @param string $template_path Email template path |
217 | * @param string $template_dir_prefix Email template directory prefix |
218 | * |
219 | * @return bool |
220 | */ |
221 | public function template(string $template_file, string $template_lang = '', string $template_path = '', string $template_dir_prefix = ''): bool |
222 | { |
223 | $template_dir_prefix = (!$template_dir_prefix || $template_dir_prefix[0] === '/') ? $template_dir_prefix : '/' . $template_dir_prefix; |
224 | |
225 | $this->setup_template(); |
226 | |
227 | if (!trim($template_lang)) |
228 | { |
229 | // fall back to board default language if the user's language is |
230 | // missing $template_file. If this does not exist either, |
231 | // $this->template->set_filenames will do a trigger_error |
232 | $template_lang = basename($this->config['default_lang']); |
233 | } |
234 | |
235 | $ext_template_paths = [ |
236 | [ |
237 | 'name' => $template_lang . '_email', |
238 | 'ext_path' => 'language/' . $template_lang . '/email' . $template_dir_prefix, |
239 | ], |
240 | ]; |
241 | |
242 | if ($template_path) |
243 | { |
244 | $template_paths = [ |
245 | $template_path . $template_dir_prefix, |
246 | ]; |
247 | } |
248 | else |
249 | { |
250 | $template_path = (!empty($this->user->lang_path)) ? $this->user->lang_path : $this->root_path . 'language/'; |
251 | $template_path .= $template_lang . '/email'; |
252 | |
253 | $template_paths = [ |
254 | $template_path . $template_dir_prefix, |
255 | ]; |
256 | |
257 | $board_language = basename($this->config['default_lang']); |
258 | |
259 | // we can only specify default language fallback when the path is not a custom one for which we |
260 | // do not know the default language alternative |
261 | if ($template_lang !== $board_language) |
262 | { |
263 | $fallback_template_path = (!empty($this->user->lang_path)) ? $this->user->lang_path : $this->root_path . 'language/'; |
264 | $fallback_template_path .= $board_language . '/email'; |
265 | |
266 | $template_paths[] = $fallback_template_path . $template_dir_prefix; |
267 | |
268 | $ext_template_paths[] = [ |
269 | 'name' => $board_language . '_email', |
270 | 'ext_path' => 'language/' . $board_language . '/email' . $template_dir_prefix, |
271 | ]; |
272 | } |
273 | // If everything fails just fall back to en template |
274 | if ($template_lang !== 'en' && $board_language !== 'en') |
275 | { |
276 | $fallback_template_path = (!empty($this->user->lang_path)) ? $this->user->lang_path : $this->root_path . 'language/'; |
277 | $fallback_template_path .= 'en/email'; |
278 | |
279 | $template_paths[] = $fallback_template_path . $template_dir_prefix; |
280 | |
281 | $ext_template_paths[] = [ |
282 | 'name' => 'en_email', |
283 | 'ext_path' => 'language/en/email' . $template_dir_prefix, |
284 | ]; |
285 | } |
286 | } |
287 | |
288 | $this->set_template_paths($ext_template_paths, $template_paths); |
289 | |
290 | $this->template->set_filenames([ |
291 | 'body' => $template_file . '.txt', |
292 | ]); |
293 | |
294 | return true; |
295 | } |
296 | |
297 | /** |
298 | * Assign variables to email template |
299 | * |
300 | * @param array $vars Array of VAR => VALUE to assign to email template |
301 | * |
302 | * @return void |
303 | */ |
304 | public function assign_vars(array $vars): void |
305 | { |
306 | $this->setup_template(); |
307 | $this->template->assign_vars($vars); |
308 | } |
309 | |
310 | /** |
311 | * Assign block of variables to email template |
312 | * |
313 | * @param string $blockname Template block name |
314 | * @param array $vars Array of VAR => VALUE to assign to email template block |
315 | * |
316 | * @return void |
317 | */ |
318 | public function assign_block_vars(string $blockname, array $vars): void |
319 | { |
320 | $this->setup_template(); |
321 | |
322 | $this->template->assign_block_vars($blockname, $vars); |
323 | } |
324 | |
325 | /** |
326 | * Prepare message before sending out to the recipients |
327 | * |
328 | * @return void |
329 | */ |
330 | public function prepare_message(): void |
331 | { |
332 | // We add some standard variables we always use, no need to specify them always |
333 | $this->assign_vars([ |
334 | 'U_BOARD' => generate_board_url(), |
335 | 'EMAIL_SIG' => str_replace('<br />', "\n", "-- \n" . html_entity_decode($this->config['board_email_sig'], ENT_COMPAT)), |
336 | 'SITENAME' => html_entity_decode($this->config['sitename'], ENT_COMPAT), |
337 | ]); |
338 | |
339 | $subject = $this->subject; |
340 | $template = $this->template; |
341 | /** |
342 | * Event to modify the template before parsing |
343 | * |
344 | * @event core.modify_notification_template |
345 | * @var string subject The message subject |
346 | * @var string template The (readonly) template object |
347 | * @since 3.2.4-RC1 |
348 | * @changed 4.0.0-a1 Removed vars: method, break. |
349 | */ |
350 | $vars = ['subject', 'template']; |
351 | extract($this->dispatcher->trigger_event('core.modify_notification_template', compact($vars))); |
352 | |
353 | // Parse message through template |
354 | $message = trim($this->template->assign_display('body')); |
355 | |
356 | /** |
357 | * Event to modify notification message text after parsing |
358 | * |
359 | * @event core.modify_notification_message |
360 | * @var string message The message text |
361 | * @var string subject The message subject |
362 | * @since 3.1.11-RC1 |
363 | * @changed 4.0.0-a1 Removed vars: method, break. |
364 | */ |
365 | $vars = ['message', 'subject']; |
366 | extract($this->dispatcher->trigger_event('core.modify_notification_message', compact($vars))); |
367 | |
368 | $this->subject = $subject; |
369 | $this->msg = $message; |
370 | unset($subject, $message, $template); |
371 | |
372 | // Because we use \n for newlines in the body message we need to fix line encoding errors for those admins who uploaded email template files in the wrong encoding |
373 | $this->msg = str_replace("\r\n", "\n", $this->msg); |
374 | |
375 | // We now try and pull a subject from the email body ... if it exists, |
376 | // do this here because the subject may contain a variable |
377 | $drop_header = ''; |
378 | $match = []; |
379 | if (preg_match('#^(Subject):(.*?)$#m', $this->msg, $match)) |
380 | { |
381 | $this->subject = (trim($match[2]) != '') ? trim($match[2]) : (($this->subject != '') ? $this->subject : $this->language->lang('NO_EMAIL_SUBJECT')); |
382 | $drop_header .= '[\r\n]*?' . preg_quote($match[0], '#'); |
383 | } |
384 | else |
385 | { |
386 | $this->subject = (($this->subject != '') ? $this->subject : $this->language->lang('NO_EMAIL_SUBJECT')); |
387 | } |
388 | |
389 | if (preg_match('#^(List-Unsubscribe):(.*?)$#m', $this->msg, $match)) |
390 | { |
391 | $drop_header .= '[\r\n]*?' . preg_quote($match[0], '#'); |
392 | $this->additional_headers[$match[1]] = trim($match[2]); |
393 | } |
394 | |
395 | if ($drop_header) |
396 | { |
397 | $this->msg = trim(preg_replace('#' . $drop_header . '#s', '', $this->msg)); |
398 | } |
399 | } |
400 | |
401 | /** |
402 | * {@inheritdoc} |
403 | */ |
404 | public function error(string $msg): void |
405 | { |
406 | // Session doesn't exist, create it |
407 | if (!isset($this->user->session_id) || $this->user->session_id === '') |
408 | { |
409 | $this->user->session_begin(); |
410 | } |
411 | |
412 | $type = strtoupper($this->get_queue_object_name()); |
413 | $calling_page = html_entity_decode($this->request->server('PHP_SELF'), ENT_COMPAT); |
414 | $message = '<strong>' . $type . '</strong><br><em>' . htmlspecialchars($calling_page, ENT_COMPAT) . '</em><br><br>' . $msg . '<br>'; |
415 | if ($this->log) |
416 | { |
417 | $this->log->add('critical', $this->user->data['user_id'], $this->user->ip, 'LOG_ERROR_' . $type, false, [$message]); |
418 | } |
419 | } |
420 | |
421 | /** |
422 | * Save message data to the messenger file queue |
423 | * |
424 | * @return void |
425 | */ |
426 | public function save_queue(): void |
427 | { |
428 | if ($this->use_queue && !empty($this->queue)) |
429 | { |
430 | $this->queue->save(); |
431 | } |
432 | } |
433 | |
434 | /** |
435 | * Setup template engine |
436 | * |
437 | * @return void |
438 | */ |
439 | protected function setup_template(): void |
440 | { |
441 | if (isset($this->template) && $this->template instanceof \phpbb\template\template) |
442 | { |
443 | return; |
444 | } |
445 | |
446 | $template_environment = new \phpbb\template\twig\environment( |
447 | $this->assets_bag, |
448 | $this->config, |
449 | new \phpbb\filesystem\filesystem(), |
450 | $this->path_helper, |
451 | $this->template_cache_path, |
452 | $this->ext_manager, |
453 | new \phpbb\template\twig\loader(), |
454 | $this->dispatcher, |
455 | [] |
456 | ); |
457 | $template_environment->setLexer($this->twig_lexer); |
458 | |
459 | $this->template = new \phpbb\template\twig\twig( |
460 | $this->path_helper, |
461 | $this->config, |
462 | new \phpbb\template\context(), |
463 | $template_environment, |
464 | $this->template_cache_path, |
465 | $this->user, |
466 | $this->twig_extensions_collection, |
467 | $this->ext_manager |
468 | ); |
469 | } |
470 | |
471 | /** |
472 | * Set template paths to load |
473 | * |
474 | * @param string|array $path_name Email template path name |
475 | * @param string|array $paths Email template paths |
476 | * |
477 | * @return void |
478 | */ |
479 | protected function set_template_paths(string|array $path_name, string|array $paths): void |
480 | { |
481 | $this->setup_template(); |
482 | $this->template->set_custom_style($path_name, $paths); |
483 | } |
484 | } |