source: trunk/i.php @ 12958

Last change on this file since 12958 was 12958, checked in by rvelices, 12 years ago

feature 2548 multisize - small fixes

File size: 11.1 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based photo gallery                                    |
4// +-----------------------------------------------------------------------+
5// | Copyright(C) 2008-2012 Piwigo Team                  http://piwigo.org |
6// +-----------------------------------------------------------------------+
7// | This program is free software; you can redistribute it and/or modify  |
8// | it under the terms of the GNU General Public License as published by  |
9// | the Free Software Foundation                                          |
10// |                                                                       |
11// | This program is distributed in the hope that it will be useful, but   |
12// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
13// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
14// | General Public License for more details.                              |
15// |                                                                       |
16// | You should have received a copy of the GNU General Public License     |
17// | along with this program; if not, write to the Free Software           |
18// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
19// | USA.                                                                  |
20// +-----------------------------------------------------------------------+
21
22define('PHPWG_ROOT_PATH','./');
23
24// fast bootstrap - no db connection
25include(PHPWG_ROOT_PATH . 'include/config_default.inc.php');
26@include(PHPWG_ROOT_PATH. 'local/config/config.inc.php');
27
28defined('PWG_LOCAL_DIR') or define('PWG_LOCAL_DIR', 'local/');
29defined('PWG_DERIVATIVE_DIR') or define('PWG_DERIVATIVE_DIR', $conf['data_location'].'i/');
30
31function trigger_action() {}
32function get_extension( $filename )
33{
34  return substr( strrchr( $filename, '.' ), 1, strlen ( $filename ) );
35}
36
37function mkgetdir($dir)
38{
39  if ( !is_dir($dir) )
40  {
41    global $conf;
42    if (substr(PHP_OS, 0, 3) == 'WIN')
43    {
44      $dir = str_replace('/', DIRECTORY_SEPARATOR, $dir);
45    }
46    $umask = umask(0);
47    $mkd = @mkdir($dir, $conf['chmod_value'], true);
48    umask($umask);
49    if ($mkd==false)
50    {
51      return false;
52    }
53
54    $file = $dir.'/index.htm';
55    file_exists($file) or @file_put_contents( $file, 'Not allowed!' );
56  }
57  if ( !is_writable($dir) )
58  {
59    return false;
60  }
61  return true;
62}
63
64// end fast bootstrap
65
66function ilog()
67{
68  global $conf, $ilogfh;
69  if (!$conf['enable_i_log']) return;
70  if(!$ilogfh)
71  {
72    $dir=PHPWG_ROOT_PATH.$conf['data_location'].'tmp/';
73    if (!mkgetdir($dir) or ! ($ilogfh=fopen($dir.'i.log', 'a')) )
74      return;
75  }
76  $line = date("c");
77  foreach( func_get_args() as $arg)
78  {
79    $line .= ' ';
80    if (is_array($arg))
81    {
82      $line .= implode(' ', $arg);
83    }
84    else
85    {
86      $line .= $arg;
87    }
88  }
89  fwrite($ilogfh, $line."\n");
90}
91
92function ierror($msg, $code)
93{
94  if ($code==301 || $code==302)
95  {
96    if (ob_get_length () !== FALSE)
97    {
98      ob_clean();
99    }
100    // default url is on html format
101    $url = html_entity_decode($msg);
102    header('Request-URI: '.$url);
103    header('Content-Location: '.$url);
104    header('Location: '.$url);
105    exit;
106  }
107  if ($code>=400)
108  {
109    $protocol = $_SERVER["SERVER_PROTOCOL"];
110    if ( ('HTTP/1.1' != $protocol) && ('HTTP/1.0' != $protocol) )
111      $protocol = 'HTTP/1.0';
112
113    header( "$protocol $code $msg", true, $code );
114  }
115  //todo improve
116  echo $msg;
117  exit;
118}
119
120function time_step( &$step )
121{
122  $tmp = $step;
123  $step = microtime(true);
124  return intval(1000*($step - $tmp));
125}
126
127function parse_request()
128{
129  global $conf, $page;
130
131  if ( $conf['question_mark_in_urls']==false and
132       isset($_SERVER["PATH_INFO"]) and !empty($_SERVER["PATH_INFO"]) )
133  {
134    $req = $_SERVER["PATH_INFO"];
135    $req = str_replace('//', '/', $req);
136    $path_count = count( explode('/', $req) );
137    $page['root_path'] = PHPWG_ROOT_PATH.str_repeat('../', $path_count-1);
138  }
139  else
140  {
141    $req = $_SERVER["QUERY_STRING"];
142    if ($pos=strpos($req, '&'))
143    {
144      $req = substr($req, 0, $pos);
145    }
146    /*foreach (array_keys($_GET) as $keynum => $key)
147    {
148      $req = $key;
149      break;
150    }*/
151    $page['root_path'] = PHPWG_ROOT_PATH;
152  }
153
154  $req = ltrim($req, '/');
155  !preg_match('#[^a-zA-Z0-9/_.-]#', $req) or ierror('Invalid chars in request', 400);
156
157  $page['derivative_path'] = PHPWG_ROOT_PATH.PWG_DERIVATIVE_DIR.$req;
158
159  $pos = strrpos($req, '.');
160  $pos!== false || ierror('Missing .', 400);
161  $ext = substr($req, $pos);
162  $page['derivative_ext'] = $ext;
163  $req = substr($req, 0, $pos);
164
165  $pos = strrpos($req, '-');
166  $pos!== false || ierror('Missing -', 400);
167  $deriv = substr($req, $pos+1);
168  $req = substr($req, 0, $pos);
169
170  $deriv = explode('_', $deriv);
171  foreach (ImageStdParams::get_defined_type_map() as $type => $params)
172  {
173    if ( derivative_to_url($type) == $deriv[0])
174    {
175      $page['derivative_type'] = $type;
176      $page['derivative_params'] = $params;
177      break;
178    }
179  }
180
181  if (!isset($page['derivative_type']))
182  {
183    if (derivative_to_url(IMG_CUSTOM) == $deriv[0])
184    {
185      $page['derivative_type'] = IMG_CUSTOM;
186    }
187    else
188    {
189      ierror('Unknown parsing type', 400);
190    }
191  }
192  array_shift($deriv);
193  $page['coi'] = '';
194  if (count($deriv) && $deriv[0][0]=='c' && $deriv[0][1]=='i')
195  {
196    $page['coi'] = substr(array_shift($deriv), 2);
197    preg_match('#^[a-zA-Z]{4}$#', $page['coi']) or ierror('Invalid center of interest', 400);
198  }
199
200  if ($page['derivative_type'] == IMG_CUSTOM)
201  {
202    try
203    {
204      $params = $page['derivative_params'] = DerivativeParams::from_url_tokens($deriv);
205    }
206    catch (Exception $e)
207    {
208      ierror($e->getMessage(), 400);
209    }
210    if ($params->sizing->ideal_size[0] < 20 or $params->sizing->ideal_size[1] < 20)
211    {
212      ierror('Invalid size', 400);
213    }
214    if ($params->sizing->max_crop < 0 or $params->sizing->max_crop > 1)
215    {
216      ierror('Invalid crop', 400);
217    }
218  }
219
220  if (!is_file(PHPWG_ROOT_PATH.$req.$ext) and
221      is_file(PHPWG_ROOT_PATH.'../'.$req.$ext) )
222    $req = '../'.$req;
223
224  $page['src_location'] = $req.$ext;
225  $page['src_path'] = PHPWG_ROOT_PATH.$page['src_location'];
226  $page['src_url'] = $page['root_path'].$page['src_location'];
227}
228
229
230function send_derivative($expires)
231{
232  global $page;
233  $fp = fopen($page['derivative_path'], 'rb');
234
235  $fstat = fstat($fp);
236  header('Last-Modified: '.gmdate('D, d M Y H:i:s', $fstat['mtime']).' GMT');
237  if ($expires!==false)
238  {
239    header('Expires: '.gmdate('D, d M Y H:i:s', $expires).' GMT');
240  }
241  header('Content-length: '.$fstat['size']);
242  header('Connection: close');
243
244  $ctype="application/octet-stream";
245  switch (strtolower($page['derivative_ext']))
246  {
247    case ".jpe": case ".jpeg": case ".jpg": $ctype="image/jpeg"; break;
248    case ".png": $ctype="image/png"; break;
249    case ".gif": $ctype="image/gif"; break;
250  }
251  header("Content-Type: $ctype");
252
253  fpassthru($fp);
254  fclose($fp);
255}
256
257
258$page=array();
259$begin = $step = microtime(true);
260$timing=array();
261foreach( explode(',','load,rotate,crop,scale,sharpen,watermark,save,send') as $k )
262{
263  $timing[$k] = '';
264}
265
266include_once( PHPWG_ROOT_PATH .'/include/derivative_params.inc.php');
267include_once( PHPWG_ROOT_PATH .'/include/derivative_std_params.inc.php');
268
269ImageStdParams::load_from_file();
270
271
272parse_request();
273//var_export($page);
274
275$params = $page['derivative_params'];
276
277$src_mtime = @filemtime($page['src_path']);
278if ($src_mtime === false)
279{
280  ierror('Source not found', 404);
281}
282
283$need_generate = false;
284$derivative_mtime = @filemtime($page['derivative_path']);
285if ($derivative_mtime === false or
286    $derivative_mtime < $src_mtime or
287    $derivative_mtime < $params->last_mod_time)
288{
289  $need_generate = true;
290}
291
292$expires=false;
293$now = time();
294if ( isset($_GET['b']) )
295{
296  $expires = $now + 100;
297  header("Cache-control: no-store, max-age=100");
298}
299elseif ( $now > (max($src_mtime, $params->last_mod_time) + 24*3600) )
300{// somehow arbitrary - if derivative params or src didn't change for the last 24 hours, we send an expire header for several days
301  $expires = $now + 10*24*3600;
302}
303
304if (!$need_generate)
305{
306  if ( isset( $_SERVER['HTTP_IF_MODIFIED_SINCE'] )
307    and strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $derivative_mtime)
308  {// send the last mod time of the file back
309    header('Last-Modified: '.gmdate('D, d M Y H:i:s', $derivative_mtime).' GMT', true, 304);
310    header('Expires: '.gmdate('D, d M Y H:i:s', time()+10*24*3600).' GMT', true, 304);
311    exit;
312  }
313  send_derivative($expires);
314}
315
316if (!mkgetdir(dirname($page['derivative_path'])))
317{
318  ierror("dir create error", 500);
319}
320
321include_once(PHPWG_ROOT_PATH . 'admin/include/image.class.php');
322
323ignore_user_abort(true);
324set_time_limit(0);
325
326$image = new pwg_image($page['src_path']);
327$timing['load'] = time_step($step);
328
329$changes = 0;
330
331// todo rotate
332
333// Crop & scale
334$o_size = $d_size = array($image->get_width(),$image->get_height());
335$params->sizing->compute($o_size , $page['coi'], $crop_rect, $scaled_size );
336if ($crop_rect)
337{
338  $changes++;
339  $image->crop( $crop_rect->width(), $crop_rect->height(), $crop_rect->l, $crop_rect->t);
340  $timing['crop'] = time_step($step);
341}
342
343if ($scaled_size)
344{
345  $changes++;
346  $image->resize( $scaled_size[0], $scaled_size[1] );
347  $d_size = $scaled_size;
348  $timing['scale'] = time_step($step);
349}
350
351if ($params->sharpen)
352{
353  $changes += $image->sharpen( $params->sharpen );
354  $timing['sharpen'] = time_step($step);
355}
356
357if ($params->use_watermark)
358{
359  $wm = ImageStdParams::get_watermark();
360  $wm_image = new pwg_image(PHPWG_ROOT_PATH.$wm->file);
361  $wm_size = array($wm_image->get_width(),$wm_image->get_height());
362  if ($d_size[0]<$wm_size[0] or $d_size[1]<$wm_size[1])
363  {
364    $wm_scaling_params = SizingParams::classic($d_size[0], $d_size[1]);
365    $wm_scaling_params->compute($wm_size, null, $tmp, $wm_scaled_size);
366    $wm_size = $wm_scaled_size;
367    $wm_image->resize( $wm_scaled_size[0], $wm_scaled_size[1] );
368  }
369  $x = round( ($wm->xpos/100)*($d_size[0]-$wm_size[0]) );
370  $y = round( ($wm->ypos/100)*($d_size[1]-$wm_size[1]) );
371  if ($image->compose($wm_image, $x, $y, $wm->opacity))
372  {
373    $changes++;
374    if ($wm->xrepeat)
375    {
376      // todo
377      $pad = $wm_size[0] + max(30, round($wm_size[0]/4));
378      for($i=-$wm->xrepeat; $i<=$wm->xrepeat; $i++)
379      {
380        if (!$i) continue;
381        $x2 = $x + $i * $pad;
382        if ($x2>=0 && $x2+$wm_size[0]<$d_size[0])
383          if (!$image->compose($wm_image, $x2, $y, $wm->opacity))
384            break;
385      }
386    }
387  }
388  $wm_image->destroy();
389  $timing['watermark'] = time_step($step);
390}
391
392// no change required - redirect to source
393if (!$changes)
394{
395  header("X-i: No change");
396  ierror( $page['src_url'], 301);
397}
398
399if ($d_size[0]*$d_size[1] < 100000)
400{// strip metadata for small images
401  $image->strip();
402}
403$image->set_compression_quality( $params->quality );
404$image->write( $page['derivative_path'] );
405$image->destroy();
406$timing['save'] = time_step($step);
407
408send_derivative($expires);
409$timing['send'] = time_step($step);
410
411ilog('perf',
412  basename($page['src_path']), $o_size, $o_size[0]*$o_size[1],
413  basename($page['derivative_path']), $d_size, $d_size[0]*$d_size[1],
414  function_exists('memory_get_peak_usage') ? round( memory_get_peak_usage()/(1024*1024), 1) : '',
415  time_step($begin),
416  '|', $timing);
417?>
Note: See TracBrowser for help on using the repository browser.