PHP handled CSV not generating in linux environment - php

hi im currently using a script which generates csv and sends its download link(destination) in a email. in the following code,the email is sent correctly but it does not generate the csv.
Code
$fileD = "Weekly_Report_From_".date('d-m-Y', strtotime('-1 week'))."_to_".date('d-m-Y').".csv";
$url_down = (Config_Reader::readProjectConfig('report')->exportDirectory.'/weeklyReport/'.$fileD);
echo "<br/>";
echo $url_down;
if(file_exists($url_down) == false){
echo "FILE DOES NOT EXISTs";
$fp = fopen($url_down, 'w');
$header = array("XX","XX","XX","XX","XX","XX","XX","XX","XX","XX");
fputcsv($fp, $header, ',');
foreach ($tables as $fields) {
fputcsv($fp, $fields,',');
}
}
else{ echo "FILE EXISTs";
$time_start = time();
$fileD = "Weekly_Report_From_".date('d-m-Y', strtotime('-1 week'))."_to_".date('d-m-Y')."#".$time_start.".csv";
$url_down = (Config_Reader::readProjectConfig('report')->exportDirectory.'/weeklyReport/'.$fileD);
$fp = fopen($url_down, 'w');
$header = array("XX","XX","XX","XX","XX","XX","XX","XX","XX","XX");
fputcsv($fp, $header, ',');
foreach ($tables as $fields) {
fputcsv($fp, $fields,',');
}
}
header("Pragma: public");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false);
header("Content-Transfer-Encoding: binary");
fclose($fp);
$mail = new Zend_Mail ();
$sentFromEmail = $config->sentFrom_new;
$tr = new Zend_Mail_Transport_Sendmail ( '-f' . $sentFromEmail );
Zend_Mail::setDefaultTransport ( $tr );
$mail->setReturnPath($sentFromEmail);
$mail->setFrom ( $sentFromEmail, 'Reporters' );
$rty = "Hi,<br /><br />This system is working perfectly Report.";
$mail->setBodyHtml ( $rty );
$mail->addTo ( $weeklyReportRecipients );
$mail->setSubject ( "Weekly Report" );
try {
$mail->send ();
echo "success";
}
when i go in more detail. it always prints the file does not exist which is correct but it never makes the csv inside the directory,
I allowed all read write and excute permissions to the weeklyReport folder as well, but still no luck,, will any body be able to help me over this...
P.S $tables is the array that take use of to generate the csv... that works fine. and also $weeklyReportRecipients, $sentFromEmail are obtained from the config file and they are also working fine

Related

How to export comma separated values from database to csv in codeigniter php

I have a database table where except the id column all other columns have comma separated values. I am trying to download the data related to the id, so I used the following code:
view:
<a href="<?php echo base_url('admin_works/downloadexcel/'.$val['id']);?>" style="margin-left:7%">
<i class="fa fa-file-excel-o" aria-hidden="true" style="color:green"></i>
</a>
controller:
public function downloadexcel(){
$this->load->helper('file');
$this->load->helper('download');
// file name
$filename = 'users_'.date('Ymd').'.csv';
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=$filename");
header("Content-Type: application/csv; ");
// get data
$eid = $this->uri->segment(3);
$response = $this->db->where("id", $eid)->get('tbl_plans')->result();
// file creation
$file = fopen('php://output', 'w');
$header = array("Table ID","Date","Topic","Name","Client ID","Type","Reference","Status","Assigned","Image URL","Remarks","Captions");
fputcsv($file, $header);
foreach ($response as $val){
$s1=explode(',',$val->ddate);
$s2=explode(',',$val->details);
$s3=explode(',',$val->type);
$s4=explode(',',$val->ref);
$s5=explode(',',$val->status);
$s6=explode(',',$val->assign);
$s7=explode(',',$val->imageurl);
$s8=explode(',',$val->remarks);
$s9=explode(',',$val->captions);
for($i=1;$i<10;$i++){
for($j=1;$j<10;$j++){
$var = 's'.$j;
$newArr[] = $$var[$i]??'';
}
fputcsv($file,$newArr);
}
}
fclose($file);
exit;
}
however this gives me a blank file, what is wrong with my code?
for($i=0;$i<count($s1);$i++){
$newArr=[];
for($j=1;$j<12;$j++){
$var = 's'.$j;
$newArr[] = $$var[$i]??'';
}
fputcsv($file,$newArr);
}

PHP exporting several excel files

I'm trying to export several tables from a database and creating a excel file for each table using PHP. The loop however is "bugged". Instead of creating a new file for each loop it just puts all data into the same file.
The code:
foreach ($pdo->query("SHOW TABLES;") as $allTables) {
$table = $allTables[0];
$allDataStmt = $pdo->prepare("SELECT * FROM $table;");
$allDataStmt->execute();
$fieldcount = $allDataStmt->columnCount();
$col_title = "";
$data = "";
for ($i = 0; $i < $fieldcount; $i++) {
$col = $allDataStmt->getColumnMeta($i);
$column = $col['name'];
$col_title .= '<Cell ss:StyleID="2"><Data ss:Type="String">' . $column . '</Data></Cell>';
}
$col_title = '<Row>' . $col_title . '</Row>';
while ($row = $allDataStmt->fetch(PDO::FETCH_NUM)) {
$line = '';
foreach ($row as $value) {
if ((!isset($value)) or ($value == "")) {
$value = '<Cell ss:StyleID="1"><Data ss:Type="String"></Data></Cell>\t';
} else {
$value = str_replace('"', '', $value);
$value = '<Cell ss:StyleID="1"><Data ss:Type="String">' . $value . '</Data></Cell>\t';
}
$line .= $value;
}
$data .= trim("<Row>" . $line . "</Row>") . "\n";
}
$data = str_replace("\r", "", $data);
header("Content-Type: application/vnd.ms-excel;");
header("Content-Disposition: attachment; filename=" . $table . ".xls");
header("Pragma: no-cache");
header("Expires: 0");
}
}
If I kill the loop after the first iteration it exports the data correctly from ONE table. If I let the loop run it just loads the same file with the data and the file becomes corrupted. I can't even open it in Excel.
What am I missing? Been stuck with this for hours.
Thank you!
What you are attempting with making multiple different attachments in the same HTTP request is not possible. The HTTP protocol does not have support for downloading multiple files. The most common workaround is to put the files in a zip archive for the client to download, so something like this:
$zip = new ZipArchive;
$zip_name = "excel_tables.zip";
if ($zip->open($zip_name, ZipArchive::CREATE|ZipArchive::OVERWRITE) === TRUE) {
foreach ($pdo->query("SHOW TABLES;") as $allTables) {
// (Your logic to build Excel file)
$file_content = $col_title . "\n" . $data;
$file_name = $table . ".xls";
file_put_contents($file_name, $file_content);
// Add file to the zip file
$zip->addFile($file_name);
}
$zip->close();
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename=' . $zip_name);
header("Content-Length: " . filesize($zip_name));
header("Pragma: no-cache");
header("Expires: 0");
ob_clean();
flush();
readfile(__DIR__ . "/" . $zip_name);
}

Display success message after downloading CSV

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 } ?>

How can I remove duplicates and add a new unique file?

I have on my website to grab 5 random files from all the files in my directory and all is going well but about %50 of the time I get a duplicate. I would like to:
1) Remove duplicate
2) Replace with new unique file
.. or maybe I can prevent duplicates in an easier manner all together? I tried to find a function for this without asking a question of here but I have not found one. Any ideas? Thanks!!
<?php
//define stuff
$dir = "uploads/";
$allfiles = array_diff(scandir($dir), array('.', '..'));
echo '<pre>';
print_r("all files ready for access");
echo '<pre>';
// create zip
$zip = new ZipArchive();
$zip_name = "zipfile.zip";
if($zip->open($zip_name, ZIPARCHIVE::CREATE)!==TRUE){
$error .= "* Sorry ZIP creation failed at this time";
}
else {
echo '<pre>';
print("created zip");
echo '<pre>';
}
// array of random files
$n=1;
while ($n<=6){
$n ++;
$file = array_rand($allfiles);
$randomfile = $allfiles[$file];
echo '<pre>';
print_r($randomfile);
echo '<pre>';
if (file_exists($dir.$randomfile)) {
$content = $dir.$randomfile;
echo '<pre>';
print_r($content);
echo '<pre>';
$zip->addfile($content,$randomfile);
echo 'ok';
} else {
echo 'failed';
}
}
//present for download
$zip->close();
ob_get_clean();
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/zip");
header("Content-Disposition: attachment; filename=" . basename($zip_name) . ";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . filesize($zip_name));
readfile($zip_name);
if(file_exists($zip_name))
{
unlink('zipfile.zip');
}
?>
Just check if you already found this file. And if you already found it, get a new one by continuing without incrementing $n.
Look at this:
// array of random files
$n = 1;
$myfiles = [];
while ($n<=6){
$file = array_rand($allfiles);
$randomfile = $allfiles[$file];
if(!in_array($randomfile, $myfiles)) { // this line checks if you already got this file
$myfiles[] = $randomfile;
} else {
continue; // if you already got it, continue (http://php.net/manual/de/control-structures.continue.php)
}
echo '<pre>';
print_r($randomfile);
echo '<pre>';
if (file_exists($dir.$randomfile)) {
$content = $dir.$randomfile;
echo '<pre>';
print_r($content);
echo '<pre>';
$zip->addfile($content,$randomfile);
echo 'ok';
} else {
echo 'failed';
}
$n++; // increment in the end
}
You can pass a second parameter to the array_randfunction:
$my_files = array_rand($allfiles, 5);
or shuffle the array and get -for example- the first five items:
shuffle($allfiles);
// now $allfiles[0...4] are 5 different files.
create a an array for the files already added to the zip :
$added = //array
$zip->addfile($content,$randomfile);
array_push($added,$randomfile)
and check any new file in the above array before inserting:
if(!in_array($randomfile, $added)){
//add the file to zip
}

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;

Categories