source: trunk/i.php @ 12908

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

feature 2548 multisize - ability to choose displayed size on index page
-added some logs on i.php (configurable) to measure the perf

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