From 17cf824545a4e059183f0a43af9692a90100c55a Mon Sep 17 00:00:00 2001 From: Max Kostikov Date: Thu, 8 Nov 2018 18:00:18 +0100 Subject: Return image modification date using HTTP 'Last-Modified' and '304 Not Modified' on remote fetch for caching --- include/photo/photo_driver.php | 274 ++++++++++++++++++++++++----------------- 1 file changed, 159 insertions(+), 115 deletions(-) (limited to 'include/photo') diff --git a/include/photo/photo_driver.php b/include/photo/photo_driver.php index 2e2f5a758..911b97ade 100644 --- a/include/photo/photo_driver.php +++ b/include/photo/photo_driver.php @@ -570,122 +570,166 @@ function delete_thing_photo($url,$ob_hash) { -function import_xchan_photo($photo,$xchan,$thing = false) { - - $flags = (($thing) ? PHOTO_THING : PHOTO_XCHAN); - $album = (($thing) ? 'Things' : 'Contact Photos'); - - logger('import_xchan_photo: updating channel photo from ' . $photo . ' for ' . $xchan, LOGGER_DEBUG); - - if($thing) - $hash = photo_new_resource(); - else { - $r = q("select resource_id from photo where xchan = '%s' and photo_usage = %d and imgscale = 4 limit 1", - dbesc($xchan), - intval(PHOTO_XCHAN) - ); - if($r) { - $hash = $r[0]['resource_id']; - } - else { - $hash = photo_new_resource(); - } - } - - $photo_failure = false; - $img_str = ''; - - if($photo) { - $filename = basename($photo); - - $result = z_fetch_url($photo,true); - - if($result['success']) { - $img_str = $result['body']; - $type = guess_image_type($photo, $result['header']); - - $h = explode("\n",$result['header']); - if($h) { - foreach($h as $hl) { - if(stristr($hl,'content-type:')) { - if(! stristr($hl,'image/')) { - $photo_failure = true; - } - } - } - } - } - } - else { - $photo_failure = true; - } - - if(! $photo_failure) { - $img = photo_factory($img_str, $type); - if($img->is_valid()) { - $width = $img->getWidth(); - $height = $img->getHeight(); - - if($width && $height) { - if(($width / $height) > 1.2) { - // crop out the sides - $margin = $width - $height; - $img->cropImage(300,($margin / 2),0,$height,$height); - } - elseif(($height / $width) > 1.2) { - // crop out the bottom - $margin = $height - $width; - $img->cropImage(300,0,0,$width,$width); - - } - else { - $img->scaleImageSquare(300); - } - - } - else - $photo_failure = true; - - $p = array('xchan' => $xchan,'resource_id' => $hash, 'filename' => basename($photo), 'album' => $album, 'photo_usage' => $flags, 'imgscale' => 4); - - $r = $img->save($p); - - if($r === false) - $photo_failure = true; - - $img->scaleImage(80); - $p['imgscale'] = 5; - - $r = $img->save($p); - - if($r === false) - $photo_failure = true; - - $img->scaleImage(48); - $p['imgscale'] = 6; - - $r = $img->save($p); - - if($r === false) - $photo_failure = true; - - $photo = z_root() . '/photo/' . $hash . '-4'; - $thumb = z_root() . '/photo/' . $hash . '-5'; - $micro = z_root() . '/photo/' . $hash . '-6'; - } - else { - logger('import_xchan_photo: invalid image from ' . $photo); - $photo_failure = true; - } - } - if($photo_failure) { - $photo = z_root() . '/' . get_default_profile_photo(); - $thumb = z_root() . '/' . get_default_profile_photo(80); - $micro = z_root() . '/' . get_default_profile_photo(48); - $type = 'image/png'; - } +/** + * @brief fetches an photo from external site and prepares its miniatures. + * + * @param string $photo + * external URL to fetch base image + * @param string $xchan + * channel unique hash + * @param boolean $thing + * TRUE if this is a thing URL + * @param boolean $force + * TRUE if ignore image modification date check (force fetch) + * + * @return array of results + * * \e string \b 0 => local URL to full image + * * \e string \b 1 => local URL to standard thumbnail + * * \e string \b 2 => local URL to micro thumbnail + * * \e string \b 3 => image type + * * \e boolean \b 4 => TRUE if fetch failure + * * \e string \b 5 => modification date + */ - return(array($photo,$thumb,$micro,$type,$photo_failure)); +function import_xchan_photo($photo,$xchan,$thing = false,$force = false) { + + $modified = ''; + + $flags = (($thing) ? PHOTO_THING : PHOTO_XCHAN); + $album = (($thing) ? 'Things' : 'Contact Photos'); + + logger('import_xchan_photo: updating channel photo from ' . $photo . ' for ' . $xchan, LOGGER_DEBUG); + + if($thing) { + $hash = photo_new_resource(); + } + else { + $r = q("select resource_id, edited, mimetype from photo where xchan = '%s' and photo_usage = %d and imgscale = 4 limit 1", + dbesc($xchan), + intval(PHOTO_XCHAN) + ); + if($r) { + $hash = $r[0]['resource_id']; + $modified = $r[0]['edited']; + $type = $r[0]['mimetype']; + } + else { + $hash = photo_new_resource(); + } + } + + $photo_failure = false; + $img_str = ''; + + if($photo) { + $filename = basename($photo); + + if($force || $modified == '') { + $result = z_fetch_url($photo,true); + } + else { + $h = array('headers' => array("If-Modified-Since: " . gmdate("D, d M Y H:i:s", strtotime($modified . "Z")) . " GMT")); + $result = z_fetch_url($photo,true,0,$h); + } + + if($result['success']) { + $img_str = $result['body']; + $type = guess_image_type($photo, $result['header']); + $modified = gmdate('Y-m-d H:i:s', (preg_match('/last-modified: (.+) \S+/i', $result['header'], $o) ? strtotime($o[1] . 'Z') : time())); + + $h = explode("\n",$result['header']); + if($h) { + foreach($h as $hl) { + if(stristr($hl,'content-type:')) { + if(! stristr($hl,'image/')) { + $photo_failure = true; + } + } + } + } + } + elseif($result['return_code'] = 304) { + $photo = z_root() . '/photo/' . $hash . '-4'; + $thumb = z_root() . '/photo/' . $hash . '-5'; + $micro = z_root() . '/photo/' . $hash . '-6'; + } + else { + $photo_failure = true; + } + + } + else { + $photo_failure = true; + } + + if(! $photo_failure && $result['return_code'] != 304) { + $img = photo_factory($img_str, $type); + if($img->is_valid()) { + $width = $img->getWidth(); + $height = $img->getHeight(); + + if($width && $height) { + if(($width / $height) > 1.2) { + // crop out the sides + $margin = $width - $height; + $img->cropImage(300,($margin / 2),0,$height,$height); + } + elseif(($height / $width) > 1.2) { + // crop out the bottom + $margin = $height - $width; + $img->cropImage(300,0,0,$width,$width); + + } + else { + $img->scaleImageSquare(300); + } + + } + else + $photo_failure = true; + + $p = array('xchan' => $xchan,'resource_id' => $hash, 'filename' => basename($photo), 'album' => $album, 'photo_usage' => $flags, 'imgscale' => 4); + + $r = $img->save($p); + + if($r === false) + $photo_failure = true; + + $img->scaleImage(80); + $p['imgscale'] = 5; + + $r = $img->save($p); + + if($r === false) + $photo_failure = true; + + $img->scaleImage(48); + $p['imgscale'] = 6; + + $r = $img->save($p); + + if($r === false) + $photo_failure = true; + + $photo = z_root() . '/photo/' . $hash . '-4'; + $thumb = z_root() . '/photo/' . $hash . '-5'; + $micro = z_root() . '/photo/' . $hash . '-6'; + } + else { + logger('import_xchan_photo: invalid image from ' . $photo); + $photo_failure = true; + } + } + if($photo_failure) { + $default = get_default_profile_photo(); + $photo = z_root() . '/' . $default; + $thumb = z_root() . '/' . get_default_profile_photo(80); + $micro = z_root() . '/' . get_default_profile_photo(48); + $type = 'image/png'; + $modified = gmdate('Y-m-d H:i:s', filemtime($default)); + } + + return(array($photo,$thumb,$micro,$type,$photo_failure,$modified)); } -- cgit v1.2.3 From 098ec1abb46c70774a6c239f59c77df4b6437335 Mon Sep 17 00:00:00 2001 From: Max Kostikov Date: Thu, 8 Nov 2018 22:43:17 +0100 Subject: remove image type double guess by checking HTTP headers --- include/photo/photo_driver.php | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) (limited to 'include/photo') diff --git a/include/photo/photo_driver.php b/include/photo/photo_driver.php index 911b97ade..12465c794 100644 --- a/include/photo/photo_driver.php +++ b/include/photo/photo_driver.php @@ -485,11 +485,11 @@ function guess_image_type($filename, $headers = '') { $h = explode("\n",$headers); foreach ($h as $l) { list($k,$v) = array_map("trim", explode(":", trim($l), 2)); - $hdrs[$k] = $v; + $hdrs[strtolower($k)] = $v; } logger('Curl headers: '.var_export($hdrs, true), LOGGER_DEBUG); - if (array_key_exists('Content-Type', $hdrs)) - $type = $hdrs['Content-Type']; + if (array_key_exists('content-type', $hdrs)) + $type = $hdrs['content-type']; } if (is_null($type)){ @@ -637,16 +637,8 @@ function import_xchan_photo($photo,$xchan,$thing = false,$force = false) { $type = guess_image_type($photo, $result['header']); $modified = gmdate('Y-m-d H:i:s', (preg_match('/last-modified: (.+) \S+/i', $result['header'], $o) ? strtotime($o[1] . 'Z') : time())); - $h = explode("\n",$result['header']); - if($h) { - foreach($h as $hl) { - if(stristr($hl,'content-type:')) { - if(! stristr($hl,'image/')) { - $photo_failure = true; - } - } - } - } + if(is_null($type)) + $photo_failure = true; } elseif($result['return_code'] = 304) { $photo = z_root() . '/photo/' . $hash . '-4'; @@ -744,16 +736,8 @@ function import_channel_photo_from_url($photo,$aid,$uid) { $img_str = $result['body']; $type = guess_image_type($photo, $result['header']); - $h = explode("\n",$result['header']); - if($h) { - foreach($h as $hl) { - if(stristr($hl,'content-type:')) { - if(! stristr($hl,'image/')) { - $photo_failure = true; - } - } - } - } + if(is_null($type)) + $photo_failure = true; } } else { -- cgit v1.2.3