Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations derfloh on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

downloading BLOB - pdf file type problem 1

Status
Not open for further replies.

mrsbean

Technical User
Jul 14, 2004
203
US
The following script works beautifully except for PDF documents:

Code:
$blobId = $_REQUEST[fileId];
if(!is_numeric($blobId))
die("Invalid blobId specified");
include("dbConnection.php");
$dbQuery = "SELECT blobType, blobData ";
$dbQuery .= "FROM phForms ";
$dbQuery .= "WHERE blobId = $blobId";
$result = mysql_query($dbQuery) or die("Couldn't get file list");

if(mysql_num_rows($result) == 1)
{
$fileType = @mysql_result($result, 0, "blobType");
$fileContent = @mysql_result($result, 0, "blobData");
header("Content-type: $fileType");
echo $fileContent;
}
else
{
echo "Record doesn't exist.";
}

I'm not sure if I have a problem with settings on my own computer, or if something in the code must be tweaked to accommodate PDF documents. I get a dialogue box which says :

Cannot find 'some really long cryptic name in a temporary folder on my computer.php' Make sure the path or internet address is correct

Can somebody help me?

MrsBean
 
try adding some more headers. You should also provide a file name instead of the somefilename.pdf. it probably means you have to store a filename in your database too.

Code:
header("Content-Length: " . strlen($fileContent) );
header("Content-Type: application/octet-stream");
header('Content-Disposition: attachment; filename="somefilename.pdf"');
header("Content-Transfer-Encoding: binary\n");
echo $fileContent;

you might also want to add some no-caching headers but these are optional.

also remember to turn off magic_quotes_runtime() (set_magic_quotes_runtime(0);) before your database call (if you have it turned on in your php.ini file).

if this doesn't work (and you are certain that there is not a fault in the pdf file itself) then we should look at your upload script - in particular magic_quotes_runtime and escaping before entry into the db are often the culprits here with pdf files.
 
Thanks! I'm getting closer. I have removed the line that echoed the file content so that it would give the user the option of saving or opening the file. Otherwise, I had a screen full of strange characters.

The only thing I want to change now is that when it asks you if you want to save the file, it wants to save the file with the name download.php instead of selecting the file name ($fileDescription) which I have provided. How can I change this?

MrsBean

Code:
if(mysql_num_rows($result) == 1)

{

$fileType = @mysql_result($result, 0, "blobType");
$fileContent = @mysql_result($result, 0, "blobData");
$fileName=@mysql_result($result, 0, "blobDescription");


header("Content-Length: " . strlen($fileContent) );
header("Content-Type: application/octet-stream");
header('Content-Disposition: attachment; filename='.$fileName);
header("Content-Transfer-Encoding: binary\n");
//echo $fileContent;


} else {

echo "Record doesn\"t exist.";

}
 
Uh oh ... the further I go into this, the more problems I find. I'm not able to download the PDF documents, or if I am, they're damaged. This is all new enough to me, that I need to broken down a bit. Here is the code which uploads the file into the database. Is the problem with the upload?

MrsBean

Code:
if(empty($strDesc) || $fileUpload == "none")
die("You must enter both a description and file");

include_once("dbConnection.php");

$fileHandle = fopen($fileUpload, "r");
$fileContent = fread($fileHandle, $fileUpload_size);
$fileContent = addslashes($fileContent);

$dbQuery = "INSERT INTO phForms VALUES ";
$dbQuery .= "(0, '$fileUpload_name', '$fileContent', '$fileUpload_type', '$fileUpload_size', '$strDesc', $thisSecurity)";
mysql_query($dbQuery) or die("Couldn't add file to database");

echo "<h1>File Uploaded</h1>";
echo "The details of the uploaded file are shown below:<br><br>";
echo "<b>File name:</b> $fileUpload_name <br>";
echo "<b>File type:</b> $fileUpload_type <br>";
echo "<b>File size:</b> $fileUpload_size <br>";
echo "<b>Uploaded to:</b> $fileUpload <br>";
?><b>Admin Only?: </b>
<? If ($thisSecurity == 1){
$thisAdm = "Yes";
} else {
$thisAdm = "No";
}
echo $thisAdm."<br>";
echo "<p><a href='uploadfile.php'>Add Another File</a></p>";
echo "<p><a href='listForms.php'>List of Forms</a></p>";
 
can i direct you, in the first instance, to an upload/download manager i wrote for another tek-tips member?

you can find it at
don't worry about the PEAR reference and the bit about text highlighting at the bottom of the source - that is just to make the code look pretty on the web page.

post back if you still have problems.

btw
I have removed the line that echoed the file content so that it would give the user the option of saving or opening the file. Otherwise, I had a screen full of strange characters.
this doesn't make sense. the strange characters you mention is the actual pdf file being output to your screen meaning that something is going wrong with the headers. the application/octet-stream forces most browsers to assume a download and you are then prompted by most browsers to save or open in the default application for that filetype.
 
Thank you jpadie, but I want to understand where I went wrong. If I tried to implement your solution, I would have to break it down and replace code I partially understand with code that I haven't digested yet.

Anybody else?

MrsBean
 
i was rather hoping you would apply the code that i wrote as a way of understanding where you went wrong.

i'm happy to debug your code but you need to provide all of it if the process is to be efficient for you:

1. the upload form
2. the complete script handling the upload form
3. the schema of your database
4. the script allowing users to select which file to download; and
5. the script serving the file to the user.

please also supply the results of a call to phpinfo() as to whether magic_quotes_runtime and magic_quotes_gpc are on by default and the value for upload_max_file_size.
 
Thank you so much for your assitance. Here are the answers:

1) Upload form:
Code:
<form enctype="multipart/form-data" name="frmUploadFile" action="fileuploaded.php" method="post">

<table border="0" cellpadding="0" cellspacing="0" width = "80%">

<tr><td width="100%" height="22" colspan="2"><h2>Upload a File</h2></td></tr>

<tr>
<td width="100%" colspan="2">
<h3>Select a document to be uploaded.  Any document which is uploaded will be visible by all agents who are able to log into the Transaction Management Tool unless you select Admin Only = Yes.</h3>
<br> 
</td></tr>

<tr>

<td width="15%"><b>File Description:</b></td>

<td width="85%"><input type="text" name="strDesc" size="20" maxlength="50"></td>

</tr>

<tr>

<td width="15%"><b>File Location:</b></td>

<td width="85%"><input type="file" name="fileUpload" size="20"></td>

</tr>
<tr>
<td width = "15%"><b>Admin Only?</b></td>
<td width = "85%"><br>
<input name="AdminOnly" type="radio" value="1">Yes<br>
<input name="AdminOnly" type="radio" checked value="0">No<br>

</td>

<tr>

<td width="33%">&nbsp;</td>

<td width="67%">
<br><br>
<input type="submit" value="Upload this file" name="cmdSubmit"></td>

</tr>
</table>
</form>

2. the complete script handling the upload form ... It was posted already, but here is a repeat:

Code:
<? include_once("./common/dbConnection.php");
include_once("./common/header.php");

$SPhID = $_SESSION['userID'];

global $strDesc;
global $fileUpload;
global $fileUpload_name;
global $fileUpload_size;
global $fileUpload_type;

$strDesc = $_REQUEST[strDesc];
$thisSecurity = $_REQUEST[AdminOnly];

// Make sure both a description and
// file have been entered

if(empty($strDesc) || $fileUpload == "none")
die("You must enter both a description and file");

$fileHandle = fopen($fileUpload, "r");
$fileContent = fread($fileHandle, $fileUpload_size);
$fileContent = mysql_real_escape_string($fileContent);

$dbQuery = "INSERT INTO phForms VALUES ";
$dbQuery .= "(0, '$fileUpload_name', '$fileContent', '$fileUpload_type', '$fileUpload_size', '$strDesc', $thisSecurity)";
mysql_query($dbQuery) or die("Couldn't add file to database");

echo "<h1>File Uploaded</h1>";
echo "The details of the uploaded file are shown below:<br><br>";

echo "<b>File name:</b> $fileUpload_name <br>";
echo "<b>File type:</b> $fileUpload_type <br>";
echo "<b>File size:</b> $fileUpload_size <br>";
echo "<b>Uploaded to:</b> $fileUpload <br>";
?><b>Admin Only?: </b>
<? If ($thisSecurity == 1){
$thisAdm = "Yes";
} else {
$thisAdm = "No";
}
echo $thisAdm."<br>";

echo "<p><a href='uploadfile.php'>Add Another File</a></p>";
echo "<p><a href='listForms.php'>List of Forms</a></p>";

include_once("./common/footer.php"); ?>

3. the schema of the database:
I'm not sure how to best show you this ... Here is SQL code to create the table:

Code:
DROP TABLE IF EXISTS `MyDatabase`.`phForms`;
CREATE TABLE `phForms` (
  `blobId` int(11) NOT NULL auto_increment,
  `blobDescription` varchar(50) default NULL,
  `blobData` longblob,
  `blobType` varchar(50) default NULL,
  `blobSize` varchar(45) default NULL,
  `blobName` varchar(255) default NULL,
  `blobSecurity` tinyint(3) unsigned NOT NULL default '0',
  PRIMARY KEY  (`blobId`),
  UNIQUE KEY `id` (`blobId`)
) TYPE=MyISAM;
4. The script allowing users to select which file to download:

Code:
<?
$initStartLimit = 0;
$limitPerPage = 10;

$startLimit = $_REQUEST['startLimit'];
$numberOfRows = $_REQUEST['rows'];
$sortBy = $_REQUEST['sortBy'];
if (Is_Null($sortBy)) {
$sortBy = "blobName";
}
$sortOrder = $_REQUEST['sortOrder'];

if ($startLimit=="")
{
		$startLimit = $initStartLimit;
}

if ($numberOfRows=="")
{
		$numberOfRows = $limitPerPage;
}

if ($sortOrder=="")
{
		$sortOrder  = "ASC";
}
if ($sortOrder == "ASC") { $newSortOrder = "DESC"; } else  { $newSortOrder = "ASC"; }
$limitQuery = " LIMIT ".$startLimit.",".$numberOfRows;
$nextStartLimit = $startLimit + $limitPerPage;
$previousStartLimit = $startLimit - $limitPerPage;

if ($sortBy!="")
{
		$orderByQuery = " ORDER BY ".$sortBy." ".$sortOrder;
}


$sql = "SELECT * FROM phForms".$orderByQuery.$limitQuery;
$result = MYSQL_QUERY($sql);
$numberOfRows = MYSQL_NUM_ROWS($result);

if ($numberOfRows==0) {  
?>

Sorry. No records found !!


<?
}
else if ($numberOfRows>0) {

	$i=0;
?>

<h2>Agent Forms</h2>
<?
if ($_REQUEST['startLimit'] != "")
{
?>

<a href="<? echo  $_SERVER['PHP_SELF']; ?>?startLimit=<? echo $previousStartLimit; ?>&limitPerPage=<? echo $limitPerPage; ?>&sortBy=<? echo $sortBy; ?>&sortOrder=<? echo $sortOrder; ?>">Previous <? echo $limitPerPage; ?> Results</a>....
<? } ?>
<?
if ($numberOfRows == $limitPerPage)
{
?>
<a href="<? echo $_SERVER['PHP_SELF']; ?>?startLimit=<? echo $nextStartLimit; ?>&limitPerPage=<? echo $limitPerPage; ?>&sortBy=<? echo $sortBy; ?>&sortOrder=<? echo $sortOrder; ?>">Next <? echo $limitPerPage; ?> Results</a>
<? } ?>

<br><br>
<TABLE CELLSPACING="0" CELLPADDING="3" BORDER="0" WIDTH="85%">
	<TR>
		<TD>
			<a href="<? echo $PHP_SELF; ?>?sortBy=blobName&sortOrder=<? echo $newSortOrder; ?>&startLimit=<? echo $startLimit; ?>&rows=<? echo $limitPerPage; ?>">
				<B>Form Description</B>
			</a>
</TD>
		<TD>
			<a href="<? echo $PHP_SELF; ?>?sortBy=blobType&sortOrder=<? echo $newSortOrder; ?>&startLimit=<? echo $startLimit; ?>&rows=<? echo $limitPerPage; ?>">
				<B>File Type</B>
			</a>
</TD>
		<TD>
			<a href="<? echo $PHP_SELF; ?>?sortBy=blobSize&sortOrder=<? echo $newSortOrder; ?>&startLimit=<? echo $startLimit; ?>&rows=<? echo $limitPerPage; ?>">
				<B>File Size</B>
			</a>
</TD>

	</TR>
<?
	while ($i<$numberOfRows)
	{

		if (($i%2)==0) { $bgColor = "#C0C0C0"; } else { $bgColor = "#FFFFFF"; }

	$thisBlobID =   MYSQL_RESULT($result,$i,"blobID");
	$thisBlobName = MYSQL_RESULT($result,$i,"blobName");
	$thisBlobType = MYSQL_RESULT($result,$i,"blobType");
	$thisBlobSize = MYSQL_RESULT($result,$i,"blobSize");

?>
	<TR BGCOLOR="<? echo $bgColor; ?>">
		<td><a href="/phoenician/common/downloadfile.php?fileId=<?php echo $thisBlobID; ?>" target="_top">
			<?php echo $thisBlobName; ?></a></td>
		
		<td><? echo $thisBlobType; ?></td>
		<td><? echo $thisBlobSize; ?></td>
	<TD><a href="editForm.php?fieldID=<? echo $thisBlobID; ?>">Edit</a></TD>
	<TD><a href="deleteForm.php?fieldID=<? echo $thisBlobID; ?>">Delete</a></TD>
	</TR>
<?
		$i++;

	} // end while loop
?>
<TR><TD colSPAN = "5"><hr color="#808080"></TD></TR>
</TABLE>

<br>
<?
if ($_REQUEST['startLimit'] != "")
{
?>

<a href="<? echo  $_SERVER['PHP_SELF']; ?>?startLimit=<? echo $previousStartLimit; ?>&limitPerPage=<? echo $limitPerPage; ?>&sortBy=<? echo $sortBy; ?>&sortOrder=<? echo $sortOrder; ?>">Previous <? echo $limitPerPage; ?> Results</a>....
<? } ?>
<?
if ($numberOfRows == $limitPerPage)
{
?>
<a href="<? echo $_SERVER['PHP_SELF']; ?>?startLimit=<? echo $nextStartLimit; ?>&limitPerPage=<? echo $limitPerPage; ?>&sortBy=<? echo $sortBy; ?>&sortOrder=<? echo $sortOrder; ?>">Next <? echo $limitPerPage; ?> Results</a>
<? } ?>

<br><br>
<a href="uploadfile.php">Add New Form</a>
<br><br>

<?
} // end of if numberOfRows > 0 
 ?>

5. the script serving the file to the user:

The was also provided earlier, but here is the latest version:

Code:
$blobId = $_REQUEST[fileId];
if(!is_numeric($blobId))
die("Invalid blobId specified");

include("dbConnection.php");

$dbQuery = "SELECT blobType, blobData ";
$dbQuery .= "FROM phForms ";
$dbQuery .= "WHERE blobId = $blobId";

$result = mysql_query($dbQuery) or die("Couldn't get file list");

if(mysql_num_rows($result) == 1)
{
$fileType = @mysql_result($result, 0, "blobType");
$fileContent = @mysql_result($result, 0, "blobData");
$fileName=@mysql_result($result, 0, "blobDescription");

header("Content-Length: " . strlen($fileContent) );
header("Content-Type: application/octet-stream");
header('Content-Disposition: attachment; filename='.$fileName);
header("Content-Transfer-Encoding: binary\n");
//echo $fileContent;
//if the line above is uncommented, nothing but garbage appears

} else {
echo "Record doesn\'t exist.";
}

Again, thank you.

MrsBean
 
thanks. be with you in five minutes.

in the meantime, please turn register globals off on your server. big security hole - there is a section of the manual on this.

 
Regarding register globals ... it is hosted externally, and I don't think I can make that change. Can I?

MrsBean
 
Thank you 1000 times over. The general idea for the code I used came from a -- a tutorial which was offered. Many others have tried to fix what was wrong with it without success. Based on the forum thread which allows wannabe users to post their issues, there are a lot of people who have been very frustrated by the experience.

If you have no objection, I will post your solution to that forum.

Here is the original article:

Here is the forum:


I learn more here than ANYWHERE. You're the greatest.

MrsBean
 
good o!

by all means feel free to cross-post the soln. please credit tek-tips though!

key learnings are:

1. always develop with register globals switched off
2. never use $_REQUEST always use $_POST/$_GET/$_COOKIE (this is kind of the same as register globals)
3. always check for the existence of variables before using them (and develop with error_reporting(E_ALL) so that php can help you locate the uninstantiated variables.
4. always set magic_quotes_gpc and its runtime to off and add your own escaping code as necessary for your database. magic quotes is deprecated in php 6 so application developers should (never have) no longer rely on it.

that said - the critical problem for you was the omission of the "b" in the fopen call. with binary files you need a binary safe resource handle. with php it's best to use file_get_contents() but you can use fopen so long as you add the "b" after the r, w or a as the case is.

the above stands in place of reposting the source code here.

one last rant though:

i just can't see the point of storing binary data in a database rather than the filesystem. at least with current filesystems that is. dbs are not typically optimised for the storage of binary data whereas that's exactly what filesystems are designed to do (some better than others at multiple i/os). filesystem backup is segmented and well practised. contrariwise if your db becomes corrupted you risk not only losing metadata but also the actual files! big database tables tend to max out at about 4GB whereas that is not the case for a file system and lastly, many hosts put an arbitrary limit on db size that is many times smaller than the filesystem allocation they provide. My own host allows me 100MB of db space against 4GB of fileserver space. Quite apart from the technical reasons, this is enough alone to be a slamdunk answer to why not to store binaries in a database...

rant over!



 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top