The error message i am getting is with the headers. I am using mysqli_ i used mysql_ on a blank page to test it. When I put it into the click on my real page it told me I couldn't use mySql_ as it was old so converted it to mySqli_. the error message i'm getting now is:
"Warning: Cannot modify header information - headers already sent by
(output started at /xx/xxx/xxx.php:183) in /xxx/xxx/xxx.php on line
232 Warning: Cannot modify header information - headers already sent
by (output started at /xxx/xxx/xxx.php:183) in /xxx/xxx/xxx.php on
line 233 Fatal error: Call to undefined function outputcsv() in
/xxx/xxx/xxx.php on line 237"
require_once 'dbconfig.php';
$conn = new mysqli("xxxx", "xxxx", $password, $dbname);//host, user, password, database
$result = $conn->query('SELECT * FROM reports') or die(mysqli_error());
//these two lines are the lines 232 and 233
header('Content-Type: text/csv'); // tell the browser to treat file as CSV
header('Content-Disposition: attachment;filename=report.csv'); // tell browser to download a file in user's system with name export.csv
$row = mysqli_fetch_assoc($result); // Get the column names
if ($row) {
outputcsv(array_keys($row)); // It wil pass column names to outputcsv function
}
//this line here is 237
while ($row) {
outputcsv($row); // loop is used to fetch all the rows from table and pass them to outputcsv func
$row = mysqli_fetch_assoc($result);
}
function outputcsv($fields) {
$csv = '';
foreach ($fields as $field) {
$csv .= '"' . $field . '",';
}
$csv .= "\r\n"; //Give a carriage return and new line space after each record
echo $csv;
}
You need to set output buffer on in config file
or
Just write ob_start() at first line of code ..
And i also suggest to export in xls format for better compatibilty .
You need to look up php output buffering.
You are echoing or sending some sort of data on line 183 headers already sent by (output started at /xx/xxx/xxx.php:183) and then modifying the headers. You can use OB to buffer the information you would send to the browser, modify the headers and then flush the buffer.
ob_start();
require_once 'dbconfig.php';
$conn = new mysqli("xxxx", "xxxx", $password, $dbname);//host, user, password, database
$result = $conn->query('SELECT * FROM reports') or die(mysqli_error());
//these two lines are the lines 232 and 233
header('Content-Type: text/csv'); // tell the browser to treat file as CSV
header('Content-Disposition: attachment;filename=report.csv'); // tell browser to download a file in user's system with name export.csv
$row = mysqli_fetch_assoc($result); // Get the column names
if ($row) {
outputcsv(array_keys($row)); // It wil pass column names to outputcsv function
}
//this line here is 237
while ($row) {
outputcsv($row); // loop is used to fetch all the rows from table and pass them to outputcsv func
$row = mysqli_fetch_assoc($result);
}
function outputcsv($fields) {
$csv = '';
foreach ($fields as $field) {
$csv .= '"' . $field . '",';
}
$csv .= "\r\n"; //Give a carriage return and new line space after each record
echo $csv;
}
ob_flush();
You can also use ob_get_flush() or ob_get_contents() to return the contents of the buffer to a string, allowing it to be returned from functions etc. Note: ob_get_contents() does not clear the buffer it just returns contents at that point.
I also see an error about outputcsv($fields) not being defined, but that might clear-up after the interpreter can get past the header issue.
Related
I have this piece of PHP code that's intended to retrieve data from a mySQL database, and export it to a CSV file that has to be automatically downloaded after it was created.
$connection = mysqli_connect($host, $username, $password, $dbname) or die("Connection Error " . mysqli_error($connection));
// fetch mysql table rows
$sql = "select * from users";
$result = mysqli_query($connection, $sql) or die("Selection Error " . mysqli_error($connection));
$fp = fopen('users.csv', 'w');
while($row = mysqli_fetch_assoc($result)) {
fputcsv($fp, $row);
}
fclose($fp);
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="users.csv"');
mysqli_close($connection);
The problem here is that it:
Retrieves the data.
Retrieves the CSV file on the server in the same directory of the export.php file with the data on it.
Downloads the file with the same name BUT it's EMPTY
Thanks.
You're writing it to a file called users.csv, but the file you are forcing the user to download is the output of the page.
As long as your query is correct, once the PHP script has run, there should be a file called users.csv in the same directory as the PHP file that contains the correct data.
You need to output the data to the browser for it to be attributed to the file you're downloading.
Try this:
//Connect to database
$connection = mysqli_connect($host, $username, $password, $dbname) or die("Connection Error " . mysqli_error($connection));
//Fetch mysql table rows
$sql = "select * from users";
$result = mysqli_query($connection, $sql) or die("Selection Error " . mysqli_error($connection));
//Close connection
mysqli_close($connection);
//Set $output
$output = "";
//Set header values
$headers = array("Header 1", "Header 2", "Header 3");
//Insert header values to $output
foreach($headers as $h){
$output .= fieldCheck($h) . ",";
}
$output = rtrim($output, ","). "\n";
//Iterate through results
while($row = mysqli_fetch_assoc($result)) {
foreach($row as $cell){
//Comma-separate each value
$output .= fieldCheck($cell).",";
}
//Remove last comma of each line and add newline
$output = rtrim($output, ",") . "\n";
}
//Set headers
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="users.csv"');
//Output
echo $output;
exit;
//Function in case of comma in field
function fieldCheck($string){
if(strpos($string, ",") !== false){
$string = '"'.$string.'"';
}
return $string;
}
I have seen this question come up quite a few times and here the user is sending the data to "users.csv" as shown below:
$fp = fopen('users.csv', 'w');
The issue is that unless the file "users.csv" is already created there is nothing to write the data to, so the CSV is blank. The "fopen" does not create the file it only opens an existing file and the "w" directive then instructs "fputcsv" to put it into the file "users.csv" which may not exist and if the file does exist it writes over the existing file.
Here is an explainer PHP script that will send the output (CSV) to a filename of your choice for downloading:
//Connect to database
$connection = mysqli_connect($host, $username, $password, $dbname) or die("Connection Error " . mysqli_error($connection));
//Get the data
//The order and number of elements must match the header below or the data
//will appear in the wrong columns.
$sql = "SELECT FirstName,LastName,Address,City,State,Zip FROM users";
$result = mysqli_query($connection, $sql) or die("Selection Error " . mysqli_error($connection));
//Close connection
mysqli_close($connection);
//Name of the file you want the user to download can be any name but
//use the .CSV file extension so it will be recognized
//as a CSV when downloaded.
$NameOfCSVFileToDownload = "MyCSVFile.csv";
//set headers tells the page what to do
header("Content-Type: application/csv; charset=utf-8");
header("Content-Disposition: attachment;filename=\"$NameOfCSVFileToDownload\"");
//Where to send the data -
//there are several option but sending it to output will insert
//the data into "$NameOfCSVFileToDownload" when complete, your output.
//Output is a way to access I/O streams
$output = fopen("php://output", 'w');
//Add the header or 1st row for your data
//-notice we are sending it to "$output" you can add any names you want
//for this header row but make sure that the number of columns in the header
//matches the number of columns you are retrieving from the database or they
//will not line up when you open up the CSV and things will look scrambled.
fputcsv($output, array('FirstName','LastName','Address','City','State','Zip'));
//Loop through the data and insert the data into "$output"
while($rows = $result->fetch_assoc()){
fputcsv($output, $rows);
}
//Close the "$output" file to complete the write.
fclose($output);
That's all, call the page and it will prompt to open or download the CSV that contains data. If it is still blank make sure your SQL statement is actually pulling data.
You can also review the PHP manual on streams to better understand.
PHP Manual
Combining a few ideas mentioned in the comments:
Output directly to stdout (rather than a users.csv file). This prevents concurrent processes from clashing with the same output file. No need to buffer temporary results in a variable, either.
Use fputcsv()'s 3rd argument to specify ';' as the field separator. No need to rewrite special code for that.
Use array_map() and a custom filter to add quotes around all the fields.
// Helper function to surround a string with double quotes
function pad_with_quotes($s) {
return '"' . $s . '"';
}
// Helper function to output a row to $fp:
function output_row($fp, $row) {
// Separate fields with ';':
fputcsv($fp, array_map('pad_with_quotes', $row), ';');
}
// Send HTTP headers
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="users.csv"');
// Open a pointer to stdout:
$fp = fopen('php://output', 'w'); // TO DO: check for fopen() failure
// Output headers (padded with quotes):
output_row($fp, ['foo', 'bar']); // TO DO: change headers
// DB connection/query goes here; omitted for brevity
// Loop through DB results:
while($row = mysqli_fetch_assoc($result)) {
// Output a row of results:
output_row($fp, row);
}
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 sure this is simple for someone else, but it escapes me.
I have a function that generates a .csv file based on a query input from an internal website.
The problem is, for speed purposes, I want to run 1 query to save to two different arrays. One of which I can pass to a function, the other to use for printing a table.
I've tried to pass the same $result var to the function. It seems to strip the data once sent through function? I need some help.
code for function:
function save_to_csv($result1, $filename, $attachment = false, $headers = true) {
if($attachment) {
// send response headers to the browser
header( 'Content-Type: text/csv' );
header( 'Content-Disposition: attachment;filename='.$filename);
$fp = fopen('php://output', 'w');
} else {
$fp = fopen($filename, 'w');
}
$result1 = mysql_query($query1) or die( mysql_error() );
if($headers) {
// output header row (if at least one row exists)
$row = mysql_fetch_assoc($result1);
if($row) {
fputcsv($fp, array_keys($row));
// reset pointer back to beginning
mysql_data_seek($result1, 0);
}
}
while($row = mysql_fetch_assoc($result1)) {
fputcsv($fp, $row);
}
fclose($fp);
}
I've tried setting second array like so
$csv_result = array();
also tried
$csv_result = $result = mysql_query($query);
I'm assuming it's something here, but I just cant see it.
There's nothing in this code that demonstrates why you need two separate arrays. After the line where you set $result1, you can simply do the following for the exact same effect:
$row = mysql_fetch_assoc($result1);
if ($row) {
if ($headers) {
fputcsv($fp, array_keys($row));
}
fputcsv($fp, $row);
}
The variable $row hasn't been modified, and is still equal to the data retrieved from $query1. There's really no need to make a duplicate array unless one of them is going to be modified. However, if you want to make a copy of the data at any point, you can just use:
$new_copy = $row;
For better or worse, I am storing binary information in a database table and am having a problem retrieving it. Each BLOB has a newline prepended to it upon retrieval, at least, I believe it's upon retrieval, as the binary object in the table is exactly the same size as the source file.
I've searched for a similar problem to mine, and the closest I have found is this However, I am using PDO instead of mysql_* and I have checked for empty lines prior to the opening
Here's the retrieval function stored in a separate file that I'm including in my test:
(in raw.php):
function return_raw_rawid($raw_id) {
$data = array();
$aggregate_data = array();
$sql = "SELECT * FROM `raw` WHERE `raw_id` = :rawid";
try {
$db_obj = dbCore::getInstance();
$query = $db_obj->dbh->prepare($sql);
$query->bindValue(':rawid', $raw_id);
if ($query->execute()) {
while($results = $query->fetch(PDO::FETCH_ASSOC)) {
$data['raw_id'] = $results['raw_id'];
$data['filename'] = $results['filename'];
$data['mime_type'] = $results['mime_type'];
$data['file_size'] = $results['file_size'];
$data['file_data'] = $results['file_data'];
$data['test_id'] = $results['test_id'];
$data['user_id'] = $results['user_id'];
$data['time'] = date('Y-m-d H:i:s', $results['time']);
$aggregate_data[] = $data;
} // while
} // if
$query->closeCursor();
return $aggregate_data;
} catch (PDOException $ex) {
$errors[] = $ex;
} // catch
}
Here's the code I'm testing it with in a separate file:
<?php
include 'core/init.php'; // Contains protect_page() and includes for return_raw_rawid
protect_page();
$blob_id = 20;
$blob = return_raw_rawid($blob_id);
$data = ltrim($blob[0]['file_data']);
$name = ltrim($blob[0]['filename']);
$size = ltrim($blob[0]['file_size']);
$type = ltrim($blob[0]['mime_type']);
header("Content-type: $type");
header("Content-length: $size");
header("Content-disposition: attachment; filename=$name");
header("Content-Description: PHP Generated Data");
echo $data;
When I load this page in my browser, it will prompt me to download the file identified by blob_id and has the correct filename and type. However, upon downloading it and opening in ghex, I see that the first byte is '0A' Using cmp original_file downloaded_file I determine that the only difference is this first byte. Googling led me to the ltrim() function that I've (perhaps too) liberally applied above.
I can't tell for sure if this problem is not being caused during upload, though as I said before, I don't believe it is since the "file_size" value in phpmyadmin is exactly the same as the source file. I'm not sure if the use of the aggregate_data array in the retrieval function could be to blame or what.
Any help is greatly appreciated!
Are you sure those 4 header lines are being properly executed? 0x0A is the newline char. You could have a newline in your core/init.php triggering output, and the headers are never executed. With display_errors/error_reporting off, you'd never see the warnings about "headers not sent - output started at line X...".
I am trying to send email exported csv file. However, when i click the link, have a pop-up to download a CVS with the record from MySQL. how can i send an email this csv file to spesific email adress ? thanks a lot for help and ideas.
best regards.
Here is my code
header("Content-type: application/x-msdownload");
header("Content-Disposition: attachment; filename=log.csv");
header("Pragma: no-cache");
header("Expires: 0");
$resultstr = array();
foreach ($selectionlist as $result)
$resultstr[] = $result;
$ww=implode(",",$resultstr);
function escape_csv_value($value) {
$value = str_replace('"', '""', $value); // First off escape all " and make them ""
if(preg_match('/,/', $value) or preg_match("/\n/", $value) or preg_match('/"/', $value)) { // Check if I have any commas or new lines
return '"'.$value.'"'; // If I have new lines or commas escape them
} else {
return $value; // If no new lines or commas just return the value
}
}
$sql = mysql_query("SELECT * FROM article
WHERE idArticle in ($ww) ORDER BY idArticle DESC"); // Start our query of the database
$numberFields = mysql_num_fields($sql) or die('MySql Error' . mysql_error());; // Find out how many fields we are fetching
if($numberFields) { // Check if we need to output anything
for($i=0; $i<$numberFields; $i++) {
$keys[] = mysql_field_name($sql, $i); // Create array of the names for the loop of data below
$col_head[] = escape_csv_value(mysql_field_name($sql, $i)); // Create and escape the headers for each column, this is the field name in the database
}
$col_headers = join(',', $col_head)."\n"; // Make our first row in the CSV
$data = '';
while($info = mysql_fetch_object($sql)) {
foreach($keys as $fieldName) { // Loop through the array of headers as we fetch the data
$row[] = escape_csv_value($info->$fieldName);
} // End loop
$data .= join(',', $row)."\n"; // Create a new row of data and append it to the last row
$row = ''; // Clear the contents of the $row variable to start a new row
}
// Start our output of the CSV
/*header("Content-type: application/x-msdownload");
header("Content-Disposition: attachment; filename=log.csv");
header("Pragma: no-cache");
header("Expires: 0");*/
echo $col_headers.$data;
} else {
// Nothing needed to be output. Put an error message here or something.
echo 'No data available for this CSV.';
}
OK. First you have to Save the CSV file. If you set headers as you mentioned the file will be automatically downloaded. Please read this article on this.
http://us2.php.net/manual/en/function.fputcsv.php
Once you create your CSV file you can email it using PHP mail function. If you need some library just check this out. It's easy to implement.
http://www.redvodkajelly.com/code/php-email-class/