Completed
Push — 5.x ( c9dc5a...95e895 )
by Lars
17:11 queued 04:33
created

getLocalDomain()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 2
cts 2
cp 1
crap 1
1
<?php
2
3
/*
4
 * This file is part of SwiftMailer.
5
 * (c) 2004-2009 Chris Corbyn
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
use voku\helper\UTF8;
12
13
/**
14
 * Sends Messages over SMTP.
15
 *
16
 * @author Chris Corbyn
17
 */
18
abstract class Swift_Transport_AbstractSmtpTransport implements Swift_Transport
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
19
{
20
    /**
21
     * Input-Output buffer for sending/receiving SMTP commands and responses
22
     *
23
     * @var Swift_Transport_IoBuffer|Swift_Transport_StreamBuffer
24
     */
25
    protected $_buffer;
26
27
    /**
28
     * Connection status
29
     *
30
     * @var bool
31
     */
32
    protected $_started = false;
33
34
    /**
35
     * The domain name to use in HELO command
36
     *
37
     * @var string
38
     */
39
    protected $_domain = '[127.0.0.1]';
40
41
    /**
42
     * The event dispatching layer
43
     *
44
     * @var Swift_Events_EventDispatcher
45
     */
46
    protected $_eventDispatcher;
47
48
    /**
49
     * Source Ip
50
     *
51
     * @var string
52
     */
53
    protected $_sourceIp;
54
55
    /**
56
     * Return an array of params for the Buffer
57
     */
58
    abstract protected function _getBufferParams();
59
60
    /**
61
     * Creates a new EsmtpTransport using the given I/O buffer.
62
     *
63
     * @param Swift_Transport_IoBuffer     $buf
64
     * @param Swift_Events_EventDispatcher $dispatcher
65
     * @param string                       $localDomain
66
     */
67 176
    public function __construct(Swift_Transport_IoBuffer $buf, Swift_Events_EventDispatcher $dispatcher, $localDomain)
68
    {
69 176
        $this->_eventDispatcher = $dispatcher;
70 176
        $this->_buffer = $buf;
71 176
        $this->setLocalDomain($localDomain);
72 176
    }
73
74
    /**
75
     * Set the name of the local domain which Swift will identify itself as.
76
     *
77
     * This should be a fully-qualified domain name and should be truly the domain
78
     * you're using.
79
     *
80
     * If your server does not have a domain name, use the IP address. This will
81
     * automatically be wrapped in square brackets as described in RFC 5321,
82
     * section 4.1.3.
83
     *
84
     * @param string $domain
85
     *
86
     * @return $this
87
     */
88 176
    public function setLocalDomain($domain)
89
    {
90 176
        if (UTF8::substr($domain, 0, 1) !== '[') {
91 176
            if (filter_var($domain, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
92 5
                $domain = '['.$domain.']';
93 176
            } elseif (filter_var($domain, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
94
                $domain = '[IPv6:'.$domain.']';
95
            }
96 176
        }
97
98 176
        $this->domain = $domain;
0 ignored issues
show
Bug introduced by
The property domain does not seem to exist. Did you mean _domain?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
99
100 176
        return $this;
101
    }
102
103
    /**
104
     * Get the name of the domain Swift will identify as.
105
     *
106
     * If an IP address was specified, this will be returned wrapped in square
107
     * brackets as described in RFC 5321, section 4.1.3.
108
     *
109
     * @return string
110
     */
111 4
    public function getLocalDomain()
112
    {
113 4
        return $this->_domain;
114
    }
115
116
    /**
117
     * Sets the source IP.
118
     *
119
     * @param string $source
120
     */
121
    public function setSourceIp($source)
122
    {
123
        $this->_sourceIp = $source;
124
    }
125
126
    /**
127
     * Returns the IP used to connect to the destination.
128
     *
129
     * @return string
130
     */
131
    public function getSourceIp()
132
    {
133
        return $this->_sourceIp;
134
    }
135
136
    /**
137
     * Start the SMTP connection.
138
     */
139 140
    public function start()
140
    {
141 140
        if (!$this->_started) {
142
143 140
            $evt = $this->_eventDispatcher->createTransportChangeEvent($this);
144 140
            if ($evt) {
145
146 22
                $this->_eventDispatcher->dispatchEvent($evt, 'beforeTransportStarted');
147 22
                if ($evt->bubbleCancelled()) {
148 3
                    return;
149
                }
150 19
            }
151
152
            try {
153 137
                $this->_buffer->initialize($this->_getBufferParams());
154 137
            } catch (Swift_TransportException $e) {
155
                $this->_throwException($e);
156
            }
157 137
            $this->_readGreeting();
158 131
            $this->_doHeloCommand();
159
160 129
            if ($evt) {
161 19
                $this->_eventDispatcher->dispatchEvent($evt, 'transportStarted');
162 19
            }
163
164 129
            $this->_started = true;
165 129
        }
166 129
    }
167
168
    /**
169
     * Test if an SMTP connection has been established.
170
     *
171
     * @return bool
172
     */
173 23
    public function isStarted()
174
    {
175 23
        return $this->_started;
176
    }
177
178
    /**
179
     * Send the given Message.
180
     *
181
     * Recipient/sender data will be retrieved from the Message API.
182
     * The return value is the number of recipients who were accepted for delivery.
183
     *
184
     * @param Swift_Mime_Message $message
185
     * @param string[]|null      $failedRecipients An array of failures by-reference
186
     *
187
     * @return int
188
     *
189
     * @throws Exception
190
     * @throws Swift_TransportException
191
     */
192 84
    public function send(Swift_Mime_Message $message, &$failedRecipients = null)
193
    {
194 84
        $sent = 0;
195 84
        $failedRecipients = (array)$failedRecipients;
196
197 84
        $evt = $this->_eventDispatcher->createSendEvent($this, $message);
198 84
        if ($evt) {
199
200 25
            $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed');
201 25
            if ($evt->bubbleCancelled()) {
202 3
                return 0;
203
            }
204 22
        }
205
206 81
        if (!$reversePath = $this->_getReversePath($message)) {
207
            $this->_throwException(
208
                new Swift_TransportException(
209
                    'Cannot send message without a sender address'
210
                )
211
            );
212
        }
213
214 81
        $to = (array)$message->getTo();
215 81
        $cc = (array)$message->getCc();
216 81
        $tos = array_merge($to, $cc);
217 81
        $bcc = (array)$message->getBcc();
218
219 81
        $message->setBcc(array());
220
221
        try {
222 81
            $sent += $this->_sendTo($message, $reversePath, $tos, $failedRecipients);
223 69
            $sent += $this->_sendBcc($message, $reversePath, $bcc, $failedRecipients);
224 81
        } catch (Exception $e) {
225 12
            $message->setBcc($bcc);
226 12
            throw $e;
227
        }
228
229 69
        $message->setBcc($bcc);
230
231 69
        if ($evt) {
232
233 22
            if ($sent === count($to) + count($cc) + count($bcc)) {
234 13
                $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS);
235 22
            } elseif ($sent > 0) {
236 3
                $evt->setResult(Swift_Events_SendEvent::RESULT_TENTATIVE);
237 3
            } else {
238 6
                $evt->setResult(Swift_Events_SendEvent::RESULT_FAILED);
239
            }
240
241 22
            $evt->setFailedRecipients($failedRecipients);
242 22
            $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed');
243 22
        }
244
245 69
        $message->generateId(); // Make sure a new Message ID is used
246
247 69
        return $sent;
248
    }
249
250
    /**
251
     * Stop the SMTP connection.
252
     */
253 42
    public function stop()
254
    {
255 42
        if ($this->_started) {
256
257 16
            $evt = $this->_eventDispatcher->createTransportChangeEvent($this);
258 16
            if ($evt) {
259
260 13
                $this->_eventDispatcher->dispatchEvent($evt, 'beforeTransportStopped');
261 13
                if ($evt->bubbleCancelled()) {
262 3
                    return;
263
                }
264 10
            }
265
266
            try {
267 13
                $this->executeCommand("QUIT\r\n", array(221));
268 13
            } catch (Swift_TransportException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
269
            }
270
271
            try {
272 13
                $this->_buffer->terminate();
273
274 13
                if ($evt) {
275 10
                    $this->_eventDispatcher->dispatchEvent($evt, 'transportStopped');
276 10
                }
277 13
            } catch (Swift_TransportException $e) {
278
                $this->_throwException($e);
279
            }
280 13
        }
281 39
        $this->_started = false;
282 39
    }
283
284
    /**
285
     * Register a plugin.
286
     *
287
     * @param Swift_Events_EventListener $plugin
288
     */
289 3
    public function registerPlugin(Swift_Events_EventListener $plugin)
290
    {
291 3
        $this->_eventDispatcher->bindEventListener($plugin);
292 3
    }
293
294
    /**
295
     * Reset the current mail transaction.
296
     */
297 12
    public function reset()
298
    {
299 12
        $this->executeCommand("RSET\r\n", array(250));
300 12
    }
301
302
    /**
303
     * Get the IoBuffer where read/writes are occurring.
304
     *
305
     * @return Swift_Transport_IoBuffer
306
     */
307 34
    public function getBuffer()
308
    {
309 34
        return $this->_buffer;
310
    }
311
312
    /**
313
     * Run a command against the buffer, expecting the given response codes.
314
     *
315
     * If no response codes are given, the response will not be validated.
316
     * If codes are given, an exception will be thrown on an invalid response.
317
     *
318
     * @param string   $command
319
     * @param int[]    $codes
320
     * @param string[] $failures An array of failures by-reference
321
     *
322
     * @return string
323
     */
324 137
    public function executeCommand($command, $codes = array(), &$failures = null)
325
    {
326 137
        $failures = (array)$failures;
327 137
        $seq = $this->_buffer->write($command);
328 137
        $response = $this->_getFullResponse($seq);
329
330 137
        $evt = $this->_eventDispatcher->createCommandEvent($this, $command, $codes);
331 137
        if ($evt) {
332 7
            $this->_eventDispatcher->dispatchEvent($evt, 'commandSent');
333 7
        }
334
335 137
        $this->_assertResponseCode($response, $codes);
336
337 132
        return $response;
338
    }
339
340
    /** Read the opening SMTP greeting */
341 137
    protected function _readGreeting()
342
    {
343 137
        $this->_assertResponseCode($this->_getFullResponse(0), array(220));
344 131
    }
345
346
    /** Send the HELO welcome */
347 45
    protected function _doHeloCommand()
348
    {
349 45
        $this->executeCommand(
350 45
            sprintf("HELO %s\r\n", $this->_domain), array(250)
351 45
        );
352 43
    }
353
354
    /**
355
     * Send the MAIL FROM command
356
     *
357
     * @param string $address
358
     */
359 25
    protected function _doMailFromCommand($address)
360
    {
361 25
        $this->executeCommand(
362 25
            sprintf("MAIL FROM:<%s>\r\n", $address), array(250)
363 25
        );
364 24
    }
365
366
    /**
367
     * Send the RCPT TO command
368
     *
369
     * @param string $address
370
     */
371 24
    protected function _doRcptToCommand($address)
372
    {
373 24
        $this->executeCommand(
374 24
            sprintf("RCPT TO:<%s>\r\n", $address), array(250, 251, 252)
375 24
        );
376 21
    }
377
378
    /** Send the DATA command */
379 69
    protected function _doDataCommand()
380
    {
381 69
        $this->executeCommand("DATA\r\n", array(354));
382 63
    }
383
384
    /**
385
     * Stream the contents of the message over the buffer
386
     *
387
     * @param Swift_Mime_Message $message
388
     *
389
     * @throws Swift_TransportException
390
     */
391 63
    protected function _streamMessage(Swift_Mime_Message $message)
392
    {
393 63
        $this->_buffer->setWriteTranslations(array("\r\n." => "\r\n.."));
394
395
        try {
396 63
            $message->toByteStream($this->_buffer);
397 63
            $this->_buffer->flushBuffers();
398 63
        } catch (Swift_TransportException $e) {
399
            $this->_throwException($e);
400
        }
401
402 63
        $this->_buffer->setWriteTranslations(array());
403 63
        $this->executeCommand("\r\n.\r\n", array(250));
404 60
    }
405
406
    /**
407
     * Determine the best-use reverse path for this message
408
     *
409
     * @param Swift_Mime_Message $message
410
     *
411
     * @return mixed|null|string
412
     */
413 85 View Code Duplication
    protected function _getReversePath(Swift_Mime_Message $message)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
414
    {
415 85
        $return = $message->getReturnPath();
416 85
        $sender = $message->getSender();
417 85
        $from = $message->getFrom();
418 85
        $path = null;
419
420 85
        if (!empty($return)) {
421 3
            $path = $return;
422 85
        } elseif (!empty($sender)) {
423
            // don't use array_keys
424 3
            reset($sender); // reset Pointer to first pos
425 3
            $path = key($sender); // get key
426 82
        } elseif (!empty($from)) {
427 75
            reset($from); // reset Pointer to first pos
428 75
            $path = key($from); // get key
429 75
        }
430
431 85
        return $path;
432
    }
433
434
    /**
435
     * Throw a TransportException, first sending it to any listeners.
436
     *
437
     * @param Swift_TransportException $e
438
     *
439
     * @throws Swift_TransportException
440
     */
441 54 View Code Duplication
    protected function _throwException(Swift_TransportException $e)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
442
    {
443 54
        $evt = $this->_eventDispatcher->createTransportExceptionEvent($this, $e);
444 54
        if ($evt) {
445
446 6
            $this->_eventDispatcher->dispatchEvent($evt, 'exceptionThrown');
447 6
            if (!$evt->bubbleCancelled()) {
448 3
                throw $e;
449
            }
450
451 3
        } else {
452 48
            throw $e;
453
        }
454 3
    }
455
456
    /**
457
     * Throws an Exception if a response code is incorrect
458
     *
459
     * @param string    $response
460
     * @param integer[] $wanted
461
     *
462
     * @throws Swift_TransportException
463
     */
464 143
    protected function _assertResponseCode($response, $wanted)
465
    {
466
        /** @noinspection PrintfScanfArgumentsInspection */
467 143
        list($code) = sscanf($response, '%3d');
468
469
        /** @noinspection TypeUnsafeArraySearchInspection */
470 143
        $valid = (empty($wanted) || in_array($code, $wanted));
471
472 143
        $evt = $this->_eventDispatcher->createResponseEvent($this, $response, $valid);
473 143
        if ($evt) {
474 7
            $this->_eventDispatcher->dispatchEvent($evt, 'responseReceived');
475 7
        }
476
477 143
        if (!$valid) {
478 54
            $this->_throwException(
479 54
                new Swift_TransportException(
480 54
                    'Expected response code ' . implode('/', $wanted) . ' but got code ' .
481 54
                    '"' . $code . '", with message "' . $response . '"',
482
                    $code
483 54
                )
484 54
            );
485 3
        }
486 134
    }
487
488
    /**
489
     * Get an entire multi-line response using its sequence number
490
     *
491
     * @param int $seq
492
     *
493
     * @return string
494
     * @throws Swift_TransportException
495
     */
496 143
    protected function _getFullResponse($seq)
497
    {
498 143
        $response = '';
499
        try {
500
            do {
501 143
                $line = $this->_buffer->readLine($seq);
502 143
                $response .= $line;
503 143
            } while (null !== $line && false !== $line && ' ' !== $line[3]);
504 143
        } catch (Swift_TransportException $e) {
505
            $this->_throwException($e);
506
        } catch (Swift_IoException $e) {
507
            $this->_throwException(
508
                new Swift_TransportException(
509
                    $e->getMessage()
510
                )
511
            );
512
        }
513
514 143
        return $response;
515
    }
516
517
    /**
518
     * Send an email to the given recipients from the given reverse path
519
     *
520
     * @param Swift_Mime_Message $message
521
     * @param string             $reversePath
522
     * @param array              $recipients
523
     * @param array              $failedRecipients
524
     *
525
     * @return int
526
     *
527
     * @throws Swift_TransportException
528
     */
529 81
    private function _doMailTransaction($message, $reversePath, array $recipients, array &$failedRecipients)
530
    {
531 81
        $sent = 0;
532 81
        $this->_doMailFromCommand($reversePath);
533
534 78
        foreach ($recipients as $forwardPath) {
535
            try {
536 78
                $this->_doRcptToCommand($forwardPath);
537 69
                ++$sent;
538 78
            } catch (Swift_TransportException $e) {
539 18
                $failedRecipients[] = $forwardPath;
540
541
                // $this->_throwException($e);
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
542
                // throw $e;
543
                // <-- TODO: check this
544
                // <-- https://github.com/michaelhogg/swiftmailer/commit/b824cba068d10c46291018947e463cb201a3e572
545
            }
546 78
        }
547
548 78
        if ($sent !== 0) {
549 69
            $this->_doDataCommand();
550 63
            $this->_streamMessage($message);
551 60
        } else {
552 12
            $this->reset();
553
        }
554
555 69
        return $sent;
556
    }
557
558
    /**
559
     * Send a message to the given To: recipients
560
     *
561
     * @param Swift_Mime_Message $message
562
     * @param                    $reversePath
563
     * @param array              $to
564
     * @param array              $failedRecipients
565
     *
566
     * @return int
567
     *
568
     * @throws Swift_TransportException
569
     */
570 81
    private function _sendTo(Swift_Mime_Message $message, $reversePath, array $to, array &$failedRecipients)
571
    {
572 81
        if (empty($to)) {
573
            return 0;
574
        }
575
576 81
        return $this->_doMailTransaction($message, $reversePath, array_keys($to), $failedRecipients);
577
    }
578
579
    /**
580
     * Send a message to all Bcc: recipients
581
     *
582
     * @param Swift_Mime_Message $message
583
     * @param                    $reversePath
584
     * @param array              $bcc
585
     * @param array              $failedRecipients
586
     *
587
     * @return int
588
     *
589
     * @throws Swift_TransportException
590
     */
591 69
    private function _sendBcc(Swift_Mime_Message $message, $reversePath, array $bcc, array &$failedRecipients)
592
    {
593 69
        $sent = 0;
594 69
        foreach ($bcc as $forwardPath => $name) {
595 9
            $message->setBcc(array($forwardPath => $name));
596 9
            $sent += $this->_doMailTransaction(
597 9
                $message,
598 9
                $reversePath,
599 9
                array($forwardPath),
600
                $failedRecipients
601 9
            );
602 69
        }
603
604 69
        return $sent;
605
    }
606
607
608
609
    /**
610
     * Destructor.
611
     */
612 30
    public function __destruct()
613
    {
614
        try {
615 30
            $this->stop();
616 30
        } catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
617
        }
618 30
    }
619
}
620