Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
87 / 87
100.00% covered (success)
100.00%
25 / 25
CRAP
100.00% covered (success)
100.00%
1 / 1
Body
100.00% covered (success)
100.00%
87 / 87
100.00% covered (success)
100.00%
25 / 25
48
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
 setContent
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 setContentFromFile
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
3
 getContent
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 loadFileContent
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 hasContent
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 setEncoding
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getEncoding
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasEncoding
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isBase64Encoding
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isQuotedPrintableEncoding
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isUrlEncoding
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isRawUrlEncoding
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isBinaryEncoding
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 is7BitEncoding
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 is8BitEncoding
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setSplit
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getSplit
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasSplit
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setAsFile
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 isFile
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setAsEncoded
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 isEncoded
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 render
100.00% covered (success)
100.00%
37 / 37
100.00% covered (success)
100.00%
1 / 1
16
 __toString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (https://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/popphp-framework
7 * @author     Nick Sagona, III <dev@noladev.com>
8 * @copyright  Copyright (c) 2009-2027 NOLA Interactive, LLC.
9 * @license    https://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\Mime\Part;
16
17/**
18 * MIME part body class
19 *
20 * @category   Pop
21 * @package    Pop\Mime
22 * @author     Nick Sagona, III <dev@noladev.com>
23 * @copyright  Copyright (c) 2009-2027 NOLA Interactive, LLC.
24 * @license    https://www.popphp.org/license     New BSD License
25 * @version    3.0.0
26 */
27class Body
28{
29
30    /**
31     * Content
32     * @var ?string
33     */
34    protected ?string $content = null;
35
36    /**
37     * Pending file path - set by setContentFromFile(), read lazily by
38     * render()/getContent(), never both this and $content set at once.
39     * @var ?string
40     */
41    protected ?string $file = null;
42
43    /**
44     * Encoding
45     * @var ?Body\Encoding
46     */
47    protected ?Body\Encoding $encoding = null;
48
49    /**
50     * Chunk split
51     * @var int|bool|null
52     */
53    protected int|bool|null $split = null;
54
55    /**
56     * Is file flag
57     * @var bool
58     */
59    protected bool $isFile = false;
60
61    /**
62     * Is encoded flag
63     * @var bool
64     */
65    protected bool $isEncoded = false;
66
67    /**
68     * Constructor
69     *
70     * Instantiate the body object
71     *
72     * @param ?string        $content
73     * @param ?Body\Encoding $encoding
74     * @param int|bool|null  $split
75     */
76    public function __construct(?string $content = null, ?Body\Encoding $encoding = null, int|bool|null $split = null)
77    {
78        if ($content !== null) {
79            $this->setContent($content);
80        }
81        if ($encoding !== null) {
82            $this->setEncoding($encoding);
83        }
84        if ($split !== null) {
85            $this->setSplit($split);
86        }
87    }
88
89    /**
90     * Set the body content
91     *
92     * @param  string $content
93     * @return Body
94     */
95    public function setContent(string $content): Body
96    {
97        $this->content   = $content;
98        $this->file      = null;
99        $this->isEncoded = false;
100        return $this;
101    }
102
103    /**
104     * Set the body content from file
105     *
106     * @param  string         $file
107     * @param  ?Body\Encoding $encoding
108     * @param  int|bool|null  $split
109     * @throws Exception
110     * @return Body
111     */
112    public function setContentFromFile(string $file, ?Body\Encoding $encoding = null, int|bool|null $split = null): Body
113    {
114        $this->file      = $file;
115        $this->content   = null;
116        $this->isEncoded = false;
117        $this->setAsFile(true);
118
119        if ($encoding !== null) {
120            $this->setEncoding($encoding);
121        }
122        if ($split !== null) {
123            $this->setSplit($split);
124        }
125
126        return $this;
127    }
128
129    /**
130     * Get the body content
131     *
132     * @return string
133     */
134    public function getContent(): string
135    {
136        $this->loadFileContent();
137        return $this->content;
138    }
139
140    /**
141     * Materialize a pending file's content, if one is set - lazy, so a
142     * Body that's never rendered or read never touches the filesystem.
143     *
144     * @throws Exception
145     * @return void
146     */
147    protected function loadFileContent(): void
148    {
149        if ($this->file === null) {
150            return;
151        }
152        if (!file_exists($this->file)) {
153            throw new Exception("Error: The file '" . $this->file . "' does not exist.");
154        }
155        $this->content = file_get_contents($this->file);
156        $this->file    = null;
157    }
158
159    /**
160     * Has body content
161     *
162     * @return bool
163     */
164    public function hasContent(): bool
165    {
166        return (($this->content !== null) || ($this->file !== null));
167    }
168
169    /**
170     * Set the encoding
171     *
172     * @param  Body\Encoding $encoding
173     * @return Body
174     */
175    public function setEncoding(Body\Encoding $encoding): Body
176    {
177        $this->encoding = $encoding;
178        return $this;
179    }
180
181    /**
182     * Get the encoding
183     *
184     * @return Body\Encoding|null
185     */
186    public function getEncoding(): Body\Encoding|null
187    {
188        return $this->encoding;
189    }
190
191    /**
192     * Has encoding
193     *
194     * @return bool
195     */
196    public function hasEncoding(): bool
197    {
198        return ($this->encoding !== null);
199    }
200
201    /**
202     * Is encoding base64
203     *
204     * @return bool
205     */
206    public function isBase64Encoding(): bool
207    {
208        return ($this->encoding === Body\Encoding::BASE64);
209    }
210
211    /**
212     * Is encoding quoted-printable
213     *
214     * @return bool
215     */
216    public function isQuotedPrintableEncoding(): bool
217    {
218        return ($this->encoding === Body\Encoding::QUOTED_PRINTABLE);
219    }
220
221    /**
222     * Is encoding URL
223     *
224     * @return bool
225     */
226    public function isUrlEncoding(): bool
227    {
228        return ($this->encoding === Body\Encoding::URL);
229    }
230
231    /**
232     * Is encoding raw URL
233     *
234     * @return bool
235     */
236    public function isRawUrlEncoding(): bool
237    {
238        return ($this->encoding === Body\Encoding::RAW_URL);
239    }
240
241    /**
242     * Is encoding binary
243     *
244     * @return bool
245     */
246    public function isBinaryEncoding(): bool
247    {
248        return ($this->encoding === Body\Encoding::BINARY);
249    }
250
251    /**
252     * Is encoding 7bit
253     *
254     * @return bool
255     */
256    public function is7BitEncoding(): bool
257    {
258        return ($this->encoding === Body\Encoding::_7BIT);
259    }
260
261    /**
262     * Is encoding 8bit
263     *
264     * @return bool
265     */
266    public function is8BitEncoding(): bool
267    {
268        return ($this->encoding === Body\Encoding::_8BIT);
269    }
270
271    /**
272     * Set the split
273     *
274     * @param  int|bool $split
275     * @return Body
276     */
277    public function setSplit(int|bool $split): Body
278    {
279        $this->split = $split;
280        return $this;
281    }
282
283    /**
284     * Get the split
285     *
286     * @return int|bool
287     */
288    public function getSplit(): int|bool
289    {
290        return $this->split;
291    }
292
293    /**
294     * Has split
295     *
296     * @return bool
297     */
298    public function hasSplit(): bool
299    {
300        return ($this->split !== null);
301    }
302
303    /**
304     * Set as file
305     *
306     * @param  bool $isFile
307     * @return Body
308     */
309    public function setAsFile(bool $isFile): Body
310    {
311        $this->isFile = (bool)$isFile;
312        return $this;
313    }
314
315    /**
316     * Is file
317     *
318     * @return bool
319     */
320    public function isFile(): bool
321    {
322        return $this->isFile;
323    }
324
325    /**
326     * Set as encoded
327     *
328     * @param  bool $isEncoded
329     * @return Body
330     */
331    public function setAsEncoded(bool $isEncoded): Body
332    {
333        $this->isEncoded = (bool)$isEncoded;
334        return $this;
335    }
336
337    /**
338     * Is encoded
339     *
340     * @return bool
341     */
342    public function isEncoded(): bool
343    {
344        return $this->isEncoded;
345    }
346
347    /**
348     * Render the body
349     *
350     * @return string
351     */
352    public function render(): string
353    {
354        if (($this->file !== null) && (!$this->isEncoded) && ($this->encoding === Body\Encoding::BASE64)) {
355            if (!file_exists($this->file)) {
356                throw new Exception("Error: The file '" . $this->file . "' does not exist.");
357            }
358            $content         = file_get_contents('php://filter/convert.base64-encode/resource=' . $this->file);
359            $this->content   = $content;
360            $this->file      = null;
361            $this->isEncoded = true;
362        } else {
363            $this->loadFileContent();
364            $content = $this->content;
365
366            if (!$this->isEncoded) {
367                switch ($this->encoding) {
368                    case Body\Encoding::BASE64:
369                        $content = base64_encode($this->content);
370                        $this->isEncoded = true;
371                        break;
372                    case Body\Encoding::QUOTED_PRINTABLE:
373                        $content = quoted_printable_encode($this->content);
374                        $this->isEncoded = true;
375                        break;
376                    case Body\Encoding::URL:
377                        $content = urlencode($this->content);
378                        $this->isEncoded = true;
379                        break;
380                    case Body\Encoding::RAW_URL:
381                        $content = rawurlencode($this->content);
382                        $this->isEncoded = true;
383                        break;
384                    case Body\Encoding::BINARY:
385                    case Body\Encoding::_7BIT:
386                    case Body\Encoding::_8BIT:
387                        $this->isEncoded = true;
388                        break;
389                }
390                if ($this->isEncoded) {
391                    $this->content = $content;
392                }
393            }
394        }
395
396        if ($this->split !== null) {
397            $content = ($this->split === true) ? chunk_split($content) : chunk_split($content, (int)$this->split);
398        }
399
400        return (string)$content;
401    }
402
403    /**
404     * Render the body
405     *
406     * @return string
407     */
408    public function __toString(): string
409    {
410        return $this->render();
411    }
412
413}