Completed
Push — 5.x ( 0b26a1...a498b0 )
by Lars
53:47 queued 44:42
created

Swift_Signers_DKIMSigner   F

Complexity

Total Complexity 77

Size/Duplication

Total Lines 716
Duplicated Lines 10.75 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 2.38%
Metric Value
wmc 77
lcom 1
cbo 4
dl 77
loc 716
ccs 6
cts 252
cp 0.0238
rs 3.7895

29 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 7 7 1
A newInstance() 0 4 1
A commit() 0 5 1
A bind() 0 7 1
A flushBuffers() 0 4 1
A setSignerIdentity() 0 6 1
A setSignatureExpiration() 0 6 1
A setDebugHeaders() 0 6 1
A ignoreHeader() 0 6 1
A _endOfHeaders() 0 3 1
A unbind() 13 13 3
A setBodySignedLen() 0 15 3
A reset() 0 11 1
A write() 0 7 2
A setHashAlgorithm() 0 11 2
A setBodyCanon() 0 10 2
A setHeaderCanon() 0 10 2
A setSignatureTimestamp() 0 6 1
A startBody() 0 13 3
A endBody() 0 4 1
A getAlteredHeaders() 0 8 2
B setHeaders() 22 22 6
F addSignature() 0 46 11
A _addHeader() 15 15 4
C _canonicalizeBody() 20 52 13
A _endOfBody() 0 9 2
A _addToBodyHash() 0 10 2
A _addToHeaderHash() 0 7 2
B _getEncryptedHash() 0 20 5

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Swift_Signers_DKIMSigner often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Swift_Signers_DKIMSigner, and based on these observations, apply Extract Interface, too.

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 1 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 1
        $this->_privateKey = $privateKey;
203 1
        $this->_domainName = $domainName;
204 1
        $this->_signerIdentity = '@' . $domainName;
205 1
        $this->_selector = $selector;
206 1
    }
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
    public function reset()
228
    {
229
        $this->_headerHash = null;
230
        $this->_signedHeaders = array();
231
        $this->_bodyHash = null;
232
        $this->_bodyHashHandler = null;
233
        $this->_bodyCanonIgnoreStart = 2;
234
        $this->_bodyCanonEmptyCounter = 0;
235
        $this->_bodyCanonLastChar = null;
236
        $this->_bodyCanonSpace = false;
237
    }
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
    public function write($bytes)
256
    {
257
        $this->_canonicalizeBody($bytes);
258
        foreach ($this->_bound as $is) {
259
            $is->write($bytes);
260
        }
261
    }
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
    public function setHashAlgorithm($hash)
331
    {
332
        // Unable to sign with rsa-sha256
333
        if ($hash == 'rsa-sha1') {
334
            $this->_hashAlgorithm = 'rsa-sha1';
335
        } else {
336
            $this->_hashAlgorithm = 'rsa-sha256';
337
        }
338
339
        return $this;
340
    }
341
342
    /**
343
     * Set the body canonicalization algorithm.
344
     *
345
     * @param string $canon
346
     *
347
     * @return Swift_Signers_DKIMSigner
348
     */
349
    public function setBodyCanon($canon)
350
    {
351
        if ($canon == 'relaxed') {
352
            $this->_bodyCanon = 'relaxed';
353
        } else {
354
            $this->_bodyCanon = 'simple';
355
        }
356
357
        return $this;
358
    }
359
360
    /**
361
     * Set the header canonicalization algorithm.
362
     *
363
     * @param string $canon
364
     *
365
     * @return Swift_Signers_DKIMSigner
366
     */
367
    public function setHeaderCanon($canon)
368
    {
369
        if ($canon == 'relaxed') {
370
            $this->_headerCanon = 'relaxed';
371
        } else {
372
            $this->_headerCanon = 'simple';
373
        }
374
375
        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
    public function setSignatureTimestamp($time)
423
    {
424
        $this->_signatureTimestamp = $time;
425
426
        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
    public function startBody()
461
    {
462
        // Init
463
        switch ($this->_hashAlgorithm) {
464
            case 'rsa-sha256':
465
                $this->_bodyHashHandler = hash_init('sha256');
466
                break;
467
            case 'rsa-sha1':
468
                $this->_bodyHashHandler = hash_init('sha1');
469
                break;
470
        }
471
        $this->_bodyCanonLine = '';
472
    }
473
474
    /**
475
     * End Body.
476
     */
477
    public function endBody()
478
    {
479
        $this->_endOfBody();
480
    }
481
482
    /**
483
     * Returns the list of Headers Tampered by this plugin.
484
     *
485
     * @return string[]
486
     */
487
    public function getAlteredHeaders()
488
    {
489
        if ($this->_debugHeaders) {
490
            return array('DKIM-Signature', 'X-DebugHash');
491
        } else {
492
            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 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
        $this->_headerCanonData = '';
520
        // Loop through Headers
521
        $listHeaders = $headers->listAll();
522
        foreach ($listHeaders as $hName) {
523
            // Check if we need to ignore Header
524
            if (!isset($this->_ignoredHeaders[strtolower($hName)])) {
525
                if ($headers->has($hName)) {
526
                    $tmp = $headers->getAll($hName);
527
                    foreach ($tmp as $header) {
528
                        if ($header->getFieldBody() != '') {
529
                            $this->_addHeader($header->toString());
530
                            $this->_signedHeaders[] = $header->getFieldName();
531
                        }
532
                    }
533
                }
534
            }
535
        }
536
537
        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
    public function addSignature(Swift_Mime_HeaderSet $headers)
548
    {
549
        // Prepare the DKIM-Signature
550
        $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
        if ($this->_bodyCanon != 'simple') {
552
            $params['c'] = $this->_headerCanon . '/' . $this->_bodyCanon;
553
        } elseif ($this->_headerCanon != 'simple') {
554
            $params['c'] = $this->_headerCanon;
555
        }
556
        if ($this->_showLen) {
557
            $params['l'] = $this->_bodyLen;
558
        }
559
        if ($this->_signatureTimestamp === true) {
560
            $params['t'] = time();
561
            if ($this->_signatureExpiration !== false) {
562
                $params['x'] = $params['t'] + $this->_signatureExpiration;
563
            }
564
        } else {
565
            if ($this->_signatureTimestamp !== false) {
566
                $params['t'] = $this->_signatureTimestamp;
567
            }
568
            if ($this->_signatureExpiration !== false) {
569
                $params['x'] = $this->_signatureExpiration;
570
            }
571
        }
572
        if ($this->_debugHeaders) {
573
            $params['z'] = implode('|', $this->_debugHeadersData);
574
        }
575
        $string = '';
576
        foreach ($params as $k => $v) {
577
            $string .= $k . '=' . $v . '; ';
578
        }
579
        $string = trim($string);
580
        $headers->addTextHeader('DKIM-Signature', $string);
581
        // Add the last DKIM-Signature
582
        $tmp = $headers->getAll('DKIM-Signature');
583
        $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
        $this->_addHeader(trim($this->_dkimHeader->toString()) . "\r\n b=", true);
585
        $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
        if ($this->_debugHeaders) {
587
            $headers->addTextHeader('X-DebugHash', base64_encode($this->_headerHash));
588
        }
589
        $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
        return $this;
592
    }
593
594
    /* Private helpers */
595
596 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
        switch ($this->_headerCanon) {
599
            case 'relaxed':
0 ignored issues
show
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
                $exploded = explode(':', $header, 2);
602
                $name = Swift::strtolowerWithStaticCache(trim($exploded[0]));
603
                $value = str_replace("\r\n", '', $exploded[1]);
604
                $value = preg_replace("/[ \t][ \t]+/", ' ', $value);
605
                $header = $name . ':' . trim($value) . ($is_sig ? '' : "\r\n");
606
            case 'simple':
607
                // Nothing to do
608
        }
609
        $this->_addToHeaderHash($header);
610
    }
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
    protected function _canonicalizeBody($string)
622
    {
623
        $len = strlen($string);
624
        $canon = '';
625
        $method = ($this->_bodyCanon == 'relaxed');
626
        for ($i = 0; $i < $len; ++$i) {
627
            if ($this->_bodyCanonIgnoreStart > 0) {
628
                --$this->_bodyCanonIgnoreStart;
629
                continue;
630
            }
631
            switch ($string[$i]) {
632
                case "\r":
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...
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 ' ':
652
                case "\t":
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
653
                    if ($method) {
654
                        $this->_bodyCanonSpace = true;
655
                        break;
656
                    }
657
                default:
658 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
                    if ($this->_bodyCanonSpace) {
663
                        $this->_bodyCanonLine .= ' ';
664
                        $canon .= ' ';
665
                        $this->_bodyCanonSpace = false;
666
                    }
667
                    $this->_bodyCanonLine .= $string[$i];
668
                    $canon .= $string[$i];
669
            }
670
        }
671
        $this->_addToBodyHash($canon);
672
    }
673
674
    protected function _endOfBody()
675
    {
676
        // Add trailing Line return if last line is non empty
677
        if ($this->_bodyCanonLine !== '') {
678
            $this->_addToBodyHash("\r\n");
679
        }
680
681
        $this->_bodyHash = hash_final($this->_bodyHashHandler, true);
682
    }
683
684
    /**
685
     * @param string $string
686
     */
687
    private function _addToBodyHash($string)
688
    {
689
        $len = strlen($string);
690
        if ($len > ($new_len = ($this->_maxLen - $this->_bodyLen))) {
691
            $string = substr($string, 0, $new_len);
692
            $len = $new_len;
693
        }
694
        hash_update($this->_bodyHashHandler, $string);
695
        $this->_bodyLen += $len;
696
    }
697
698
    private function _addToHeaderHash($header)
699
    {
700
        if ($this->_debugHeaders) {
701
            $this->_debugHeadersData[] = trim($header);
702
        }
703
        $this->_headerCanonData .= $header;
704
    }
705
706
    /**
707
     * @throws Swift_SwiftException
708
     *
709
     * @return string
710
     */
711
    private function _getEncryptedHash()
712
    {
713
        $signature = '';
714
        switch ($this->_hashAlgorithm) {
715
            case 'rsa-sha1':
716
                $algorithm = OPENSSL_ALGO_SHA1;
717
                break;
718
            case 'rsa-sha256':
719
                $algorithm = OPENSSL_ALGO_SHA256;
720
                break;
721
        }
722
        $pkeyId = openssl_get_privatekey($this->_privateKey);
723
        if (!$pkeyId) {
724
            throw new Swift_SwiftException('Unable to load DKIM Private Key [' . openssl_error_string() . ']');
725
        }
726
        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
            return $signature;
728
        }
729
        throw new Swift_SwiftException('Unable to sign DKIM Hash [' . openssl_error_string() . ']');
730
    }
731
}
732