Imgurl.php
Go to the documentation of this file.
1<?php
2
3namespace Depage\Graphics;
4
5/*
6 * @todo test to stay inside 3MP as maximum image size for safety reasons and
7 * to be able to support all iOS devices:
8 * http://www.williammalone.com/articles/html5-javascript-ios-maximum-image-size/
9 */
10
11class Imgurl
12{
13 protected $options = [];
14 protected $actions = [];
15 protected $srcImg = '';
16 protected $outImg = '';
17 protected $notFound = false;
18 public $id = "";
19 public $rendered = false;
20 protected $invalidAction = false;
21 protected $cachePath = '';
22
23 /*
24 * action aliases
25 *
26 * Note that the order is important so shoter action names should
27 * come after larger ones
28 */
29 protected $aliases = array(
30 'quality' => "setQuality",
31 'q' => "setQuality",
32 'crop' => "addCrop",
33 'c' => "addCrop",
34 'resize' => "addResize",
35 'r' => "addResize",
36 'thumbfill' => "addThumbfill",
37 'tf' => "addThumbfill",
38 'thumb' => "addThumb",
39 't' => "addThumb",
40 'background' => "addBackground",
41 'bg' => "addBackground",
42 );
43
44 /*
45 * @param $options hold the same options as the graphics class
46 */
47 public function __construct($options = array())
48 {
49 $this->options = $options;
50 }
51
52 /*
53 * Analyzes the image url and set the path for srcImg and outImg
54 */
55 protected function analyze($url)
56 {
57 $this->invalidAction = false;
58 $this->notFound = false;
59 $this->rendered = false;
60 $this->id = "";
61 $this->actions = [];
62
63 if (isset($this->options['baseUrl']) && isset($this->options['cachePath'])) {
64 $baseUrl = rtrim($this->options['baseUrl'], '/');
65 $this->cachePath = $this->options['cachePath'];
66 $relativePath = $this->options['relPath'] ?? '';
67 } else if (defined('DEPAGE_PATH') && defined('DEPAGE_CACHE_PATH')) {
68 // we are using depage-framework so use constants for paths
69 $info = parse_url(DEPAGE_BASE);
70 $baseUrl = rtrim($info['path'], '/');
71 $relativePath = "";
72 $this->cachePath = \DEPAGE_CACHE_PATH . "graphics/";
73 } else {
74 // we using the library plainly -> get path through url
75 $scriptParts = explode("/", $_SERVER["SCRIPT_NAME"]);
76 $uriParts = explode("/", $_SERVER["REQUEST_URI"]);
77
78 if (strpos($_SERVER["SCRIPT_NAME"], "/lib/") !== false) {
79 for ($i = 0; $i < count($uriParts); $i++) {
80 // find common parts of url up to lib parameter
81 if ($uriParts[$i] == "lib") {
82 break;
83 }
84 }
85 } else {
86 for ($i = 0; $i < count($uriParts); $i++) {
87 // find common parts of url up to lib parameter
88 if ($scriptParts[$i] != $uriParts[$i]) {
89 break;
90 }
91 }
92 }
93 $baseUrl = implode("/", array_slice($uriParts, 0, $i));
94 if (isset($this->options['relPath'])) {
95 $relativePath = $this->options['relPath'];
96 } else {
97 $relativePath = str_repeat("../", count($scriptParts) - $i - 1);
98 }
99 $this->cachePath = $relativePath . "lib/cache/graphics/";
100 }
101 $baseUrlStatic = $baseUrl;
102 if (isset($this->options['baseUrlStatic'])) {
103 $baseUrlStatic = rtrim($this->options['baseUrlStatic'], '/');
104 }
105
106 // get image name
107 $imgUrl = $url;
108 if ($baseUrl == "" && $baseUrlStatic == "") {
109 $imgUrl = substr($url, 1);
110 } else if (strpos($url, $baseUrlStatic) === 0) {
111 $imgUrl = substr($url, strlen($baseUrlStatic) + 1);
112 } else if (strpos($url, $baseUrl) === 0) {
113 $imgUrl = substr($url, strlen($baseUrl) + 1);
114 }
115
116 // get action parameters
117 $matches = [];
118 $success = preg_match("/(.*\.(jpg|jpeg|gif|png|webp|eps|tif|tiff|pdf|svg))\.([^\\\]*)\.(jpg|jpeg|gif|png|webp)/i", $imgUrl, $matches);
119
120 if (!$success) {
121 $this->invalidAction = true;
122
123 return;
124 }
125
126 $this->id = rawurldecode($matches[0]);
127 $this->srcImg = $relativePath . rawurldecode($matches[1]);
128 $this->outImg = $this->cachePath . rawurldecode($matches[0]);
129 $this->actions = $this->analyzeActions($matches[3]);
130 }
131 /*
132 * Analyzes actions and replaces shortcuts with real actions
133 */
134 protected function analyzeActions($actionString)
135 {
136 $actions = explode(".", $actionString);
137
138 foreach ($actions as &$action) {
139 $regex = implode("|", array_keys($this->aliases));
140 preg_match("/^($regex)/i", $action, $matches);
141
142 if (isset($matches[1]) && isset($this->aliases[$matches[1]])) {
143 $func = $this->aliases[$matches[1]];
144 $params = substr($action, strlen($matches[1]));
145 } else {
146 $func = "";
147 $params = "";
148 }
149
150 if (!empty($func)) {
151 $params = preg_split("/[-x,]+/", $params, -1, PREG_SPLIT_NO_EMPTY);
152
153 if ($func == "addBackground") {
154 if (!in_array($params[0], array("transparent", "checkerboard"))) {
155 $params[0] = "#{$params[0]}";
156 }
157 } else {
158 foreach ($params as $i => &$p) {
159 $p = intval($p);
160 if ($p == 0 && $i < 2) {
161 $p = null;
162 }
163 }
164 }
165
166 $this->actions[] = array($func, $params);
167 } else {
168 $this->invalidAction = true;
169 }
170 }
171
172 return $this->actions;
173 }
174 public function render($url = null)
175 {
176 if (is_null($url)) {
177 $url = $_SERVER["REQUEST_URI"];
178 }
179 $this->analyze($url);
180
181 if ($this->invalidAction) {
182 return $this;
183 }
184 // make cache diretories
185 $outDir = dirname($this->outImg);
186 if (!is_dir($outDir)) {
187 mkdir($outDir, 0755, true);
188 }
189 if (file_exists($this->outImg) && filemtime($this->outImg) >= filemtime($this->srcImg)) {
190 // rendered image does exist already
191 return $this;
192 }
193
194 try {
195 $graphics = Graphics::factory($this->options);
196
197 // add actions to graphics class
198 foreach ($this->actions as $action) {
199 list($func, $params) = $action;
200 if (is_callable(array($graphics, $func))) {
201 call_user_func_array(array($graphics, $func), $params);
202 }
203 }
204
205 // render image out
206 $graphics->render($this->srcImg, $this->outImg);
207
208 $this->rendered = true;
209 } catch (Exceptions\FileNotFound $e) {
210 $this->notFound = true;
211 return $this;
212 } catch (Exceptions\Exception $e) {
213 $this->invalidAction = true;
214 }
215
216 return $this;
217 }
218
219 public function display()
220 {
221 $info = pathinfo($this->outImg);
222 $ext = strtolower($info['extension']);
223
224 if ($this->invalidAction) {
225 header("HTTP/1.1 500 Internal Server Error");
226 echo("invalid image action");
227 die();
228 }
229 if ($this->notFound) {
230 header("HTTP/1.1 404 Not Found");
231 echo("file not found");
232 die();
233 }
234
235 if ($ext == "jpg" || $ext == "jpeg") {
236 header("Content-type: image/jpeg");
237 } elseif ($ext == "png") {
238 header("Content-type: image/png");
239 } elseif ($ext == "gif") {
240 header("Content-type: image/gif");
241 } elseif ($ext == "webp") {
242 header("Content-type: image/webp");
243 }
244 readfile($this->outImg);
245
246 return $this;
247 }
248
249 public function getUrl($img)
250 {
251 $info = pathinfo($img);
252 $ext = $info['extension'];
253
254 if (count($this->actions) > 0) {
255 return $img . "." . implode(".", $this->actions) . "." . $ext;
256 } else {
257 return $img;
258 }
259 }
260
261 public function addBackground($background)
262 {
263 $this->actions[] = "bg{$background}";
264
265 return $this;
266 }
267 public function addCrop($width, $height, $x = 0, $y = 0)
268 {
269 $this->actions[] = "crop{$width}x{$height}-{$x}x{$y}";
270
271 return $this;
272 }
273 public function addResize($width, $height)
274 {
275 $this->actions[] = "r{$width}x{$height}";
276
277 return $this;
278 }
279 public function addThumb($width, $height)
280 {
281 $this->actions[] = "t{$width}x{$height}";
282
283 return $this;
284 }
285 public function addThumbfill($width, $height, $centerX = 50, $centerY = 50)
286 {
287 $action = "tf{$width}x{$height}";
288 if ($centerX != 50 || $centerY != 50) {
289 $action .= "-{$centerX}x{$centerY}";
290 }
291
292 $this->actions[] = $action;
293
294 return $this;
295 }
296 public function setQuality($quality)
297 {
298 $this->actions[] = "q{$quality}";
299
300 return $this;
301 }
302}
303/* vim:set ft=php sw=4 sts=4 fdm=marker et : */
static factory($options=array())
graphics object factory
Definition Graphics.php:115
addThumbfill($width, $height, $centerX=50, $centerY=50)
Definition Imgurl.php:285
addThumb($width, $height)
Definition Imgurl.php:279
__construct($options=array())
Definition Imgurl.php:47
addCrop($width, $height, $x=0, $y=0)
Definition Imgurl.php:267
analyzeActions($actionString)
Definition Imgurl.php:134
addBackground($background)
Definition Imgurl.php:261
addResize($width, $height)
Definition Imgurl.php:273