From 25b9776bf662c14f0296f776616266a214650136 Mon Sep 17 00:00:00 2001 From: Max Kostikov Date: Sun, 13 Sep 2020 11:56:02 +0200 Subject: Support remote host cache directives on profile photo fetching --- include/photo/photo_driver.php | 126 +++++++++++++++++++++++++++-------------- 1 file changed, 85 insertions(+), 41 deletions(-) (limited to 'include/photo') diff --git a/include/photo/photo_driver.php b/include/photo/photo_driver.php index 284206161..52f761b65 100644 --- a/include/photo/photo_driver.php +++ b/include/photo/photo_driver.php @@ -190,25 +190,27 @@ function delete_thing_photo($url, $ob_hash) { * * \e string \b 5 => modification date */ function import_xchan_photo($photo, $xchan, $thing = false, $force = false) { + $modified = ''; $o = null; - $flags = (($thing) ? PHOTO_THING : PHOTO_XCHAN); $album = (($thing) ? 'Things' : 'Contact Photos'); logger('Updating channel photo from ' . $photo . ' for ' . $xchan, LOGGER_DEBUG); - if($thing) { + 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)); + else { + $r = q("SELECT resource_id, edited, mimetype, expires, description 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(); + $exp = strtotime($r[0]['expires']); + $etag = $r[0]['description']; } + else + $hash = photo_new_resource(); } $photo_failure = false; @@ -216,37 +218,74 @@ function import_xchan_photo($photo, $xchan, $thing = false, $force = false) { if($photo) { - if($force || $modified == '') { + if($force || empty($modified)) $result = z_fetch_url($photo, true); - } else { - $h = [ - 'headers' => [ - 'If-Modified-Since: ' . gmdate('D, d M Y H:i:s', strtotime($modified . 'Z')) . ' GMT' - ] - ]; - $result = z_fetch_url($photo, true, 0, $h); + elseif($exp - 60 < time()) { + $h = []; + $h[] = "If-Modified-Since: " . gmdate("D, d M Y H:i:s", $exp) . " GMT"; + if(! empty($etag)) + $h[] = "If-None-Match: " . $etag; + $result = z_fetch_url($photo, true, 0, [ 'headers' => $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())); - if(is_null($type)) + if(isset($result)) { + $hdrs = []; + $h = explode("\n", $result['header']); + foreach ($h as $l) { + list($t,$v) = array_map("trim", explode(":", trim($l), 2)); + $hdrs[strtolower($t)] = $v; + } + + if(array_key_exists('expires', $hdrs)) + $expires = strtotime($hdrs['expires']); + if($expires - 60 < time()) + $expires = time() + 60; + else { + $cc = ''; + if(array_key_exists('cache-control', $hdrs)) + $cc = $hdrs['cache-control']; + if(strpos($cc, 'no-cache')) + $expires = time() + 60; + else { + $ttl = (preg_match('/max-age=(\d+)/i', $cc, $o) ? intval($o[1]) : 86400); + $expires = time() + $ttl; + } + } + + $modified = gmdate('Y-m-d H:i:s', (array_key_exists('last-modified', $hdrs) ? strtotime($hdrs['last-modified']) : time())); + + if($result['success']) { + $img_str = $result['body']; + $type = guess_image_type($photo, $result['header']); + if(is_null($type)) + $photo_failure = true; + } + else $photo_failure = true; - } elseif($result['return_code'] == 304) { + } + + if(! isset($result) || $result['return_code'] == 304) { $photo = z_root() . '/photo/' . $hash . '-4'; $thumb = z_root() . '/photo/' . $hash . '-5'; $micro = z_root() . '/photo/' . $hash . '-6'; - } else { + if(isset($result)) + q("UPDATE photo SET expires = '%s' WHERE xchan = '%s' and photo_usage = %d and imgscale IN (4, 5, 6)", + dbescdate(gmdate('Y-m-d H:i:s', (isset($expires) ? $expires : time() + 86400))), + dbesc($xchan), + intval(PHOTO_XCHAN) + ); + $photo_notmodified = true; $photo_failure = true; } - } else { - $photo_failure = true; } + else + $photo_failure = true; + + if(! $photo_failure) { - if(!$photo_failure && $result['return_code'] != 304) { $img = photo_factory($img_str, $type); if($img->is_valid()) { + $width = $img->getWidth(); $height = $img->getHeight(); @@ -255,25 +294,28 @@ function import_xchan_photo($photo, $xchan, $thing = false, $force = false) { // crop out the sides $margin = $width - $height; $img->cropImage(300, ($margin / 2), 0, $height, $height); - } elseif(($height / $width) > 1.2) { + } + 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; + else + $img->scaleImageSquare(300); } + else + $photo_failure = true; $p = [ - 'xchan' => $xchan, - 'resource_id' => $hash, - 'filename' => basename($photo), - 'album' => $album, - 'photo_usage' => $flags, - 'imgscale' => 4, - 'edited' => $modified, + 'xchan' => $xchan, + 'resource_id' => $hash, + 'filename' => basename($photo), + 'album' => $album, + 'photo_usage' => $flags, + 'imgscale' => 4, + 'edited' => $modified, + 'description' => (array_key_exists('etag', $hdrs) ? $hdrs['etag'] : ''), + 'expires' => gmdate('Y-m-d H:i:s', (isset($expires) ? $expires : time() + 86400)) ]; $r = $img->save($p); @@ -295,12 +337,14 @@ function import_xchan_photo($photo, $xchan, $thing = false, $force = false) { $photo = z_root() . '/photo/' . $hash . '-4'; $thumb = z_root() . '/photo/' . $hash . '-5'; $micro = z_root() . '/photo/' . $hash . '-6'; - } else { + } + else { logger('Invalid image from ' . $photo); $photo_failure = true; } } - if($photo_failure) { + + if($photo_failure && ! isset($photo_notmodified)) { $default = get_default_profile_photo(); $photo = z_root() . '/' . $default; $thumb = z_root() . '/' . get_default_profile_photo(80); @@ -309,12 +353,12 @@ function import_xchan_photo($photo, $xchan, $thing = false, $force = false) { $modified = gmdate('Y-m-d H:i:s', filemtime($default)); } - logger('HTTP code: ' . $result['return_code'] . '; modified: ' . $modified - . '; failure: ' . ($photo_failure ? 'yes' : 'no') . '; URL: ' . $photo, LOGGER_DEBUG); + logger('xchan: ' . $xchan . '; HTTP code: ' . (isset($result) && array_key_exists('return_code', $result) ? $result['return_code'] : 'none') . '; modified: ' . $modified . '; URL: ' . $photo, LOGGER_DEBUG); - return([$photo, $thumb, $micro, $type, $photo_failure, $modified]); + return([ $photo, $thumb, $micro, $type, $photo_failure, $modified ]); } + /** * @brief Import channel photo from a URL. * -- cgit v1.2.3