Completed
Push — 5.x ( 546220...bd8586 )
by Lars
16:02
created

Swift_Mime_Headers_AbstractHeader::getFieldName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 4
ccs 0
cts 0
cp 0
crap 2
rs 10
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
 * An abstract base MIME Header.
13
 *
14
 * @author Chris Corbyn
15
 */
16
abstract class Swift_Mime_Headers_AbstractHeader implements Swift_Mime_Header
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
    const PHRASE_PATTERN = '(?:(?:(?:(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?[a-zA-Z0-9!#\$%&\'\*\+\-\/=\?\^_`\{\}\|~]+(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?)|(?:(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?"((?:(?:[ \t]*(?:\r\n))?[ \t])?(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21\x23-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])))*(?:(?:[ \t]*(?:\r\n))?[ \t])?"(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?))+?)';
19
20
    /**
21
     * The name of this Header.
22
     *
23
     * @var string
24
     */
25
    private $_name;
26
27
    /**
28
     * The Encoder used to encode this Header.
29
     *
30
     * @var Swift_Encoder|Swift_Mime_ContentEncoder
31
     */
32
    private $_encoder;
33
34
    /**
35
     * The maximum length of a line in the header.
36
     *
37
     * @var int
38
     */
39
    private $_lineLength = 78;
40
41
    /**
42
     * The language used in this Header.
43
     *
44
     * @var string|null
45
     */
46
    private $_lang;
47
48
    /**
49
     * The character set of the text in this Header.
50
     *
51
     * @var string
52
     */
53
    private $_charset = 'utf-8';
54
55
    /**
56
     * The value of this Header, cached.
57
     *
58
     * @var string|null
59
     */
60
    private $_cachedValue;
61
62
    /**
63
     * Creates a new Header.
64
     */
65 256
    public function __construct()
66
    {
67 256
    }
68
69
    /**
70
     * Set the character set used in this Header.
71
     *
72
     * @param string $charset
73
     */
74 185
    public function setCharset($charset)
75
    {
76 185
        if ($charset && $charset !== $this->_charset) {
77 185
            $this->clearCachedValue();
78 185
79 185
            $this->_charset = $charset;
80
81 185
            if ($this->_encoder) {
82
                $this->_encoder->charsetChanged($charset);
83
            }
84
        }
85
    }
86
87
    /**
88 83
     * Get the character set used in this Header.
89
     *
90 83
     * @return string
91
     */
92
    public function getCharset()
93
    {
94
        return $this->_charset;
95
    }
96
97
    /**
98
     * Set the language used in this Header.
99
     *
100
     * For example, for US English, 'en-us'.
101 4
     * This can be unspecified.
102
     *
103 4
     * @param string $lang
104 4
     */
105 4
    public function setLanguage($lang)
106
    {
107
        if ($lang && $this->_lang !== $lang) {
108
            $this->clearCachedValue();
109
            $this->_lang = (string)$lang;
110
        }
111
    }
112 7
113
    /**
114 7
     * Get the language used in this Header.
115
     *
116
     * @return string
117
     */
118
    public function getLanguage()
119
    {
120
        return $this->_lang;
121
    }
122 216
123
    /**
124 216
     * Set the encoder used for encoding the header.
125 216
     *
126
     * @param Swift_Mime_HeaderEncoder $encoder
127 216
     */
128 216
    public function setEncoder(Swift_Mime_HeaderEncoder $encoder)
129
    {
130
        $this->_encoder = $encoder;
131
        $this->_encoder->charsetChanged($this->_charset);
132
133
        $this->setCachedValue(null);
134
    }
135 77
136
    /**
137 77
     * Get the encoder used for encoding this Header.
138
     *
139
     * @return Swift_Mime_HeaderEncoder
140
     */
141
    public function getEncoder()
142
    {
143
        return $this->_encoder;
144
    }
145 153
146
    /**
147 153
     * Get the name of this header (e.g. charset).
148
     *
149
     * @return string
150
     */
151
    public function getFieldName()
152
    {
153
        return $this->_name;
154
    }
155 20
156
    /**
157 20
     * Set the maximum length of lines in the header (excluding EOL).
158 20
     *
159 20
     * @param int $lineLength
160
     *
161
     * @return bool
162
     */
163
    public function setMaxLineLength($lineLength)
164
    {
165
        if ($lineLength && $this->_lineLength !== $lineLength) {
166 82
            $this->clearCachedValue();
167
168 82
            $this->_lineLength = (int)$lineLength;
169
170
            return true;
171
        }
172
173
        return false;
174
    }
175
176 157
    /**
177
     * Get the maximum permitted length of lines in this Header.
178 157
     *
179
     * @return int
180
     */
181
    public function getMaxLineLength()
182
    {
183
        return $this->_lineLength;
184
    }
185
186
    /**
187
     * Get this Header rendered as a RFC 2822 compliant string.
188
     *
189
     * @return string
190
     */
191
    public function toString()
192
    {
193
        return $this->_tokensToString($this->toTokens());
194
    }
195
196
    /**
197
     * Returns a string representation of this object.
198 256
     *
199
     * @return string
200 256
     *
201 256
     * @see toString()
202
     */
203
    public function __toString()
204
    {
205
        return $this->toString();
206
    }
207
208
    /**
209
     * Set the name of this Header field.
210
     *
211 77
     * @param string $name
212
     */
213
    protected function setFieldName($name)
214 77
    {
215
        $this->_name = $name;
216
    }
217 77
218
    /**
219 6
     * Produces a compliant, formatted RFC 2822 'phrase' based on the string given.
220
     *
221 3
     * @param Swift_Mime_Header        $header
222
     * @param string                   $string  as displayed
223
     *
224 4
     * @return string
225
     */
226
    protected function createPhrase(Swift_Mime_Header $header, $string)
227
    {
228 6
        // Treat token as exactly what was given.
229
        $phraseStr = $string;
230
231 77
        // If it's not valid ...
232
        if (!preg_match('/^' . self::PHRASE_PATTERN . '$/D', $phraseStr)) {
233
234
            if (preg_match('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/D', $phraseStr)) {
235
                // ... but it is just ascii text, try escaping some characters
236
                $phraseStr = $this->escapeSpecials($phraseStr, array('"'));
237
            } else {
238
                // ... otherwise it needs encoding
239
                $phraseStr = $this->encodeWords($header, $string);
240
            }
241
242 3
            // ... and make it a quoted-string.
243
            $phraseStr = '"' . $phraseStr . '"';
244 3
        }
245 3
246
        return $phraseStr;
247
    }
248 3
249
    /**
250
     * Escape special characters in a string (convert to quoted-pairs).
251
     *
252
     * @param string   $token
253
     * @param string[] $include additional chars to escape
254
     *
255
     * @return string
256
     */
257
    protected function escapeSpecials($token, array $include = array())
258
    {
259 161
        foreach (array_merge(array('\\'), $include) as $char) {
260
            $token = str_replace($char, '\\' . $char, $token);
261 161
        }
262
263 161
        return $token;
264
    }
265 161
266
    /**
267 161
     * Encode needed word tokens within a string of input.
268
     *
269 16
     * @param Swift_Mime_Header|Swift_Mime_Headers_AbstractHeader $header
270
     * @param string                                              $input
271 16
     *
272 12
     * @return string
273 5
     */
274 5
    protected function encodeWords(Swift_Mime_Header $header, $input)
275
    {
276
        $value = '';
277 16
278 16
        $tokens = $this->getEncodableWordTokens($input);
279
280 16
        foreach ($tokens as $token) {
281
            // See RFC 2822, Sect 2.2 (really 2.2 ?? TODO ?)
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% 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...
282 161
            if ($this->tokenNeedsEncoding($token)) {
283
                // Don't encode starting WSP
284
                $firstChar = substr($token, 0, 1);
285
                switch ($firstChar) {
286 161
                    case ' ':
287
                    case "\t":
288
                        $value .= $firstChar;
289
                        $token = substr($token, 1);
290
                }
291
292
                $usedLength = strlen($header->getFieldName() . ': ') + strlen($value);
293
                $value .= $this->getTokenAsEncodedWord($token, $usedLength);
294
295
                $header->setMaxLineLength(74); // Forcefully override (we need to save two chars for quoting)
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Swift_Mime_Header as the method setMaxLineLength() does only exist in the following implementations of said interface: Swift_Mime_Headers_AbstractHeader, Swift_Mime_Headers_DateHeader, Swift_Mime_Headers_IdentificationHeader, Swift_Mime_Headers_MailboxHeader, Swift_Mime_Headers_ParameterizedHeader, Swift_Mime_Headers_PathHeader, Swift_Mime_Headers_UnstructuredHeader.

Let’s take a look at an example:

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

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
296 161
            } else {
297
                $value .= $token;
298 161
            }
299 16
        }
300
301 150
        return $value;
302
    }
303
304
    /**
305
     * Test if a token needs to be encoded or not.
306
     *
307
     * @param string $token
308
     *
309
     * @return integer
310
     */
311
    protected function tokenNeedsEncoding($token)
312 161
    {
313
        if (preg_match('~[\x00-\x08\x10-\x19\x7F-\xFF\r\n]~', $token)) {
314 161
            return 1;
315
        } else {
316 161
            return 0;
317
        }
318 161
    }
319 161
320 16
    /**
321
     * Splits a string into tokens in blocks of words which can be encoded quickly.
322 150
     *
323 3
     * @param string $string
324 3
     *
325
     * @return string[]
326 161
     */
327
    protected function getEncodableWordTokens($string)
328
    {
329
        $tokens = array();
330 161
331 16
        $encodedToken = '';
332
        // Split at all whitespace boundaries
333
        foreach (preg_split('~(?=[\t ])~', $string) as $token) {
334 161
            if ($this->tokenNeedsEncoding($token)) {
335
                $encodedToken .= $token;
336
            } else {
337
                if ($encodedToken !== '') {
338
                    $tokens[] = $encodedToken;
339
                    $encodedToken = '';
340
                }
341
                $tokens[] = $token;
342
            }
343
        }
344
345 17
        if ($encodedToken !== '') {
346
            $tokens[] = $encodedToken;
347
        }
348
349 17
        return $tokens;
350
    }
351 17
352 2
    /**
353
     * Get a token as an encoded word for safe insertion into headers.
354
     *
355 17
     * @param string $token           token to encode
356
     * @param int    $firstLineOffset optional
357 17
     *
358
     * @return string
359
     */
360
    protected function getTokenAsEncodedWord($token, $firstLineOffset = 0)
361
    {
362
        // Adjust $firstLineOffset to account for space needed for syntax.
363 17
364 17
        $charsetDecl = $this->_charset;
365 17
366
        if ($this->_lang) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->_lang 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...
367
            $charsetDecl .= '*' . $this->_lang;
368 17
        }
369
370 17
        $encodingWrapperLength = strlen('=?' . $charsetDecl . '?' . $this->_encoder->getName() . '??=');
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Swift_Encoder as the method getName() does only exist in the following implementations of said interface: Swift_Mime_ContentEncoder_Base64ContentEncoder, Swift_Mime_ContentEncoder_NativeQpContentEncoder, Swift_Mime_ContentEncoder_PlainContentEncoder, Swift_Mime_ContentEncoder_QpContentEncoder, Swift_Mime_ContentEncoder_QpContentEncoderProxy, Swift_Mime_ContentEncoder_RawContentEncoder, Swift_Mime_HeaderEncoder_Base64HeaderEncoder, Swift_Mime_HeaderEncoder_QpHeaderEncoder.

Let’s take a look at an example:

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

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
371 17
372
        if ($firstLineOffset >= 75) {
373
            // Does this logic need to be here?
374
            $firstLineOffset = 0;
375 17
        }
376
377
        /** @noinspection PhpMethodParametersCountMismatchInspection */
378
        $encodedTextLines = explode(
379
            "\r\n",
380
            $this->_encoder->encodeString($token, $firstLineOffset, 75 - $encodingWrapperLength, $this->_charset)
0 ignored issues
show
Unused Code introduced by
The call to Swift_Encoder::encodeString() has too many arguments starting with $this->_charset.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
381
        );
382
383
        if (Swift::strtolowerWithStaticCache($this->_charset) !== 'iso-2022-jp') {
384
            // special encoding for iso-2022-jp using mb_encode_mimeheader
385 157
            foreach ($encodedTextLines as $lineNum => $line) {
386
                $encodedTextLines[$lineNum] = '=?' . $charsetDecl . '?' . $this->_encoder->getName() . '?' . $line . '?=';
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Swift_Encoder as the method getName() does only exist in the following implementations of said interface: Swift_Mime_ContentEncoder_Base64ContentEncoder, Swift_Mime_ContentEncoder_NativeQpContentEncoder, Swift_Mime_ContentEncoder_PlainContentEncoder, Swift_Mime_ContentEncoder_QpContentEncoder, Swift_Mime_ContentEncoder_QpContentEncoderProxy, Swift_Mime_ContentEncoder_RawContentEncoder, Swift_Mime_HeaderEncoder_Base64HeaderEncoder, Swift_Mime_HeaderEncoder_QpHeaderEncoder.

Let’s take a look at an example:

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

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
387 157
            }
388
        }
389
390
        return implode("\r\n ", $encodedTextLines);
391
    }
392
393
    /**
394
     * Generates tokens from the given string which include CRLF as individual tokens.
395 245
     *
396
     * @param string $token
397 245
     *
398 245
     * @return string[]
399
     */
400
    protected function generateTokenLines($token)
401
    {
402
        return preg_split('~(\r\n)~', $token, -1, PREG_SPLIT_DELIM_CAPTURE);
403
    }
404
405 176
    /**
406
     * Set a value into the cache.
407 176
     *
408
     * @param string $value
409
     */
410
    protected function setCachedValue($value)
411
    {
412
        $this->_cachedValue = $value;
413
    }
414
415 231
    /**
416
     * Get the value in the cache.
417 231
     *
418 206
     * @return string
419
     */
420 231
    protected function getCachedValue()
421
    {
422
        return $this->_cachedValue;
423
    }
424
425
    private function clearCachedValue()
426
    {
427
        $this->setCachedValue(null);
428
    }
429 157
430
    /**
431 157
     * Clear the cached value if $condition is met.
432 152
     *
433
     * @param bool $condition
434
     */
435 157
    protected function clearCachedValueIf($condition)
436
    {
437
        if (true === $condition) {
438 157
            $this->clearCachedValue();
439 157
        }
440 157
    }
441 157
442
    /**
443
     * Generate a list of all tokens in the final header.
444
     *
445 157
     * @param string $string The string to tokenize
446
     *
447
     * @return array An array of tokens as strings
448
     */
449
    protected function toTokens($string = null)
450
    {
451
        if (null === $string) {
452
            $string = $this->getFieldBody();
453
        }
454
455
        $tokens = array();
456 157
457
        // Generate atoms; split at all invisible boundaries followed by WSP
458 157
        foreach (preg_split('~(?=[ \t])~', $string) as $token) {
459 157
            $newTokens = $this->generateTokenLines($token);
460 157
            foreach ($newTokens as $newToken) {
461 157
                $tokens[] = $newToken;
462
            }
463
        }
464 157
465
        return $tokens;
466
    }
467 157
468
    /**
469
     * Takes an array of tokens which appear in the header and turns them into
470 157
     * an RFC 2822 compliant string, adding FWSP where needed.
471
     *
472
     * @param string[] $tokens
473 157
     *
474
     * @return string
475 157
     */
476
    private function _tokensToString(array $tokens)
477
    {
478
        $lineCount = 0;
479 48
        $headerLines = array();
480 48
        $headerLines[] = $this->_name . ': ';
481
        $currentLine = &$headerLines[$lineCount++];
482
483
        // Build all tokens back into compliant header
484 157
        foreach ($tokens as $i => $token) {
485 157
            // Line longer than specified maximum or token was just a new line
486
            if (
487
                ("\r\n" === $token)
488
                ||
489
                (
490 157
                    strlen($currentLine) > 0
491
                    &&
492
                    (
493
                        $i > 0
494
                        &&
495
                        strlen($currentLine . $token) > $this->_lineLength
496 5
                    )
497
                )
498 5
            ) {
499 5
                $headerLines[] = '';
500
                $currentLine = &$headerLines[$lineCount++];
501 5
            }
502
503
            // Append token to the line
504
            if ("\r\n" !== $token) {
505
                $currentLine .= $token;
506
            }
507
        }
508
509
        // Implode with FWS (RFC 2822, 2.2.3)
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% 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...
510
        return implode("\r\n", $headerLines) . "\r\n";
511
    }
512
513
    /**
514
     * Make a deep copy of object
515
     */
516
    public function __clone()
517
    {
518
        if ($this->_encoder !== null) {
519
            $this->_encoder = clone $this->_encoder;
520
        }
521
    }
522
}
523