Completed
Pull Request — master (#28)
by Frederik
01:39
created

OptimalTransferEncodedPhraseStream::getSize()   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
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
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
     * @var string
17
     */
18
    private $encoding = '7bit';
19
    /**
20
     * @var int
21
     */
22
    private $lineLength = 78;
23
    /**
24
     *
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
     * @var string
29
     */
30
    private $lineBreak;
31
32
    /**
33
     * OptimalEncodedTextStream constructor.
34
     * @param string $text
35
     * @param int $lineLength
36
     * @param string $lineBreak
37
     */
38 36
    public function __construct(string $text, int $lineLength = 78, string $lineBreak = "\r\n")
39
    {
40 36
        $this->lineLength = $lineLength;
41 36
        $this->lineBreak = $lineBreak;
42 36
        $this->decoratedStream = $this->calculateOptimalStream($text);
43 36
    }
44
45
    /**
46
     * @param string $text
47
     * @return StreamInterface
48
     */
49 36
    private function calculateOptimalStream(string $text): StreamInterface
50
    {
51 36
        if (strcspn($text, self::NON_7BIT_CHARS) === strlen($text)) {
52 27
            $this->encoding = '7bit';
53 27
            return new AsciiEncodedStream($text, $this->lineLength, $this->lineBreak);
54
        }
55
56 10
        if (strcspn($text, HeaderValueParameter::RFC_822_T_SPECIAL) !== strlen($text)) {
57 2
            $this->encoding = 'base64';
58 2
            return Base64EncodedStream::fromString($text, $this->lineLength, $this->lineBreak);
59
        }
60
61 8
        if (preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $text) > (strlen($text) / 3)) {
62 7
            $this->encoding = 'base64';
63 7
            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 28
    public function __toString(): string
74
    {
75 28
        return $this->decoratedStream->__toString();
76
    }
77
78
    /**
79
     *
80
     */
81
    public function close(): void
82
    {
83
        $this->decoratedStream->close();
84
    }
85
86
    /**
87
     * @return mixed
88
     */
89
    public function detach()
90
    {
91
        return $this->decoratedStream->detach();
92
    }
93
94
    /**
95
     * @return int|null
96
     */
97
    public function getSize(): ?int
98
    {
99
        return $this->decoratedStream->getSize();
100
    }
101
102
    /**
103
     * @return int
104
     * @throws \RuntimeException
105
     */
106
    public function tell(): int
107
    {
108
        return $this->decoratedStream->tell();
109
    }
110
111
    /**
112
     * @return bool
113
     */
114
    public function eof(): bool
115
    {
116
        return $this->decoratedStream->eof();
117
    }
118
119
    /**
120
     * @return bool
121
     */
122
    public function isSeekable(): bool
123
    {
124
        return $this->decoratedStream->isSeekable();
125
    }
126
127
    /**
128
     * @param int $offset
129
     * @param int $whence
130
     * @return int
131
     */
132
    public function seek(int $offset, int $whence = SEEK_SET): int
133
    {
134
        return $this->decoratedStream->seek($offset, $whence);
135
    }
136
137
    /**
138
     * @return bool
139
     */
140
    public function rewind(): bool
141
    {
142
        return $this->decoratedStream->rewind();
143
    }
144
145
    /**
146
     * @return bool
147
     */
148
    public function isWritable(): bool
149
    {
150
        return $this->decoratedStream->isWritable();
151
    }
152
153
    /**
154
     * @param $string
155
     * @return int
156
     */
157
    public function write($string): int
158
    {
159
        return $this->decoratedStream->write($string);
160
    }
161
162
    /**
163
     * @return bool
164
     */
165
    public function isReadable(): bool
166
    {
167
        return $this->decoratedStream->isReadable();
168
    }
169
170
    /**
171
     * @param int $length
172
     * @return string
173
     */
174
    public function read(int $length): string
175
    {
176
        return $this->decoratedStream->read($length);
177
    }
178
179
    /**
180
     * @return string
181
     */
182
    public function getContents(): string
183
    {
184
        return $this->decoratedStream->getContents();
185
    }
186
187
    /**
188
     * @param array $keys
189
     * @return array
190
     */
191 36
    public function getMetadata(array $keys = []): array
192
    {
193 36
        $metaData = $this->decoratedStream->getMetadata($keys);
194 36
        $metaData['transfer-encoding'] = $this->encoding;
195
196 36
        $keys = array_map('strtolower', $keys);
197
198 36
        return array_filter(
199 36
            $metaData,
200 36
            function ($key) use ($keys) {
201 36
                return in_array(strtolower($key), $keys);
202 36
            },
203
            ARRAY_FILTER_USE_KEY
204
        );
205
    }
206
207
}