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