Completed
Push — 5.x ( 801190...049872 )
by Lars
05:29
created

Swift_Mime_SimpleMimeEntity::getRandomId()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3.1406

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 4
nop 0
dl 0
loc 14
ccs 6
cts 8
cp 0.75
crap 3.1406
rs 9.4285
c 0
b 0
f 0
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
 * A MIME entity, in a multipart message.
13
 *
14
 * @author Chris Corbyn
15
 */
16
class Swift_Mime_SimpleMimeEntity implements Swift_Mime_MimeEntity
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
     * A collection of Headers for this mime entity
20
     *
21
     * @var Swift_Mime_HeaderSet
22
     */
23
    private $_headers;
24
25
    /**
26
     * The body as a string, or a stream
27
     */
28
    private $_body;
29
30
    /**
31
     * The encoder that encodes the body into a streamable format
32
     *
33
     * @var Swift_Mime_ContentEncoder
34
     */
35
    private $_encoder;
36
37
    /**
38
     * The validator for email
39
     *
40
     * @var Swift_EmailValidatorBridge
41
     */
42
    private $_emailValidator;
43
44
    /**
45
     * A mime boundary, if any is used
46
     */
47
    private $_boundary;
48
49
    /**
50
     * Mime types to be used based on the nesting level
51
     *
52
     * @var array
53
     */
54
    private $_compositeRanges = array(
55
        'multipart/mixed' => array(self::LEVEL_TOP, self::LEVEL_MIXED),
56
        'multipart/alternative' => array(self::LEVEL_MIXED, self::LEVEL_ALTERNATIVE),
57
        'multipart/related' => array(self::LEVEL_ALTERNATIVE, self::LEVEL_RELATED),
58
    );
59
60
    /**
61
     * A set of filter rules to define what level an entity should be nested at
62
     *
63
     * @var array
64
     */
65
    private $_compoundLevelFilters = array();
66
67
    /**
68
     * The nesting level of this entity
69
     *
70
     * @var int
71
     */
72
    private $_nestingLevel = self::LEVEL_ALTERNATIVE;
73
74
    /**
75
     * A KeyCache instance used during encoding and streaming
76
     *
77
     * @var Swift_KeyCache
78
     */
79
    private $_cache;
80
81
    /**
82
     * Direct descendants of this entity
83
     *
84
     * @var Swift_Mime_MimeEntity[]|array
85
     */
86
    private $_immediateChildren = array();
87
88
    /**
89
     * All descendants of this entity
90
     *
91
     * @var Swift_Mime_MimeEntity[]
92
     */
93
    private $_children = array();
94
95
    /**
96
     * The maximum line length of the body of this entity
97
     *
98
     * @var int
99
     */
100
    private $_maxLineLength = 78;
101
102
    /**
103
     * The order in which alternative mime types should appear
104
     *
105
     * @var array
106
     */
107
    private $_alternativePartOrder = array(
108
        'text/plain' => 1,
109
        'text/html' => 2,
110
        'multipart/related' => 3,
111
    );
112
113
    /**
114
     * The CID of this entity
115
     *
116
     * @var string
117
     */
118
    private $_id;
119
120
    /**
121
     * The key used for accessing the cache
122
     *
123
     * @var string
124
     */
125
    private $_cacheKey;
126
127
    /**
128
     * @var string
129
     */
130
    protected $_userContentType;
131
132
    /**
133
     * Create a new SimpleMimeEntity with $headers, $encoder and $cache.
134
     *
135
     * @param Swift_Mime_HeaderSet       $headers
136
     * @param Swift_Mime_ContentEncoder  $encoder
137
     * @param Swift_KeyCache             $cache
138
     * @param Swift_EmailValidatorBridge $emailValidator
139
     */
140 497
    public function __construct(Swift_Mime_HeaderSet $headers, Swift_Mime_ContentEncoder $encoder, Swift_KeyCache $cache, Swift_EmailValidatorBridge $emailValidator)
141
    {
142 497
        $this->_cacheKey = $this->_generateNewCacheKey();
143 497
        $this->_cache = $cache;
144 497
        $this->_headers = $headers;
145 497
        $this->_emailValidator = $emailValidator;
146 497
        $this->setEncoder($encoder);
147 497
        $this->_headers->defineOrdering(array('Content-Type', 'Content-Transfer-Encoding'));
148
149
        // This array specifies that, when the entire MIME document contains
150
        // $compoundLevel, then for each child within $level, if its Content-Type
151
        // is $contentType then it should be treated as if it's level is
152
        // $neededLevel instead.  I tried to write that unambiguously! :-\
153
        // Data Structure:
154
        // array (
155
        //   $compoundLevel => array(
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
156
        //     $level => array(
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
157
        //       $contentType => $neededLevel
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
158
        //     )
159
        //   )
160
        // )
161
162 354
        $this->_compoundLevelFilters = array(
163 354
            (self::LEVEL_ALTERNATIVE + self::LEVEL_RELATED) => array(
164 354
                self::LEVEL_ALTERNATIVE => array(
165 354
                    'text/plain' => self::LEVEL_ALTERNATIVE,
166 354
                    'text/html' => self::LEVEL_RELATED,
167
                ),
168
            ),
169
        );
170
171 354
        $this->_id = $this->getRandomId();
172 354
    }
173
174
    /**
175
     * Generate a new Content-ID or Message-ID for this MIME entity.
176
     *
177
     * @return string
178
     */
179 10
    public function generateId()
180
    {
181 10
        $this->setId($this->getRandomId());
182
183 10
        return $this->_id;
184
    }
185
186
    /**
187
     * Get the {@link Swift_Mime_HeaderSet} for this entity.
188
     *
189
     * @return Swift_Mime_HeaderSet
190
     */
191 227
    public function getHeaders()
192
    {
193 227
        return $this->_headers;
194
    }
195
196
    /**
197
     * Get the nesting level of this entity.
198
     *
199
     * @see LEVEL_TOP, LEVEL_MIXED, LEVEL_RELATED, LEVEL_ALTERNATIVE
200
     *
201
     * @return int
202
     */
203 10
    public function getNestingLevel()
204
    {
205 10
        return $this->_nestingLevel;
206
    }
207
208
    /**
209
     * Get the Content-type of this entity.
210
     *
211
     * @return string
212
     */
213 10
    public function getContentType()
214
    {
215 10
        return $this->_getHeaderFieldModel('Content-Type');
216
    }
217
218
    /**
219
     * Set the Content-type of this entity.
220
     *
221
     * @param string $type
222
     *
223
     * @return Swift_Mime_SimpleMimeEntity
224
     */
225 309
    public function setContentType($type)
226
    {
227 309
        $this->_setContentTypeInHeaders($type);
228
        // Keep track of the value so that if the content-type changes automatically
229
        // due to added child entities, it can be restored if they are later removed
230 309
        $this->_userContentType = $type;
231
232 309
        return $this;
233
    }
234
235
    /**
236
     * Get the CID of this entity.
237
     *
238
     * The CID will only be present in headers if a Content-ID header is present.
239
     *
240
     * @return string
241
     */
242 186
    public function getId()
243
    {
244 186
        $tmp = (array) $this->_getHeaderFieldModel($this->_getIdField());
245
246 186
        return $this->_headers->has($this->_getIdField()) ? current($tmp) : $this->_id;
247
    }
248
249
    /**
250
     * Set the CID of this entity.
251
     *
252
     * @param string $id
253
     *
254
     * @return Swift_Mime_SimpleMimeEntity
255
     */
256 189
    public function setId($id)
257
    {
258 189
        if (!$this->_setHeaderFieldModel($this->_getIdField(), $id)) {
259 182
            $this->_headers->addIdHeader($this->_getIdField(), $id);
260
        }
261 189
        $this->_id = $id;
262
263 189
        return $this;
264
    }
265
266
    /**
267
     * Get the description of this entity.
268
     *
269
     * This value comes from the Content-Description header if set.
270
     *
271
     * @return string
272
     */
273 5
    public function getDescription()
274
    {
275 5
        return $this->_getHeaderFieldModel('Content-Description');
276
    }
277
278
    /**
279
     * Set the description of this entity.
280
     *
281
     * This method sets a value in the Content-ID header.
282
     *
283
     * @param string $description
284
     *
285
     * @return Swift_Mime_SimpleMimeEntity
286
     */
287 15
    public function setDescription($description)
288
    {
289 15
        if (!$this->_setHeaderFieldModel('Content-Description', $description)) {
290 10
            $this->_headers->addTextHeader('Content-Description', $description);
291
        }
292
293 15
        return $this;
294
    }
295
296
    /**
297
     * Get the maximum line length of the body of this entity.
298
     *
299
     * @return int
300
     */
301 52
    public function getMaxLineLength()
302
    {
303 52
        return $this->_maxLineLength;
304
    }
305
306
    /**
307
     * Set the maximum line length of lines in this body.
308
     *
309
     * Though not enforced by the library, lines should not exceed 1000 chars.
310
     *
311
     * @param int $length
312
     *
313
     * @return Swift_Mime_SimpleMimeEntity
314
     */
315 15
    public function setMaxLineLength($length)
316
    {
317 15
        $this->_maxLineLength = $length;
318
319 15
        return $this;
320
    }
321
322
    /**
323
     * Get all children added to this entity.
324
     *
325
     * @return Swift_Mime_MimeEntity[]
326
     */
327 47
    public function getChildren()
328
    {
329 47
        return $this->_children;
330
    }
331
332
    /**
333
     * Set all children of this entity.
334
     *
335
     * @param Swift_Mime_MimeEntity[] $children
336
     * @param int                     $compoundLevel For internal use only
337
     *
338
     * @return Swift_Mime_SimpleMimeEntity
339
     */
340 71
    public function setChildren(array $children, $compoundLevel = null)
341
    {
342
        // TODO: Try to refactor this logic
343
344 71
        $compoundLevel = isset($compoundLevel) ? $compoundLevel : $this->_getCompoundLevel($children);
345 71
        $immediateChildren = array();
346 71
        $grandchildren = array();
347 71
        $newContentType = $this->_userContentType;
348
349 71
        foreach ($children as $child) {
350 67
            $level = $this->_getNeededChildLevel($child, $compoundLevel);
351 67
            if (empty($immediateChildren)) {
352
                // first iteration
353 67
                $immediateChildren = array($child);
354
            } else {
355 22
                $nextLevel = $this->_getNeededChildLevel($immediateChildren[0], $compoundLevel);
356 22
                if ($nextLevel === $level) {
357 12
                    $immediateChildren[] = $child;
358 10
                } elseif ($level < $nextLevel) {
359
                    // re-assign immediateChildren to grandchildren
360 5
                    $grandchildren = array_merge($grandchildren, $immediateChildren);
361
                    // set new children
362 5
                    $immediateChildren = array($child);
363
                } else {
364 67
                    $grandchildren[] = $child;
365
                }
366
            }
367
        }
368
369 71
        if ($immediateChildren) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $immediateChildren of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
370 67
            $lowestLevel = $this->_getNeededChildLevel($immediateChildren[0], $compoundLevel);
371
372
            // Determine which composite media type is needed to accommodate the immediate children.
373 67
            foreach ($this->_compositeRanges as $mediaType => $range) {
374 67
                if ($lowestLevel > $range[0] && $lowestLevel <= $range[1]) {
375 41
                    $newContentType = $mediaType;
376
377 67
                    break;
378
                }
379
            }
380
381
            // Put any grandchildren in a sub-part.
382 67
            if (!empty($grandchildren)) {
383 10
                $subentity = $this->_createChild();
384 10
                $subentity->_setNestingLevel($lowestLevel);
385 10
                $subentity->setChildren($grandchildren, $compoundLevel);
386 10
                array_unshift($immediateChildren, $subentity);
387
            }
388
        }
389
390 71
        $this->_immediateChildren = $immediateChildren;
391 71
        $this->_children = $children;
392 71
        $this->_setContentTypeInHeaders($newContentType);
393 71
        $this->_fixHeaders();
394 71
        $this->_sortChildren();
395
396 71
        return $this;
397
    }
398
399
    /**
400
     * Get the body of this entity as a string.
401
     *
402
     * @return string
403
     */
404 62
    public function getBody()
405
    {
406 62
        return $this->_body instanceof Swift_OutputByteStream ? $this->_readStream($this->_body) : $this->_body;
407
    }
408
409
    /**
410
     * Set the body of this entity, either as a string, or as an instance of
411
     * {@link Swift_OutputByteStream}.
412
     *
413
     * @param mixed       $body
414
     * @param string|null $contentType optional
415
     *
416
     * @return Swift_Mime_SimpleMimeEntity
417
     */
418 85
    public function setBody($body, $contentType = null)
419
    {
420 85
        if ($body !== $this->_body) {
421 85
            $this->_clearCache();
422
        }
423
424 85
        $this->_body = $body;
425
426 85
        if ($contentType) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $contentType of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
427 9
            $this->setContentType($contentType);
428
        }
429
430 85
        return $this;
431
    }
432
433
    /**
434
     * Get the encoder used for the body of this entity.
435
     *
436
     * @return Swift_Mime_ContentEncoder
437
     */
438 10
    public function getEncoder()
439
    {
440 10
        return $this->_encoder;
441
    }
442
443
    /**
444
     * Set the encoder used for the body of this entity.
445
     *
446
     * @param Swift_Mime_ContentEncoder $encoder
447
     *
448
     * @return Swift_Mime_SimpleMimeEntity
449
     */
450 497
    public function setEncoder(Swift_Mime_ContentEncoder $encoder)
451
    {
452 497
        if ($encoder !== $this->_encoder) {
453 497
            $this->_clearCache();
454
        }
455
456 497
        $this->_encoder = $encoder;
457 497
        $this->_setEncoding($encoder->getName());
458 497
        $this->_notifyEncoderChanged($encoder);
459
460 497
        return $this;
461
    }
462
463
    /**
464
     * Get the boundary used to separate children in this entity.
465
     *
466
     * @return string
467
     */
468 82
    public function getBoundary()
469
    {
470 82
        if (!isset($this->_boundary)) {
471 66
            $this->_boundary = '_=_swift_v5_' . time() . '_' . md5(getmypid() . mt_rand() . uniqid('', true)) . '_=_';
472
        }
473
474 82
        return $this->_boundary;
475
    }
476
477
    /**
478
     * Set the boundary used to separate children in this entity.
479
     *
480
     * @param string $boundary
481
     *
482
     * @throws Swift_RfcComplianceException
483
     *
484
     * @return Swift_Mime_SimpleMimeEntity
485
     */
486 25
    public function setBoundary($boundary)
487
    {
488 25
        $this->_assertValidBoundary($boundary);
489 25
        $this->_boundary = $boundary;
490
491 25
        return $this;
492
    }
493
494
    /**
495
     * Receive notification that the charset of this entity, or a parent entity
496
     * has changed.
497
     *
498
     * @param string $charset
499
     */
500 21
    public function charsetChanged($charset)
501
    {
502 21
        $this->_notifyCharsetChanged($charset);
503 21
    }
504
505
    /**
506
     * Receive notification that the encoder of this entity or a parent entity
507
     * has changed.
508
     *
509
     * @param Swift_Mime_ContentEncoder $encoder
510
     */
511 5
    public function encoderChanged(Swift_Mime_ContentEncoder $encoder)
512
    {
513 5
        $this->_notifyEncoderChanged($encoder);
514 5
    }
515
516
    /**
517
     * Get this entire entity as a string.
518
     *
519
     * @return string
520
     */
521 67
    public function toString()
522
    {
523 67
        $string = $this->_headers->toString();
524 67
        $string .= $this->_bodyToString();
525
526 67
        return $string;
527
    }
528
529
    /**
530
     * Get this entire entity as a string.
531
     *
532
     * @return string
533
     */
534 67
    protected function _bodyToString()
535
    {
536 67
        $string = '';
537
538
        if (
539 67
            isset($this->_body)
540
            &&
541 67
            empty($this->_immediateChildren)
542
        ) {
543 47
            if ($this->_cache->hasKey($this->_cacheKey, 'body')) {
544 5
                $body = $this->_cache->getString($this->_cacheKey, 'body');
545
            } else {
546 42
                $body = "\r\n" . $this->_encoder->encodeString($this->getBody(), 0, $this->getMaxLineLength());
547 42
                $this->_cache->setString($this->_cacheKey, 'body', $body, Swift_KeyCache::MODE_WRITE);
548
            }
549 47
            $string .= $body;
550
        }
551
552 67
        if (!empty($this->_immediateChildren)) {
553 15
            foreach ($this->_immediateChildren as $child) {
554 15
                $string .= "\r\n\r\n--" . $this->getBoundary() . "\r\n";
555 15
                $string .= $child->toString();
556
            }
557 15
            $string .= "\r\n\r\n--" . $this->getBoundary() . "--\r\n";
558
        }
559
560 67
        return $string;
561
    }
562
563
    /**
564
     * Returns a string representation of this object.
565
     *
566
     * @see toString()
567
     *
568
     * @return string
569
     */
570
    public function __toString()
571
    {
572
        return $this->toString();
573
    }
574
575
    /**
576
     * Write this entire entity to a {@see Swift_InputByteStream}.
577
     *
578
     * @param Swift_InputByteStream
579
     */
580 20
    public function toByteStream(Swift_InputByteStream $is)
581
    {
582 20
        $is->write($this->_headers->toString());
583 20
        $is->commit();
584
585 20
        $this->_bodyToByteStream($is);
586 20
    }
587
588
    /**
589
     * Write this entire entity to a {@link Swift_InputByteStream}.
590
     *
591
     * @param Swift_InputByteStream
592
     */
593 20
    protected function _bodyToByteStream(Swift_InputByteStream $is)
594
    {
595 20
        if (empty($this->_immediateChildren)) {
596 20
            if (isset($this->_body)) {
597 10
                if ($this->_cache->hasKey($this->_cacheKey, 'body')) {
598 5
                    $this->_cache->exportToByteStream($this->_cacheKey, 'body', $is);
599
                } else {
600 5
                    $cacheIs = $this->_cache->getInputByteStream($this->_cacheKey, 'body');
601 5
                    if ($cacheIs) {
602
                        $is->bind($cacheIs);
603
                    }
604
605 5
                    $is->write("\r\n");
606
607 5
                    if ($this->_body instanceof Swift_OutputByteStream) {
608
                        $this->_body->setReadPointer(0);
609
610
                        $this->_encoder->encodeByteStream($this->_body, $is, 0, $this->getMaxLineLength());
611
                    } else {
612 5
                        $is->write($this->_encoder->encodeString($this->getBody(), 0, $this->getMaxLineLength()));
613
                    }
614
615 5
                    if ($cacheIs) {
616
                        $is->unbind($cacheIs);
617
                    }
618
                }
619
            }
620
        }
621
622 20
        if (!empty($this->_immediateChildren)) {
623
            foreach ($this->_immediateChildren as $child) {
624
                $is->write("\r\n\r\n--" . $this->getBoundary() . "\r\n");
625
                $child->toByteStream($is);
626
            }
627
            $is->write("\r\n\r\n--" . $this->getBoundary() . "--\r\n");
628
        }
629 20
    }
630
631
    /**
632
     * Get the name of the header that provides the ID of this entity.
633
     */
634 83
    protected function _getIdField()
635
    {
636 83
        return 'Content-ID';
637
    }
638
639
    /**
640
     * Get the model data (usually an array or a string) for $field.
641
     *
642
     * @param string $field
643
     *
644
     * @return string
645
     */
646 196
    protected function _getHeaderFieldModel($field)
647
    {
648 196
        if ($this->_headers->has($field)) {
649 40
            return $this->_headers->get($field)->getFieldBodyModel();
650
        } else {
651 179
            return null;
652
        }
653
    }
654
655
    /**
656
     * Set the model data for $field.
657
     *
658
     * @param string $field
659
     * @param $model
660
     *
661
     * @return bool
662
     */
663 497
    protected function _setHeaderFieldModel($field, $model)
664
    {
665 497
        if ($this->_headers->has($field)) {
666 109
            $this->_headers->get($field)->setFieldBodyModel($model);
667
668 109
            return true;
669
        }
670
671 496
        return false;
672
    }
673
674
    /**
675
     * Get the parameter value of $parameter on $field header.
676
     * @param string $field
677
     * @param string $parameter
678
     *
679
     * @return string|false
680
     */
681 40
    protected function _getHeaderParameter($field, $parameter)
682
    {
683 40
        if ($this->_headers->has($field)) {
684 12
            return $this->_headers->get($field)->getParameter($parameter);
0 ignored issues
show
Bug introduced by
The method getParameter does only exist in Swift_Mime_ParameterizedHeader, but not in Swift_Mime_Headers_MailboxHeader.

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

Let’s take a look at an example:

class A
{
    public function foo() { }
}

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

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

Available Fixes

  1. Add an additional type-check:

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

    function someFunction(B $x) { /** ... */ }
    
Loading history...
685
        } else {
686 28
            return false;
687
        }
688
    }
689
690
    /**
691
     * Set the parameter value of $parameter on $field header.
692
     * @param string $field
693
     * @param string $parameter
694
     * @param mixed  $value
695
     *
696
     * @return bool
697
     */
698 99
    protected function _setHeaderParameter($field, $parameter, $value)
699
    {
700 99
        if ($this->_headers->has($field)) {
701 50
            $this->_headers->get($field)->setParameter($parameter, $value);
0 ignored issues
show
Bug introduced by
The method setParameter does only exist in Swift_Mime_ParameterizedHeader, but not in Swift_Mime_Headers_MailboxHeader.

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

Let’s take a look at an example:

class A
{
    public function foo() { }
}

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

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

Available Fixes

  1. Add an additional type-check:

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

    function someFunction(B $x) { /** ... */ }
    
Loading history...
702
703 50
            return true;
704
        }
705
706 55
        return false;
707
    }
708
709
    /**
710
     * Re-evaluate what content type and encoding should be used on this entity.
711
     */
712 71
    protected function _fixHeaders()
713
    {
714 71
        if (count($this->_immediateChildren)) {
715 67
            $this->_setHeaderParameter('Content-Type', 'boundary', $this->getBoundary());
716 67
            $this->_headers->remove('Content-Transfer-Encoding');
717
        } else {
718 10
            $this->_setHeaderParameter('Content-Type', 'boundary', null);
719 10
            $this->_setEncoding($this->_encoder->getName());
720
        }
721 71
    }
722
723
    /**
724
     * Get the KeyCache used in this entity.
725
     *
726
     * @return Swift_KeyCache
727
     */
728
    protected function _getCache()
729
    {
730
        return $this->_cache;
731
    }
732
733
    /**
734
     * Get the email-validator.
735
     *
736
     * @return Swift_EmailValidatorBridge
737
     */
738
    protected function _getEmailValidator()
739
    {
740
        return $this->_emailValidator;
741
    }
742
743
    /**
744
     * Empty the KeyCache for this entity.
745
     */
746 497
    protected function _clearCache()
747
    {
748 497
        $this->_cache->clearKey($this->_cacheKey, 'body');
749 497
    }
750
751
    /**
752
     * Returns a random Content-ID or Message-ID.
753
     *
754
     * @return string
755
     */
756 354
    protected function getRandomId()
0 ignored issues
show
Coding Style introduced by
getRandomId uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
757
    {
758 354
        $idLeft = $this->_generateNewCacheKey();
759 354
        $idRight = !empty($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'swift.generated';
760 354
        $id = $idLeft . '@' . $idRight;
761
762
        try {
763 354
            $this->_assertValidId($id);
764
        } catch (Swift_RfcComplianceException $e) {
765
            $id = $idLeft . '@swift.generated';
766
        }
767
768 354
        return $id;
769
    }
770
771
    /**
772
     * generate a new cache-key
773
     *
774
     * @return string
775
     */
776 497
    private function _generateNewCacheKey()
777
    {
778 497
        return md5(getmypid() . '.' . time() . '.' . uniqid(mt_rand(), true));
779
    }
780
781 12
    private function _readStream(Swift_OutputByteStream $os)
782
    {
783 12
        $string = '';
784 12
        while (false !== $bytes = $os->read(8192)) {
785 12
            $string .= $bytes;
786
        }
787
788 12
        $os->setReadPointer(0);
789
790 12
        return $string;
791
    }
792
793
    /**
794
     * @param string $encoding
795
     */
796 497
    private function _setEncoding($encoding)
797
    {
798 497
        if (!$this->_setHeaderFieldModel('Content-Transfer-Encoding', $encoding)) {
799 492
            $this->_headers->addTextHeader('Content-Transfer-Encoding', $encoding);
800
        }
801 497
    }
802
803
    /**
804
     * @param string $boundary
805
     *
806
     * @throws Swift_RfcComplianceException
807
     */
808 25
    private function _assertValidBoundary($boundary)
809
    {
810 25
        if (!preg_match('/^[a-z0-9\'\(\)\+_\-,\.\/:=\?\ ]{0,69}[a-z0-9\'\(\)\+_\-,\.\/:=\?]$/Di', $boundary)) {
811
            throw new Swift_RfcComplianceException('Mime boundary set is not RFC 2046 compliant.');
812
        }
813 25
    }
814
815 320
    private function _setContentTypeInHeaders($type)
816
    {
817 320
        if (!$this->_setHeaderFieldModel('Content-Type', $type)) {
818 259
            $this->_headers->addParameterizedHeader('Content-Type', $type);
819
        }
820 320
    }
821
822 10
    private function _setNestingLevel($level)
823
    {
824 10
        $this->_nestingLevel = $level;
825 10
    }
826
827
    /**
828
     * @param Swift_Mime_MimeEntity[] $children
829
     *
830
     * @return int
831
     */
832 71
    private function _getCompoundLevel($children)
833
    {
834 71
        $level = 0;
835 71
        foreach ($children as $child) {
836 67
            $level |= $child->getNestingLevel();
837
        }
838
839 71
        return $level;
840
    }
841
842
    /**
843
     * @param Swift_Mime_MimeEntity $child
844
     * @param integer $compoundLevel
845
     *
846
     * @return int
847
     */
848 67
    private function _getNeededChildLevel($child, $compoundLevel)
849
    {
850 67
        $filter = array();
851 67
        foreach ($this->_compoundLevelFilters as $bitmask => $rules) {
852 67
            if (($compoundLevel & $bitmask) === $bitmask) {
853 67
                $filter = $rules + $filter;
854
            }
855
        }
856
857 67
        $realLevel = $child->getNestingLevel();
858 67
        $lowercaseType = Swift::strtolowerWithStaticCache($child->getContentType());
859
860 67
        if (isset($filter[$realLevel], $filter[$realLevel][$lowercaseType])) {
861
            return (int)$filter[$realLevel][$lowercaseType];
862
        }
863
864 67
        return (int)$realLevel;
865
    }
866
867
    /**
868
     * @return Swift_Mime_SimpleMimeEntity
869
     */
870 10
    private function _createChild()
871
    {
872 10
        return new self($this->_headers->newInstance(), $this->_encoder, $this->_cache, $this->_emailValidator);
873
    }
874
875
    /**
876
     * @param Swift_Mime_ContentEncoder $encoder
877
     */
878 497
    private function _notifyEncoderChanged(Swift_Mime_ContentEncoder $encoder)
879
    {
880 497
        foreach ($this->_immediateChildren as $child) {
881 10
            $child->encoderChanged($encoder);
882
        }
883 497
    }
884
885
    /**
886
     * @param string $charset
887
     */
888 21
    private function _notifyCharsetChanged($charset)
889
    {
890 21
        $this->_encoder->charsetChanged($charset);
891 21
        $this->_headers->charsetChanged($charset);
892 21
        foreach ($this->_immediateChildren as $child) {
893 7
            $child->charsetChanged($charset);
894
        }
895 21
    }
896
897 71
    private function _sortChildren()
898
    {
899 71
        $shouldSort = false;
900 71
        foreach ($this->_immediateChildren as $child) {
901
            // NOTE: This include alternative parts moved into a related part
902 67
            if ($child->getNestingLevel() === self::LEVEL_ALTERNATIVE) {
903 30
                $shouldSort = true;
904 67
                break;
905
            }
906
        }
907
908
        // Sort in order of preference, if there is one
909 71
        if ($shouldSort) {
910 30
            usort($this->_immediateChildren, array($this, '_childSortAlgorithm'));
911
        }
912 71
    }
913
914
    /**
915
     * @param Swift_Mime_MimeEntity $a
916
     * @param Swift_Mime_MimeEntity $b
917
     *
918
     * @return int
919
     */
920 15
    private function _childSortAlgorithm($a, $b)
921
    {
922 15
        $typePrefs = array();
923
924
        $types = array(
925 15
            Swift::strtolowerWithStaticCache($a->getContentType()),
926 15
            Swift::strtolowerWithStaticCache($b->getContentType())
927
        );
928
929 15
        foreach ($types as $type) {
930 15
            if (isset($this->_alternativePartOrder[$type])) {
931 15
                $typePrefs[] = $this->_alternativePartOrder[$type];
932
            } else {
933 15
                $typePrefs[] = max($this->_alternativePartOrder) + 1;
934
            }
935
        }
936
937 15
        return $typePrefs[0] >= $typePrefs[1] ? 1 : -1;
938
    }
939
940
    /**
941
     * Empties it's own contents from the cache.
942
     */
943 355
    public function __destruct()
944
    {
945 355
        $this->_cache->clearAll($this->_cacheKey);
946 355
    }
947
948
    /**
949
     * Throws an Exception if the id passed does not comply with RFC 2822.
950
     *
951
     * @param string $id
952
     *
953
     * @throws Swift_RfcComplianceException
954
     */
955 354
    private function _assertValidId($id)
956
    {
957 354 View Code Duplication
        if ($this->_emailValidator->isValidWrapper($id) === false) {
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...
958
            throw new Swift_RfcComplianceException('Invalid ID given <' . $id . '>');
959
        }
960 354
    }
961
962
    /**
963
     * Make a deep copy of object.
964
     */
965
    public function __clone()
966
    {
967
        $this->_headers = clone $this->_headers;
968
        $this->_encoder = clone $this->_encoder;
969
970
        // TODO? do we need this ? -> https://github.com/bmurashin/swiftmailer/commit/ef5c5134e6e02afc2e8ff3287bfa74be1b33dcaf
971
        //$this->_cacheKey = $this->_generateNewCacheKey();
0 ignored issues
show
Unused Code Comprehensibility introduced by
59% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
972
        //$this->generateId();
0 ignored issues
show
Unused Code Comprehensibility introduced by
84% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
973
974
        $children = array();
975
        foreach ($this->_children as $pos => $child) {
976
            if ($child instanceof Swift_Mime_Attachment || $child instanceof Swift_Mime_EmbeddedFile) {
977
                $children[$pos] = $child;
978
            } else {
979
                $children[$pos] = clone $child;
980
            }
981
        }
982
        $this->setChildren($children);
983
    }
984
}
985