Completed
Push — ticket/25 ( aba345...4d88d7 )
by Marc
01:59
created

StreamReader::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

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