Passed
Push — master ( 37aad3...325143 )
by Zaahid
03:26
created

MessagePartStream::getCharsetDecoratorForStream()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 1
dl 0
loc 11
ccs 8
cts 8
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of the ZBateson\MailMimeParser project.
4
 *
5
 * @license http://opensource.org/licenses/bsd-license.php BSD
6
 */
7
namespace ZBateson\MailMimeParser\Stream;
8
9
use GuzzleHttp\Psr7;
10
use GuzzleHttp\Psr7\AppendStream;
11
use GuzzleHttp\Psr7\StreamDecoratorTrait;
12
use Psr\Http\Message\StreamInterface;
13
use ZBateson\MailMimeParser\MailMimeParser;
14
use ZBateson\MailMimeParser\Message\Part\MessagePart;
15
use ZBateson\MailMimeParser\Message\Part\MimePart;
16
use ZBateson\MailMimeParser\Message\Part\ParentHeaderPart;
17
use ZBateson\MailMimeParser\Stream\StreamFactory;
18
19
/**
20
 * Provides a readable stream for a MessagePart.
21
 *
22
 * @author Zaahid Bateson
23
 */
24
class MessagePartStream implements StreamInterface
25
{
26
    use StreamDecoratorTrait;
27
28
    /**
29
     * @var StreamFactory For creating needed stream decorators.
30
     */
31
    protected $streamFactory;
32
33
    /**
34
     * @var MessagePart The part to read from.
35
     */
36
    protected $part;
37
38
    /**
39
     * @param StreamFactory $sdf
40
     * @param MessagePart $part
41
     */
42 4
    public function __construct(StreamFactory $sdf, MessagePart $part)
43
    {
44 4
        $this->streamFactory = $sdf;
45 4
        $this->part = $part;
46 4
    }
47
48
    /**
49
     * Attaches and returns a CharsetStream decorator to the passed $stream.
50
     *
51
     * If the current attached $part doesn't specify a $charset, $stream is
52
     * returned as-is.
53
     *
54
     * @return StreamInterface
55
     */
56 4
    private function getCharsetDecoratorForStream(StreamInterface $stream)
57
    {
58 4
        $charset = $this->part->getCharset();
59 4
        if (!empty($charset)) {
60 1
            $stream = $this->streamFactory->newCharsetStream(
61 1
                $stream,
62 1
                $charset,
63 1
                MailMimeParser::DEFAULT_CHARSET
64
            );
65
        }
66 4
        return $stream;
67
    }
68
    
69
    /**
70
     * Attaches and returns a transfer encoding stream decorator to the passed
71
     * $stream.
72
     *
73
     * The attached stream decorator is based on the attached part's returned
74
     * value from MessagePart::getContentTransferEncoding, using one of the
75
     * following stream decorators as appropriate:
76
     *
77
     * o QuotedPrintableStream
78
     * o Base64Stream
79
     * o UUStream
80
     *
81
     * @param StreamInterface $stream
82
     * @return StreamInterface
83
     */
84 4
    private function getTransferEncodingDecoratorForStream(StreamInterface $stream)
85
    {
86 4
        $encoding = $this->part->getContentTransferEncoding();
87 4
        $decorator = null;
88
        switch ($encoding) {
89 4
            case 'quoted-printable':
90 1
                $decorator = $this->streamFactory->newQuotedPrintableStream($stream);
91 1
                break;
92 3
            case 'base64':
93 1
                $decorator = $this->streamFactory->newBase64Stream(
94 1
                    $this->streamFactory->newChunkSplitStream($stream));
95 1
                break;
96 2
            case 'x-uuencode':
97 1
                $decorator = $this->streamFactory->newUUStream($stream);
98 1
                $decorator->setFilename($this->part->getFilename());
99 1
                break;
100
            default:
101 1
                return $stream;
102
        }
103 3
        return $decorator;
104
    }
105
106
    /**
107
     * Writes out the content portion of the attached mime part to the passed
108
     * $stream.
109
     *
110
     * @param MessagePart $part
111
     * @param StreamInterface $stream
112
     */
113 4
    private function writePartContentTo(StreamInterface $stream)
114
    {
115 4
        $contentStream = $this->part->getContentStream();
116 4
        if ($contentStream !== null) {
117 4
            $copyStream = $this->streamFactory->newNonClosingStream($stream);
118 4
            $es = $this->getTransferEncodingDecoratorForStream($copyStream);
119 4
            $cs = $this->getCharsetDecoratorForStream($es);
120 4
            Psr7\copy_to_stream($contentStream, $cs);
0 ignored issues
show
Bug introduced by
The function copy_to_stream was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

120
            /** @scrutinizer ignore-call */ 
121
            Psr7\copy_to_stream($contentStream, $cs);
Loading history...
121 4
            $cs->close();
122
        }
123 4
    }
124
125
    /**
126
     * Creates an array of streams based on the attached part's mime boundary
127
     * and child streams.
128
     *
129
     * ParentHeaderPart $part passed in because $this->part is declared as
130
     *                  MessagePart
131
     * @return StreamInterface[]
132
     */
133 2
    protected function getBoundaryAndChildStreams(ParentHeaderPart $part)
134
    {
135 2
        $boundary = $part->getHeaderParameter('Content-Type', 'boundary');
136 2
        if ($boundary === null) {
0 ignored issues
show
introduced by
The condition $boundary === null is always false.
Loading history...
137 1
            return array_map(
138 1
                function ($child) {
139 1
                    return $child->getStream();
140 1
                },
141 1
                $part->getChildParts()
142
            );
143
        }
144 1
        $streams = [];
145 1
        foreach ($part->getChildParts() as $i => $child) {
146 1
            if ($i !== 0 || $part->hasContent()) {
147 1
                $streams[] = Psr7\stream_for("\r\n");
0 ignored issues
show
Bug introduced by
The function stream_for was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

147
                $streams[] = /** @scrutinizer ignore-call */ Psr7\stream_for("\r\n");
Loading history...
148
            }
149 1
            $streams[] = Psr7\stream_for("--$boundary\r\n");
150 1
            $streams[] = $child->getStream();
151
        }
152 1
        $streams[] = Psr7\stream_for("\r\n--$boundary--\r\n");
153
        
154 1
        return $streams;
155
    }
156
157
    /**
158
     * Returns an array of Psr7 Streams representing the attached part and it's
159
     * direct children.
160
     *
161
     * @return StreamInterface[]
162
     */
163 4
    protected function getStreamsArray()
164
    {
165 4
        $content = Psr7\stream_for();
0 ignored issues
show
Bug introduced by
The function stream_for was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

165
        $content = /** @scrutinizer ignore-call */ Psr7\stream_for();
Loading history...
166 4
        $this->writePartContentTo($content);
167 4
        $content->rewind();
168 4
        $streams = [ $this->streamFactory->newHeaderStream($this->part), $content ];
169
170
        /**
171
         * @var ParentHeaderPart
172
         */
173 4
        $part = $this->part;
174 4
        if ($part instanceof ParentHeaderPart && $part->getChildCount()) {
175 2
            $streams = array_merge($streams, $this->getBoundaryAndChildStreams($part));
176
        }
177
178 4
        return $streams;
179
    }
180
181
    /**
182
     * Creates the underlying stream lazily when required.
183
     *
184
     * @return StreamInterface
185
     */
186 4
    protected function createStream()
187
    {
188 4
        return new AppendStream($this->getStreamsArray());
189
    }
190
}
191