I am trying to create a csv with PHP, that separate the the headers and columns.
Currently I am able to create the csv and dump the data, but each row in dumped into one cell.
The result is:
I expected this:
Here is my code
<?php
// Load the database configuration file
require_once('db/connect_db.php');
//$time = date('Y-m-d:').preg_replace("/^.*\./i","", microtime(true));
$time = date('Y-m-d');
$dteTimetamp = date('Y-m-d');
// Fetch records from database
$find = $conn->prepare("SELECT School, SchoolAddress, School_Email, Principle_Name, Reception_Number, QuantityFingerPrintScanner, InvoiceNumber from School");
$find->execute();
$udonr = "$dteTimetamp" . "Request";
//$filename = "$udonr.csv";
// Create a file pointer
$f = fopen(dirname(__FILE__).'/testfolder/'.$udonr.'.csv', 'w');
// Set column headers
$header = array('School Name', 'Contact Person', 'Contact Number', 'School Address', 'Number of scanners to deliver', 'Invoice Nuber');
fputcsv($f, $header);
// Output each row of the data, format line as csv and write to file pointer
while($row = $find->fetch(PDO::FETCH_ASSOC)){
$lineData = array($row['School'], $row['Principle_Name'], $row['Reception_Number'], $row['SchoolAddress'], $row['QuantityFingerPrintScanner'], $row['InvoiceNumber']);
fputcsv($f, $lineData);
// Set headers to download file rather than displayed
//header('Content-Type: text/csv');
// header('Content-Disposition: attachment; filename="' . $filename . '";');
//output all remaining data on a file pointer
fpassthru($f);
}
//exit;
#FROSIT is right. Excel is kinda dumb about opening CSV files, especially ones with comma separator (ironically).
Your file looks good but if you need to have it automatically open in Excel (e.i. someone else will need to open it), you might want to find which one is the default separator for Excel and set that in your script.
Related
Im trying to create a loop that when executed it created multiple csv files and downloads them. This is my code:
session_start();
require '../connect.php'; //connect.php has connection info for my database
// and uses the variable $connect
$sqldept = "SELECT department_name from department;";
$departments = mysqli_query($connect, $sqldept);
while ($department = mysqli_fetch_array($departments)) {
$department = $department[0];
header('Content-Type: text/csv; charset=utf-8');
header("Content-Transfer-Encoding: UTF-8");
header('Content-Disposition: attachment; filename=summary-' . $department . '.csv');
header("Cache-Control: no-cache, no-store, must-revalidate"); // HTTP 1.1
header("Pragma: no-cache"); // HTTP 1.0
header("Expires: 0"); // Proxies
$date = date("Y-m-d", strtotime("-28 days" . date("Y-m-d")));
$edate = date("Y-m-d");
$startdate = "(time.dateadded BETWEEN '$date' AND '$edate') AND";
$department = " and department_name = '$department'";
// create a file pointer connected to the output stream
$output = fopen('php://output', 'w');
// output the column headings
$sql2 = "SELECT time.id as timeid, time.staff_id, SUM(time.timein), COUNT(NULLIF(time.reasonforabsence,'')) AS count_reasonforabsence, GROUP_CONCAT(CONCAT(NULLIF(time.reasonforabsence,''),' ', date_format(time.dateadded, '%d-%m-%Y'),' ')) AS reasonforabsence, time.dateadded, staff.id AS staffid, department.id AS departmentid, department.department_name, staff.staff_name, staff.department_id, SUM(staff.workhoursperday), staff.payrollnum FROM time, staff, department WHERE $startdate staff.id = time.staff_id AND staff.department_id = department.id $department $staffsearch GROUP BY staff.id ORDER BY `time`.`dateadded` ASC;";
// output headers so that the file is downloaded rather than displayed
fputcsv($output, array(
'Payroll Number',
'Name',
'Department',
'Hours Worked',
'Days Absent',
'Overtime',
'Reasons for Absence'
));
$rows = mysqli_query($connect, $sql2);
while ($rowcsv = mysqli_fetch_assoc($rows)) {
$reasonforabsence = $rowcsv['reasonforabsence'];
//$reasonforabsence = explode( ',', $rowcsv['reasonforabsence'] );
$overtime = 0;
if (empty($rowcsv['SUM(time.timein)']) == true) {
$rowcsv['SUM(time.timein)'] = 0;
}
;
if ($rowcsv['SUM(time.timein)'] > $rowcsv['SUM(staff.workhoursperday)']) {
$overtime = $rowcsv['SUM(time.timein)'] - $rowcsv['SUM(staff.workhoursperday)'];
}
;
fputcsv($output, array(
$rowcsv['payrollnum'],
$rowcsv['staff_name'],
$rowcsv['department_name'],
$rowcsv['SUM(time.timein)'],
$rowcsv['count_reasonforabsence'],
$overtime,
$reasonforabsence
));
};
readfile("php://output");
fclose($output);
};
Currently the loop created 1 CSV with a new header and the department details below it like this
I want the loop to create a new CSV for each department but its just not working for me. Any help is appreciated.
Thanks
Unfortunately you can't, 1 PHP Request results in one file, and there isn't really a way around this. You can, however, try to download them all as a ZIP file. Take a look at this question f.e.
The below are some workaround ideas, which might be useful in certain scenarios (and might be dangerous in other scenarios). Use under your own risk!
Workaround A: Loop by redirect
Output a single file normally
Do a redirect to same url that's creating the CSV file in step#1, but append a GET flag to that, like http://www.example.net/output_csv?i=1
Make sure to add a loop-breaker in step#1, like if($i==10) { exit; }
Workaround B: Loop by cronjob
Output a single file normally
Make 2nd file output be handled by a separate cronjob call.
Make sure to add a loop-breaker in step#1, like if($mycron==10) { exit; }
You can not do this by for loop.
However, You can make a php file which can do your purpose.
<a onclick="getcsv()" href="php_file_location.php?table_name=test"> Download </a>
<script>
function getcsv() {
window.open(php_file_location);
}
</script>
I was in the same problem as mentioned. But in my case I was not trying to download multiple CSVs but I was uploading it to sFTP server. While creating the file instead of using
$output = fopen('php://output', 'w');
I used
$output = fopen($path_and_name, 'w');
where $path_and_name = $path_to_sftp_folder.'/'.$file_name;
after the execution the correct file was uploaded to there respective folders correctly the way I wanted it to be. But yes the wrong file was also downloaded with same issue as sent above.
So if you are looking for uploading files on a server it can be done(even if they all have same name).
On my local machine it is working fine. but on server it is printing the output on the same page instead of creating of a CSV file. can anyone help
// output headers so that the file is downloaded rather than displayed
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=memberList.csv');
ob_end_clean();
// create a file pointer connected to the output stream
$output = fopen('php://output', 'w');
// output the column headings
fputcsv($output, array('First Name', 'Last Nameenter code here', 'Street Name', 'City', 'State', 'Zip Code'));
// fetch the data
$csvQry = "SELECT * from tabel where num=1";
if ($_POST['stateList']!='all'){
$csvQry = "SELECT * from table";
}
$csvRows = mysqli_query($db,$csvQry);
// loop over the rows, outputting them
while ($csvRow = mysqli_fetch_assoc($csvRows)) {
fputcsv($output, $csvRow);
}
fclose($output);
I don't have a lot of experience with using the fputcsv function.
I'm trying to make a function, by which an admin can download a file with all the user information.
The CSV should be generated in this way :
Serial Number Username Email etc etc
And then the records from a query.
I have this function which I'm using to generate the csv file :
function array_to_csv_download($array, $filename = "export.csv", $delimiter=";") {
// open raw memory as file so no temp files needed, you might run out of memory though
$f = fopen('php://memory', 'w');
// loop over the input array
foreach ($array as $line) {
// generate csv lines from the inner arrays
fputcsv($f, $line, $delimiter);
}
// rewrind the "file" with the csv lines
fseek($f, 0);
// tell the browser it's going to be a csv file
header('Content-Type: application/csv');
// tell the browser we want to save it instead of displaying it
header('Content-Disposition: attachement; filename="'.$filename.'";');
// make php send the generated csv lines to the browser
fpassthru($f);
}
And then I call the function:
<?php
include 'inc/inc.functions.php';
include 'dbconnector.php';
$query="SELECT * from users order by email LIMIT 0,30";
$result=mysql_query($query,$db) or die(mysql_error($db));
$array=mysql_fetch_array($result);
foreach($array as $arr)
{
array_to_csv_download($arr,"records.csv",":");
}
?>
The CSV generated displays: Warning, Invalid argument supplied for foreach.
What should I do to display in the way I require?
UPDATE
http://i.imgur.com/2xH0gT1.png
You're currently calling your function for a single row in the database, rather than for the entire result set. The following should use your function correctly:
$query = "SELECT * from users order by email LIMIT 0,30";
$result = mysql_query($query,$db) or die(mysql_error($db));
$array = array();
# Headers
$array[] = array("Serial Number","Username","Email","etc etc");
while($row = mysql_fetch_row($result)) {
$array[] = $row;
}
array_to_csv_download($array,"records.csv",":");
I'm trying to generate a CSV file on the fly, depending on what the user selects as report output. Retrieving the data and writing it to a file using CakeResponse is done, however I'm struggling to set the file extension to '.csv', the file get downloaded as a normal text file.
CakePHP documentation suggests I do this:
$this->response->type('csv');
..but even this is not working, I'm still getting a text file. Can anyone shed some light? Please note, I'm not looking for new methods to generate a CSV file, I just want to change the extension. Thank you.
This is how I download the file:
$this->response->body($this->constructFileBody($logs));
return $this->response;
This is the method 'constructFileBody', although I think its beyond the scope of this question:
public function constructFileBody($logs = array()){
$content = "";
for($i = 0; $i < count($logs); $i++){
$row = $logs[$i]['EventLog'];
$line = $row['description'] . "," . $row['user'] . "," . $row['affected_user'] . "," . $row['report_title'] . "," . $row['date_created'] . "\n";
$content = $content . $line;
}
return $content;
}
As i saw your code, I don't think you used the header anywhere, try this code:
//create a file
$filename = "export_".date("Y.m.d").".csv";
$csv_file = fopen('php://output', 'w');
header('Content-type: application/csv');
header('Content-Disposition: attachment; filename="'.$filename.'"');
$results = $this->ModelName->query($sql); // This is your sql query to pull that data you need exported
//or
$results = $this->ModelName->find('all', array());
// The column headings of your .csv file
$header_row = array("ID", "Received", "Status", "Content", "Name", "Email", "Source", "Created");//columns you want in csv file
fputcsv($csv_file,$header_row,',','"');
// Each iteration of this while loop will be a row in your .csv file where each field corresponds to the heading of the column
foreach($results as $result)
{
// Array indexes correspond to the field names in your db table(s)
$row = array(
$result['ModelName']['id'],
$result['ModelName']['received'],
$result['ModelName']['status'],
$result['ModelName']['content'],
$result['ModelName']['name'],
$result['ModelName']['email'],
$result['ModelName']['source'],
$result['ModelName']['created']
);
fputcsv($csv_file,$row,',','"');
}
fclose($csv_file);
Now look at your code and get the line of code mine which needs to be replaced.
I want to create a csv file, but when I run the code, it returns a blank page and no csv file. I use PHP 5.
I use the following code:
<?php
$data = array ('aaa,bbb,ccc,dddd',
'123,456,789',
'"aaa","bbb"');
$fp = fopen('data.csv', 'w');
foreach($data as $line){
$val = explode(",",$line);
fputcsv($fp, $val);
}
fclose($fp);
?>
Thank you!
Its blank because you are writing to file. you should write to output using php://output instead and also send header information to indicate that it's csv.
Example
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="sample.csv"');
$data = array(
'aaa,bbb,ccc,dddd',
'123,456,789',
'"aaa","bbb"'
);
$fp = fopen('php://output', 'wb');
foreach ( $data as $line ) {
$val = explode(",", $line);
fputcsv($fp, $val);
}
fclose($fp);
#Baba's answer is great. But you don't need to use explode because fputcsv takes an array as a parameter
For instance, if you have a three columns, four lines document, here's a more straight version:
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="sample.csv"');
$user_CSV[0] = array('first_name', 'last_name', 'age');
// very simple to increment with i++ if looping through a database result
$user_CSV[1] = array('Quentin', 'Del Viento', 34);
$user_CSV[2] = array('Antoine', 'Del Torro', 55);
$user_CSV[3] = array('Arthur', 'Vincente', 15);
$fp = fopen('php://output', 'wb');
foreach ($user_CSV as $line) {
// though CSV stands for "comma separated value"
// in many countries (including France) separator is ";"
fputcsv($fp, $line, ',');
}
fclose($fp);
Just in case if someone is wondering to save the CSV file to a specific path for email attachments. Then it can be done as follows
I know I have added a lot of comments just for newbies :)
I have added an example so that you can summarize well.
$activeUsers = /** Query to get the active users */
/** Following is the Variable to store the Users data as
CSV string with newline character delimiter,
its good idea of check the delimiter based on operating system */
$userCSVData = "Name,Email,CreatedAt\n";
/** Looping the users and appending to my earlier csv data variable */
foreach ( $activeUsers as $user ) {
$userCSVData .= $user->name. "," . $user->email. "," . $user->created_at."\n";
}
/** Here you can use with H:i:s too. But I really dont care of my old file */
$todayDate = date('Y-m-d');
/** Create Filname and Path to Store */
$fileName = 'Active Users '.$todayDate.'.csv';
$filePath = public_path('uploads/'.$fileName); //I am using laravel helper, in case if your not using laravel then just add absolute or relative path as per your requirements and path to store the file
/** Just in case if I run the script multiple time
I want to remove the old file and add new file.
And before deleting the file from the location I am making sure it exists */
if(file_exists($filePath)){
unlink($filePath);
}
$fp = fopen($filePath, 'w+');
fwrite($fp, $userCSVData); /** Once the data is written it will be saved in the path given */
fclose($fp);
/** Now you can send email with attachments from the $filePath */
NOTE: The following is a very bad idea to increase the
memory_limit and time limit, but I have only added to make sure if anyone faces the problem of connection time out or any other.
Make sure to find out some alternative before sticking to it.
You have to add the following at the start of the above script.
ini_set("memory_limit", "10056M");
set_time_limit(0);
ini_set('mysql.connect_timeout', '0');
ini_set('max_execution_time', '0');
In case someone is still looking for an answer (a simple one), here is the simple way of creating a csv with PHP.
//Let's say you want your csv file to have something like this:
**Title 1** | **Title 2** | **Title 3**
Value 1 | Value 2 | Value 3
Value 4 | Value 5 | Value 6
//create a variable and add your data to it
$data = "TITLE 1, TITLE 2, TITLE 3 \n";
$data .= val1 .",". val2 .",". val3 \n ;
$data .= val3 .",". val4 .",". val5 \n ;
//you can use a loop to add dynamic data to this variable, if you want.
//give your file a name.
$fileName = 'myData.csv';
//add the file path where you want to store your csv file
//you can use **$_SERVER['DOCUMENT_ROOT']** in your file path. Avoid using absoultue paths like **../** this
$filePath = 'your_path_to' . $fileName;
$fp = fopen($filePath, 'w+');
fwrite($fp, print_r($data, true));
//Once the data is written, it will be saved in the path given.
fclose($fp);
I think this is the shortest way
$columns = [
'id',
'product_name',
'product_url',
'price',
'category'
];
$products = [
[1, 'product 1', 'https://example.com/product-1', '9.99', 'category 1'],
[2, 'product 2', 'https://example.com/product-2', '19.99', 'category 2'],
[3, 'product 3', 'https://example.com/product-3', '29.99', 'category 3'],
[4, 'product 4', 'https://example.com/product-4', '39.99', 'category 4'],
];
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="products.csv"');
echo implode(',', $columns) . PHP_EOL;
foreach ($products as $product){
echo implode(',', $product) . PHP_EOL;
}