Completed
Push — 5.x ( d8493a...43b0cc )
by Lars
06:45
created

Swift_Signers_DKIMSigner::_canonicalizeBody()   C

Complexity

Conditions 13
Paths 22

Size

Total Lines 54
Code Lines 39

Duplication

Lines 22
Ratio 40.74 %

Code Coverage

Tests 29
CRAP Score 20.5992

Importance

Changes 0
Metric Value
cc 13
eloc 39
nc 22
nop 1
dl 22
loc 54
ccs 29
cts 45
cp 0.6444
crap 20.5992
rs 6.7593
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
     * @see RFC6376 3.3: Signers MUST implement and SHOULD sign using rsa-sha256.
43
     *
44
     * @var string
45
     */
46
    protected $_hashAlgorithm = 'rsa-sha256';
47
48
    /**
49
     * Body canon method.
50
     *
51
     * @var string
52
     */
53
    protected $_bodyCanon = 'simple';
54
55
    /**
56
     * Header canon method.
57
     *
58
     * @var string
59
     */
60
    protected $_headerCanon = 'simple';
61
62
    /**
63
     * Headers not being signed.
64
     *
65
     * @var array
66
     */
67
    protected $_ignoredHeaders = array('return-path' => true);
68
69
    /**
70
     * Signer identity.
71
     *
72
     * @var string
73
     */
74
    protected $_signerIdentity;
75
76
    /**
77
     * BodyLength.
78
     *
79
     * @var int
80
     */
81
    protected $_bodyLen = 0;
82
83
    /**
84
     * Maximum signedLen.
85
     *
86
     * @var int
87
     */
88
    protected $_maxLen = PHP_INT_MAX;
89
90
    /**
91
     * Embbed bodyLen in signature.
92
     *
93
     * @var bool
94
     */
95
    protected $_showLen = false;
96
97
    /**
98
     * When the signature has been applied (true means time()), false means not embedded.
99
     *
100
     * @var mixed
101
     */
102
    protected $_signatureTimestamp = true;
103
104
    /**
105
     * When will the signature expires false means not embedded, if sigTimestamp is auto
106
     * Expiration is relative, otherwise it's absolute.
107
     *
108
     * @var int
109
     */
110
    protected $_signatureExpiration = false;
111
112
    /**
113
     * Must we embed signed headers?
114
     *
115
     * @var bool
116
     */
117
    protected $_debugHeaders = false;
118
119
    // work variables
120
    /**
121
     * Headers used to generate hash.
122
     *
123
     * @var array
124
     */
125
    protected $_signedHeaders = array();
126
127
    /**
128
     * If debugHeaders is set store debugData here.
129
     *
130
     * @var string
131
     */
132
    private $_debugHeadersData = '';
133
134
    /**
135
     * Stores the bodyHash.
136
     *
137
     * @var string
138
     */
139
    private $_bodyHash = '';
140
141
    /**
142
     * Stores the signature header.
143
     *
144
     * @var Swift_Mime_Headers_ParameterizedHeader
145
     */
146
    protected $_dkimHeader;
147
148
    /**
149
     * @var resource
150
     */
151
    private $_bodyHashHandler;
152
153
    /**
154
     * @var null
155
     *
156
     * no used?
157
     */
158
    private $_headerHash;
159
160
    /**
161
     * @var string
162
     */
163
    private $_headerCanonData = '';
164
165
    /**
166
     * @var int
167
     */
168
    private $_bodyCanonEmptyCounter = 0;
169
170
    /**
171
     * @var int
172
     */
173
    private $_bodyCanonIgnoreStart = 2;
174
175
    /**
176
     * @var bool
177
     */
178
    private $_bodyCanonSpace = false;
179
180
    /**
181
     * @var null|string
182
     */
183
    private $_bodyCanonLastChar = null;
184
185
    /**
186
     * @var string
187
     */
188
    private $_bodyCanonLine = '';
189
190
    /**
191
     * @var array
192
     */
193
    private $_bound = array();
194
195
    /**
196
     * Constructor.
197
     *
198
     * @param string $privateKey
199
     * @param string $domainName
200
     * @param string $selector
201
     */
202 7
    public function __construct($privateKey, $domainName, $selector)
203
    {
204 7
        $this->_privateKey = $privateKey;
205 7
        $this->_domainName = $domainName;
206 7
        $this->_signerIdentity = '@' . $domainName;
207 7
        $this->_selector = $selector;
208
209
        // keep fallback hash algorithm sha1 if php version is lower than 5.4.8
210 7
        if (PHP_VERSION_ID < 50408) {
211
            $this->_hashAlgorithm = 'rsa-sha1';
212
        }
213 7
    }
214
215
    /**
216
     * Instanciate DKIMSigner.
217
     *
218
     * @param string $privateKey
219
     * @param string $domainName
220
     * @param string $selector
221
     *
222
     * @return self
223
     */
224
    public static function newInstance($privateKey, $domainName, $selector)
225
    {
226
        return new static($privateKey, $domainName, $selector);
227
    }
228
229
    /**
230
     * Reset the Signer.
231
     *
232
     * @see Swift_Signer::reset()
233
     */
234 6
    public function reset()
235
    {
236 6
        $this->_headerHash = null;
237 6
        $this->_signedHeaders = array();
238 6
        $this->_bodyHash = null;
239 6
        $this->_bodyHashHandler = null;
240 6
        $this->_bodyCanonIgnoreStart = 2;
241 6
        $this->_bodyCanonEmptyCounter = 0;
242 6
        $this->_bodyCanonLastChar = null;
243 6
        $this->_bodyCanonSpace = false;
244 6
    }
245
246
    /**
247
     * Writes $bytes to the end of the stream.
248
     *
249
     * Writing may not happen immediately if the stream chooses to buffer.  If
250
     * you want to write these bytes with immediate effect, call {@link commit()}
251
     * after calling write().
252
     *
253
     * This method returns the sequence ID of the write (i.e. 1 for first, 2 for
254
     * second, etc etc).
255
     *
256
     * @param string $bytes
257
     *
258
     * @throws Swift_IoException
259
     *
260
     * @return int
261
     */
262
    // TODO fix return
263 6
    public function write($bytes)
264
    {
265 6
        $this->_canonicalizeBody($bytes);
266 6
        foreach ($this->_bound as $is) {
267
            $is->write($bytes);
268 6
        }
269 6
    }
270
271
    /**
272
     * For any bytes that are currently buffered inside the stream, force them
273
     * off the buffer.
274
     */
275
    public function commit()
276
    {
277
        // Nothing to do
278
        return;
279
    }
280
281
    /**
282
     * Attach $is to this stream.
283
     * The stream acts as an observer, receiving all data that is written.
284
     * All {@link write()} and {@link flushBuffers()} operations will be mirrored.
285
     *
286
     * @param Swift_InputByteStream $is
287
     */
288
    public function bind(Swift_InputByteStream $is)
289
    {
290
        // Don't have to mirror anything
291
        $this->_bound[] = $is;
292
293
        return;
294
    }
295
296
    /**
297
     * Remove an already bound stream.
298
     * If $is is not bound, no errors will be raised.
299
     * If the stream currently has any buffered data it will be written to $is
300
     * before unbinding occurs.
301
     *
302
     * @param Swift_InputByteStream $is
303
     */
304 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...
305
    {
306
        // Don't have to mirror anything
307
        foreach ($this->_bound as $k => $stream) {
308
            if ($stream === $is) {
309
                unset($this->_bound[$k]);
310
311
                return;
312
            }
313
        }
314
    }
315
316
    /**
317
     * Flush the contents of the stream (empty it) and set the internal pointer
318
     * to the beginning.
319
     *
320
     * @throws Swift_IoException
321
     */
322
    public function flushBuffers()
323
    {
324
        $this->reset();
325
    }
326
327
    /**
328
     * Set hash_algorithm, must be one of rsa-sha256 | rsa-sha1.
329
     *
330
     * @param string $hash 'rsa-sha1' or 'rsa-sha256'
331
     *
332
     * @throws Swift_SwiftException
333
     *
334
     * @return $this
335
     */
336 5
    public function setHashAlgorithm($hash)
337
    {
338
        switch ($hash) {
339 5
            case 'rsa-sha1':
340 1
                $this->_hashAlgorithm = 'rsa-sha1';
341 1
                break;
342 4
            case 'rsa-sha256':
343 4
                $this->_hashAlgorithm = 'rsa-sha256';
344 4
                if (!defined('OPENSSL_ALGO_SHA256')) {
345
                    throw new Swift_SwiftException('Unable to set sha256 as it is not supported by OpenSSL.');
346
                }
347 4
                break;
348
            default:
349
                throw new Swift_SwiftException('Unable to set the hash algorithm, must be one of rsa-sha1 or rsa-sha256 (%s given).', $hash);
350
        }
351
352 5
        return $this;
353
    }
354
355
    /**
356
     * Set the body canonicalization algorithm.
357
     *
358
     * @param string $canon
359
     *
360
     * @return $this
361
     */
362 2
    public function setBodyCanon($canon)
363
    {
364 2
        if ($canon === 'relaxed') {
365 2
            $this->_bodyCanon = 'relaxed';
366 2
        } else {
367
            $this->_bodyCanon = 'simple';
368
        }
369
370 2
        return $this;
371
    }
372
373
    /**
374
     * Set the header canonicalization algorithm.
375
     *
376
     * @param string $canon
377
     *
378
     * @return $this
379
     */
380 2
    public function setHeaderCanon($canon)
381
    {
382 2
        if ($canon === 'relaxed') {
383 2
            $this->_headerCanon = 'relaxed';
384 2
        } else {
385
            $this->_headerCanon = 'simple';
386
        }
387
388 2
        return $this;
389
    }
390
391
    /**
392
     * Set the signer identity.
393
     *
394
     * @param string $identity
395
     *
396
     * @return $this
397
     */
398
    public function setSignerIdentity($identity)
399
    {
400
        $this->_signerIdentity = $identity;
401
402
        return $this;
403
    }
404
405
    /**
406
     * Set the length of the body to sign.
407
     *
408
     * @param mixed $len (bool or int)
409
     *
410
     * @return $this
411
     */
412
    public function setBodySignedLen($len)
413
    {
414
        if ($len === true) {
415
            $this->_showLen = true;
416
            $this->_maxLen = PHP_INT_MAX;
417
        } elseif ($len === false) {
418
            $this->_showLen = false;
419
            $this->_maxLen = PHP_INT_MAX;
420
        } else {
421
            $this->_showLen = true;
422
            $this->_maxLen = (int) $len;
423
        }
424
425
        return $this;
426
    }
427
428
    /**
429
     * Set the signature timestamp.
430
     *
431
     * @param int $time A timestamp
432
     *
433
     * @return $this
434
     */
435 5
    public function setSignatureTimestamp($time)
436
    {
437 5
        $this->_signatureTimestamp = $time;
438
439 5
        return $this;
440
    }
441
442
    /**
443
     * Set the signature expiration timestamp.
444
     *
445
     * @param int $time A timestamp
446
     *
447
     * @return $this
448
     */
449
    public function setSignatureExpiration($time)
450
    {
451
        $this->_signatureExpiration = $time;
452
453
        return $this;
454
    }
455
456
    /**
457
     * Enable / disable the DebugHeaders.
458
     *
459
     * @param bool $debug
460
     *
461
     * @return Swift_Signers_DKIMSigner
462
     */
463
    public function setDebugHeaders($debug)
464
    {
465
        $this->_debugHeaders = (bool) $debug;
466
467
        return $this;
468
    }
469
470
    /**
471
     * Start Body.
472
     */
473 6
    public function startBody()
474
    {
475
        // Init
476 6
        switch ($this->_hashAlgorithm) {
477 6
            case 'rsa-sha256':
478 5
                $this->_bodyHashHandler = hash_init('sha256');
479 5
                break;
480 1
            case 'rsa-sha1':
481 1
                $this->_bodyHashHandler = hash_init('sha1');
482 1
                break;
483 6
        }
484 6
        $this->_bodyCanonLine = '';
485 6
    }
486
487
    /**
488
     * End Body.
489
     */
490 6
    public function endBody()
491
    {
492 6
        $this->_endOfBody();
493 6
    }
494
495
    /**
496
     * Returns the list of Headers Tampered by this plugin.
497
     *
498
     * @return string[]
499
     */
500 6
    public function getAlteredHeaders()
501
    {
502 6
        if ($this->_debugHeaders) {
503
            return array('DKIM-Signature', 'X-DebugHash');
504
        } else {
505 6
            return array('DKIM-Signature');
506
        }
507
    }
508
509
    /**
510
     * Adds an ignored Header.
511
     *
512
     * @param string $header_name
513
     *
514
     * @return Swift_Signers_DKIMSigner
515
     */
516
    public function ignoreHeader($header_name)
517
    {
518
        $this->_ignoredHeaders[Swift::strtolowerWithStaticCache($header_name)] = true;
519
520
        return $this;
521
    }
522
523
    /**
524
     * Set the headers to sign.
525
     *
526
     * @param Swift_Mime_HeaderSet $headers
527
     *
528
     * @return Swift_Signers_DKIMSigner
529
     */
530 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...
531
    {
532 6
        $this->_headerCanonData = '';
533
        // Loop through Headers
534 6
        $listHeaders = $headers->listAll();
535 6
        foreach ($listHeaders as $hName) {
536
            // Check if we need to ignore Header
537 1
            if (!isset($this->_ignoredHeaders[Swift::strtolowerWithStaticCache($hName)])) {
538 1
                if ($headers->has($hName)) {
539 1
                    $tmp = $headers->getAll($hName);
540 1
                    foreach ($tmp as $header) {
541 1
                        if ($header->getFieldBody() != '') {
542 1
                            $this->_addHeader($header->toString());
543 1
                            $this->_signedHeaders[] = $header->getFieldName();
544 1
                        }
545 1
                    }
546 1
                }
547 1
            }
548 6
        }
549
550 6
        return $this;
551
    }
552
553
    /**
554
     * Add the signature to the given Headers.
555
     *
556
     * @param Swift_Mime_HeaderSet $headers
557
     *
558
     * @return Swift_Signers_DKIMSigner
559
     */
560 6
    public function addSignature(Swift_Mime_HeaderSet $headers)
561
    {
562
        // Prepare the DKIM-Signature
563 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);
564 6
        if ($this->_bodyCanon != 'simple') {
565 2
            $params['c'] = $this->_headerCanon . '/' . $this->_bodyCanon;
566 6
        } elseif ($this->_headerCanon != 'simple') {
567 1
            $params['c'] = $this->_headerCanon;
568 1
        }
569 6
        if ($this->_showLen) {
570
            $params['l'] = $this->_bodyLen;
571
        }
572 6
        if ($this->_signatureTimestamp === true) {
573 1
            $params['t'] = time();
574 1
            if ($this->_signatureExpiration !== false) {
575
                $params['x'] = $params['t'] + $this->_signatureExpiration;
576
            }
577 1
        } else {
578 5
            if ($this->_signatureTimestamp !== false) {
579 5
                $params['t'] = $this->_signatureTimestamp;
580 5
            }
581 5
            if ($this->_signatureExpiration !== false) {
582
                $params['x'] = $this->_signatureExpiration;
583
            }
584
        }
585 6
        if ($this->_debugHeaders) {
586
            $params['z'] = implode('|', $this->_debugHeadersData);
587
        }
588 6
        $string = '';
589 6
        foreach ($params as $k => $v) {
590 6
            $string .= $k . '=' . $v . '; ';
591 6
        }
592 6
        $string = trim($string);
593 6
        $headers->addTextHeader('DKIM-Signature', $string);
594
        // Add the last DKIM-Signature
595 6
        $tmp = $headers->getAll('DKIM-Signature');
596 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...
597 6
        $this->_addHeader(trim($this->_dkimHeader->toString()) . "\r\n b=", true);
598 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 overridden 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...
599 6
        if ($this->_debugHeaders) {
600
            $headers->addTextHeader('X-DebugHash', base64_encode($this->_headerHash));
601
        }
602 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...
603
604 6
        return $this;
605
    }
606
607
    /* Private helpers */
608
609
    /**
610
     * @param string $header
611
     * @param bool   $is_sig
612
     */
613 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...
614
    {
615 6
        switch ($this->_headerCanon) {
616 6
            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...
617
                // Prepare Header and cascade
618 2
                $exploded = explode(':', $header, 2);
619 2
                $name = Swift::strtolowerWithStaticCache(trim($exploded[0]));
620 2
                $value = str_replace("\r\n", '', $exploded[1]);
621 2
                $value = preg_replace("/[ \t][ \t]+/", ' ', $value);
622 2
                $header = $name . ':' . trim($value) . ($is_sig ? '' : "\r\n");
623 6
            case 'simple':
624
                // Nothing to do
625 6
        }
626 6
        $this->_addToHeaderHash($header);
627 6
    }
628
629
    /**
630
     * @deprecated This method is currently useless in this class but it must be
631
     *             kept for BC reasons due to its "protected" scope. This method
632
     *             might be overridden by custom client code.
633
     */
634
    protected function _endOfHeaders()
635
    {
636
    }
637
638
    /**
639
     * @param string $string
640
     */
641 6
    protected function _canonicalizeBody($string)
642
    {
643 6
        $len = strlen($string);
644 6
        $canon = '';
645 6
        $method = ($this->_bodyCanon === 'relaxed');
646 6
        for ($i = 0; $i < $len; ++$i) {
647 6
            if ($this->_bodyCanonIgnoreStart > 0) {
648 6
                --$this->_bodyCanonIgnoreStart;
649 6
                continue;
650
            }
651 6
            switch ($string[$i]) {
652 6
                case "\r":
653
                    $this->_bodyCanonLastChar = "\r";
654
                    break;
655 6 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...
656
                    if ($this->_bodyCanonLastChar === "\r") {
657
                        if ($method) {
658
                            $this->_bodyCanonSpace = false;
659
                        }
660
661
                        if ($this->_bodyCanonLine === '') {
662
                            ++$this->_bodyCanonEmptyCounter;
663
                        } else {
664
                            $this->_bodyCanonLine = '';
665
                            $canon .= "\r\n";
666
                        }
667
668
                    } 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...
669
                        // Wooops Error
670
                        // todo handle it but should never happen
671
                    }
672
                    break;
673 6
                case ' ':
674 6
                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...
675 6
                    if ($method) {
676 2
                        $this->_bodyCanonSpace = true;
677 2
                        break;
678
                    }
679 6
                default:
680 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...
681
                        $canon .= str_repeat("\r\n", $this->_bodyCanonEmptyCounter);
682
                        $this->_bodyCanonEmptyCounter = 0;
683
                    }
684 6
                    if ($this->_bodyCanonSpace) {
685 2
                        $this->_bodyCanonLine .= ' ';
686 2
                        $canon .= ' ';
687 2
                        $this->_bodyCanonSpace = false;
688 2
                    }
689 6
                    $this->_bodyCanonLine .= $string[$i];
690 6
                    $canon .= $string[$i];
691 6
            }
692 6
        }
693 6
        $this->_addToBodyHash($canon);
694 6
    }
695
696 6
    protected function _endOfBody()
697
    {
698
        // Add trailing Line return if last line is non empty
699 6
        if ($this->_bodyCanonLine !== '') {
700 6
            $this->_addToBodyHash("\r\n");
701 6
        }
702
703 6
        $this->_bodyHash = hash_final($this->_bodyHashHandler, true);
704 6
    }
705
706
    /**
707
     * @param string $string
708
     */
709 6
    private function _addToBodyHash($string)
710
    {
711 6
        $len = strlen($string);
712 6
        if ($len > ($new_len = ($this->_maxLen - $this->_bodyLen))) {
713
            $string = substr($string, 0, $new_len);
714
            $len = $new_len;
715
        }
716 6
        hash_update($this->_bodyHashHandler, $string);
717 6
        $this->_bodyLen += $len;
718 6
    }
719
720
    /**
721
     * @param string $header
722
     */
723 6
    private function _addToHeaderHash($header)
724
    {
725 6
        if ($this->_debugHeaders) {
726
            $this->_debugHeadersData[] = trim($header);
727
        }
728 6
        $this->_headerCanonData .= $header;
729 6
    }
730
731
    /**
732
     * @throws Swift_SwiftException
733
     *
734
     * @return string
735
     */
736 6
    private function _getEncryptedHash()
737
    {
738 6
        $signature = '';
739
740 6
        switch ($this->_hashAlgorithm) {
741 6
            case 'rsa-sha1':
742 1
                $algorithm = OPENSSL_ALGO_SHA1;
743 1
                break;
744 5
            case 'rsa-sha256':
745 5
                $algorithm = OPENSSL_ALGO_SHA256;
746 5
                break;
747 6
        }
748 6
        $pkeyId = openssl_get_privatekey($this->_privateKey);
749 6
        if (!$pkeyId) {
750
            throw new Swift_SwiftException('Unable to load DKIM Private Key [' . openssl_error_string() . ']');
751
        }
752 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...
753 6
            return $signature;
754
        }
755
        throw new Swift_SwiftException('Unable to sign DKIM Hash [' . openssl_error_string() . ']');
756
    }
757
}
758