Test Failed
Pull Request — master (#171)
by Zaahid
04:32
created

PartBuilder::getStreamContentLength()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
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\Parser;
8
9
use GuzzleHttp\Psr7\StreamWrapper;
10
use Psr\Http\Message\StreamInterface;
11
use ZBateson\MailMimeParser\Message\PartHeaderContainer;
12
use ZBateson\MailMimeParser\Parser\Proxy\ParserPartProxy;
13
use ZBateson\MailMimeParser\Header\HeaderConsts;
14
15
/**
16
 * Holds information about a part while it's being parsed, proxies calls between
17
 * parsed part containers (ParserPartChildrenContainer,
18
 * ParserPartStreamContainer) and the parser as more parts need to be parsed.
19
 *
20
 * The class holds:
21
 *  - a HeaderContainer to hold headers
22
 *  - stream positions (part start/end positions, content start/end)
23
 *  - parser markers, e.g. 'mimeBoundary, 'endBoundaryFound',
24
 *    'parentBoundaryFound', 'canHaveHeaders', 'isNonMimePart'
25
 *  - properties for UUEncoded parts (filename, mode)
26
 *  - the message's psr7 stream and a resource handle created from it (held
27
 *    only for a top-level PartBuilder representing the message, child
28
 *    PartBuilders do not duplicate/hold a separate stream).
29
 *  - ParserPartChildrenContainer, ParserPartStreamContainer to update children
30
 *    and streams dynamically as a part is parsed.
31
 * @author Zaahid Bateson
32
 */
33
class PartBuilder
34
{
35
    /**
36
     * @var int The offset read start position for this part (beginning of
37
     * headers) in the message's stream.
38
     */
39
    protected $streamPartStartPos = null;
40
    
41
    /**
42
     * @var int The offset read end position for this part.  If the part is a
43
     * multipart mime part, the end position is after all of this parts
44
     * children.
45
     */
46
    protected $streamPartEndPos = null;
47
    
48
    /**
49
     * @var int The offset read start position in the message's stream for the
50
     * beginning of this part's content (body).
51
     */
52
    protected $streamContentStartPos = null;
53
    
54
    /**
55
     * @var int The offset read end position in the message's stream for the
56
     * end of this part's content (body).
57
     */
58
    protected $streamContentEndPos = null;
59
60
    /**
61
     * @var PartHeaderContainer The parsed part's headers.
62
     */
63
    protected $headerContainer;
64
65
    /**
66
     * @var StreamInterface the raw message input stream for a message, or null
67
     *      for a child part.
68
     */
69
    protected $messageStream = null;
70
71
    /**
72
     * @var resource the raw message input stream handle constructed from
73
     *      $messageStream or null for a child part
74
     */
75
    protected $messageHandle = null;
76
77
    /**
78
     * @var ParserPartProxy
79
     */
80
    private $parent = null;
81
82
    public function __construct(PartHeaderContainer $headerContainer, StreamInterface $messageStream = null, ParserPartProxy $parent = null)
83
    {
84
        $this->headerContainer = $headerContainer;
85
        $this->messageStream = $messageStream;
86
        $this->parent = $parent;
87
        if ($messageStream !== null) {
88
            $this->messageHandle = StreamWrapper::getResource($messageStream);
89
        }
90
        $this->setStreamPartStartPos($this->getMessageResourceHandlePos());
91
    }
92
93
    public function __destruct()
94
    {
95
        if ($this->messageHandle) {
96
            fclose($this->messageHandle);
97
        }
98
    }
99
100
    /**
101
     *
102
     * @return ParserPartProxy
103
     */
104
    public function getParent()
105
    {
106
        return $this->parent;
107
    }
108
109
    /**
110
     * Returns this part's PartHeaderContainer.
111
     *
112
     * @return PartHeaderContainer the container
113
     */
114
    public function getHeaderContainer()
115
    {
116
        return $this->headerContainer;
117
    }
118
119
    public function getStream()
120
    {
121
        return ($this->parent !== null) ?
122
            $this->parent->getStream() :
123
            $this->messageStream;
124
    }
125
126
    public function getMessageResourceHandle()
127
    {
128
        return ($this->parent !== null) ?
129
            $this->parent->getMessageResourceHandle() :
130
            $this->messageHandle;
131
    }
132
133
    public function getMessageResourceHandlePos()
134
    {
135
        return ftell($this->getMessageResourceHandle());
0 ignored issues
show
Bug introduced by
It seems like $this->getMessageResourceHandle() can also be of type mixed; however, parameter $stream of ftell() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

135
        return ftell(/** @scrutinizer ignore-type */ $this->getMessageResourceHandle());
Loading history...
136
    }
137
138
    /**
139
     * Returns the offset for this part's stream within its parent stream.
140
     *
141
     * @return int
142
     */
143
    public function getStreamPartStartPos()
144
    {
145
        return $this->streamPartStartPos;
146
    }
147
148
    /**
149
     * Returns the length of this part's stream.
150
     *
151
     * @return int
152
     */
153
    public function getStreamPartLength()
154
    {
155
        return $this->streamPartEndPos - $this->streamPartStartPos;
156
    }
157
158
    /**
159
     * Returns the offset for this part's content within its part stream.
160
     *
161
     * @return int
162
     */
163
    public function getStreamContentStartPos()
164
    {
165
        return $this->streamContentStartPos;
166
    }
167
168
    /**
169
     * Returns the length of this part's content stream.
170
     *
171
     * @return int
172
     */
173
    public function getStreamContentLength()
174
    {
175
        return $this->streamContentEndPos - $this->streamContentStartPos;
176
    }
177
178
    /**
179
     * Sets the start position of the part in the input stream.
180
     * 
181
     * @param int $streamPartStartPos
182
     */
183
    public function setStreamPartStartPos($streamPartStartPos)
184
    {
185
        $this->streamPartStartPos = $streamPartStartPos;
186
    }
187
188
    /**
189
     * Sets the end position of the part in the input stream, and also calls
190
     * parent->setParentStreamPartEndPos to expand to parent parts.
191
     * 
192
     * @param int $streamPartEndPos
193
     */
194
    public function setStreamPartEndPos($streamPartEndPos)
195
    {
196
        $this->streamPartEndPos = $streamPartEndPos;
197
        if ($this->parent !== null) {
198
            $this->parent->setStreamPartEndPos($streamPartEndPos);
199
        }
200
    }
201
202
    /**
203
     * Sets the start position of the content in the input stream.
204
     * 
205
     * @param int $streamContentStartPos
206
     */
207
    public function setStreamContentStartPos($streamContentStartPos)
208
    {
209
        $this->streamContentStartPos = $streamContentStartPos;
210
    }
211
212
    /**
213
     * Sets the end position of the content and part in the input stream.
214
     * 
215
     * @param int $streamContentEndPos
216
     */
217
    public function setStreamPartAndContentEndPos($streamContentEndPos)
218
    {
219
        $this->streamContentEndPos = $streamContentEndPos;
220
        $this->setStreamPartEndPos($streamContentEndPos);
221
    }
222
223
    public function isContentParsed()
224
    {
225
        return ($this->streamContentEndPos !== null);
226
    }
227
228
    public function isMime()
229
    {
230
        if ($this->getParent() !== null) {
231
            return $this->getParent()->isMime();
232
        }
233
        return ($this->headerContainer->exists(HeaderConsts::CONTENT_TYPE) ||
234
            $this->headerContainer->exists(HeaderConsts::MIME_VERSION));
235
    }
236
}
237