Display success message after downloading CSV - php

I have developed a small Wordpress Plugin to download as a CSV file users' data from the database.
Everything works fine, although I am having issues figuring out how to display a success message.
Below the code of the method that takes care of the data export:
/*
* Export CSV File
*/
public function export_CSV()
{
if ($this->users) {
$fileName = "Export_users_" . date("Y-m-d_H:i:s", time());
$fileName = $fileName.".csv";
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header('Content-Description: File Transfer');
header('Content-Encoding: UTF-8');
header("Content-type: application/csv;charset=UTF-8");
header("Content-Disposition: attachment; filename={$fileName}");
header("Expires: 0");
header("Pragma: public");
echo "\xEF\xBB\xBF"; // UTF-8 BOM
$fh = #fopen( 'php://output', 'w' );
$headerDisplayed = false;
foreach ($this->users as $user) {
if($user) {
$user_meta = get_user_meta($user->data->ID);
//Push user meta into $user array
foreach($user_meta as $key => $var)
{
$user->data->$key = trim($var[0]);
}
//convert object in array;
$usersArray = (array)$user->data;
// Add a header row if it hasn't been added yet
if ( $headerDisplayed == false ) {
// Use the keys from $directory as the titles
fputcsv($fh, array_keys($usersArray));
$headerDisplayed = true;
}
// Put the data into the stream
fputcsv($fh,$usersArray);
}//end if
}//end foreach
// Close the file
fclose($fh);
// Users exported successfully
$this->response = "Users exported successfully!";
// Make sure nothing else is sent
exit;
} else {
// No results found
$this->response = "Sorry, no results found!";
}
}
I have to use exit otherwise the CSV file will contain all the html of the page. Is there a way to run a javascript file to update the message in the front end?
Thanks in advance!

First of all:
Put the download details in a separate page. You can only send the headers once, that's one of the reasons why you can't print html after sending the csv header.
Secondly you could then create an if/else statement for if the function has succeeded. and if it did you could add some JS code like the example below:
if($download = true) {
echo "<script> alert('Download succesfull!'); </script>";
}
else {
echo "<script> alert('Download failed!'); </script>";
}
Tho i'm not sure if it could work like above since it's an server event. Another possible solution would be by creating a ServerEventCheck.

I came up with a solution by passing the response message as a variable in the header.
$this->response = "Users downloaded Successfully!";
header("Location:?page=export-users&response=".$this->response);
and then retrieve it like so:
<?php if(isset($_GET['response'])){ ?>
<div class="updated notice">
<p><?php echo __( $_GET['response']);?></p>
</div><!--error notice-->
<?php } ?>

Related

How to create a pdf file from encoded string content - Codeigniter

I am getting response from cURL which is an encoded string format of pdf(i guess) - see attached image.
I am getting pdf file if i directly put the url in browser. Since its asking for api credentials for viewing the pdf, its not user friendly and i am looking for another way to directly download the file.
So i am trying to get the string content of the pdf file with cURL and i am getting exactly what in the image attached(only small portion attached).
Using that string content, i tried to save it as a plain txt file and from there i tried to decode the string text and to create a pdf file newly. After creating i need to download the same.
I could create text file with the string data i got from cURL and could create pdf also. But the downloaded file showing Failed to load PDF document.
Below is the code i have tried and i am not sure whether i tried correctly or not.
function pdf_download(){
$this->load->helper('file');
$curl = $this->api_call->callapi('GET',APIURL."carts/96171/tickets");
$content = $curl;
$my_file = FCPATH . '/document/text.txt';
if (write_file($my_file, $content) == FALSE)
{
echo 'Unable to write the file';
}
else
{
echo 'File written!';
}
$pdf_base64 = $my_file;
//Get File content from txt file
$pdf_base64_handler = fopen($pdf_base64,'r');
$pdf_content = fread ($pdf_base64_handler,filesize($pdf_base64));
fclose ($pdf_base64_handler);
//Decode pdf content
$pdf_decoded = base64_decode ($pdf_content);
//Write data back to pdf file
$pdf_file=FCPATH . '/document/ticket.pdf';
$pdf = fopen ($pdf_file,'w');
fwrite ($pdf,$pdf_decoded);//Creating a pdf from the encoded content in txt file
fclose ($pdf);
header('Content-Type: application/octet-stream');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=tickets.pdf");
ob_clean(); flush();
readfile($pdf_file);//downloading the pdf file
exit();
}
Since streaming a download to the browser requires sending headers, you must not output anything before sending headers. Therefore, you must get rid of:
if (write_file($my_file, $content) == FALSE)
{
echo 'Unable to write the file';
}
else
{
echo 'File written!';
}
If you definitely need to check if the file was written (for debugging purposes, I assume) you may use CI's log_message() to write a debug entry in the logs or just set a control variable. For example:
if (write_file($my_file, $content) == FALSE)
{
log_message('debug', "Unable to write file");
$file_written = false;
}
else
{
log_message('debug', "File succesfully written");
$file_written = true;
}
Also, there's some headers missing to ensure the file is not streamed to the browser but sent for download, as well as some required to make sure the file is correctly downloaded
header('Content-Description: File Transfer');
header('Content-Type: '. mime_content_type($pdf_file)); // since you're using Codeigniter, this will try to use the correct mimetype
header('Content-Disposition: attachment; filename="ticket.pdf"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($pdf_file));
readfile($pdf_file);
The wrong line in the above given code is $pdf_decoded = base64_decode ($pdf_content);.
It should be changed to $pdf_decoded = $pdf_content;
Since string in encoded format is already getting which is needed for creating PDF. So no need to decode it.
Also the above code is reduced as below.
function pdf_download(){
$this->load->helper('file');
$this->load->helper('download');
$cart_id=$this->input->get('cart_id');
$curl = $this->api_call->callapi('GET',APIURL."cart/'.$cart_id.'/tickets");
$pdf_file=FCPATH . 'document\voucher-'.$cart_id.'.pdf';
if (write_file($pdf_file, $curl))
{
force_download($pdf_file, NULL);
}
}

Download a file with php and polymer

I'm having some trouble with this one. I have found some helpful scripts on the web and have been modifying them for my needs. However, I can't seem to download a file. It will respond back with the contents of the file but doesn't download it. I am using Polymer 1.0+ for my client side and PHP for my server side. The client side code to download a file is as follows:
<!--THIS IS THE HTML SIDE-->
<iron-ajax
id="ajaxDownloadItem"
url="../../../dropFilesBackend/index.php/main/DownloadItem"
method="GET"
handle-as="document"
last-response="{{downloadResponse}}"
on-response="ajaxDownloadItemResponse">
</iron-ajax>
//THIS IS THE JAVASCRIPT THAT WILL CALL THE "iron-ajax" ELEMENT
downloadItem:function(e){
this.$.ajaxDownloadItem.params = {"FILENAME":this.selectedItem.FILENAME,
"PATH":this.folder};
this.$.ajaxDownloadItem.generateRequest();
},
The server side code is as follows (the url is different because I do some url modification to get to the correct script):
function actionDownloadItem(){
valRequestMethodGet();
$username = $_SESSION['USERNAME'];
if(validateLoggedIn($username)){
$itemName = arrayGet($_GET,"FILENAME");
$path = arrayGet($_GET,"PATH");
$username = $_SESSION['USERNAME'];
$downloadItem = CoreFilePath();
$downloadItem .= "/".$_SESSION['USERNAME']."".$path."".$itemName;
DownloadFile($downloadItem);
}
else {
echo "Not Logged In.";
}
}
function DownloadFile($filePath) {
//ignore_user_abort(true);
set_time_limit(0); // disable the time limit for this script
//touch($filePath);
//chmod($filePath, 0775);
if ($fd = fopen($filePath, "r")) {
$fsize = filesize($filePath);//this returns 12
$path_parts = pathinfo($filePath);//basename = textfile.txt
$ext = strtolower($path_parts["extension"]);//this returns txt
$header = headerMimeType($ext); //this returns text/plain
header('Content-disposition: attachment; filename="'.$path_parts["basename"].'"'); // use 'attachment' to force a file download
header("Content-type: $header");
header("Content-length: $fsize");
header("Cache-control: private"); //use this to open files directly
while(!feof($fd)) {
$buffer = fread($fd, 2048);
echo $buffer;
}
}
fclose ($fd);
}
Any help on this one would be greatly appreciated.
First you will need the file handle
$pathToSave = '/home/something/something.txt';
$writeHandle = fopen($pathToSave, 'wb');
Then, while you are reading the download, write to the file instead of echoing
fwrite($writeHandle, fread($fd, 2048));
Finally, after writing to the file finished close the handle
fclose($writeHandle);
I neglect the error check, you should implement your own.

How can I create a CSV file in a directory and store data from my loop in a proper format?

I want to create a CSV file from my data. This is my loop:
foreach($animals as $row) {
$row['species'];
$row['name'];
$row['size']
}
This is how I create my CSV. So far this works:
$country = 'africa';
$newFileName = './files/'.$country.".csv";
$newFileContent = 'here should be my content';
if(file_put_contents($newFileName,$newFileContent)!=false) {
echo "File created (".basename($newFileName).")";
} else {
echo "Cannot create file (".basename($newFileName).")";
}
But I have a problem to create from my loop in a proper CSV format.
With the help of a tutorial I tried this:
$country = 'africa';
$newFileName = './files/'.$country.".csv";
$newFileContent = $animals;
foreach ($animals as $line) {
fputcsv($newFileName,explode(',',$line));
}
if(file_put_contents($newFileName,$newFileContent)!=false) {
echo "File created (".basename($newFileName).")";
} else {
echo "Cannot create file (".basename($newFileName).")";
}
But this is not working.
You need to open your file for writing first and grab the file handle:
$country = 'africa';
$newFileName = "./files/" . $country . ".csv";
$fileHandle = fopen($newFileName,"w"); // Open file for writing
foreach ($animals as $line){
fputcsv($fileHandle, explode(',',$line));
}
fclose($fileHandle); // Make sure we close file after finishing writing to it
Regarding the first foreach loop in your question $animals is an array containing arrays with keys species, name and size.
So you have to change
foreach ($animals as $line){
fputcsv($newFileName,explode(',',$line));
}
to
foreach ($animals as $line){
fputcsv($newFileName, array($line['species'], $line['name'], $line['size']));
}
because $line is already an array and should be exploded.
This is how I've always done it in the past.
$country = 'africa';
$fileName = "./files/" . $country . ".csv";
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header('Content-Description: File Transfer');
header("Content-type: text/csv");
header("Content-Disposition: attachment; filename={$fileName}");
header("Expires: 0");
header("Pragma: public");
$fh = #fopen( 'php://output', 'w' );
$headerDisplayed = false;
foreach ( $animals as $line ) {
// Add a header row if it hasn't been added yet
if ( !$headerDisplayed ) {
// Use the keys from $line as the titles
fputcsv($fh, array_keys($line));
$headerDisplayed = true;
}
// Put the data into the stream
fputcsv($fh, $line);
}
// Close the file
fclose($fh);
// Make sure nothing else is sent, our file is done
exit;

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.

Exporting CSV | Weird Behaviour

So, I think that I have asked this question and others related to it for more than twice. But I cannot figure out what's happening.
I'm using this PHP function to export some data from a table to a CSV table. I am testing on local host ( XAAMP ):
// Export CSV By User Level
public function CSVData($path, $level) {
switch ($level) {
case 0:
$filename = $path."/standard_members_".date('Y')."_".date('m')."_".date('d').".csv";
break;
case 1:
$filename = $path."/special_members_".date('Y')."_".date('m')."_".date('d').".csv";
break;
case 2:
$filename = $path."/admin_members_".date('Y')."_".date('m')."_".date('d').".csv";
break;
default:
break;
}
$sql = "SELECT user_name, user_username, user_email, user_register_date INTO OUTFILE '$filename' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n' FROM users WHERE user_level = '$level'";
if ($stmt = $this->connect->prepare($sql)) {
if(!($stmt->execute())){
print_r($stmt->error);
}
$stmt->close();
} else {
$error = true;
$message['error'] = true;
$message['message'] = CANNOT_PREPARE_DATABASE_CONNECTION_MESSAGE;
return json_encode($message);
}
if(!is_file($filename)) {
die('file not found');
} else {
header('Content-Type: application/csv');
header("Content-Disposition: attachment; filename=$filename");
header('Expires: 0');
header('Pragma: no-cache');
readfile($filename);
}
}
And I have a form that performs the action, I mean it submits the action to the PHP file which processes the above function, and this is the action code:
<?php
include '../assets/class/login/loginsys.php';
$extension = new extension;
if ($_GET['action'] == 0) {
$extension->CSVData('exports', 0);
} elseif ($_GET['action'] == 1) {
$extension->CSVData('exports', 1);
} elseif ($_GET['action'] == 2) {
$extension->CSVData('exports', 2);
}
exit();
?>
What happens is the following:
-when I click the submit button on the form I have it sends either the value 0, 1 or 2 to the action code;
-the action code gets the value and processes accordingly;
-but if I haven't created the folder 'exports' on localhost if would have given me this error:
Can't create/write to file 'C:xampphtdocsloginadminexports\standard_members_2012_01_28.csv' (Errcode: 2);
-and I have created it so it can work;
-now that the folder it's there the CSV file is created and the data is dumped into the CSV table;
-but the file that opens in my browser ( the attachment that downloads like you'd click on a file from some website and downloaded it ) it's empty even though the file exported in 'exports' has the data in it;
-and another thing is that when the file already exists in the folder 'exports' the table that is created is tells me:
File 'exports/admin_members_2012_01_29.csv' already exists
So my question is why is what I described happening ? And is there a way to make the MySql query overwrite the previous CSV file ?
You don't need that temporary file. How about this:
define('CSV_SEPARATOR', ',');
// CSV download headers
header('Content-Type: text/csv; charset=UTF-8');
header('Content-Disposition: attachment; filename="my.csv"');
// A file handle to PHP output stream
$fp = fopen('php://output', 'w');
// UTF-8 BOM
echo "\xEF\xBB\xBF";
// Get data from database
$data = ...;
// List of columns
$columns = array(
'User name',
'First name',
'Last name'
);
foreach ($data as $key => $row) {
// Write columns
if ($key == 0) {
fputcsv($fp, $columns, CSV_SEPARATOR);
}
// Write data
fputcsv($fp, $row, CSV_SEPARATOR);
}
fclose($fp);
Beautiful, isn't it?

Categories