Jump to content

stream image files


topcoder1

Recommended Posts

I am streaming some files from the database and serve it over http, for text files and even pdf files it works, but for image files and xls files the files seem to be corrupted.  For testing purpose, after I grab the file from the blob field in mysql db, I write it to a file on the server which looks good by manual inspection.  However when the user downloads and opens the file it's corrupted.  For xls, there are bunch of binary codes scattered around with texts. For image file it simply can't be viewed.  What's wrong?? 

	
function html_item_file($item_id){
	$this->init_db();
		$query="...";
		if($res=mysql_query($query)){
		$item=mysql_fetch_assoc($res);
		$file=$item['file_content'];

		$file_name=html_entity_decode($item['item']);
		$file_len=$item['file_len'];
		error_log("file is ".$file_name.", ".$file_len);
		error_log("q is ".$query);
		//extract raw and save to file, this result file looks good
		/*
		$handle = fopen("c://temp//output//".$file_name, 'w');
		fwrite($handle, $file);
		fclose($handle);
		*/
		$this->stream_file($file_name, $file_len, $file);
	}
}
function stream_file($filename, $file_len, $file){

		header("Content-Disposition: inline; filename=\"".$filename."\"");
	header("Content-Type: image/png");//application/octet-stream
//	header("Content-Length: ".$file_len);
	header("Pragma: no-cache");
	header("Expires: 0");
	echo $file;
	exit();
}

Link to comment
Share on other sites

first the file type is always set to PNG

header("Content-Type: image/png"

 

also i don't think echo in binary safe, maybe use

convert_uuencode/convert_uudecode

 

thanks for the help.  I tried using header application/octet-stream and base64_encode since convert_uuencode is a php5 function and I use php4.

still doesn't help.  Image gets downloaded then can't be opened.

function stream_file($filename, $file_len, $file){

		header("Content-Disposition: inline; filename=\"".$filename."\"");
	header("Content-Type: application/octet-stream");//
//	header("Content-Length: ".$file_len);
	header("Pragma: no-cache");
	header("Expires: 0");
	print base64_encode($file);
	exit();
}

Link to comment
Share on other sites

what about this

 

keep the

			//extract raw and save to file, this result file looks good
		/*
		$handle = fopen("c://temp//output//".$file_name, 'w');
		fwrite($handle, $file);
		fclose($handle);
		*/

then use readfile($filename); instead of echo'ing the data.., then after the steaming unlink($filename)

 

as for the

header("Content-Type: application/octet-stream");//

try this instead

header("Content-Type: application/force-download");//

 

NOTE:

header("Content-Type: application/octet-stream");//

will probably fail in IE

IEs version is

header("Content-Type: application/octetstream");//

Link to comment
Share on other sites

Ok I tried outputting to a temp file, then readfile(), still after I download the file, i can't open it.  But I view the temp file on server and it's fine.  the temp file and the file I DL are the same size. What is going on??  I am using FF. 

something's very bizzare here...

 

 

		$handle = fopen("c://temp//output//".$file_name, 'w');
		fwrite($handle, $file);
		fclose($handle);
		/*
		$handle=fopen("c://temp//output//".$file_name, 'rb');
		error_log("fread ".fread($handle, filesize("c://temp//output//".$file_name)));
		fclose($handle);
		*/
		$this->stream_file($file_name, $file_len, $file);
	}
}
function stream_file($filename, $file_len, $file){

		header("Content-Disposition: inline; filename=\"".$filename."\"");
	header("Content-Type: application/octet-stream");//
//	header("Content-Length: ".$file_len);
	header("Pragma: no-cache");
	header("Expires: 0");
	//print base64_encode($file);
	error_log("file name is ".$filename);
	error_log("file read ".readfile("c://temp//output//".$filename));

	exit();
}

Link to comment
Share on other sites

just out of curiosity, why are you actually storing the image in the database? Why not store the name of the file in the database and then store the actual file in the file system?

 

It seems to me that this would be easier and less chance of file corruption.

 

Nate

I am just trying out this way to see how it will work. I know there's a whole debate of db vs flat file going on...

Anyway debugging to this point it seems that it's unrelated to db, the server reads from a flat file and then stream it to client, but the file is corrupt after DL... maybe I'm just insane here...

Link to comment
Share on other sites

OK I FINALLY FIGURED IT OUT.  You guys would not believe what's the cause of the problem..  It's not the db, not even the streaming function...  I had a funny feeling something as obscure as this is the problem.

case 1: it works

<?php require_once "item.php";
$item=new Item();
$item->test_stream_file(); //stream a file over http
?>

 

case 2: it corrupts the file!!

<?php require_once "item.php"; ?>
<?php
$item=new Item();
$item->test_stream_file();
?>

 

It seems that when closing and restarting the php tag something is send over http that messed the file download up.  Who would have thought!!!

thanks all

Link to comment
Share on other sites

Ok I was a little quick on making the conclusion about php tag.  The root of all evil is the empty lines before the php tag starts the blank lines before <?php are being sent as part of the server response to the client.  In my case, my include class had blank lines in the beginning and these lines are sent back to the client as part of the download, hence caused the problem.  I am still vague as to why that caused the download problem since those blank lines are sent before the http headers and the file data itself, but I'm beat and need some sleep.

 

my working test code follows, if I add any blank lines before any of those php starting tags, it will break.

test.php

<?php require_once "Streamer.php";?>
<?php
$a=new Streamer();
$a->stream_file("test.jpg", "c://temp//output//test.jpg");
?>

 

Streamer.php

<?php
class Streamer{

function stream_file($filename,  $file, $file_len=null){

		header("Content-Disposition: inline; filename=\"".$filename."\"");
	header("Content-Type: application/force-download");//octet-stream
	if($file_len!=null)header("Content-Length: ".$file_len);
	header("Pragma: no-cache");
	header("Expires: 0");
	readfile($file);
	exit();
}
}
?>

Link to comment
Share on other sites

Blank lines aka whitespace is the same as text as far as a webserver is concerned. All headers MUST be sent before anything else. If any output is sent to the browser before the headers are sent, you will generally get a Header error.

 

You can circumvent this by using ob_start() at the top of the page and ob_end_flush() at the end, this will buffer all output and send it all at once in the end after the headers have been sent.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.