When we output images via PHP with image_jpeg or file_get_contents it takes more than twice as long as when we use straight links to the jpg files.
These files are about 180kb.
With our thumbnails (4kb images) there's not much of a time difference between the link and output via PHP.
Anyone know of a why PHP output is slower with larger files and a way to fix it?
All I can think of is that it is being parsed twice when parsed through PHP, instead of directly sending it to the client. Because file_get_contents does what it says, it reads the contents, then sends it to the client. I could be wrong though.
There is different between image_jpeg and file_get_contents. The first is a gd function that creates a jpeg and this take time. The second just reads data from a file.
The problem is how you output it to the browser. If you don't take appropriate measures, content is never cached, so the browser has to download it every time. Static images are always cached by the browser and after the first load, takes almost no time (just a HEAD request).
Try this code:
function CachedFileResponse($thefile,$nocache=0) {
if (!file_exists($thefile)) {
error_log('cache error: file not found: '.$thefile);
header('HTTP/1.0 404 Not Found',true,404);
} else {
$lastmodified=gmdate('D, d M Y H:i:s \G\M\T', filemtime($thefile));
$etag = '"'.md5($lastmodified.filesize($thefile).$thefile).'"';
header('ETag: '.$etag);
header('Last-Modified: '.$lastmodified);
header('Cache-Control: max-age=3600');
header('Expires: '.gmdate('D, d M Y H:i:s \G\M\T', time()+86400));
$ext=strtolower(substr($thefile,strrpos($thefile,'.')+1));
$fname=substr($thefile,strrpos($thefile,'/')+1);
if ($ext=='jpg' || $ext=='jpeg') {
header('Content-Type: image/jpeg');
} elseif ($ext=='gif') {
header('Content-Type: image/gif');
} elseif ($ext=='png') {
header('Content-Type: image/png');
} else {
header('Content-Type: application/binary');
}
header('Content-Length: ' . filesize($thefile));
header('Content-Disposition: filename="'.$fname.'"');
$ifmodifiedsince = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']) : false;
$ifnonematch = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) : false;
if ($nocache || (!$ifmodifiedsince && !$ifnonematch) ||
($ifnonematch && $ifnonematch != $etag) ||
($ifmodifiedsince && $ifmodifiedsince != $lastmodified)) {
error_log('cache miss: '.$thefile);
$fp = fopen($thefile, 'rb');
fpassthru($fp);
fclose($fp);
} else {
error_log('cache hit: '.$thefile);
header("HTTP/1.0 304 Not Modified",true,304);
}
}
}
Related
I'm using ImageMagick to dynamically resize avatars and serve them. This has proven to be a great benefit to development as when we build out new pages, we don't know how large an image should be.
Here's an example of how I am doing this:
First my file runs through and checks headers for if it needs to be re-generated:
$ModifiedDate = filemtime($UseFile);
header('Last-Modified: '.date(DATE_RFC2822, $ModifiedDate));
header("Cache-Control: public, max-age=66600");
header('Expires: '.gmdate('D, d M Y H:i:s \G\M\T', time() + 66600));
if (isset($_SERVER["HTTP_IF_MODIFIED_SINCE"]))
{
$ModifiedSince = strtotime($_SERVER["HTTP_IF_MODIFIED_SINCE"]);
if($ModifiedDate <= $ModifiedSince)
{
header($_SERVER["SERVER_PROTOCOL"]." 304 Not Modified");
die;
}
}
Then we determine the highest size available:
list($width, $height) = getimagesize($UseFile);
$NewSize = $_GET["Size"]; // I handle sanitizing this, I removed sanitation code to make this code simpler as it is not the problem I am encountering
if($NewSize > $width || $NewSize <= 0)
$NewSize = $width;
Then we handle resizing of the image:
header("Content-type: image/" . ($Animated ? "webp" : "jpg"));
$Avatar = new imagick($UseFile);
if ($Animated)
{
$Avatar = $Avatar->coalesceImages();
foreach ($Avatar as $Frame)
{
$Frame->cropThumbnailImage($NewSize, $NewSize);
$Frame->setImagePage($NewSize, $NewSize, 0, 0);
}
}
else
{
$Avatar->cropThumbnailImage($NewSize, $NewSize);
}
Then we return the image to the user:
echo $Avatar->getImagesBlob();
$Avatar->clear();
However, we recently added the ability for users to upload GIFs and we will serve them as animated webp images. We've noticed that while this functionality works, it can be extremely slow to resize.
Is there a way to potentially speed this up, maybe by flushing the first frame once it has been generated? I'm having trouble finding any information about this online, so maybe this isn't feasible.
I need to read an image (based on HTTP) on an SSL connection. This script reads the image location and encodes/decodes it, then transfers the file contents and returns the image. However, I keep getting the error cannot be displayed because it contains errors.
Here is my code:
<?php
$image = 'http://www.teleovronnaz.ch/webcam/ovronnazweb.jpg';
$info = getimagesize($image);
$strFileExt = image_type_to_extension($info[2]);
if($strFileExt == '.jpg' or $strFileExt == '.jpeg'){
header('Content-Type: image/jpeg');
}elseif($strFileExt == '.png'){
header('Content-Type: image/png');
}elseif($strFileExt == '.gif'){
header('Content-Type: image/gif');
}else{
die('not supported');
}
if($strFile != ''){
$cache_ends = 60*60*24*365;
header("Pragma: public");
header("Cache-Control: maxage=". $cache_ends);
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $cache_ends).' GMT');
$img_safe = file_get_contents($strFile);
echo $img_safe;
}
exit;
?>
This worked for me.
<?php
$url = 'http://www.teleovronnaz.ch/webcam/ovronnazweb.jpg';
header('Content-type: image/jpeg');
readfile($url);
?>
I don't know why you do it so complicated. I just stripped your cache handling, but really
<?PHP
$image = 'http://www.teleovronnaz.ch/webcam/ovronnazweb.jpg';
$imageContent = file_get_contents($image);
header("Content-Type: image/jpeg");
echo $imageContent;
die(1);
?>
Is enough to display the image. No base64 or additional stuff needed. And if the url is static, you don't even need the distinction of the file extension. You stated an image - that's singular. So I'm guessing that's the only use case here.
I just took some more time to explain a few things:
read an image (based on HTTP) on an SSL connection
If it's HTTP, there is no SSL. That's what HTTPS is for.
This script reads the image location and encodes/decodes it,
I don't know what you think, but it is not. It is base64_encoding the URL to directly decode it again into another variable. That's like doing the following: 0 is your $image - then you make $image+1 (base64_encode) - which will result in 1 - then you do $image-1 (base64_decode) which will result in 0 again.
currently using a simple php image proxy to load external images to ensure they don't mess with SSL. The problem is, on my live site they only seem to get stored in the memory cache and not the disk cache, so as soon as you close the tab/browser they get downloaded again.
Here's the code:
session_cache_limiter('public');
if (isset($_GET['url']))
{
header('Cache-control: max-age='.(60*60*24*365));
header('Expires: '.gmdate(DATE_RFC1123,time()+60*60*24*365));
header('Last-Modified: '.gmdate(DATE_RFC1123,filemtime($_GET['url'])));
define("APP_ROOT", dirname(dirname(__FILE__)));
require APP_ROOT . "/includes/bootstrap.php";
$url_check = parse_url($_GET['url']);
if (isset($url_check['scheme']) && ($url_check['scheme'] == 'http' || $url_check['scheme'] == 'https'))
{
$image_raw = core::file_get_contents_curl($_GET['url']);
$new_image = imagecreatefromstring($image_raw);
if ($new_image !== false)
{
$image_info = getimagesizefromstring($image_raw);
$image_type = $image_info['mime'];
if (stripos($image_type, 'image/') !== false)
{
header('Content-Type: '.$image_type);
imagepng($new_image);
imagedestroy($new_image);
}
}
}
else
{
echo 'Not a valid image url!';
}
}
I need to embed http image in my https website, because if simply use <img src="http://www.sof.com/abc.jpg"/> will not show in https website.
After that, I was search some topic of this function, I found that something like <img src="https://www.some.com/image.php?url=http://www.sof.com/abc.jpg" /> can be show in https
So now I was genarate 2 source. 1 is the image file: http://www.website1.com/abc.png,
and the https web adress is https://fb.ccc.com
after that I create the image.php code was below:
<?
$strFile = base64_decode(#$_GET['url']);
$strFileExt = end(explode('.' , $strFile));
if($strFileExt == 'jpg' or $strFileExt == 'jpeg'){
header('Content-Type: image/jpeg');
}elseif($strFileExt == 'png'){
header('Content-Type: image/png');
}elseif($strFileExt == 'gif'){
header('Content-Type: image/gif');
}else{
die('not supported');
}
if($strFile != ''){
$cache_expire = 60*60*24*365;
header("Pragma: public");
header("Cache-Control: maxage=". $cache_expire);
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $cache_expire).' GMT');
}
exit;
?>
if I request the link: https://fb.ccc.com/image.php?url=http://www.website1.com/abc.png , then the page will be respone not supported
I was also try $strFile = $_GET['url']; but it only show blank.
if I try $strFile = var_dump(#$_GET['url']); and the page will respone string(31) "http://www.website1.com/abc.png" not supported
so someone can help to find out what is my script problem?
thank you very much!
I am building a php script to write texts over an background image.
I used GD functions like imagecopy(), imagejpeg(), imagedestroy() to merge save text image and the background image. Everything is working perfectly. Upon form submit, the new image will be saved in the same file name of the background image and so on page reload, the edited image is not showing on the browser. It needs me to refresh the page using ctrl + F5(on windows) to load the edited image. Can anyone help me how to clear that cache?
just add ?v=something to background path everytime you edit your background image, it will force refresh
To handle image caching properly, you can write a rules either in your apache configuration or htaccess... or you can create simple "image provider", something like...
public function img($imgfile = '')
{
$imgfile = $_GET['q'];
$age = 60*60*24*31;
$file = $_SERVER['DOCUMENT_ROOT'].'/'.$imgfile;
if ( ! file_exists($file))
{
header('HTTP/1.0 404 Not Found');
}
else
{
$last_modified = filemtime($file);
// Check for cached version
if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) OR isset($_SERVER['HTTP_IF_NONE_MATCH']))
{
if ($_SERVER['HTTP_IF_MODIFIED_SINCE'] == gmdate('D, d M Y H:i:s \G\M\T', $last_modified))
{
header('HTTP/1.0 304 Not Modified');
exit;
}
}
if(strpos($imgfile,'.png') !== FALSE)
{
Header('Content-Type: image/png');
}
elseif(strpos($imgfile,'.jpg') !== FALSE || strpos($img_file,'.jpeg') !== FALSE)
{
Header('Content-Type: image/jpg');
}
elseif(strpos($img_file,'.gif') !== FALSE)
{
Header('Content-Type: image/gif')
}
Header('Last-Modified : '.gmdate('D, d M Y H:i:s \G\M\T', $last_modified));
Header('Cache-Control : max-age='.$age.', must-revalidate');
Header('Expires : '.gmdate('D, d M Y H:i:s \G\M\T', $last_modified + $age));
echo file_get_contents($file);
}
Then you can use that in your image tag, like <img src="provider.php?q=foo.jpg" alt="Foo" />