I have various images split in the database as blob files. I have written a php script which accesses these blob files and downloads them locally.
As there are many images I have put an loop which would download all images which are stored in the database, however when I run the script in the loop I get one big download and no separate images.
My code is as follows:
$query="SELECT `id` FROM `images` LIMIT 10";
$result=mysql_query($query);
$imageid = array();
while($row = mysql_fetch_assoc($result)){
//iterate over all the fields
foreach($row as $key){
$imageid[] = $key;
}
}
$fileName ='';
for ($i = 0; $i < count($imageid); $i++) {
$query="SELECT `filename` FROM `images` WHERE `id`=".$imageid[$i]."";
$result=mysql_query($query);
while($row = mysql_fetch_assoc($result)){
foreach($row as $key){
$fileName = $key;
}
}
header("Pragma: public");
header("Expires: 0"); // set expiration time
header("Cache-Control: must-revalidate, post-check=0,pre-check=0");
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header("Content-Transfer-Encoding: binary");
header('Content-type: application/octet-stream');
header('Content-Disposition: inline; filename='.$fileName.'');
$sql = "SELECT `data` FROM `images_data` WHERE `image_id`=".$imageid[$i]." ORDER BY id";
$result1=mysql_query($sql);
while($row = mysql_fetch_array($result1)) echo $row['data'];
}//END FOR LOOP
Is there any way I can download all of the images from running the script?
If I manually change the parameter of $imageid[$i] (eg 0,1,2,3 etc) the different images will download but its useless for the amount of images I have to use.
Any help is much appreciated!
You can get only on file once from one php script run.
In you case I think best way is, store all files from DB into temporal folder, when zip (or GZ) this folder, and after output this ZIP (or GZ) archive using corresponding MIME type in you header()
Related
I have this PHP script to update a specific table of MySQL db:
<?php
error_reporting(E_ALL);
ini_set("display_errors", 1);
//Include connection file
require_once('../connection/connect.php');
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=reports.csv");
header("Pragma: no-cache");
header("Expires: 0");
$sql = "SELECT * FROM patient";
$stmt = $conn->prepare($sql);
$stmt->execute();
//var_dump($stmt->fetch(PDO::FETCH_ASSOC));
$data = fopen('backup.csv', 'w');
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
// Export every row to a file
fputcsv($data, $row);
}
?>
I created a file in the same directory called: backup.csv and the data are updated correctly each time I execute this script. But the problem is that I can't add a header to table inside the .csv file.
And the downloaded file is empty. I need to download backup.csv and not reports.csv.
I tried:
header("Content-Disposition: attachment; filename="'.$data.'";");
But it didn't helped. The file is still empty.
Your problem is that you have not actually sent the file that you have created.
This is a better structure but remember you also have to sent the file you have built to the browser
<?php
error_reporting(E_ALL);
ini_set("display_errors", 1);
//Include connection file
require_once('../connection/connect.php');
$sql = "SELECT * FROM patient";
$stmt = $conn->prepare($sql);
$stmt->execute();
$data = fopen('backup.csv', 'w');
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
// Export every row to a file
fputcsv($data, $row);
}
fclose($data); // <- close file
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=reports.csv");
header("Pragma: no-cache");
header("Expires: 0");
readfile('backup.csv'); // <- new line
?>
You should do fclose($data); right after while loop. I recommend you to use headers after execution of your query code. Please try/see the following example code.
Example
<?php
error_reporting(E_ALL);
ini_set("display_errors", 1);
//Include connection file
require_once('../connection/connect.php');
$sql = "SELECT * FROM patient";
$stmt = $conn->prepare($sql);
$stmt->execute();
//var_dump($stmt->fetch(PDO::FETCH_ASSOC));
$data = fopen('backup.csv', 'w');
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
// Export every row to a file
fputcsv($data, $row);
}
// Closing the file
fclose($data);
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=backup.csv");
header("Pragma: no-cache");
header("Expires: 0");
?>
Below is the script im using to export a MySQL database to a .csv file.
It seems to do fine with smaller outputs (under about 30,000 rows), but hangs on my larger outputs and just wont complete (1 million rows total).
Any ideas why?
Also, the PHPMyAdmin export utility dumps it incredibly quickly (just a few seconds). Wondering how it does it.
if(isset($_POST['submit'])) {
// Fetch Record from Database
$output = "";
$table = "tt_output";
$sql = mysqli_query($connection,"select * from {$table}");
$columns_total = mysqli_num_fields($sql);
// Get The Field Name
$query = "SHOW COLUMNS FROM {$table}"; $result_set = mysqli_query($connection,$query);
while ($result = mysqli_fetch_array($result_set)) {
$heading = $result[0];
$output .= trim($heading.',');
}
$output = substr($output,0,strlen($output)-1)."\r\n";
// Get Records from the table
while ($row = mysqli_fetch_array($sql)) {
for ($i = 0; $i < $columns_total; $i++) {
$output .='"'.$row["$i"].'",';
}
$output = substr($output,0,strlen($output)-1)."\r\n";
}
// Download the file
$filename = "output".".csv";
header("Pragma: public", true);
header("Expires: 0"); // set expiration time
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header('Content-Disposition: attachment; filename='.$filename);
header("Content-Transfer-Encoding: binary");
header('Connection: Keep-Alive');
echo $output;
exit;
}
On problem I can see is that you are reading everything into a variable / memory and only then start outputting it.
You should put your loop below the headers and output it right away:
...
header('Connection: Keep-Alive');
// Get Records from the table
while ($row = mysqli_fetch_array($sql)) {
for ($i = 0; $i < $columns_total; $i++) {
$output .='"'.$row["$i"].'",';
}
echo substr($output,0,strlen($output)-1)."\r\n";
}
Another possible problem is how you are building your row. If any of the fields contains an unescaped " character, it will break your csv. You might want to use fputcsv() to save the csv to a temporary file and only then send it to the client.
You can also save yourself a query as the column names will be the keys of your results arrays and if you really want to build the csv manually, you could use implode() instead of a loop but you would have to test if that is faster.
I can't get the browser to prompt for download. The output gets displayed on the screen instead. I've tried so many other threads regarding this topic on this site but to no avail. I could change the fopen("php://output","w") to fopen("export.csv","w") but that will save a copy of the export.csv file on the server, which I don't want. I want the file to be downloaded on the client without it being saved on the server. Here's my code:
$sql = mysql_query($_SESSION["export-query"]);
$fields = mysql_num_fields($sql);
$header = array();
for ($i = 0; $i < $fields; $i++) {
$header[] = mysql_field_name($sql, $i);
}
$f = fopen("php://output","w");
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename=export.csv');
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate');
fputcsv($f, $header);
while ($row = mysql_fetch_row($sql)) {
fputcsv($f, $row);
}
fclose($f);
Please help! Much appreciated.
Your code is really close to mine, but I have this
header("Content-type: application/vnd.ms-excel");
for the content type. I think this works because browsers know how to handle text/csv but they don't know how to handle excel. It will prompt to download because it doesn't open this type of file itself.
I also don't have "must-revalidate," but I don't think that makes a difference.
EDIT:
Here are my full headers, which have worked 100% of the time. There are minor differences from yours, so maybe one of them is the reason.
header("Content-type: application/vnd.ms-excel");
header("Content-disposition: attachment; filename=".$filename.".csv");
header("Pragma: no-cache");
header("Expires: 0");
EDIT 2:
Judging from your comment on your answer, you are putting all of this code as an ajax call inside a div. The reason that doesn't work is that you can only set headers on the initial call to a page. Setting headers on an ajax call will be ignored.
Here is how my system handles csv generation. Because I needed specific information that could vary between different csv files, I put the name of the generator file into the "action" of a form and provided a submit button:
<form action="thegeneratorpage.php" method="get"><fieldset>
<p>Download [...] in .csv (Excel) form. You can narrow by [...].</p>
<!-- code here that allows users to narrow down what is in the csv -->
<input type="submit" value="Download" />
</fieldset></form>
If the information doesn't vary, you can just do this:
Download CSV
All the code we have been discussing would be on thegeneratorpage.php.
Rather than using the fputcsv function, I would suggest just echoing the rows of the CSV file like so (note that the headers I use are slightly different from yours):
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false);
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename={$fileName}");
header("Content-Transfer-Encoding: binary");
while ($row = mysql_fetch_row($sql)) {
// optionally enclose data if necessary
foreach ($row as $k => $v) {
if (strpos($v, ',') !== false) {
$row[$k] = '"' . $v . '"';
}
}
echo implode(',', array_values($row));
}
First time I've had to do this, but I need to save the results of a query to CSV and create a file on the server, prior to it being passed via SFTP to a remote server. I can successfully create the CSV which is downloaded in the browser, per the code below, but cant seem to get it to save a file on the server. I think I may need file_put_contents? If anyone can suggest a method, or indeed a better approach to sending the outputs via sftp, its much apopreciated.
$result = mysql_query("SELECT * FROM `policy_details` WHERE `policyNumber` = '848938'");
if (!$result) die('Couldn\'t fetch records');
$num_fields = mysql_num_fields($result);
$headers = array();
for ($i = 0; $i < $num_fields; $i++)
{
$headers[] = mysql_field_name($result , $i);
}
$fp = fopen('php://output', 'w');
if ($fp && $result)
{
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="export.csv"');
header('Pragma: no-cache');
header('Expires: 0');
fputcsv($fp, $headers);
while ($row = mysql_fetch_row($result))
{
fputcsv($fp, array_values($row));
}
//die;
}
Immediate thought would be that you don't need to send headers when saving a file. If you are just saving a regular csv file to the local server (and doing the FTP thing separately), I also don't see the benefit of using the 'php://' scheme. I'd use something like
$fp = fopen('/path/to/new/file.csv', 'w+');
if ($fp && $result)
{
while ($row = mysql_fetch_row($result))
{
fputcsv($fp, array_values($row));
}
}
On the other hand, you could save the file directly over FTP, and avoid a 2 stage process.
What I would do is change your php://output file pointer to the file on the server that you want to save to. Move your headers below your while loop, that way you're writing each line from the db to the file. Once you exit your while loop, read the file that you just wrote as one big variable and print echo it with your headers.
$fp=fopen('/path/to/file/on/server/','w');
while ($row = mysql_fetch_row($result))
{
fputcsv($fp, array_values($row));
}
fclose($fp);
$csvFile = fopen('/path/to/file/on/server','r');
$csvData = fread($csvFile,filesize('/path/to/file/on/server');
fclose($csvFile);
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="export.csv"');
header('Pragma: no-cache');
header('Expires: 0');
echo $csvData;
Obviously this isn't the whole script, but these are the pieces I would change to accomplish what you want to do.
I want display an image instead of downloading it.
I have image in my database table, column as BLOB.
This snippet downloads the image, but I want to display it instead:
$query = "SELECT * FROM upload";
$result = mysql_query($query);
$row = mysql_fetch_array($result);
$content = $row['content'];
$size = $row['size'];
$type = $row['type'];
header("Content-length: $size");
header("Content-type: $type");
// The following headers make the image download, but I don't want it to
// download, I want to show the image. What should I do?
// header("Content-Disposition: attachment; filename=$name");
echo $content;
The opposite content-disposition of attachment is inline. Try this:
header("Content-Disposition: inline; filename=$name");
if you want to use this more dynamically make a script of your original code and call it like this:
<img src="image.php?imageid=$myImageID" />
and your script is:
$myImageID = $_GET["myImageID"];
$query = "SELECT * FROM upload where id='"+$myImageID+"'";
$result = mysql_query($query);
$row = mysql_fetch_array($result);
$content = $row['content'];
$size = $row['size'];
$type = $row['type'];
header("Content-length: $size");
header("Content-type: $type");
//header("Content-Disposition: attachment; filename=$name");---> this headers make system to download , but i dont want to download, i want to show image, what should i do ,
echo $content; ?>"
you need to be sure nothing else than your headers and the image content is sent to the client. maybe you want to do an exit after echo $content; this is not a best practice and also does not ensure that nothing else has been sent before you output the image content, but it should do the job.
You can display the image instead of downloading it with this code:
Click to download