From a php script (PHP 5.3.10-1 on Ubuntu3.6) I connect to an MSSQL Server and I would like to retrive image data from image field type. And I want to print it.
I can get the data from MSSQL but I can't print/echo it as a valid image. How can I print/echo/save it?
$db= new PDO('odbc:MYODBC', '***', '***');
$stmt = $db->prepare("USE database");
$stmt->execute();
$tsql = "SELECT image
FROM Pics
WHERE id = 12";
$stmt = $db->prepare($tsql);
$stmt->execute();
$stmt->bindColumn(1, $lob, PDO::PARAM_LOB);
$stmt->fetch(PDO::FETCH_BOUND);
header("Content-Type: image/jpg");
echo($lob); //not an image: 424df630030000000000360000002800 ...
imagecreatefromstring($lob); // Data is not in a recognized format ...
$lob = fopen('data://text/plain;base64,' . base64_encode($lob), 'r'); //Resource
fpassthru($lob); //not an image: 424df63003000000000036000000280000 ...
PHP script encoding: UTF-8.
In /etc/freetds/freetds.conf
[MYODBC]
host = myhost.com
client charset = UTF-8
tds version = 7
((With sqlsrv on the server of MSSQL I could use this:
$image = sqlsrv_get_field( $stmt, 0,
SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY));
header("Content-Type: image/jpg");
fpassthru($image);
))
UPDATE:
echo base64_decode($lob); //Not an image: γnτΣ}4ΣM4ΣM4ί4ΣM4ΫΝ4ΣM4s...
Try adding the following headers :
Content-Disposition
Content-Transfer-Encoding
Content-Length
In PHP code :
header('Content-Type: image/jpg');
header('Content-Disposition:attachment; filename="my_file.jpg"');// Set the filename to your needs
header('Content-Transfer-Encoding: binary');
header('Content-Length: 12345');// Replace 12345 with the actual size of the image in bytes
I was recently fighting with a similar storage issue. It turned out that I was quoting my binary image data before insert into the database table. So, make sure you are not adding quotes and turning it into a string - like I accidentally did.
Here's the prep work that is done on an existing local file to get the proper data to store into your database. Also, make sure you have bin2hex() available or get a replacement version of the function.
function prepareImageDBString($filepath) {
$out = 'null';
$handle = #fopen($filepath, 'rb');
if ($handle) {
$content = #fread($handle, filesize($filepath));
// bin2hex() PHP Version >= 5.4 Only!
$content = bin2hex($content);
#fclose($handle);
$out = "0x" . $content;
}
return $out;
}
I hope this helps someone.
Related
I need to save a pdf file into BLOB (database is MsSql 2012, but I would need it work on 2008 too).
Here is compilation of what I have tried so far:
(File where I save pdf into database)
function preparePDF2String($filepath)
{
$handle = #fopen($filepath, 'rb');
if ($handle)
{
$content = #fread($handle, filesize($filepath));
$content = bin2hex($content);
#fclose($handle);
return "0x".$content;
}
}
$out = preparePDF2String('pdf/pdf.pdf');
$q_blob = "INSERT INTO HISTORIA_ARCHIWUM_test(PDFName, PDFData) VALUES('First test pdf', $out) ";
$r_blob = mssql_query($q_blob,$polacz);
Results (ok, I think)
(Now the php file where I try to output the pdf)
// header('Content-type: application/pdf');
// readfile('pdf/pdf.pdf'); - this works just fine, so pdf is ok
$q_blob = "select top 1 * from HISTORIA_ARCHIWUM_test";
$r_blob = mssql_query($q_blob,$polacz);
$w_blob = mssql_fetch_array($r_blob);
header('Content-type: application/pdf');
header('Content-Disposition: inline; filename="the.pdf"');
echo $w_blob['PDFData'];
//echo hex2bin ($w_blob['PDFData']); - I also tried this - same problem
Problem: when I try to output the pdf in the browser I get error (this pdf is of not supported format). It won't open in Adobe reader also. My guess is that I output it wrong, but maybe it is the way I save it?
EDIT from comments
It seems php+mssql truncates string when you get it from db, but its manageable in php.ini. I set mssql.textlimit = 160000 and mssql.textsize = 160000 and it works fine with Hex conversion and varchar(max).
You are transforming the pdf data before you save it to the database, you have to undo the transformation before you output it.
header('Content-type: application/pdf');
header('Content-Disposition: inline; filename="the.pdf"');
echo hex2bin(substr($w_blob['PDFData'], 2));
Also why are you transforming the data in the first place, just save it as binary.
I've managed to put the code to download a medium blob saved in mysql table. The code works in terms of it retrieves the right file, names it correctly, gives it the correct extension and the browser force downloads it.
The thing is when I try to open file I get an error. That is for example if it is a jpeg file the image won't show. If it is a pdf I do not get the pdf. I checked the file size and it seems to correspond to the stored Blob file size.
I think it is a format issue but do not know how to correct it. Any help appreciated. My code is:
Front End:
Test
BackEnd:
$doc_id = 24122565639274498;
$conn = new PDO("mysql:host=localhost;dbname=$dbname", $db->id, $db->pass); //connect to db
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //error modes
$stmt = $conn->prepare('SELECT content,type,name,size FROM docmgmt WHERE doc_id=:doc_id');
$stmt->bindParam(':doc_id', $doc_id, PDO::PARAM_INT);
$stmt->execute();
$stmt->bindColumn(1, $lob, PDO::PARAM_LOB);
$stmt->bindColumn(2, $type, PDO::PARAM_STR, 256);
$stmt->bindColumn(3, $name, PDO::PARAM_STR, 256);
$stmt->bindColumn(4, $size, PDO::PARAM_INT);
$stmt->fetch(PDO::FETCH_BOUND);
header("Content-length: $size");
header("Content-type: $type");
header("Content-Disposition: attachment; filename=$name");
echo $lob;
Screen Dump of contents of PNG file retrieved
It could be some kind of encoding issue I'd try base64 encode / decode on the data on the way in / out of the database
Also make sure you have no whitespace in the source as that would corrupt the output.
Check:
<-- Here
<?php
and
?>
<-- here
or better still remove the final closing php tag altogether
Maybe my simple encoding function can help you. As #andrew said it's most likely not working because you're not using base64 encoding / decoding
Send a file like
<input type="file" name="image" accept="image/*">
Process it like
// Make sure the user uploaded a file
if (isset($_FILES['image']) && $_FILES['image']['size'] > 0) {
// Temporary file name stored on the server
$tmpName = $_FILES['image']['tmp_name'];
// Read the file
$fp = fopen($tmpName, 'r');
$data = fread($fp, filesize($tmpName));
$data = addslashes($data);
fclose($fp);
}
Store the $data in db then read it with
$img=base64_encode($row['image_from_db']);
put the $img into the display function
// Return <img> if there is any provided.
function displayImage(&$link){
if(!empty($link)){
return "<img alt=\"Profile Picture\" src=\"data:image/*;charset=utf8;base64, $link \">";
}
else
{
return "<img alt=\"Profile Picture\" src='../img/nopicture.jpg'>";
}
}
If you want other files than images you need to change the input accept="image/*" and the a display function that fits your needs.
I'm trying to extract a BLOB from mysql and send it to the requester without saving it on the server. I've gotten it to work with PDF files, but some of our clients want xls files. When getting the xls file, the downloaded file is garbage. In HxD it looks like it is putting an extra 11 bytes on the front of the file.
Here is my code, both working and not working:
function blob_download_xls() {
$mysqli = openMySQLconnetion();
$sql = "SELECT * FROM Uploads;";
$results = $mysqli->query($sql);
$row = $results->fetch_assoc();
$bytes = $row['filedata'];
header('Content-type: application/vnd.ms-excel');
header('Content-Disposition: attachment; filename="report.xls"');
print $bytes;
}
function blob_download_pdf() {
$mysqli = openMySQLconnetion();
$sql = "SELECT * FROM Uploads;";
$results = $mysqli->query($sql);
$row = $results->fetch_assoc();
$bytes = $row['filedata'];
header("Content-type: application/pdf");
header('Content-Disposition: inline; filename="report.pdf"');
print $bytes;
}
Any idea what I'm doing wrong?
I asked this question with a new account without realizing that I already had an account here. I've solved the problem and it was stupid.
When writing my function.php, I put a closing tag '?>' on the end of the file. After this tag was a 0d0a for a line feed return and then 9 20's for 9 spaces. I removed the closing tag and now it works perfectly.
The correct way to deal with this is to die() immediately after printing the bytes, before the server has a chance to output any HTML that may succeed the PHP code.
function blob_download_xls() {
$mysqli = openMySQLconnetion();
$sql = "SELECT * FROM Uploads;";
$results = $mysqli->query($sql);
$row = $results->fetch_assoc();
$bytes = $row['filedata'];
header('Content-type: application/vnd.ms-excel');
header('Content-Disposition: attachment; filename="report.xls"');
print $bytes;
die();
}
This must be common asked question, But I could not find from google. We have a table and has photo column in bytea type in postgresql.
We are saving upcoming image with this snippet:
$photo->attributes = $_FILES['Photo'];
$file = CUploadedFile::getInstance($photo, 'photo');
$path = Yii::app()->basePath . '/data/' . $file->name;
$file->saveAs($path); //save the file to the $path
$fp = fopen($path, 'rb');
$content = fread($fp, filesize($path)); //get the file content
fclose($fp);
$photo->photo = base64_encode($content); //encode it
$photo->save(); //save the record to db
unlink(Yii::app()->basePath . '/data/' . $file->name);
saving seems working good.
this is where we are reading blob field from db:
base64_decode($data->photo) //this call is giving base64_decode() expects parameter 1 to be string, resource given error.
if I do:
print_r($data->photo) //I am getting: Resource id #51
Obviously $data->photo is not binary string, it is coming as a resource. Any idea how to make it work?
thanks in advance.
If you're using base64 then you don't need bytea, you can use a regular text field. It'll be less efficient for disk space, but that's about it.
If you want to store the actual bytes, you don't encode it as base64, you use pg_escape_bytea to convert it to PostgreSQL's hex-string representation (for modern PostgreSQL versions) of bytea values. You use pg_bytea_decode when extracting the data.
If you're using PDO instead of the native PostgreSQL driver, look up how to work with bytea using PDO. You haven't actually shown your database code at all, only some wrapper for it, so it's very hard to tell what's going on.
Of course, all this only applies to PHP; most languages have separate data types for "textual data" and "binary data" that let the client library automatically convert binary data without you having to jump through escape/unescape hooks.
For me work this solution:
Save file to DB:
$file = CUploadedFile::getInstanceByName('file');
if ($file!=null) {
$fp = fopen($file->tempName,'r');
$content = fread($fp, $file->size);
fclose($fp);
$doc->doc=null; //bytea field
$doc->docname = $file->name;
$doc->mime = $file->type;
$doc->size = $file->size;
$doc->save();
$msg = $doc->getErrors();
$command = Yii::app()->db->createCommand('UPDATE '.
$doc->tableName().' SET "doc"=:doc WHERE id='.$doc->id);
$command->bindParam(":doc", $content, PDO::PARAM_LOB); // <-- look this!
$command->execute();
}
Show file from DB:
header('Content-Type: '.$doc->mime );
header('Content-Description: File Transfer');
header('Content-Disposition: attachment; filename*=UTF-8\'\'' . rawurlencode ($doc->docname ) );
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . $doc->size);
$content = fread($doc->doc, $doc->size);
echo $content;
exit;
I'm having a problem with PHP and my SQL Server.
When I try to save a file into the database as a varbinary(MAX) type, it works perfectly, but when I try to save a file of 180k or more in the result, I only get part of the image:
$handle = #fopen($fileTmpName, 'rb');
if ($handle)
{
$content = #fread($handle, filesize($fileTmpName));
$content = bin2hex($content);
#fclose($handle);
}
$select = mssql_query("EXEC [DB_Name].[dbo].[Table_Name] #Data = ".$content."");
$result = mssql_fetch_array($select);
$_SESSION['fileContent'] = $result['Data'];
<img src="../applications/framework/images.php" />
image.php file contains the following:
header("Content-type: ".$fileType);
header("Content-Length: ".$fileSize);
header("Content-Disposition: inline; filename=".$fileName);
echo $_SESSION['fileContent'];
As a result, I only get part of the image.
I mean that it only loads the first part of the real image. It seems that it inserts only the first part of the content into the database instead of all of it.
How can this be solved?
check the table structure. It might be the column might not be set up as a var(max)