OptimalTransferEncodedPhraseStream::__toString()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Genkgo\Mail\Stream;
5
6
use Genkgo\Mail\Header\HeaderValueParameter;
7
use Genkgo\Mail\StreamInterface;
8
9
final class OptimalTransferEncodedPhraseStream implements StreamInterface
10
{
11
    /**
12
     * @var StreamInterface
13
     */
14
    private $decoratedStream;
15
16
    /**
17
     * @var string
18
     */
19
    private $encoding = '7bit';
20
21
    /**
22
     * @var int
23
     */
24
    private $lineLength = 78;
25
    
26
    private const NON_7BIT_CHARS = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x7F\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF";
27
28
    /**
29
     * @var string
30
     */
31
    private $lineBreak;
32
33
    /**
34
     * @param string $text
35
     * @param int $lineLength
36
     * @param string $lineBreak
37
     */
38 59
    public function __construct(string $text, int $lineLength = 78, string $lineBreak = "\r\n")
39
    {
40 59
        $this->lineLength = $lineLength;
41 59
        $this->lineBreak = $lineBreak;
42 59
        $this->decoratedStream = $this->calculateOptimalStream($text);
43 59
    }
44
45
    /**
46
     * @param string $text
47
     * @return StreamInterface
48
     */
49 59
    private function calculateOptimalStream(string $text): StreamInterface
50
    {
51 59
        if (\strcspn($text, self::NON_7BIT_CHARS) === \strlen($text)) {
52 48
            $this->encoding = '7bit';
53 48
            return new AsciiEncodedStream($text, $this->lineLength, $this->lineBreak);
54
        }
55
56 12
        if (\strcspn($text, HeaderValueParameter::RFC_822_T_SPECIAL) !== \strlen($text)) {
57 3
            $this->encoding = 'base64';
58 3
            return Base64EncodedStream::fromString($text, $this->lineLength, $this->lineBreak);
59
        }
60
61 9
        if (\preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $text) > (\strlen($text) / 3)) {
62 8
            $this->encoding = 'base64';
63 8
            return Base64EncodedStream::fromString($text, $this->lineLength, $this->lineBreak);
64
        }
65
66 1
        $this->encoding = 'quoted-printable';
67 1
        return QuotedPrintableStream::fromString($text, $this->lineLength, $this->lineBreak);
68
    }
69
70
    /**
71
     * @return string
72
     */
73 51
    public function __toString(): string
74
    {
75 51
        return $this->decoratedStream->__toString();
76
    }
77
    
78
    public function close(): void
79
    {
80
        $this->decoratedStream->close();
81
    }
82
83
    /**
84
     * @return mixed
85
     */
86
    public function detach()
87
    {
88
        return $this->decoratedStream->detach();
89
    }
90
91
    /**
92
     * @return int|null
93
     */
94
    public function getSize(): ?int
95
    {
96
        return $this->decoratedStream->getSize();
97
    }
98
99
    /**
100
     * @return int
101
     * @throws \RuntimeException
102
     */
103
    public function tell(): int
104
    {
105
        return $this->decoratedStream->tell();
106
    }
107
108
    /**
109
     * @return bool
110
     */
111
    public function eof(): bool
112
    {
113
        return $this->decoratedStream->eof();
114
    }
115
116
    /**
117
     * @return bool
118
     */
119
    public function isSeekable(): bool
120
    {
121
        return $this->decoratedStream->isSeekable();
122
    }
123
124
    /**
125
     * @param int $offset
126
     * @param int $whence
127
     * @return int
128
     */
129
    public function seek(int $offset, int $whence = SEEK_SET): int
130
    {
131
        return $this->decoratedStream->seek($offset, $whence);
132
    }
133
134
    /**
135
     * @return bool
136
     */
137
    public function rewind(): bool
138
    {
139
        return $this->decoratedStream->rewind();
140
    }
141
142
    /**
143
     * @return bool
144
     */
145
    public function isWritable(): bool
146
    {
147
        return $this->decoratedStream->isWritable();
148
    }
149
150
    /**
151
     * @param string $string
152
     * @return int
153
     */
154
    public function write($string): int
155
    {
156
        return $this->decoratedStream->write($string);
157
    }
158
159
    /**
160
     * @return bool
161
     */
162
    public function isReadable(): bool
163
    {
164
        return $this->decoratedStream->isReadable();
165
    }
166
167
    /**
168
     * @param int $length
169
     * @return string
170
     */
171
    public function read(int $length): string
172
    {
173
        return $this->decoratedStream->read($length);
174
    }
175
176
    /**
177
     * @return string
178
     */
179
    public function getContents(): string
180
    {
181
        return $this->decoratedStream->getContents();
182
    }
183
184
    /**
185
     * @param array<int, string> $keys
186
     * @return array<string, mixed>
0 ignored issues
show
Documentation introduced by
The doc-type array<string, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
187
     */
188 59
    public function getMetadata(array $keys = []): array
189
    {
190 59
        $metaData = $this->decoratedStream->getMetadata($keys);
191 59
        $metaData['transfer-encoding'] = $this->encoding;
192
193 59
        $keys = \array_map('strtolower', $keys);
194
195 59
        return \array_filter(
196 59
            $metaData,
197
            function ($key) use ($keys) {
198 59
                return \in_array(\strtolower($key), $keys);
199 59
            },
200 59
            ARRAY_FILTER_USE_KEY
201
        );
202
    }
203
}
204