Mysql Blob to xls using php without making a file on server? - php

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();
}

Related

SQL array only output last answer

I am trying to make a pdf-library where users can fill in which pdf-files they want to download and then the PHP file will get the filename from a database and make a path to the file and then it should download all selected files. But only get the last file downloaded.
This is my code for the download/output from the database:
Grateful for answer
$sql = "SELECT * FROM pdf WHERE id='$check'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
$path = $row["path"];
$filename = $row["name"];
$file = $path."/".$filename;
header("Content-disposition: attachment; filename=".$filename);
header("Content-type: application/pdf");
readfile($file);
}
} else {
echo "0 results";
}
You can't send multiple files in a single response and you can't give multiple responses to a single request.
You might build an array of files to be downloaded and instruct the client (probably javascript in the browser) to request the files. Or you could zip them in a single ball and respond with that.

PHPExcel save and retrieve MySql

I am using PHPExcel to generate a spreadsheet.
If I generate and download at the same time, everything is fine.
But when I save to a MediumBlob in my MySQL and then download it, MSExcel says it is not ok.
I am using the same headers in both situations.
Gera is the function that generates the file:
$agora=date("Y-m-d H:i:s");
$relatorio_rh_xls=$dbHandle->real_escape_string(RelatorioBaseRH::Gera($ciclo,$dbHandle));
$qry="insert into tb_relatorio_rh (id_avaliacao_ciclo,relatorio_base_RH_xls,inicio_vigencia,fim_vigencia) values ( $ciclo,'".$relatorio_rh_xls."','".$agora."',null)";
$result4=$dbHandle->query($qry);
And then to retrieve it:
$query = "SELECT $nomeRelatorio, OCTET_LENGTH($nomeRelatorio) as tamanho " .
"FROM tb_relatorio_rh WHERE id_avaliacao_ciclo = '$id_avaliacao_ciclo' and fim_vigencia is null order by inicio_vigencia desc";
$resultadoConsulta= $dbHandle->query($query);
$qtdeLinhas=$resultadoConsulta->num_rows;
if ($qtdeLinhas>0) {
$fetBuscaRelatorio = $resultadoConsulta->fetch_assoc();
$relatorio=$fetBuscaRelatorio[$nomeRelatorio];
$size=$fetBuscaRelatorio['tamanho'];
$type= substr($nomeRelatorio, -3, 3);
if ($type == "xls"){ $type="xlsx";}
$nomeAvaliado= str_replace(' ','_',$nomeAvaliado);
$nomeDownload=substr($nomeRelatorio, 0, strlen($nomeRelatorio)-4) .'_' . $nomeAvaliado .'.'. $type;
header("Content-Length: $size");
header("Content-Type: $type");
header("Content-Disposition: attachment; filename=$nomeDownload");
print $relatorio;
}
The problem was with another php file I was including with include_once(anotherfile.php).
That anotherfile.php had blank lines after ?> closing tag.

Export CSV file using PHP create corrupt file when try to open in MS Excel

I have the following script that will export data from my database using php to csv file. Everything works fine, except when I try to open the file in excel, I get "file is corrupt". When I run this code it shows the error - "The file is corrupted and can not be opened." Thanks in advance!
<?php
// Connection
include_once('conn.php');
$sql = "select * from info";
$qur = mysql_query($sql);
// Enable to download this file
$filename = "sampledata.csv";
header("Content-Disposition: attachment; filename=\"$filename\"");
header("Content-Type: text/csv");
$display = fopen("php://output", 'w');
$flag = false;
while($row = mysql_fetch_assoc($qur)) {
if(!$flag) {
// display field/column names as first row
fputcsv($display, array_keys($row), ",", '"');
$flag = true;
}
fputcsv($display, array_values($row), ",", '"');
}
fclose($display);
exit;
?>
I found the answer of my own question. Just need to add the ob_clean() line before we call the headers to download csv file to clear the output buffer. This will solve the error of not opening csv file in excel.

Retrieve image data from mssql with php (utf-8)

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.

PHP File Download stops

I am writing a basic license-validated PHP download script. The target file is about 50MB, and it works for some. Others can't finish it, sometimes retrying it works.
Here is the script:
$method = $_GET['method'];
if($method == "webdownload") {
$airlineid = $_GET['airline'];
$sql = "SELECT * FROM airlines WHERE airlineid='$airlineid'";
$result = mysql_query($sql) or die(mysql_error());
$row = mysql_fetch_array($result);
if($row['licensekey'] == "")
die("Invalid airline id");
$filename = $row['code'].'_installer.exe';
$file_path = '../resources/application/files/'.$row['airlineid'].'/'.$row['clientversion'].'/application_installer.exe';
if($row['licensestate'] != "OK")
die("The license associated with this downloaded has been deauthorized.");
if(!is_file($file_path))
die("The file associated with this version for this airline appears to be invalid.");
//download code here - it runs once only, if refreshed it will not allow it.
header('Content-type: application/exe');
header("Content-Disposition: attachment; filename=".$filename);
header("Content-Length: ".filesize($file_path));
header("Content-Transfer-Encoding: binary");
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
//header('X-Sendfile: '.$file_path); I tried this - it had no effect and I want the portability.
$file = #fopen($file_path,"rb");
while(!feof($file)) {
$buffer = fread($file, 1024 * 8);
print($buffer);
flush();
}
close($file);
}
EDIT: Upon advice, I discovered that the script, among others, is highly vulnerable to SQL injection. I have replaced direct variable-SQL expressions with the use of this function:
function secure_string($raw) {
$sid = strtolower($raw);
$sid = str_replace("'","_SINGLE_QUOTE", $sid);
$sid = str_replace('"','_DOUBLE_QUOTE', $sid);
$cmd[0] = "insert";
$cmd[1] = "select";
$cmd[2] = "union";
$cmd[3] = "delete";
$cmd[4] = "modify";
$cmd[5] = "replace";
$cmd[6] = "update";
$cmd[7] = "create";
$cmd[8] = "alter";
for($index = 0; $index <= 8; $index++) {
$sid = str_replace($cmd[$index],"_SQL_COMMAND", $sid);
}
return $sid;
}
Is that sufficient to block SQL-injection?
EDIT2: I have used this function in conjunction with a PDO prepare functions to eliminate this exploit. Thanks 100x for letting me learn this lesson without disastrous results.
readfile() is a function that puts the entire file into the buffer in one go. Will probably prevent PHP from timing out. Use it instead of the fopen() and print() loop you have at the bottom.
Another solution is to see if you server has mod_x_sendfile as this takes the downloading out of PHP and into apache internals.
Edit: I notice you say you've tried sendfile. Might be a better option if you can get it working.

Categories