inserting/reading blob data from php - php

I am using the following scripts to test inserting and then reading blob data.
insertion script:
include('session.php');
$provider =$_POST['provider_id'];
$trd_period =$_POST['trading_period_month'];
$pdf_statement =stream_get_contents(fopen($_FILES['pdf_statement']['tmp_name'], 'rb'));
$pdf_statement_clean=addslashes($pdf_statement);
$insert="update rd_provider_statement
set pdf_statement='".$pdf_statement_clean."', creation_user_id='SCO'
where provider_id='".$provider."' and trading_period_month='".$trd_period."'";
mysql_query($insert);
mysql_query("COMMIT");
echo mysql_error();
Download Script:
include('session.php');
//Gather Post Variables
$TP_Month =$_POST["trading_period_month"];
$provider =$_POST["provider_id"];
$TP_format =substr($TP_Month, 0, 7);
//Download Statement
$sql_qry="select *
from rd_provider_statement
where provider='".$provider."' and trading_period_month='".$TP_Month."'";
$sql_err_no=sql_select($sql_qry,$sql_res,$sql_row_count,$sql_err,$sql_uerr);
$row = mysql_fetch_assoc($sql_res);
$bytes =stripslashes($row['pdf_statement']);
header("Content-type: application/pdf");
header('Content-disposition: attachment; filename="'.$provider.'statement'.$TP_format.'"');
print $bytes;
However, when the file is downloaded it cannot open on the grounds that it is not a supported format. I use the basis of the script on another page to download blob data from the database however the insertion into the database here is done by a mysql procedure and not PHP. I think it is my insertion script that is causing the problem.

try using mysql_real_escape_string() instead of addslashes(). it might fix you problem.
For debugging, you might calculate the md5() of the string before inserting into DB and then after retrieving it. I bet you're going to get different hashes, meaning you're not inserting it correctly and your binary data gets corrupted when inserted into the DB.
Side notes:
don't use inserts like that, use binding - How to bind SQL variables in Php?
check for errors and STOP, dont simply echo them(i hope you're doing this in your production code)

Generally you wouldn't want to have any output code before your http header description. See http://php.net/manual/en/function.header.php
Either store the filename and other file information in a session then just access them in another page.
A few things that you need to check:
max_allowed_packet in my.ini should be equal or higher than the file size that you're expecting to store in the database
check to see if the data type that you selected fits the file that you will store. There's tiny blob, blog, medium blob and long blob. You might want to try the largest which is long blob.
I'm not sure about this one but did you already check if file_get_contents works:
mysql_real_escape_string(file_get_contents($file))

Here's my alternative answer.
First the update query:
Prepare the file (assuming that your file is not a binary file):
$tmpName = $_FILES["pdf_statement"]["tmp_name"];
$fp = fopen($tmpName, 'r');
$data = fread($fp, filesize($tmpName));
$data = addslashes($data);
fclose($fp);
$insert="update rd_provider_statement
set pdf_statement='".$data."', creation_user_id='SCO'
where provider_id='".$provider."' and trading_period_month='".$trd_period."'";
DOWNLOAD:
enter code here
$sql_qry="select provider_id, pdf_statement
from rd_provider_statement
where provider='".$provider."'
and trading_period_month='".$TP_Month."'";
$sql_err_no=sql_select($sql_qry,$sql_res,$sql_row_count,$sql_err,$sql_uerr);
$row = mysql_fetch_assoc($sql_res);
$name=$row['provider_id'];
$file=$row['pdf_statement'];
header("Content-Disposition: attachment; filename=\".$name_statement.$TP_format.\";" );
echo $file;
Hope it helps =)

Related

Print contents of a mysql table in txt format

I am working on a web application (php, javascript, html) that holds a large amount os user information. It is designed for temporary jobs.
The thing is, I have three tables (mysql) with information about the users. One for the address and other things, other for driver license, certificates, ..., and the last one for user experience.
What I want to do, is have a "print" button that generates a txt file with all that data in one file. The thing is that I alredy have an idea of how to do it.
1) retrieve all the information for the tables in a join with username.
2) I already had the function to "resource_to_array" for building an array with all the data
3) I could just go for each column of the array and saving the information that I want
But what I am asking is for experience doing something like this. This is the first time for me, and I want it to make it good and scalable for the future.
How will be a good way to do implement it? also, how could I create a plain text with all that information? (this part is in where I have more doubts about)
I know that maybe is a weird question..but I do not want code, I just want a vision for the implementation. Also, is there is a library os something similar that do what I want to do
Thank you very much.
First of all make a link that will generate text file.
Print
Now, in print.php you have to put your logic.
Execute the join Query for fetching the data.
Fetch "array" for building an array with all the data.
Get the element from the array that you want to save in text file.
Now logic is here, Use file handling for creating the text file with save data.
Logic is here(print.php) :
<?php
$conn = new mysqli("host-name","username","password","database-name");
$query = "....";
$result = $conn->query($query);
$rs = $result->fetch_array(MYSQLI_BOTH);
while($rs = $result->fetch_array(MYSQLI_BOTH))
{
$data = $rs['column-name']; // data you want to save in text file
$f = fopen("save.txt", 'a');
fwrite($f, $data);
fclose($f);
}
$filename = "save-data.txt"; // name of the file you want to download on clicking the link
$file = "save-data.txt";
$type = filetype($file);
// Send file headers
header("Content-type: $type");
header("Content-Disposition: attachment;filename=$filename");
header("Content-Transfer-Encoding: binary");
header('Pragma: no-cache');
header('Expires: 0');
// Send the file contents.
set_time_limit(0);
readfile($file);
?>
Sidenote: The a switch appends to file. If you do not wish to keep adding to it, use the w switch:
$f = fopen("save.txt", 'w');
I hope it will help you.

Uploaded medium blob truncated on download

I upload a blob to my sql database table with a field that is defined to be of size medium blob. The blob is actually a pdf file of size 4.3mb. The file is uploaded via ftp. After upload, some php code inserts it into the database. I've checked the file within the ftp folder and I can view it correctly. I've checked the file (blob) within the database and I can view it correctly. Both sizes show 4.3mb. If I try to download the file using some code provided by another programmer (below), the file is truncated at about 300kb.
if (!($dbLink = mysql_pconnect($db_server,$db_id,$db_pwd)))
{
print("Failed to connect to database!<BR>\n");
exit();
}
if(!mysql_select_db($db_name,$dbLink))
{
print("Cannot use the database!<BR>\n");
exit();
}
$query = "SELECT name, type, content FROM table_name WHERE link_id = '" . $id . "'";
$result = mysql_query($query, $dbLink) or die('Error, query failed');
list($name, $type, $content) = mysql_fetch_array($result);
//header("Content-length: $size");
header("Content-type: $type");
header("Content-Disposition: attachment; filename=$name");
echo $content;
exit;
I checked my maximum packet size within MySQL and it appears to be about 256mb. My php.ini shows 10mb for posts. I'm at a loss as to why the file is truncated. Can someone please point me in the right direction to solve this?
The PDO interface between PHP and MySQL offers a streaming scheme for LOB-handling. Seeing as how the mysql_ interface was abandoned years ago by its developers, it might be worth trying this.
See this: http://www.php.net/manual/en/pdo.lobs.php
You might consider using code like this.
$db = new PDO('mysql:dbname=testdb;host=127.0.0.1', 'username', 'password');
$query = "SELECT name,
type,
OCTET_LENGTH(content) AS length,
content
FROM table_name
WHERE link_id = :link_id
LIMIT 1";
$stmt = $db->prepare($query);
$stmt->execute(array(":link_id" => $id));
$stmt->bindColumn(1, $name);
$stmt->bindColumn(2, $type);
$stmt->bindColumn(3, $length);
$stmt->bindColumn(4, $data, PDO::PARAM_LOB); /* binds as a stream */
if ($stmt->fetch(PDO::FETCH_BOUND)) {
header("Content-Type: $type");
header("Content-Length: $length");
header("Content-Disposition: attachment; filename=$name");
fpassthru($data);
}
Sorry to say I haven't debugged this. But it's a fairly common use case.
I have resolved this with a different methodology. No matter what I tried from several different examples, I could not get the suggested PHP code to stop truncating files. I stopped storing the file as an attachment in the database, and, simply stored it in a separate folder on the server. The database was updated to insert a "path" link for the file. I changed the php code to:
// Construct an HTTP header that will force the browser to display/download the file.
header("Location: ".$location);
ob_flush();
exit;
This forced a relocation to the actual file stored on the server. The file now opens in the browser. Note: I also had to change some html code to force the file to open in a new tab in the browser.

Javascript and PHP export data to file

I have a button. By clicking the button, I want to export some data shown on the webpage to a file for downloading.
I am doing this in this way: I have a export.php. I send the data as the parameter to PHP file (another parameter is filename), and PHP server create a file and write the data, and then send file. Code is like:
$filename = $_GET['filename'] . '.csv';
$export = $_GET['export'];
$writer = fopen($filename, 'w') or die('cannot create');
fwrite($writer, $export . "\n");
fclose($writer);
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename='.basename($filename));
readfile($filename);
unlink($filename);
exit();
For cases that the data are short, it works fine. But if the data are long, since the data are passed as part of the URL, I will get "Request-URI Too Large" error.
Is there any alternative way to do that? Is it possible to directly write data using JavaScript?
It sounds like you are sending to export.php with a GET, when you should be using a POST. GET is limited to 2048 characters, while a POST is not limited.
You'll need to POST the data to the server. Change the METHOD in your FORM tag to POST (in your html not your php code).
Each browser limits the size of the query string / length of the URL and the limit is browser dependent. You can POST a very large amount of data to the server however. The only limit is how fast is the user's upstream bandwidth and their patience.
Instead of passing the data as a query string, use javascript to create an iframe and build a form which then posts to the php file.
IF your using jquery there's a good tutorial http://tutorialzine.com/2011/05/generating-files-javascript-php/

PHP Upload to MySql

I am attempting to store files in a MySql database based upon this article. Before you suggest I store files on the file system and not in the database the files uploaded will be stored and relate to records in the database. I could keep a path to the files and just the file names but I want users to be able to modify and delete the files directly through the web interface. So, let's just pretend that storing in the database is a good option and not discuss others.
My issue is when I go to download the file the data returned from the BLOB in the MySql database is not exactly what I uploaded in test. If I use the function of addslashes then binary wise it is completely off. If I remove that function from the routine then I get much closer.
Using a Binary Diff application I can see that, while not using addslashes the file data returned has one additional byte of data at the beginning of the file and in turn one less byte at the end. The remainder of the file's data is offset by one due to this little feature of the download.
I am using a FORM to submit the data and enctype is set to multipart/form-data as it should be. Here's some code I'm using to get it all to work. DAL in the code references a class I created for my Data Access Layer. It handles all saving and retrieving routines and doesn't seem to be injecting any new data. I've checked by looking at the file's content before it goes to my DAL class for saving and the extra byte is already there.
upload
if(isset($_POST['upload']) && $_FILES['userfile']['size'] > 0)
{
$fp = fopen($_FILES['userfile']['tmp_name'], 'r');
$_FILES['userfile']['content'] = fread($fp, $_FILES['userfile']['size']);
$_FILES['userfile']['content'] = addslashes($_FILES['userfile']['content']);
fclose($fp);
if(!get_magic_quotes_gpc())
{
$_FILES['userfile']['name'] = addslashes($_FILES['userfile']['name']);
}
$fileDAL = new DAL("files");
$newID = $fileDAL->SaveItem($_FILES['userfile'], false);
echo "<br>File ".$_FILES['userfile']['name']." uploaded as ID $newID<br>";
}
download
if(isset($_GET['id']))
{
$id = $_GET['id'];
$objFiles = new DAL('files');
$objFile = $objFiles->GetItem($id);
header("Content-length: $objFile->size");
header("Content-type: $objFile->type");
header("Content-Disposition: attachment; filename=$objFile->name");
echo $objFile->content;
exit;
}
use mysql_real_escape_string().
excerpt from its man page:
Escapes special characters in the unescaped_string, taking into account the current character set of the connection so that it is safe to place it in a mysql_query(). If binary data is to be inserted, this function must be used.
so I would change the escaping part of your code to:
if( get_magic_quotes_gpc() )
{
$_FILES['userfile']['name'] = stripslashes( $_FILES['userfile']['name'] );
}
$_FILES['userfile']['name'] = mysql_real_escape_string( $_FILES['userfile']['name'] );
Turns out that I add an extra line feed or carriage return at the end of a PHP file that was in my headers prior to this code being executed. It caused the header upon writing to include the line feed (OA) in the binary data for file saving.

Insert binary data into SQL Server using PHP

I have a varbinary(MAX) field in a SQL Server 2005 database. I'm trying to figure out how to insert binary data (ie. an image) into that field using PHP. I'm using ODBC for the connection to the SQL Server database. I have seen a number of examples that explain this for use with a MySql database but I have not been able to get it to work with SQL Server. Thanks.
function prepareImageDBString($filepath)
{
$out = 'null';
$handle = #fopen($filepath, 'rb');
if ($handle)
{
$content = #fread($handle, filesize($filepath));
$content = bin2hex($content);
#fclose($handle);
$out = "0x".$content;
}
return $out;
}
usage:
$out = prepareImageDBString('/img/myimg.png');
mssql_query("INSERT INTO MyTable(MyImage) VALUES($out) ");
MyImage is SQL Server field where the type is image
I won't say it's a bad practice, it depends on how big is the image and how your application use it.
If file below 256K in size, store in db is more efficient;
More than 1 mb, store in file-system is recommended.
Storing images in SQL Server?
The simple answer is: stop what you're doing.
You don't want to store binary files inside a database unless you have some very specific security issues. Instead you want to store their filenames (possibly rename the files to prevent confliction) and then store that in the database. If security is an issue, then put them in a non web folder and use your code to retrieve the file and only serve the file if the user has access to it.
Storing images or files inside a database is a waste of file space, a mis-use of databases, and not letting things do what they do best; the filesystem knows files, the database knows data.

Categories