Test Failed
Push — 2.0 ( 4d4d2f...3431b8 )
by Zaahid
04:28
created

MimeParser::parseContent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 5
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 ZBateson\MailMimeParser\Message\PartHeaderContainer;
10
use ZBateson\MailMimeParser\Message\Factory\PartHeaderContainerFactory;
11
use ZBateson\MailMimeParser\Parser\PartBuilder;
12
use ZBateson\MailMimeParser\Parser\Proxy\ParserMimePartProxy;
13
use ZBateson\MailMimeParser\Parser\Proxy\ParserMimePartFactory;
14
use ZBateson\MailMimeParser\Parser\Proxy\ParserPartProxy;
15
16
/**
17
 * Reads the content of a mime part.
18
 *
19
 * @author Zaahid Bateson
20
 */
21
class MimeParser implements IParser
22
{
23
    /**
24
     * @var PartHeaderContainerFactory
25
     */
26
    protected $partHeaderContainerFactory;
27
28
    /**
29
     * @var PartBuilderFactory
30
     */
31
    protected $partBuilderFactory;
32
33
    /**
34
     * @var HeaderParser
35
     */
36
    protected $headerParser;
37
38
    /**
39
     * @var ParsedMimePartFactory for ParsedMimePart objects
0 ignored issues
show
Bug introduced by
The type ZBateson\MailMimeParser\...r\ParsedMimePartFactory was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
40
     */
41
    protected $parserMimePartFactory;
42
43
    /**
44
     * @var int maintains the character length of the last line separator,
45
     *      typically 2 for CRLF, to keep track of the correct 'end' position
46
     *      for a part because the CRLF before a boundary is considered part of
47
     *      the boundary.
48
     */
49
    protected $lastLineSeparatorLength = 0;
50
51
    public function __construct(
52
        PartBuilderFactory $pbf,
53
        PartHeaderContainerFactory $phcf,
54
        HeaderParser $hp,
55
        ParserMimePartFactory $pmpf,
56
        IParserFactory $ipf
57
    ) {
58
        $this->partBuilderFactory = $pbf;
59
        $this->partHeaderContainerFactory = $phcf;
60
        $this->headerParser = $hp;
61
        $this->parserMimePartFactory = $pmpf;
0 ignored issues
show
Documentation Bug introduced by
It seems like $pmpf of type ZBateson\MailMimeParser\...y\ParserMimePartFactory is incompatible with the declared type ZBateson\MailMimeParser\...r\ParsedMimePartFactory of property $parserMimePartFactory.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
62
        $this->parserMimePartFactory->setParserFactory($ipf);
63
    }
64
65
    /**
66
     * Reads a line of 2048 characters.  If the line is larger than that, the
67
     * remaining characters in the line are read and discarded, and only the
68
     * first part is returned.
69
     *
70
     * This method is identical to readLine, except it calculates the number of
71
     * characters that make up the line's new line characters (e.g. 2 for "\r\n"
72
     * or 1 for "\n") and stores it in $this->lastLineSeparatorLength.
73
     *
74
     * @param resource $handle
75
     * @return string
76
     */
77
    private function readBoundaryLine($handle)
78
    {
79
        $size = 2048;
80
        $isCut = false;
81
        $line = fgets($handle, $size);
82
        while (strlen($line) === $size - 1 && substr($line, -1) !== "\n") {
83
            $line = fgets($handle, $size);
84
            $isCut = true;
85
        }
86
        $ret = rtrim($line, "\r\n");
87
        $this->lastLineSeparatorLength = strlen($line) - strlen($ret);
88
        return ($isCut) ? '' : $ret;
89
    }
90
91
    /**
92
     * Reads lines from the passed $handle, calling
93
     * $partBuilder->setEndBoundaryFound with the passed line until it returns
94
     * true or the stream is at EOF.
95
     *
96
     * setEndBoundaryFound returns true if the passed line matches a boundary
97
     * for the $partBuilder itself or any of its parents.
98
     *
99
     * Once a boundary is found, setStreamPartAndContentEndPos is called with
100
     * the passed $handle's read pos before the boundary and its line separator
101
     * were read.
102
     *
103
     * @param PartBuilder $partBuilder
104
     */
105
    private function findContentBoundary(ParserMimePartProxy $proxy, PartBuilder $partBuilder)
106
    {
107
        $handle = $partBuilder->getMessageResourceHandle();
108
        // last separator before a boundary belongs to the boundary, and is not
109
        // part of the current part
110
        $start = ftell($handle);
0 ignored issues
show
Unused Code introduced by
The assignment to $start is dead and can be removed.
Loading history...
111
        while (!feof($handle)) {
112
            $endPos = ftell($handle) - $this->lastLineSeparatorLength;
113
            $line = $this->readBoundaryLine($handle);
114
            if (substr($line, 0, 2) === '--' && $proxy->setEndBoundaryFound($line)) {
115
                $partBuilder->setStreamPartAndContentEndPos($endPos);
116
                return;
117
            }
118
        }
119
        $partBuilder->setStreamPartAndContentEndPos(ftell($handle));
120
        $proxy->setEof();
121
    }
122
123
    public function parseContent(ParserPartProxy $proxy)
124
    {
125
        $pb = $proxy->getPartBuilder();
126
        $pb->setStreamContentStartPos($pb->getMessageResourceHandlePos());
127
        $this->findContentBoundary($proxy, $pb);
128
    }
129
130
    /**
131
     * Checks if the new child part is just content past the end boundary
132
     *
133
     * @param ParserProxy $proxy
0 ignored issues
show
Bug introduced by
The type ZBateson\MailMimeParser\Parser\ParserProxy was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
134
     * @param PartBuilder $parent
135
     * @param PartBuilder $child
136
     */
137
    private function createPart(ParserMimePartProxy $parentProxy, PartBuilder $child)
138
    {
139
        $headerContainer = $this->partHeaderContainerFactory->newInstance();
140
        if (!$parentProxy->isEndBoundaryFound()) {
141
            $this->headerParser->parse($child, $headerContainer);
142
            return $this->parserMimePartFactory->newInstance($child, $headerContainer, $parentProxy);
143
        } else {
144
            // reads content past an end boundary if there is any
145
            $parserProxy = $this->parserMimePartFactory->newParserMimePartProxy($child, $headerContainer, $parentProxy);
146
            $this->parseContent($parserProxy);
147
            return null;
148
        }
149
    }
150
151
    /**
152
     * Returns true if there are more parts
153
     *
154
     * @param PartBuilder $partBuilder
155
     * @return IMimePart
0 ignored issues
show
Bug introduced by
The type ZBateson\MailMimeParser\Parser\IMimePart was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
156
     */
157
    public function parseNextChild(ParserMimePartProxy $proxy)
158
    {
159
        if ($proxy->isParentBoundaryFound()) {
160
            return null;
161
        }
162
        $child = $this->partBuilderFactory->newChildPartBuilder($proxy->getPartBuilder());
163
        return $this->createPart($proxy, $child);
164
    }
165
}
166