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