How to solve truncated images created by php script? - php

I have an image that is severed by a php script. I call it as such.
<img src="/index.php/image-name.jpg">
If the image is more than 5 minutes old my script will retrieve a new copy of the image from a data provider and then display the new image.
When the website that provides the images has a load and this script goes to fetch a new copy, it will often only display the top part of the image. Firebug will tell me that the image is corrupt or truncated. If I open the image in a new tab, my sever has a full copy. If I run the script a second time within 5 minutes it works perfectly.
It is looking like if it takes more than a certain amount of time to get the image it fails and only shows the top part. Any thoughts on how to make it wait longer before giving up? Or maybe I am completely on the wrong track with what is going wrong.
<?php
// get the image name from the uri
$path= $_SERVER['REQUEST_URI'];
$image = explode("/", $path);
$image=$image[3];//Get the file name
$image=str_replace('%20',' ', $image); //make it all spaces
$localimage='./road_images/'.$image; //where to find the image on the sever
// check if the image exists, this prevents some kinds of attacks
if (is_file($localimage)) {
$age = filemtime($localimage); // get the file age
if ($age < time() - (60*5)) { // 5 mins old
$simage='http://www.someplace/cams/'.$image;
$simage=str_replace(' ', '%20', $simage);//need to remove the spaces for URLs
copy($simage, $localimage);
}
// serve the image to the user.
$fp = fopen($localimage, 'r');
// send the right headers
header("Content-Type: image/jpg");
header("Content-Length: " . filesize($localimage));
// dump the picture and stop the script
fpassthru($fp);
exit();
}
else
{
echo("Error, no such file: '$image'");
}
?>
EDIT: Have discovered that by editing out
header("Content-Length: " . filesize($localimage));
It works as expected. Still trying to figure out why.

That was painful. I was passing the wrong Content-Length header value. Editing out the content length solved it so that it worked just fine. Considering it is static content, I do not know why what I have above does not work.
With more research figured out a way that works.
I put ob_start() near the start.
The new Content-Length header header('Content-Length: ' . ob_get_length());goes at the bottom, just before script exits.
Done that way it works every time and is nice to the browser.

Related

Whether there generate QR code in my project directory will get mix when multi people using it?

I have a question about the application generate QR code image.
I have an application when clients click a button there will generate a QR code image, my way is store in the project library, then print <img> with the url to the screen. then clients can see it.
But I have a doubt, if there are multi clients using the QR code at the same time, whether there will get a mix?
my code is bellow:
function generate_qrcode($url){
$filename = 'hante_qrcode.png';
$errorCorrectionLevel = 'L';
$matrixPointSize = 4;
//generate QR code image
$o = QRcode::png($url, $filename, $errorCorrectionLevel, $matrixPointSize, 2);
echo "<pre>";
print_r($o);
print_r('<img src="hante_qrcode.png">');
}
if there get mix, how to solve this problem?
But I have a doubt, if there are multi clients using the QR code at the same time, whether there will get a mix?
yes
how to solve this problem?
there are two ways to solve this problem
you can provide unique name for every files like using timestamp using time() function or with user ID. cause as per you are passing parameters while generating qr code you need to store the file. without saving file also possible but in that case you can't configure pixel size and frame size. you can refer this for PHP QR code-Examples
don't store image on server and find some js to generate qr code directly from client side.
having a one demo for that check if you can use it
var qrcode = new QRCode("qrcode");
qrcode.makeCode('https://stackoverflow.com');
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/davidshimjs/qrcodejs/gh-pages/qrcode.min.js"></script>
<div id="qrcode"></div>
Of course it will be overwritten.
Solution 1
Create unique filename for every image. This way you can save your images for use later. Another benefit of this, you don't have to create image again for same url.
$filename = md5($url) . ".png";
if(!file_exists($filename)){
$o = QRcode::png($url, $filename, ...);
}
echo '<img src="'.$filename.'">';
Solution 2
If you don't want to save images for disk space reasons you can serve image directly. In your code, user sends request to index.php and fetch image address as response. After then browser makes another request to get image. You can return image rather than returning html.
// image.php
// Still we want to give uniqe filename because we can get another request while one request is processing
$filename = md5(microtime) . "_qr.png";
$o = QRcode::png($url, $filename, ...);
$image = file_get_contents($filename);
// remove the file after stored in a variable
unlink($filename);
header('Content-Type: image/jpeg');
header('Content-Length: ' . filesize($image));
echo $image;
// index.html
<img src="image.php?url=someurl">

PHP file that accepts file path from loop and returns an image

I am trying to display multiple images from my database through a loop. Basically it's something like this
while loop is running{
$_SESSION['path'] = $imageURL;
echo '<img src="pic.php">';
}
my idea is the pic php gets the path then displays it. Then another path comes in and it returns the image again.
HOWEVER IT DID NOT. It just returns the last image retrieved and repeat it until the loop is done.
so instead of displaying a.png, b.png and c.png. What displayed were 3 c.png.
here is my pic.php
<?php
session_start();
$name = $_SESSION['path'];
$fp = fopen($name, 'rb');
header("Content-Type: image/png");
header("Content-Length: " . filesize($name));
fpassthru($fp);
exit;
?>
I'm particularly new to this stuff so it will be a great help if you guys check this out! TYIA!
Here is what happens:
You access your web page through your favorite browser
The server process your request, and asks PHP to create an HTML file containing 3 <img src="pic.php" />
The server returns the HTML file to your browser
The browser analyze your HTML file and detect it has links to external resources, indeed it has 3 times pic.php, so it begins to ask the server to return the content of this file
The server process again the request and asks PHP to return to him the content of pic.php
The server returns this content, and HTML put it 3 times
You can see at the end, even if you looped 3 times and changed 3 times $_SESSION['path'], the server comes after the war and only see c.php, so it returns it to the browser.
You should adopt another strategy to fetch your images.
Workaround
One way to fix the issue is to fetch image "at demand" like this:
pic.php
<?php
session_start();
$name = filter_var($_GET['q'], FILTER_SANITIZE_URL);
$fp = fopen($name, 'rb');
header("Content-Type: image/png");
header("Content-Length: " . filesize($name));
fpassthru($fp);
exit;
?>
index.php (the file you access)
<?php
while loop is running{
echo "<img src='pic.php?q=$imageURL'>";
}
?>

How to tell when to fetch new image?

I have a copy of 350+ images on my sever, when a person tries to view one, if it is more than 5 minutes old, I want my sever to check with another website that I am mirroring data from(they insist on me mirroring instead of hotlinking) and get the newest copy. Any thoughts on how to do this?
I can do a cron script and get all of the images, but there are problems doing that.(My host limits me to once every 15 minutes, I would have to get a lot of images that my users may or may not actually view.)
I am thinking there should be a way to do this in PHP, but I have no idea where I would start.
You could serve the images via a php script that allows you to do the necessary checks before displaying the image.
<img src="/index.php/image-name.jpg">
Below is one option for the checks
// get the image name from the uri
$image = explode("/", $_SERVER['REQUEST_URI'])[2];
// check if the image exists
if (is_file($image)) {
// get the file age
$age = filemtime($image);
if ($age < time() - (60*5)) { // 5 mins old
// file too old so check for new one
// do your check and serve the appropriate image
}
else
{
// get the image and serve it to the user
$fp = fopen($image, 'rb');
// send the right headers
header("Content-Type: image/jpg");
header("Content-Length: " . filesize($image));
// dump the picture and stop the script
fpassthru($fp);
exit();
}
}
else
{
// handle error
}
You can apply ajax at your project.
call your server at every 5 minutes using ajax and refresh your content.
In short; AJAX is about loading data in the background and display it on the webpage, without reloading the whole page.

uniquely name images that are output to browser with php script

I use wordpress cms. I allow selective people to upload image. I have a script that resizes it and outputs resized image back to the browser where they can right click and save it. Here is the relevant part of the code. If needed I will put up the whole code. The script works and puts the resized image in the browser nicely.
header('Content-type: image/jpeg');
ob_start();
imagejpeg($resized, null, 100);
echo '<img src="data:image/jpeg;base64,' . base64_encode(ob_get_clean()) . '">';
imagedestroy($resized);
ISSUE : The form has just one upload field. I only allow images to be resized and saved one-by-one. Since all these resized images generated by the script has a same name index, an issue arises, which is when the visitor goes to save his image in windows the first time, say in a folder, it is saved as index.jpeg but when he goes to save images after that he is prompted to replace index.jpeg image. Because "these people " are not tech savvy so they usually replace the image end up wasting my time solving the case. So I would like these resized images to have unique name generated either by uniqid() or time().
WHAT I TRIED / AM TRYING : I am confused to what phpfunction I should be using here together with time() so that I could create a new filename each time a resized images is generated. In order to first set a variable, i tried to use basename() function like this, but it wont work.
$new_filename = basename($resized); echo '<br>' .$new_filename. '<br>';
Obviously it throws a warning:basename() expects parameter 1 to be string. I tried that and realized that in this case the variable $resized is a resource not a string. I am still crawling through threads for imagejpeg() at php.net in search of a solution, have not found any resource yet.
Bottomline question : how do I set or get a variable for resized file so
that I can manipulate it alongwith time() to create new names each
time.
FINAL UPDATE : #CBroe, pointed out that this is not possible so I am off to looking for an alternative.

content-type failing in firefox when using dynamic images (PHP) in <img src="source.php">

Okay excuse the cryptic subject.
I have a system which dynamically fetches image data and does some modification on the fly.
Essentially, missing out the unimportant bits, this is my code:
$File->Filename = "testimage.jpg";
$File->Open();
$FileData = $File->Read();
header('Content-Type: image/jpeg');
echo $FileData;
The only output on the page is $FileData. Okay. When I run the script as is, Firefox presents me with a blank page and Chrome and IE give me a 'missing picture' box.
However oddly enough, when I remove the Content Type declaration, I can see the raw image data just fine. I have tested this with several images, granted all of the JPEG type but it clearly loads up the different pictures just fine, as the raw data changes successfully, and matches the raw content of the image itself.
Anyone have any idea why it would be failing to just display the image at this point?
You need to give more information in order to let the browser handle it correctly (use the correct type and length):
header('Content-Length: '.strlen($FileData),true); // EDIT: inserted the strlen function as suggested by kgb
header('Content-Type: image/jpeg');
Try setting Content-Length appropriately. Remove the trailing ?> to make sure there is no whitespace at the end of the script and ensure that the starting it at the very start of your script.
i'll combine phant0m's and Thariama's answers ;):
header('Content-Length: '.strlen($FileData), true);
header('Content-Type: image/jpeg');
die($FileData);

Categories