Completed
Pull Request — master (#26)
by Marc
04:16 queued 02:06
created

StreamReader::resetData()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
/**
4
 * fast-image-size stream reader
5
 * @package fast-image-size
6
 * @copyright (c) Marc Alexander <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace FastImageSize;
13
14
use FastImageSize\Type\TypeJpegHelper;
15
16
class StreamReader
17
{
18
	/** @var bool Flag whether allow_url_fopen is enabled */
19
	protected $isFopenEnabled = false;
20
21
	/** @var string Data retrieved from remote */
22
	public $data = '';
23
24
	/**
25
	 * Constructor for fastImageSize class
26
	 */
27 76
	public function __construct()
28
	{
29 76
		$iniGet = new \bantu\IniGetWrapper\IniGetWrapper();
30 76
		$this->isFopenEnabled = $iniGet->getBool('allow_url_fopen');
31 76
	}
32
33
	/**
34
	 * Reset stream reader data
35
	 */
36 75
	public function resetData()
37
	{
38 75
		$this->data = '';
39 75
	}
40
41
	/**
42
	 * Get force length data
43
	 *
44
	 * @param int $offset
45
	 * @param int $length
46
	 * @return bool|string Returned data if long enough, false if not
47
	 */
48 47
	protected function getForcedLengthData($offset, $length)
49
	{
50 47
		return (strlen($this->data) < ($length + $offset)) ? false : substr($this->data, $offset, $length);
51
	}
52
53
	/**
54
	 * Get image from specified path/source
55
	 *
56
	 * @param string $filename Path to image
57
	 * @param int $offset Offset at which reading of the image should start
58
	 * @param int $length Maximum length that should be read
59
	 * @param bool $forceLength True if the length needs to be the specified
60
	 *			length, false if not. Default: true
61
	 *
62
	 * @return false|string Image data or false if result was empty
63
	 */
64 73
	public function getImage($filename, $offset, $length, $forceLength = true)
65
	{
66 73
		if (empty($this->data))
67 73
		{
68 73
			$this->getImageData($filename, $offset, $length);
69 73
		}
70
71
		// Force length to expected one. Return false if data length
72
		// is smaller than expected length
73 73
		if ($forceLength === true)
74 73
		{
75 47
			return $this->getForcedLengthData($offset, $length);
76
		}
77
78 43
		return empty($this->data) ? false : $this->data;
79
	}
80
81
	/**
82
	 * Get image data for specified filename with offset and length
83
	 *
84
	 * @param string $filename Path to image
85
	 * @param int $offset Offset at which reading of the image should start
86
	 * @param int $length Maximum length that should be read
87
	 */
88 73
	protected function getImageData($filename, $offset, $length)
89
	{
90
		// Check if we don't have a valid scheme according to RFC 3986 and
91
		// try to use file_get_contents in that case
92 73
		if (preg_match('#^([a-z][a-z0-9+\-.]+://)#i', $filename))
93 73
		{
94
			try
95
			{
96 4
				$body = $this->getSeekableImageData($filename, $offset);
97
98 2
				while ($body !== null && !$body->eof())
99
				{
100 2
					if (!$this->readDataFromBody($body, $length))
101 2
					{
102 1
						break;
103
					}
104 1
				}
105
			}
106 4
			catch (\GuzzleHttp\Exception\RequestException $exception)
107
			{
108
				// Silently fail in case of issues during guzzle request
109
			}
110 4
		}
111
112 73
		$this->getImageDataFopen($filename, $offset, $length);
113 73
	}
114
115
	/**
116
	 * Read data from guzzle request body
117
	 *
118
	 * @param \GuzzleHttp\Stream\StreamInterface $body Request body as stream
119
	 * @param int $length Requested length for file
120
	 * @return bool True while reading and not having reached the end of the
121
	 *		targeted length, false if end of targeted length has been reached
122
	 */
123 2
	protected function readDataFromBody(\GuzzleHttp\Stream\StreamInterface $body, $length)
124
	{
125 2
		$readLength = min($length - strlen($this->data), TypeJpegHelper::JPEG_CHUNK_SIZE);
126 2
		$this->data .= $body->read($readLength);
127 2
		if ($readLength < TypeJpegHelper::JPEG_CHUNK_SIZE || strlen($this->data == $readLength))
128 2
		{
129 1
			return false;
130
		}
131
132 1
		return true;
133
	}
134
135
	/**
136
	 * Get image data using file get contents if data is empty and
137
	 *		allow_url_fopen is enabled
138
	 *
139
	 * @param string $filename Path to image
140
	 * @param int $offset Offset at which reading of the image should start
141
	 * @param int $length Maximum length that should be read
142
	 */
143 73
	protected function getImageDataFopen($filename, $offset, $length)
144
	{
145 73
		if ($this->isFopenEnabled && empty($this->data))
146 73
		{
147 71
			$this->data = @file_get_contents($filename, null, null, $offset, $length);
148 71
		}
149 73
	}
150
151
	/**
152
	 * Get seekable image data in form of Guzzle stream interface
153
	 *
154
	 * @param string $filename Filename / URL to get
155
	 * @param int $offset Offset for response body
156
	 * @return \GuzzleHttp\Stream\StreamInterface|null Stream interface of
157
	 *		requested image or null if it could not be retrieved
158
	 */
159 31
	public function getSeekableImageData($filename, $offset)
160
	{
161 31
		$guzzleClient = new \GuzzleHttp\Client();
162
		// Set stream to true to not read full file data during request
163 31
		$response = $guzzleClient->get($filename, ['stream' => true]);
164
165 4
		$body = $response->getBody();
166
167 4
		if ($offset > 0 && !$body->eof())
168 4
		{
169 1
			$body->seek($offset);
170 1
		}
171
172 4
		return $body;
173
	}
174
}
175