Passed
Push — master ( 24daad...73f9da )
by Zaahid
04:25
created

AbstractMimeTransferStreamDecorator::getSize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of the ZBateson\StreamDecorators project.
4
 *
5
 * @license http://opensource.org/licenses/bsd-license.php BSD
6
 */
7
namespace ZBateson\StreamDecorators;
8
9
use Psr\Http\Message\StreamInterface;
10
use GuzzleHttp\Psr7\StreamDecoratorTrait;
11
12
/**
13
 * A default abstract implementation of GuzzleHttp\Psr7 StreamInterface for MIME
14
 * message transfer encodings that:
15
 *
16
 *  o Implements a getSize operation, reading to the end of the stream to
17
 *    determine the stream's size, and seeking back to the current position
18
 *  o Implements a seek operation, reading and discarding the desired number of
19
 *    bytes from the decorator as a 'seek' operation
20
 *  o Provides a $position member for subclasses and a default 'tell'
21
 *    implementation returning it
22
 *  o Uses StreamDecoratorTrait, setting method visibility to protected and
23
 *    changing their names to getRawSize, seekRaw, tellRaw, writeRaw and readRaw
24
 *
25
 * @author Zaahid Bateson
26
 */
27
abstract class AbstractMimeTransferStreamDecorator implements StreamInterface
28
{
29
    use StreamDecoratorTrait {
30
        StreamDecoratorTrait::getSize as protected getRawSize;
31
        StreamDecoratorTrait::seek as protected seekRaw;
32
        StreamDecoratorTrait::tell as protected tellRaw;
33
        StreamDecoratorTrait::write as protected writeRaw;
34
        StreamDecoratorTrait::read as protected readRaw;
35
        StreamDecoratorTrait::detach as protected detachRaw;
36
        StreamDecoratorTrait::close as protected closeRaw;
37
    }
38
39
    /**
40
     * @var int current read/write position
41
     */
42
    protected $position = 0;
43
44
    /**
45
     * To determine the size of the underlying stream, the entire contents are
46
     * read and discarded.  Therefore calling getSize is an expensive operation.
47
     *
48
     * @return int
49
     */
50
    public function getSize()
51
    {
52
        return $this->getSizeWithSeekBack(true);
0 ignored issues
show
Bug introduced by
true of type true is incompatible with the type ZBateson\StreamDecorators\type expected by parameter $seekBack of ZBateson\StreamDecorator...::getSizeWithSeekBack(). ( Ignorable by Annotation )

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

52
        return $this->getSizeWithSeekBack(/** @scrutinizer ignore-type */ true);
Loading history...
53
    }
54
55
    /**
56
     * Can optionally seek back to the current position.
57
     *
58
     * Useful when called from seek with SEEK_END, there's no need to seek back
59
     * to the current position when called within seek.
60
     *
61
     * @param type $seekBack
0 ignored issues
show
Bug introduced by
The type ZBateson\StreamDecorators\type 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...
62
     */
63
    private function getSizeWithSeekBack($seekBack) {
64
        $pos = $this->position;
65
        $this->rewind();
66
        while (!$this->eof()) {
67
            $this->read(1048576);
68
        }
69
        $length = $this->position;
70
        if ($seekBack) {
0 ignored issues
show
introduced by
$seekBack is of type ZBateson\StreamDecorators\type, thus it always evaluated to true.
Loading history...
71
            $this->seek($pos);
72
        }
73
        return $length;
74
    }
75
76
    /**
77
     * Overridden to return the calculated position as bytes in the decoded
78
     * stream.
79
     *
80
     * @return int
81
     */
82
    public function tell()
83
    {
84
        return $this->position;
85
    }
86
87
    /**
88
     * Called before seeking to the specified offset, can be overridden by
89
     * sub-classes to reset internal buffers, etc...
90
     */
91
    protected function beforeSeek() {
92
        // do nothing.
93
    }
94
95
    /**
96
     * Seeks to the given position.
97
     *
98
     * This operation basically reads and discards to the given position because
99
     * the size of the underlying stream can't be calculated otherwise, and is
100
     * an expensive operation.
101
     *
102
     * @param int $offset
103
     * @param int $whence
104
     */
105
    public function seek($offset, $whence = SEEK_SET)
106
    {
107
        $pos = $offset;
108
        if ($whence === SEEK_CUR) {
109
            $pos = $this->tell() + $offset;
110
        } elseif ($whence === SEEK_END) {
111
            $pos = $this->getSizeWithSeekBack(false) + $offset;
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type ZBateson\StreamDecorators\type expected by parameter $seekBack of ZBateson\StreamDecorator...::getSizeWithSeekBack(). ( Ignorable by Annotation )

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

111
            $pos = $this->getSizeWithSeekBack(/** @scrutinizer ignore-type */ false) + $offset;
Loading history...
112
        }
113
        // $this->position may not report actual position, for instance if the
114
        // underlying stream has been moved ahead.  Checking if the requested
115
        // position is the same as $pos before moving can cause problems when
116
        // using a LimitStream for instance after the parent stream has been
117
        // read from, etc...
118
        $this->beforeSeek($pos);
0 ignored issues
show
Unused Code introduced by
The call to ZBateson\StreamDecorator...Decorator::beforeSeek() has too many arguments starting with $pos. ( Ignorable by Annotation )

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

118
        $this->/** @scrutinizer ignore-call */ 
119
               beforeSeek($pos);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
119
        $this->seekRaw(0);
120
        $this->position = 0;
121
        
122
        // to avoid memory issues
123
        while ($pos > 10240 && !$this->eof()) {
124
            $this->read(10240);
125
            $pos -= 10240;
126
        }
127
        $this->read($pos);
128
    }
129
130
    /**
131
     * Override to implement 'write' functionality and write bytes to the
132
     * underlying stream.
133
     *
134
     * @param string $string
135
     * @return int the number of bytes written
136
     */
137
    public abstract function write($string);
138
139
    /**
140
     * Override to implement read functionality, reading $length bytes from the
141
     * underlying stream
142
     *
143
     * @param int $length
144
     * @return string the string that was read
145
     */
146
    public abstract function read($length);
147
148
    /**
149
     * Flushes the underlying stream object if it's an instance of
150
     * AbstractMimeTransferStreamDecorator.
151
     */
152
    public function flush()
153
    {
154
        if ($this->stream && $this->stream instanceof AbstractMimeTransferStreamDecorator) {
155
            $this->stream->flush();
156
        }
157
    }
158
159
    /**
160
     * Overridden to call flush() before detaching.
161
     */
162
    public function detach()
163
    {
164
        $this->flush();
165
        $this->detachRaw();
166
    }
167
168
    /**
169
     * Overridden to call flush() before detaching.
170
     */
171
    public function close()
172
    {
173
        $this->flush();
174
        $this->closeRaw();
175
    }
176
}
177