Completed
Pull Request — 5.x (#16)
by Lars
05:10
created

Swift_Signers_DKIMSigner::setHeaders()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 22
Code Lines 12

Duplication

Lines 22
Ratio 100 %

Code Coverage

Tests 12
CRAP Score 6
Metric Value
dl 22
loc 22
ccs 12
cts 12
cp 1
rs 8.6738
cc 6
eloc 12
nc 6
nop 1
crap 6
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
 * DKIM Signer used to apply DKIM Signature to a message.
13
 *
14
 * @author Xavier De Cock <[email protected]>
15
 */
16
class Swift_Signers_DKIMSigner implements Swift_Signers_HeaderSigner
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
     * PrivateKey.
20
     *
21
     * @var string
22
     */
23
    protected $_privateKey;
24
25
    /**
26
     * DomainName.
27
     *
28
     * @var string
29
     */
30
    protected $_domainName;
31
32
    /**
33
     * Selector.
34
     *
35
     * @var string
36
     */
37
    protected $_selector;
38
39
    /**
40
     * Hash algorithm used.
41
     *
42
     * @var string
43
     */
44
    protected $_hashAlgorithm = 'rsa-sha1';
45
46
    /**
47
     * Body canon method.
48
     *
49
     * @var string
50
     */
51
    protected $_bodyCanon = 'simple';
52
53
    /**
54
     * Header canon method.
55
     *
56
     * @var string
57
     */
58
    protected $_headerCanon = 'simple';
59
60
    /**
61
     * Headers not being signed.
62
     *
63
     * @var array
64
     */
65
    protected $_ignoredHeaders = array('return-path' => true);
66
67
    /**
68
     * Signer identity.
69
     *
70
     * @var string
71
     */
72
    protected $_signerIdentity;
73
74
    /**
75
     * BodyLength.
76
     *
77
     * @var int
78
     */
79
    protected $_bodyLen = 0;
80
81
    /**
82
     * Maximum signedLen.
83
     *
84
     * @var int
85
     */
86
    protected $_maxLen = PHP_INT_MAX;
87
88
    /**
89
     * Embbed bodyLen in signature.
90
     *
91
     * @var bool
92
     */
93
    protected $_showLen = false;
94
95
    /**
96
     * When the signature has been applied (true means time()), false means not embedded.
97
     *
98
     * @var mixed
99
     */
100
    protected $_signatureTimestamp = true;
101
102
    /**
103
     * When will the signature expires false means not embedded, if sigTimestamp is auto
104
     * Expiration is relative, otherwhise it's absolute.
105
     *
106
     * @var int
107
     */
108
    protected $_signatureExpiration = false;
109
110
    /**
111
     * Must we embed signed headers?
112
     *
113
     * @var bool
114
     */
115
    protected $_debugHeaders = false;
116
117
    // work variables
118
    /**
119
     * Headers used to generate hash.
120
     *
121
     * @var array
122
     */
123
    protected $_signedHeaders = array();
124
125
    /**
126
     * If debugHeaders is set store debugDatas here.
127
     *
128
     * @var string
129
     */
130
    private $_debugHeadersData = '';
131
132
    /**
133
     * Stores the bodyHash.
134
     *
135
     * @var string
136
     */
137
    private $_bodyHash = '';
138
139
    /**
140
     * Stores the signature header.
141
     *
142
     * @var Swift_Mime_Headers_ParameterizedHeader
143
     */
144
    protected $_dkimHeader;
145
146
    /**
147
     * @var resource
148
     */
149
    private $_bodyHashHandler;
150
151
    /**
152
     * @var null
153
     *
154
     * no used?
155
     */
156
    private $_headerHash;
157
158
    /**
159
     * @var string
160
     */
161
    private $_headerCanonData = '';
162
163
    /**
164
     * @var int
165
     */
166
    private $_bodyCanonEmptyCounter = 0;
167
168
    /**
169
     * @var int
170
     */
171
    private $_bodyCanonIgnoreStart = 2;
172
173
    /**
174
     * @var bool
175
     */
176
    private $_bodyCanonSpace = false;
177
178
    /**
179
     * @var null|string
180
     */
181
    private $_bodyCanonLastChar = null;
182
183
    /**
184
     * @var string
185
     */
186
    private $_bodyCanonLine = '';
187
188
    /**
189
     * @var array
190
     */
191
    private $_bound = array();
192
193
    /**
194
     * Constructor.
195
     *
196
     * @param string $privateKey
197
     * @param string $domainName
198
     * @param string $selector
199
     */
200 7 View Code Duplication
    public function __construct($privateKey, $domainName, $selector)
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...
201
    {
202 7
        $this->_privateKey = $privateKey;
203 7
        $this->_domainName = $domainName;
204 7
        $this->_signerIdentity = '@' . $domainName;
205 7
        $this->_selector = $selector;
206 7
    }
207
208
    /**
209
     * Instanciate DKIMSigner.
210
     *
211
     * @param string $privateKey
212
     * @param string $domainName
213
     * @param string $selector
214
     *
215
     * @return Swift_Signers_DKIMSigner
216
     */
217
    public static function newInstance($privateKey, $domainName, $selector)
218
    {
219
        return new static($privateKey, $domainName, $selector);
220
    }
221
222
    /**
223
     * Reset the Signer.
224
     *
225
     * @see Swift_Signer::reset()
226
     */
227 6
    public function reset()
228
    {
229 6
        $this->_headerHash = null;
230 6
        $this->_signedHeaders = array();
231 6
        $this->_bodyHash = null;
232 6
        $this->_bodyHashHandler = null;
233 6
        $this->_bodyCanonIgnoreStart = 2;
234 6
        $this->_bodyCanonEmptyCounter = 0;
235 6
        $this->_bodyCanonLastChar = null;
236 6
        $this->_bodyCanonSpace = false;
237 6
    }
238
239
    /**
240
     * Writes $bytes to the end of the stream.
241
     *
242
     * Writing may not happen immediately if the stream chooses to buffer.  If
243
     * you want to write these bytes with immediate effect, call {@link commit()}
244
     * after calling write().
245
     *
246
     * This method returns the sequence ID of the write (i.e. 1 for first, 2 for
247
     * second, etc etc).
248
     *
249
     * @param string $bytes
250
     *
251
     * @throws Swift_IoException
252
     *
253
     * @return int
254
     */
255 6
    public function write($bytes)
256
    {
257 6
        $this->_canonicalizeBody($bytes);
258 6
        foreach ($this->_bound as $is) {
259
            $is->write($bytes);
260
        }
261 6
    }
262
263
    /**
264
     * For any bytes that are currently buffered inside the stream, force them
265
     * off the buffer.
266
     *
267
     * @throws Swift_IoException
268
     */
269
    public function commit()
270
    {
271
        // Nothing to do
272
        return;
273
    }
274
275
    /**
276
     * Attach $is to this stream.
277
     * The stream acts as an observer, receiving all data that is written.
278
     * All {@link write()} and {@link flushBuffers()} operations will be mirrored.
279
     *
280
     * @param Swift_InputByteStream $is
281
     */
282
    public function bind(Swift_InputByteStream $is)
283
    {
284
        // Don't have to mirror anything
285
        $this->_bound[] = $is;
286
287
        return;
288
    }
289
290
    /**
291
     * Remove an already bound stream.
292
     * If $is is not bound, no errors will be raised.
293
     * If the stream currently has any buffered data it will be written to $is
294
     * before unbinding occurs.
295
     *
296
     * @param Swift_InputByteStream $is
297
     */
298 View Code Duplication
    public function unbind(Swift_InputByteStream $is)
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...
299
    {
300
        // Don't have to mirror anything
301
        foreach ($this->_bound as $k => $stream) {
302
            if ($stream === $is) {
303
                unset($this->_bound[$k]);
304
305
                return;
306
            }
307
        }
308
309
        return;
310
    }
311
312
    /**
313
     * Flush the contents of the stream (empty it) and set the internal pointer
314
     * to the beginning.
315
     *
316
     * @throws Swift_IoException
317
     */
318
    public function flushBuffers()
319
    {
320
        $this->reset();
321
    }
322
323
    /**
324
     * Set hash_algorithm, must be one of rsa-sha256 | rsa-sha1 defaults to rsa-sha256.
325
     *
326
     * @param string $hash
327
     *
328
     * @return Swift_Signers_DKIMSigner
329
     */
330 4
    public function setHashAlgorithm($hash)
331
    {
332
        // Unable to sign with rsa-sha256
333 4
        if ($hash == 'rsa-sha1') {
334
            $this->_hashAlgorithm = 'rsa-sha1';
335
        } else {
336 4
            $this->_hashAlgorithm = 'rsa-sha256';
337
        }
338
339 4
        return $this;
340
    }
341
342
    /**
343
     * Set the body canonicalization algorithm.
344
     *
345
     * @param string $canon
346
     *
347
     * @return Swift_Signers_DKIMSigner
348
     */
349 2
    public function setBodyCanon($canon)
350
    {
351 2
        if ($canon == 'relaxed') {
352 2
            $this->_bodyCanon = 'relaxed';
353
        } else {
354
            $this->_bodyCanon = 'simple';
355
        }
356
357 2
        return $this;
358
    }
359
360
    /**
361
     * Set the header canonicalization algorithm.
362
     *
363
     * @param string $canon
364
     *
365
     * @return Swift_Signers_DKIMSigner
366
     */
367 2
    public function setHeaderCanon($canon)
368
    {
369 2
        if ($canon == 'relaxed') {
370 2
            $this->_headerCanon = 'relaxed';
371
        } else {
372
            $this->_headerCanon = 'simple';
373
        }
374
375 2
        return $this;
376
    }
377
378
    /**
379
     * Set the signer identity.
380
     *
381
     * @param string $identity
382
     *
383
     * @return Swift_Signers_DKIMSigner
384
     */
385
    public function setSignerIdentity($identity)
386
    {
387
        $this->_signerIdentity = $identity;
388
389
        return $this;
390
    }
391
392
    /**
393
     * Set the length of the body to sign.
394
     *
395
     * @param mixed $len (bool or int)
396
     *
397
     * @return Swift_Signers_DKIMSigner
398
     */
399
    public function setBodySignedLen($len)
400
    {
401
        if ($len === true) {
402
            $this->_showLen = true;
403
            $this->_maxLen = PHP_INT_MAX;
404
        } elseif ($len === false) {
405
            $this->_showLen = false;
406
            $this->_maxLen = PHP_INT_MAX;
407
        } else {
408
            $this->_showLen = true;
409
            $this->_maxLen = (int) $len;
410
        }
411
412
        return $this;
413
    }
414
415
    /**
416
     * Set the signature timestamp.
417
     *
418
     * @param int $time A timestamp
419
     *
420
     * @return Swift_Signers_DKIMSigner
421
     */
422 5
    public function setSignatureTimestamp($time)
423
    {
424 5
        $this->_signatureTimestamp = $time;
425
426 5
        return $this;
427
    }
428
429
    /**
430
     * Set the signature expiration timestamp.
431
     *
432
     * @param int $time A timestamp
433
     *
434
     * @return Swift_Signers_DKIMSigner
435
     */
436
    public function setSignatureExpiration($time)
437
    {
438
        $this->_signatureExpiration = $time;
439
440
        return $this;
441
    }
442
443
    /**
444
     * Enable / disable the DebugHeaders.
445
     *
446
     * @param bool $debug
447
     *
448
     * @return Swift_Signers_DKIMSigner
449
     */
450
    public function setDebugHeaders($debug)
451
    {
452
        $this->_debugHeaders = (bool) $debug;
453
454
        return $this;
455
    }
456
457
    /**
458
     * Start Body.
459
     */
460 6
    public function startBody()
461
    {
462
        // Init
463 6
        switch ($this->_hashAlgorithm) {
464
            case 'rsa-sha256' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
465 4
                $this->_bodyHashHandler = hash_init('sha256');
466 4
                break;
467
            case 'rsa-sha1' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
468 2
                $this->_bodyHashHandler = hash_init('sha1');
469 2
                break;
470
        }
471 6
        $this->_bodyCanonLine = '';
472 6
    }
473
474
    /**
475
     * End Body.
476
     */
477 6
    public function endBody()
478
    {
479 6
        $this->_endOfBody();
480 6
    }
481
482
    /**
483
     * Returns the list of Headers Tampered by this plugin.
484
     *
485
     * @return string[]
486
     */
487 6
    public function getAlteredHeaders()
488
    {
489 6
        if ($this->_debugHeaders) {
490
            return array('DKIM-Signature', 'X-DebugHash');
491
        } else {
492 6
            return array('DKIM-Signature');
493
        }
494
    }
495
496
    /**
497
     * Adds an ignored Header.
498
     *
499
     * @param string $header_name
500
     *
501
     * @return Swift_Signers_DKIMSigner
502
     */
503
    public function ignoreHeader($header_name)
504
    {
505
        $this->_ignoredHeaders[strtolower($header_name)] = true;
506
507
        return $this;
508
    }
509
510
    /**
511
     * Set the headers to sign.
512
     *
513
     * @param Swift_Mime_HeaderSet $headers
514
     *
515
     * @return Swift_Signers_DKIMSigner
516
     */
517 6 View Code Duplication
    public function setHeaders(Swift_Mime_HeaderSet $headers)
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...
518
    {
519 6
        $this->_headerCanonData = '';
520
        // Loop through Headers
521 6
        $listHeaders = $headers->listAll();
522 6
        foreach ($listHeaders as $hName) {
523
            // Check if we need to ignore Header
524 1
            if (!isset($this->_ignoredHeaders[strtolower($hName)])) {
525 1
                if ($headers->has($hName)) {
526 1
                    $tmp = $headers->getAll($hName);
527 1
                    foreach ($tmp as $header) {
528 1
                        if ($header->getFieldBody() != '') {
529 1
                            $this->_addHeader($header->toString());
530 1
                            $this->_signedHeaders[] = $header->getFieldName();
531
                        }
532
                    }
533
                }
534
            }
535
        }
536
537 6
        return $this;
538
    }
539
540
    /**
541
     * Add the signature to the given Headers.
542
     *
543
     * @param Swift_Mime_HeaderSet $headers
544
     *
545
     * @return Swift_Signers_DKIMSigner
546
     */
547 6
    public function addSignature(Swift_Mime_HeaderSet $headers)
548
    {
549
        // Prepare the DKIM-Signature
550 6
        $params = array('v' => '1', 'a' => $this->_hashAlgorithm, 'bh' => base64_encode($this->_bodyHash), 'd' => $this->_domainName, 'h' => implode(': ', $this->_signedHeaders), 'i' => $this->_signerIdentity, 's' => $this->_selector);
551 6
        if ($this->_bodyCanon != 'simple') {
552 2
            $params['c'] = $this->_headerCanon . '/' . $this->_bodyCanon;
553 4
        } elseif ($this->_headerCanon != 'simple') {
554 1
            $params['c'] = $this->_headerCanon;
555
        }
556 6
        if ($this->_showLen) {
557
            $params['l'] = $this->_bodyLen;
558
        }
559 6
        if ($this->_signatureTimestamp === true) {
560 1
            $params['t'] = time();
561 1
            if ($this->_signatureExpiration !== false) {
562 1
                $params['x'] = $params['t'] + $this->_signatureExpiration;
563
            }
564
        } else {
565 5
            if ($this->_signatureTimestamp !== false) {
566 5
                $params['t'] = $this->_signatureTimestamp;
567
            }
568 5
            if ($this->_signatureExpiration !== false) {
569
                $params['x'] = $this->_signatureExpiration;
570
            }
571
        }
572 6
        if ($this->_debugHeaders) {
573
            $params['z'] = implode('|', $this->_debugHeadersData);
574
        }
575 6
        $string = '';
576 6
        foreach ($params as $k => $v) {
577 6
            $string .= $k . '=' . $v . '; ';
578
        }
579 6
        $string = trim($string);
580 6
        $headers->addTextHeader('DKIM-Signature', $string);
581
        // Add the last DKIM-Signature
582 6
        $tmp = $headers->getAll('DKIM-Signature');
583 6
        $this->_dkimHeader = end($tmp);
0 ignored issues
show
Documentation Bug introduced by
It seems like end($tmp) of type object<Swift_Mime_Headers_AbstractHeader> or false is incompatible with the declared type object<Swift_Mime_Headers_ParameterizedHeader> of property $_dkimHeader.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
584 6
        $this->_addHeader(trim($this->_dkimHeader->toString()) . "\r\n b=", true);
585 6
        $this->_endOfHeaders();
0 ignored issues
show
Deprecated Code introduced by
The method Swift_Signers_DKIMSigner::_endOfHeaders() has been deprecated with message: This method is currently useless in this class but it must be kept for BC reasons due to its "protected" scope. This method might be overriden by custom client code.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
586 6
        if ($this->_debugHeaders) {
587
            $headers->addTextHeader('X-DebugHash', base64_encode($this->_headerHash));
588
        }
589 6
        $this->_dkimHeader->setValue($string . ' b=' . trim(chunk_split(base64_encode($this->_getEncryptedHash()), 73, ' ')));
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Swift_Mime_Headers_AbstractHeader as the method setValue() does only exist in the following sub-classes of Swift_Mime_Headers_AbstractHeader: Swift_Mime_Headers_ParameterizedHeader, Swift_Mime_Headers_UnstructuredHeader. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
590
591 6
        return $this;
592
    }
593
594
    /* Private helpers */
595
596 6 View Code Duplication
    protected function _addHeader($header, $is_sig = false)
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...
597
    {
598 6
        switch ($this->_headerCanon) {
599
            case 'relaxed' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
600
                // Prepare Header and cascade
601 2
                $exploded = explode(':', $header, 2);
602 2
                $name = strtolower(trim($exploded[0]));
603 2
                $value = str_replace("\r\n", '', $exploded[1]);
604 2
                $value = preg_replace("/[ \t][ \t]+/", ' ', $value);
605 2
                $header = $name . ':' . trim($value) . ($is_sig ? '' : "\r\n");
606
            case 'simple' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
607
                // Nothing to do
608
        }
609 6
        $this->_addToHeaderHash($header);
610 6
    }
611
612
    /**
613
     * @deprecated This method is currently useless in this class but it must be
614
     *             kept for BC reasons due to its "protected" scope. This method
615
     *             might be overriden by custom client code.
616
     */
617
    protected function _endOfHeaders()
618
    {
619
    }
620
621 6
    protected function _canonicalizeBody($string)
622
    {
623 6
        $len = strlen($string);
624 6
        $canon = '';
625 6
        $method = ($this->_bodyCanon == 'relaxed');
626 6
        for ($i = 0; $i < $len; ++$i) {
627 6
            if ($this->_bodyCanonIgnoreStart > 0) {
628 6
                --$this->_bodyCanonIgnoreStart;
629 6
                continue;
630
            }
631 6
            switch ($string[$i]) {
632
                case "\r" :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
633
                    $this->_bodyCanonLastChar = "\r";
634
                    break;
635 View Code Duplication
                case "\n" :
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
636
                    if ($this->_bodyCanonLastChar == "\r") {
637
                        if ($method) {
638
                            $this->_bodyCanonSpace = false;
639
                        }
640
                        if ($this->_bodyCanonLine == '') {
641
                            ++$this->_bodyCanonEmptyCounter;
642
                        } else {
643
                            $this->_bodyCanonLine = '';
644
                            $canon .= "\r\n";
645
                        }
646
                    } else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
647
                        // Wooops Error
648
                        // todo handle it but should never happen
649
                    }
650
                    break;
651
                case ' ' :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
652 6
                case "\t" :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
653 6
                    if ($method) {
654 2
                        $this->_bodyCanonSpace = true;
655 2
                        break;
656
                    }
657
                default :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a DEFAULT statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in the default statement.

switch ($expr) {
    default : //wrong
        doSomething();
        break;
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
658 6 View Code Duplication
                    if ($this->_bodyCanonEmptyCounter > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
659
                        $canon .= str_repeat("\r\n", $this->_bodyCanonEmptyCounter);
660
                        $this->_bodyCanonEmptyCounter = 0;
661
                    }
662 6
                    if ($this->_bodyCanonSpace) {
663 2
                        $this->_bodyCanonLine .= ' ';
664 2
                        $canon .= ' ';
665 2
                        $this->_bodyCanonSpace = false;
666
                    }
667 6
                    $this->_bodyCanonLine .= $string[$i];
668 6
                    $canon .= $string[$i];
669
            }
670
        }
671 6
        $this->_addToBodyHash($canon);
672 6
    }
673
674 6
    protected function _endOfBody()
675
    {
676
        // Add trailing Line return if last line is non empty
677 6
        if ($this->_bodyCanonLine !== '') {
678 6
            $this->_addToBodyHash("\r\n");
679
        }
680
681 6
        $this->_bodyHash = hash_final($this->_bodyHashHandler, true);
682 6
    }
683
684
    /**
685
     * @param string $string
686
     */
687 6
    private function _addToBodyHash($string)
688
    {
689 6
        $len = strlen($string);
690 6
        if ($len > ($new_len = ($this->_maxLen - $this->_bodyLen))) {
691
            $string = substr($string, 0, $new_len);
692
            $len = $new_len;
693
        }
694 6
        hash_update($this->_bodyHashHandler, $string);
695 6
        $this->_bodyLen += $len;
696 6
    }
697
698 6
    private function _addToHeaderHash($header)
699
    {
700 6
        if ($this->_debugHeaders) {
701
            $this->_debugHeadersData[] = trim($header);
702
        }
703 6
        $this->_headerCanonData .= $header;
704 6
    }
705
706
    /**
707
     * @throws Swift_SwiftException
708
     *
709
     * @return string
710
     */
711 6
    private function _getEncryptedHash()
712
    {
713 6
        $signature = '';
714 6
        switch ($this->_hashAlgorithm) {
715
            case 'rsa-sha1':
716 2
                $algorithm = OPENSSL_ALGO_SHA1;
717 2
                break;
718
            case 'rsa-sha256':
719 4
                $algorithm = OPENSSL_ALGO_SHA256;
720 4
                break;
721
        }
722 6
        $pkeyId = openssl_get_privatekey($this->_privateKey);
723 6
        if (!$pkeyId) {
724
            throw new Swift_SwiftException('Unable to load DKIM Private Key [' . openssl_error_string() . ']');
725
        }
726 6
        if (openssl_sign($this->_headerCanonData, $signature, $pkeyId, $algorithm)) {
0 ignored issues
show
Bug introduced by
The variable $algorithm does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
727 6
            return $signature;
728
        }
729
        throw new Swift_SwiftException('Unable to sign DKIM Hash [' . openssl_error_string() . ']');
730
    }
731
}
732