Swift_Transport_EsmtpTransport::getPort()   A
last analyzed

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
/**
12
 * Sends Messages over SMTP with ESMTP support.
13
 *
14
 * @author Chris Corbyn
15
 */
16
class Swift_Transport_EsmtpTransport extends Swift_Transport_AbstractSmtpTransport implements Swift_Transport_SmtpAgent
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...
17
{
18
    /**
19
     * ESMTP extension handlers.
20
     *
21
     * @var Swift_Transport_EsmtpHandler[]
22
     */
23
    private $_handlers = array();
24
25
    /**
26
     * ESMTP capabilities.
27
     *
28
     * @var string[][]
29
     */
30
    private $_capabilities = array();
31
32
    /**
33
     * Connection buffer parameters.
34
     *
35
     * @var array
36
     */
37
    private $_params = array(
38
        'protocol'               => 'tcp',
39
        'host'                   => 'localhost',
40
        'port'                   => 25,
41
        'timeout'                => 30,
42
        'blocking'               => 1,
43
        'tls'                    => false,
44
        'type'                   => Swift_Transport_IoBuffer::TYPE_SOCKET,
45
        'stream_context_options' => array(),
46
        'verifySsl'              => array(),
47
    );
48
49
    /**
50
     * Creates a new EsmtpTransport using the given I/O buffer.
51
     *
52
     * @param Swift_Transport_IoBuffer       $buf
53
     * @param Swift_Transport_EsmtpHandler[] $extensionHandlers
54
     * @param Swift_Events_EventDispatcher   $dispatcher
55
     * @param string                         $localDomain
56
     */
57 123
    public function __construct(Swift_Transport_IoBuffer $buf, array $extensionHandlers, Swift_Events_EventDispatcher $dispatcher, $localDomain = '127.0.0.1')
58
    {
59 123
        parent::__construct($buf, $dispatcher, $localDomain);
60 123
        $this->setExtensionHandlers($extensionHandlers);
61 123
    }
62
63
    /**
64
     * Set the host to connect to.
65
     *
66
     * @param string $host
67
     *
68
     * @return $this
69
     */
70 8
    public function setHost($host)
71
    {
72 8
        $this->_params['host'] = $host;
73
74 8
        return $this;
75
    }
76
77
    /**
78
     * Get the host to connect to.
79
     *
80
     * @return string
81
     */
82 3
    public function getHost()
83
    {
84 3
        return $this->_params['host'];
85
    }
86
87
    /**
88
     * Set the port to connect to.
89
     *
90
     * @param int $port
91
     *
92
     * @return $this
93
     */
94 8
    public function setPort($port)
95
    {
96 8
        $this->_params['port'] = (int)$port;
97
98 8
        return $this;
99
    }
100
101
    /**
102
     * Get the port to connect to.
103
     *
104
     * @return int
105
     */
106 3
    public function getPort()
107
    {
108 3
        return $this->_params['port'];
109
    }
110
111
    /**
112
     * Set the connection timeout.
113
     *
114
     * @param int $timeout seconds
115
     *
116
     * @return $this
117
     */
118 4
    public function setTimeout($timeout)
119
    {
120 4
        $this->_params['timeout'] = (int)$timeout;
121 4
        $this->_buffer->setParam('timeout', (int)$timeout);
122
123 4
        return $this;
124
    }
125
126
    /**
127
     * Get the connection timeout.
128
     *
129
     * @return int
130
     */
131 3
    public function getTimeout()
132
    {
133 3
        return $this->_params['timeout'];
134
    }
135
136
    /**
137
     * Set the encryption type (tls or ssl).
138
     *
139
     * @param string $encryption
140
     *
141
     * @return $this
142
     */
143 8
    public function setEncryption($encryption)
144
    {
145 8
        $encryption = Swift::strtolowerWithStaticCache($encryption);
146
147 8
        if ('tls' === $encryption) {
148 4
            $this->_params['protocol'] = 'tcp';
149 4
            $this->_params['tls'] = true;
150 4
        } else {
151 4
            $this->_params['protocol'] = $encryption;
152 4
            $this->_params['tls'] = false;
153
        }
154
155 8
        return $this;
156
    }
157
158
    /**
159
     * Get the encryption type.
160
     *
161
     * @return string
162
     */
163 3
    public function getEncryption()
164
    {
165 3
        return $this->_params['tls'] ? 'tls' : $this->_params['protocol'];
166
    }
167
168
    /**
169
     * Disable SSL-Verify to prevent error like "SSL3_GET_SERVER_CERTIFICATE:certificate verify failed"
170
     *
171
     * @param bool $bool
172
     *
173
     * @return Swift_Transport_EsmtpTransport
174
     */
175
    public function setVerifySsl($bool = false)
176
    {
177
        $options['ssl']['verify_peer'] = $bool;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$options was never initialized. Although not strictly required by PHP, it is generally a good practice to add $options = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
178
        $options['ssl']['verify_peer_name'] = $bool;
179
        $options['ssl']['allow_self_signed'] = !$bool;
180
181
        $this->_params['verifySsl'] = $options;
182
183
        return $this;
184
    }
185
186
    /**
187
     * Sets the stream context options.
188
     *
189
     * @param array $options
190
     *
191
     * @return $this
192
     */
193
    public function setStreamOptions($options)
194
    {
195
        $this->_params['stream_context_options'] = $options;
196
197
        return $this;
198
    }
199
200
    /**
201
     * Returns the stream context options.
202
     *
203
     * @return array
204
     */
205 1
    public function getStreamOptions()
206
    {
207 1
        return $this->_params['stream_context_options'];
208
    }
209
210
    /**
211
     * Sets the source IP.
212
     *
213
     * @param string $source
214
     *
215
     * @return $this
216
     */
217
    public function setSourceIp($source)
218
    {
219
        $this->_params['sourceIp'] = $source;
220
221
        return $this;
222
    }
223
224
    /**
225
     * Returns the IP used to connect to the destination.
226
     *
227
     * @return string
228
     */
229 1
    public function getSourceIp()
230
    {
231 1
        return isset($this->_params['sourceIp']) ? $this->_params['sourceIp'] : null;
232
    }
233
234
    /**
235
     * Set ESMTP extension handlers.
236
     *
237
     * @param Swift_Transport_EsmtpHandler[] $handlers
238
     *
239
     * @return $this
240
     */
241 123
    public function setExtensionHandlers(array $handlers)
242
    {
243 123
        $assoc = array();
244 123
        foreach ($handlers as $handler) {
245 15
            $assoc[$handler->getHandledKeyword()] = $handler;
246 123
        }
247
248
        /** @noinspection PhpUsageOfSilenceOperatorInspection */
249
        /** @noinspection UsageOfSilenceOperatorInspection */
250 123
        @uasort($assoc, array($this, '_sortHandlers'));
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
251 123
          $this->_handlers = $assoc;
252 123
          $this->_setHandlerParams();
253
254 123
          return $this;
255
    }
256
257
    /**
258
     * Get ESMTP extension handlers.
259
     *
260
     * @return Swift_Transport_EsmtpHandler[]
261
     */
262 2
    public function getExtensionHandlers()
263
    {
264 2
        return array_values($this->_handlers);
265
    }
266
267
    /**
268
     * Run a command against the buffer, expecting the given response codes.
269
     *
270
     * If no response codes are given, the response will not be validated.
271
     * If codes are given, an exception will be thrown on an invalid response.
272
     *
273
     * @param string   $command
274
     * @param int[]    $codes
275
     * @param string[] $failures An array of failures by-reference
276
     *
277
     * @return string
278
     */
279 96
    public function executeCommand($command, $codes = array(), &$failures = null)
280
    {
281 96
        $failures = (array)$failures;
282 96
        $stopSignal = false;
283 96
        $response = null;
0 ignored issues
show
Unused Code introduced by
$response is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
284
285 96
        foreach ($this->_getActiveHandlers() as $handler) {
286 4
            $response = $handler->onCommand(
287 4
                $this, $command, $codes, $failures, $stopSignal
0 ignored issues
show
Bug introduced by
It seems like $failures defined by (array) $failures on line 281 can also be of type array; however, Swift_Transport_EsmtpHandler::onCommand() does only seem to accept array<integer,string>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
288 4
            );
289
290 4
            if ($stopSignal) {
291 1
                return $response;
292
            }
293 96
        }
294
295 96
        return parent::executeCommand($command, $codes, $failures);
0 ignored issues
show
Bug introduced by
It seems like $failures defined by (array) $failures on line 281 can also be of type array; however, Swift_Transport_Abstract...sport::executeCommand() does only seem to accept array<integer,string>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
296
    }
297
298
    /**
299
     * Mixin handling method for ESMTP handlers
300
     *
301
     * @param $method
302
     * @param $args
303
     *
304
     * @return $this|mixed
305
     */
306 7
    public function __call($method, $args)
307
    {
308 7
        foreach ($this->_handlers as $handler) {
309
310 7
            $inArray = in_array(
311 7
                Swift::strtolowerWithStaticCache($method),
312 7
                array_map(array('Swift', 'strtolowerWithStaticCache'), (array)$handler->exposeMixinMethods()),
313
                true
314 7
            );
315
316 7
            if ($inArray) {
317 7
                $return = call_user_func_array(array($handler, $method), $args);
318
319
                // allow fluid method calls
320
                if (
321
                    null === $return
322 7
                    &&
323 6
                    0 === strpos($method, 'set')
324 7
                ) {
325 6
                    return $this;
326
                }
327
328 1
              return $return;
329
            }
330 3
        }
331
332
        trigger_error('Call to undefined method ' . $method, E_USER_ERROR);
333
    }
334
335
    /** Get the params to initialize the buffer */
336 96
    protected function _getBufferParams()
337
    {
338 96
        return $this->_params;
339
    }
340
341
    /**
342
     * Overridden to perform EHLO instead
343
     *
344
     * @throws Swift_TransportException
345
     */
346 92
    protected function _doHeloCommand()
347
    {
348
        try {
349 92
            $response = $this->executeCommand(
350 92
                sprintf("EHLO %s\r\n", $this->_domain), array(250)
351 92
            );
352 92
        } catch (Swift_TransportException $e) {
353 6
            parent::_doHeloCommand();
354
355 4
            return null;
356
        }
357
358 86
        if ($this->_params['tls']) {
359
            try {
360
                $this->executeCommand("STARTTLS\r\n", array(220));
361
362
                if (!$this->_buffer->startTLS()) {
0 ignored issues
show
Bug introduced by
The method startTLS does only exist in Swift_Transport_StreamBuffer, but not in Swift_Transport_IoBuffer.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
363
                    throw new Swift_TransportException('Unable to connect with TLS encryption');
364
                }
365
366
                try {
367
                    $response = $this->executeCommand(
368
                        sprintf("EHLO %s\r\n", $this->_domain), array(250)
369
                    );
370
                } catch (Swift_TransportException $e) {
371
                    parent::_doHeloCommand();
372
373
                    return null;
374
                }
375
            } catch (Swift_TransportException $e) {
376
                $this->_throwException($e);
377
            }
378
        }
379
380 86
        $this->_capabilities = $this->_getCapabilities($response);
381 86
        $this->_setHandlerParams();
382 86
        foreach ($this->_getActiveHandlers() as $handler) {
383 6
            $handler->afterEhlo($this);
384 86
        }
385 86
    }
386
387
    /**
388
     * Overridden to add Extension support
389
     *
390
     * @param $address
391
     */
392 56 View Code Duplication
    protected function _doMailFromCommand($address)
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...
393
    {
394 56
        $handlers = $this->_getActiveHandlers();
395
396 56
        $params = array();
397 56
        foreach ($handlers as $handler) {
398 2
            $params = array_merge($params, (array)$handler->getMailParams());
399 56
        }
400
401 56
        $paramStr = !empty($params) ? ' ' . implode(' ', $params) : '';
402 56
        $this->executeCommand(
403 56
            sprintf("MAIL FROM:<%s>%s\r\n", $address, $paramStr), array(250)
404 56
        );
405 54
    }
406
407
    /**
408
     * Overridden to add Extension support
409
     *
410
     * @param $address
411
     */
412 54 View Code Duplication
    protected function _doRcptToCommand($address)
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...
413
    {
414 54
        $handlers = $this->_getActiveHandlers();
415
416 54
        $params = array();
417 54
        foreach ($handlers as $handler) {
418 2
            $params = array_merge($params, (array)$handler->getRcptParams());
419 54
        }
420
421 54
        $paramStr = !empty($params) ? ' ' . implode(' ', $params) : '';
422 54
        $this->executeCommand(
423 54
            sprintf("RCPT TO:<%s>%s\r\n", $address, $paramStr), array(250, 251, 252)
424 54
        );
425 48
    }
426
427
    /**
428
     * Determine ESMTP capabilities by function group
429
     *
430
     * @param string $ehloResponse
431
     *
432
     * @return array
433
     */
434 86
    private function _getCapabilities($ehloResponse)
435
    {
436 86
        $capabilities = array();
437 86
        $ehloResponse = trim($ehloResponse);
438 86
        $lines = explode("\r\n", $ehloResponse);
439 86
        array_shift($lines);
440 86
        foreach ($lines as $line) {
441 10
            if (preg_match('/^[0-9]{3}[ -]([A-Z0-9-]+)((?:[ =].*)?)$/Di', $line, $matches)) {
442 10
                $keyword = strtoupper($matches[1]);
443 10
                $paramStr = strtoupper(ltrim($matches[2], ' ='));
444 10
                $params = !empty($paramStr) ? explode(' ', $paramStr) : array();
445 10
                $capabilities[$keyword] = $params;
446 10
            }
447 86
        }
448
449 86
        return $capabilities;
450
    }
451
452
    /**
453
     * Set parameters which are used by each extension handler
454
     */
455 123
    private function _setHandlerParams()
456
    {
457 123
        foreach ($this->_handlers as $keyword => $handler) {
458 15
            if (isset($this->_capabilities[$keyword])) {
459 6
                $handler->setKeywordParams($this->_capabilities[$keyword]);
460 6
            }
461 123
        }
462 123
    }
463
464
    /**
465
     * Get ESMTP handlers which are currently ok to use
466
     *
467
     * @return Swift_Transport_EsmtpHandler[]
468
     */
469 96
    private function _getActiveHandlers()
470
    {
471 96
        $handlers = array();
472 96
        foreach ($this->_handlers as $keyword => $handler) {
473 10
            if (isset($this->_capabilities[$keyword])) {
474 6
                $handlers[] = $handler;
475 6
            }
476 96
        }
477
478 96
        return $handlers;
479
    }
480
481
    /**
482
     * Custom sort for extension handler ordering
483
     *
484
     * @param Swift_Transport_EsmtpHandler $a
485
     * @param Swift_Transport_EsmtpHandler $b
486
     *
487
     * @return integer
488
     */
489 10
    private function _sortHandlers($a, $b)
490
    {
491 10
        return $a->getPriorityOver($b->getHandledKeyword());
492
    }
493
}
494