Completed
Push — master ( 007d59...23192b )
by Sebastian
05:45
created

Mail::onPhpbuEnd()   C

Complexity

Conditions 7
Paths 21

Size

Total Lines 38
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 7.0601

Importance

Changes 0
Metric Value
dl 0
loc 38
ccs 25
cts 28
cp 0.8929
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 29
nc 21
nop 1
crap 7.0601
1
<?php
2
namespace phpbu\App\Log;
3
4
use phpbu\App\Exception;
5
use phpbu\App\Event;
6
use phpbu\App\Listener;
7
use phpbu\App\Result;
8
use phpbu\App\Log\MailTemplate as TPL;
9
use phpbu\App\Util\Arr;
10
use phpbu\App\Util\Str;
11
use PHP_Timer;
12
use Swift_Mailer;
13
use Swift_Message;
14
15
/**
16
 * Mail Logger
17
 *
18
 * @package    phpbu
19
 * @subpackage Log
20
 * @author     Sebastian Feldmann <[email protected]>
21
 * @copyright  Sebastian Feldmann <[email protected]>
22
 * @license    https://opensource.org/licenses/MIT The MIT License (MIT)
23
 * @link       http://phpbu.de/
24
 * @since      Class available since Release 1.0.0
25
 */
26
class Mail implements Listener, Logger
27
{
28
    /**
29
     * Mailer instance
30
     *
31
     * @var Swift_Mailer
32
     */
33
    protected $mailer;
34
35
    /**
36
     * Mail subject
37
     *
38
     * @var string
39
     */
40
    protected $subject;
41
42
    /**
43
     * From email address
44
     *
45
     * @var string
46
     */
47
    protected $senderMail;
48
49
    /**
50
     * From name
51
     *
52
     * @var string
53
     */
54
    protected $senderName;
55
56
    /**
57
     * Transport type [mail|smtp|null]
58
     *
59
     * @var string
60
     */
61
    protected $transportType;
62
63
    /**
64
     * List of mail recipients
65
     *
66
     * @var array<string>
67
     */
68
    protected $recipients = [];
69
70
    /**
71
     * Amount of executed backups
72
     *
73
     * @var integer
74
     */
75
    private $numBackups = 0;
76
77
    /**
78
     * Amount of executed checks
79
     *
80
     * @var integer
81
     */
82
    private $numChecks = 0;
83
84
    /**
85
     * Amount of executed Syncs
86
     *
87
     * @var integer
88
     */
89
    private $numSyncs = 0;
90
91
    /**
92
     * Amount of executed Crypts
93
     *
94
     * @var integer
95
     */
96
    private $numCrypts = 0;
97
98
    /**
99
     * Amount of executed Cleanups
100
     *
101
     * @var integer
102
     */
103
    private $numCleanups = 0;
104
105
    /**
106
     * Send mail only if there was an error
107
     *
108
     * @var bool
109
     */
110
    private $sendOnlyOnError = false;
111
112
    /**
113
     * Returns an array of event names this subscriber wants to listen to.
114
     *
115
     * The array keys are event names and the value can be:
116
     *
117
     *  * The method name to call (priority defaults to 0)
118
     *  * An array composed of the method name to call and the priority
119
     *  * An array of arrays composed of the method names to call and respective
120
     *    priorities, or 0 if unset
121
     *
122
     * @return array The event names to listen to
123
     */
124 1
    public static function getSubscribedEvents()
125
    {
126
        return [
127 1
            'phpbu.backup_start'  => 'onBackupStart',
128
            'phpbu.check_start'   => 'onCheckStart',
129
            'phpbu.crypt_start'   => 'onCryptStart',
130
            'phpbu.sync_start'    => 'onSyncStart',
131
            'phpbu.cleanup_start' => 'onCleanupStart',
132
            'phpbu.app_end'       => 'onPhpbuEnd',
133
        ];
134
    }
135
136
    /**
137
     * Setup the Logger.
138
     *
139
     * @see    \phpbu\App\Log\Logger::setup
140
     * @param  array $options
141
     * @throws \phpbu\App\Exception
142
     */
143 12
    public function setup(array $options)
144
    {
145 12
        if (empty($options['recipients'])) {
146 1
            throw new Exception('no recipients given');
147
        }
148 11
        $mails                 = $options['recipients'];
149 11
        $server                = gethostname();
150 11
        $this->sendOnlyOnError = Str::toBoolean(Arr::getValue($options, 'sendOnlyOnError'), false);
151 11
        $this->subject         = Arr::getValue($options, 'subject', 'PHPBU backup report from ' . $server);
152 11
        $this->senderMail      = Arr::getValue($options, 'sender.mail', 'phpbu@' . $server);
153 11
        $this->senderName      = Arr::getValue($options, 'sender.name');
154 11
        $this->transportType   = Arr::getValue($options, 'transport', 'mail');
155 11
        $this->recipients      = array_map('trim', explode(';', $mails));
156
157
        // create transport an mailer
158 11
        $transport    = $this->createTransport($this->transportType, $options);
159 9
        $this->mailer = Swift_Mailer::newInstance($transport);
160 9
    }
161
162
    /**
163
     * Handle the phpbu end event.
164
     *
165
     * @param  \phpbu\App\Event\App\End $event
166
     * @throws \phpbu\App\Exception
167
     */
168 4
    public function onPhpbuEnd(Event\App\End $event)
169
    {
170 4
        $result  = $event->getResult();
171 4
        $allGood = $result->allOk();
172
173 4
        if (!$this->sendOnlyOnError || !$allGood) {
174 4
            $header  = $this->getHeaderHtml();
175 4
            $status  = $this->getStatusHtml($result);
176 4
            $errors  = $this->getErrorHtml($result);
177 4
            $info    = $this->getInfoHtml($result);
178 4
            $footer  = $this->getFooterHtml();
179 4
            $body    = '<html><body '. TPL::getSnippet('sBody') . '>'
180 4
                     . $header
181 4
                     . $status
182 4
                     . $errors
183 4
                     . $info
184 4
                     . $footer
185 4
                     . '</body></html>';
186 4
            $sent    = null;
187
            $state   = $allGood ? 'OK' : ($result->backupOkButSkipsOrFails() ? 'WARNING' : 'ERROR');
188
189
            try {
190 4
                /** @var \Swift_Message $message */
191 4
                $message = Swift_Message::newInstance();
192 4
                $message->setSubject($this->subject . ' [' . $state . ']')
193 4
                        ->setFrom($this->senderMail, $this->senderName)
194 4
                        ->setTo($this->recipients)
195
                        ->setBody($body, 'text/html');
196 4
197
                $sent = $this->mailer->send($message);
198
            } catch (\Exception $e) {
199
                throw new Exception($e->getMessage());
200 4
            }
201
            if (!$sent) {
202
                throw new Exception('mail could not be sent');
203
            }
204 4
        }
205
    }
206
207
    /**
208
     * Backup start event.
209
     *
210
     * @param \phpbu\App\Event\Backup\Start $event
211 4
     */
212
    public function onBackupStart(Event\Backup\Start $event)
213 4
    {
214 4
        $this->numBackups++;
215
    }
216
217
    /**
218
     * Check start event.
219
     *
220
     * @param \phpbu\App\Event\Check\Start $event
221 1
     */
222
    public function onCheckStart(Event\Check\Start $event)
223 1
    {
224 1
        $this->numChecks++;
225
    }
226
227
    /**
228
     * Crypt start event.
229
     *
230
     * @param \phpbu\App\Event\Crypt\Start $event
231 1
     */
232
    public function onCryptStart(Event\Crypt\Start $event)
233 1
    {
234 1
        $this->numCrypts++;
235
    }
236
237
    /**
238
     * Sync start event.
239
     *
240
     * @param \phpbu\App\Event\Sync\Start $event
241 1
     */
242
    public function onSyncStart(Event\Sync\Start $event)
243 1
    {
244 1
        $this->numSyncs++;
245
    }
246
247
    /**
248
     * Cleanup start event.
249
     *
250
     * @param \phpbu\App\Event\Cleanup\Start $event
251 1
     */
252
    public function onCleanupStart(Event\Cleanup\Start $event)
253 1
    {
254 1
        $this->numCleanups++;
255
    }
256
257
    /**
258
     * Create a Swift_Mailer_Transport.
259
     *
260
     * @param  string $type
261
     * @param  array  $options
262
     * @throws \phpbu\App\Exception
263
     * @return \Swift_Transport
264 11
     */
265
    protected function createTransport($type, array $options)
266
    {
267
        switch ($type) {
268 11
            // null transport, don't send any mails
269
            case 'null':
270 4
                 /* @var $transport \Swift_NullTransport */
271 4
                $transport = \Swift_NullTransport::newInstance();
272
                break;
273 7
274 2
            case 'smtp':
275 1
                $transport = $this->getSmtpTransport($options);
276
                break;
277 5
278 3
            case 'mail':
279 4
            case 'sendmail':
280 4
                $transport = $this->getSendmailTransport($options);
281
                break;
282
283
            // UPS! no transport given
284 1
            default:
285
                throw new Exception(sprintf('mail transport not supported: \'%s\'', $type));
286 9
        }
287
        return $transport;
288
    }
289
290
    /**
291
     * Create Swift Smtp Transport.
292
     *
293
     * @param  array $options
294
     * @return \Swift_SmtpTransport
295
     * @throws \phpbu\App\Exception
296 2
     */
297
    protected function getSmtpTransport(array $options)
298 2
    {
299 1
        if (!isset($options['smtp.host'])) {
300
            throw new Exception('option \'smtp.host\' ist missing');
301 1
        }
302 1
        $host       = $options['smtp.host'];
303 1
        $port       = Arr::getValue($options, 'smtp.port', 25);
304 1
        $username   = Arr::getValue($options, 'smtp.username');
305 1
        $password   = Arr::getValue($options, 'smtp.password');
306
        $encryption = Arr::getValue($options, 'smtp.encryption');
307
308 1
        /* @var $transport \Swift_SmtpTransport */
309
        $transport = \Swift_SmtpTransport::newInstance($host, $port);
310 1
311 1
        if ($username && $password) {
312 1
            $transport->setUsername($username)
313
                      ->setPassword($password);
314 1
        }
315 1
        if ($encryption) {
316
            $transport->setEncryption($encryption);
317 1
        }
318
        return $transport;
319
    }
320
321
    /**
322
     * Create a Swift Sendmail Transport.
323
     *
324
     * @param  array $options
325
     * @return \Swift_SendmailTransport
326 4
     */
327
    protected function getSendmailTransport(array $options)
328 4
    {
329 1
        if (isset($options['sendmail.path'])) {
330 1
            $path    = $options['sendmail.path'];
331
            $options = isset($options['sendmail.options']) ? ' ' . $options['sendmail.options'] : '';
332 1
            /* @var $transport \Swift_SendmailTransport */
333
            return \Swift_SendmailTransport::newInstance($path . $options);
334 3
        }
335
        return \Swift_SendmailTransport::newInstance();
336
    }
337
338
    /**
339
     * Return mail header html
340
     *
341
     * @return string
342 4
     */
343
    protected function getHeaderHtml()
344 4
    {
345 4
        return '<table ' . TPL::getSnippet('sTableContent') . '><tr><td ' . TPL::getSnippet('sTableContentCol') . '>' .
346
               '<table ' . TPL::getSnippet('sTableHeader') . '><tr><td>PHPBU - backup report</td></tr></table>';
347
    }
348
349
    /**
350
     * Return mail status html
351
     *
352
     * @param  \phpbu\App\Result $result
353
     * @return string
354 4
     */
355
    protected function getStatusHtml(Result $result)
356 4
    {
357 1
        if (count($result->getBackups()) === 0) {
358 1
            $color  = TPL::getSnippet('cStatusWARN');
359 3
            $status = 'WARNING';
360 1
        } elseif ($result->allOk()) {
361 1
            $color  = TPL::getSnippet('cStatusOK');
362 2
            $status = 'OK';
363 1
        } elseif ($result->backupOkButSkipsOrFails()) {
364 1
            $color  = TPL::getSnippet('cStatusWARN');
365
            $status = 'WARNING';
366 1
        } else {
367 1
            $color  = TPL::getSnippet('cStatusFAIL');
368
            $status = 'FAILURE';
369 4
        }
370 4
        $info = sprintf(
371 4
            '(%d %s, %d %s, %d %s, %d %s, %d %s)',
372 4
            count($result->getBackups()),
373 4
            Str::appendPluralS('backup', count($result->getBackups())),
374 4
            $this->numChecks,
375 4
            Str::appendPluralS('check', $this->numChecks),
376 4
            $this->numCrypts,
377 4
            Str::appendPluralS('crypt', $this->numCrypts),
378 4
            $this->numSyncs,
379 4
            Str::appendPluralS('sync', $this->numSyncs),
380 4
            $this->numCleanups,
381
            Str::appendPluralS('cleanup', $this->numCleanups)
382 4
        );
383 4
        $html = '<table ' . sprintf(TPL::getSnippet('sTableStatus'), $color) .'>' .
384 4
                 '<tr><td>' .
385 4
                  '<span ' . TPL::getSnippet('sTableStatusText') . '>' . date('Y-m-d H:i') . '</span>' .
386 4
                  '<h1 ' . TPL::getSnippet('sTableStatusHead') . '>' . $status . '</h1>' .
387 4
                  '<span ' . TPL::getSnippet('sTableStatusText') . '>' . $info . '</span>' .
388 4
                 '</td></tr>' .
389
                '</table>';
390 4
391
        return $html;
392
    }
393
394
    /**
395
     * Get error information.
396
     *
397
     * @param  \phpbu\App\Result $result
398
     * @return string
399 4
     */
400
    protected function getErrorHtml(Result $result)
401 4
    {
402 4
        $html   = '';
403 4
        $errors = $result->getErrors();
404 1
        if (count($errors)) {
405
            $html .= '<table ' . TPL::getSnippet('sTableError') . '>';
406 1
            /* @var $e Exception */
407 1
            foreach ($errors as $e) {
408 1
                $html .= '<tr><td ' . TPL::getSnippet('sTableErrorCol') . '>' .
409 1
                    sprintf(
410 1
                        "Exception '%s' with message '%s' in %s:%d",
411 1
                        get_class($e),
412 1
                        $e->getMessage(),
413 1
                        $e->getFile(),
414
                        $e->getLine()
415 1
                    ) .
416
                    '</td></tr>';
417
418 1
            }
419
            $html .= '</table>';
420 4
        }
421
        return $html;
422
    }
423
424
    /**
425
     * Return backup html information.
426
     *
427
     * @param  \phpbu\App\Result $result
428
     * @return string
429 4
     */
430
    protected function getInfoHtml(Result $result)
431 4
    {
432 4
        $html    = '';
433 4
        $backups = $result->getBackups();
434 3
        if (count($backups)) {
435
            $html .= '<table ' . TPL::getSnippet('sTableBackup') . '>';
436 3
            /** @var \phpbu\App\Result\Backup $backup */
437 3
            foreach ($backups as $backup) {
438 1
                if ($backup->allOk()) {
439 1
                    $color  = TPL::getSnippet('cStatusOK');
440 2
                    $status = 'OK';
441 1
                } elseif($backup->okButSkipsOrFails()) {
442 1
                    $color  = TPL::getSnippet('cStatusWARN');
443
                    $status = 'WARNING';
444 1
                } else {
445 1
                    $color  = TPL::getSnippet('cStatusFAIL');
446
                    $status = 'FAILURE';
447
                }
448 3
                $html .= '<tr>' .
449 3
                          '<td ' . sprintf(TPL::getSnippet('sTableBackupStatusColumn'), $color) . ' colspan="4">' .
450 3
                          sprintf('backup <em>%s</em>', $backup->getName()) .
451 3
                          ' <span ' . TPL::getSnippet('sTableBackupStatusText') . '>' . $status .'</span>'.
452 3
                          '</td>' .
453 3
                         '</tr>' .
454 3
                         '<tr>' .
455 3
                          '<td ' . TPL::getSnippet('sRowHead') . '>&nbsp;</td>' .
456 3
                          '<td ' . TPL::getSnippet('sRowHead') . ' align="right">executed</td>' .
457 3
                          '<td ' . TPL::getSnippet('sRowHead') . ' align="right">skipped</td>' .
458 3
                          '<td ' . TPL::getSnippet('sRowHead') . ' align="right">failed</td>' .
459
                         '</tr>';
460
461 3
                $html .= '<tr>' .
462 3
                          '<td ' . TPL::getSnippet('sRowCheck') . '>checks</td>' .
463 3
                          '<td ' . TPL::getSnippet('sRowCheck') . ' align="right">' .
464
                            $backup->checkCount() . '
465 3
                           </td>' .
466
                          '<td ' . TPL::getSnippet('sRowCheck') . ' align="right">
467
                            &nbsp;
468 3
                           </td>' .
469 3
                          '<td ' . TPL::getSnippet('sRowCheck') . ' align="right">' .
470 3
                            $backup->checkCountFailed() .
471 3
                          '</td>' .
472 3
                         '</tr>' .
473 3
                         '<tr>' .
474 3
                          '<td ' . TPL::getSnippet('sRowCrypt') . '>crypts</td>' .
475 3
                          '<td ' . TPL::getSnippet('sRowCrypt') . ' align="right">' .
476 3
                            $backup->cryptCount() .
477 3
                          '</td>' .
478 3
                          '<td ' . TPL::getSnippet('sRowCrypt') . ' align="right">' .
479 3
                            $backup->cryptCountSkipped() .
480 3
                          '</td>' .
481 3
                          '<td ' . TPL::getSnippet('sRowCrypt') . ' align="right">' .
482 3
                            $backup->cryptCountFailed() .
483 3
                          '</td>' .
484 3
                         '</tr>' .
485 3
                         '<tr>' .
486 3
                          '<td ' . TPL::getSnippet('sRowSync') . '>syncs</td>' .
487 3
                          '<td ' . TPL::getSnippet('sRowSync') . ' align="right">' .
488 3
                            $backup->syncCount() . '</td>' .
489 3
                          '<td ' . TPL::getSnippet('sRowSync') . ' align="right">' .
490 3
                            $backup->syncCountSkipped() .
491 3
                          '</td>' .
492 3
                          '<td ' . TPL::getSnippet('sRowSync') . ' align="right">' .
493 3
                            $backup->syncCountFailed() .
494 3
                          '</td>' .
495 3
                         '</tr>' .
496 3
                         '<tr>' .
497 3
                          '<td ' . TPL::getSnippet('sRowCleanup') . '>cleanups</td>' .
498 3
                          '<td ' . TPL::getSnippet('sRowCleanup') . ' align="right">' .
499 3
                            $backup->cleanupCount() .
500 3
                          '</td>' .
501 3
                          '<td ' . TPL::getSnippet('sRowCleanup') . ' align="right">' .
502 3
                            $backup->cleanupCountSkipped() .
503 3
                          '</td>' .
504 3
                          '<td ' . TPL::getSnippet('sRowCleanup') . ' align="right">' .
505 3
                            $backup->cleanupCountFailed() .
506 3
                          '</td>' .
507
                         '</tr>';
508
509 3
            }
510
            $html .= '</table>';
511 4
        }
512
        return $html;
513
    }
514
515
    /**
516
     * Return mail body footer.
517
     *
518
     * @return string
519 4
     */
520
    protected function getFooterHtml()
521 4
    {
522 4
        return '<p ' . TPL::getSnippet('sStats') . '>' . PHP_Timer::resourceUsage() . '</p>' .
523
               '</td></tr></table>';
524
    }
525
}
526