Im just getting started with PHP, and I need to export a table from my sqlite database to a CSV or ideally XLS. I have found an example using mysql, but i cant convert it to work with sqlite.
Here is what i have so far:
<?php
$db = new PDO('sqlite:../ccm.sqlite');
$query = $db->query('SELECT * FROM Emails');
$export = sqlite_query ($query);
$fields = sqlite_num_fields ( $export );
for ( $i = 0; $i < $fields; $i++ ){
$header .= sqlite_field_name( $export , $i ) . "\t";
}
while( $row = sqlite_fetch_row( $export ) ){
//sqlite_fetch_row doesnt actually exist...
$line = '';
foreach( $row as $value ){
if ( ( !isset( $value ) ) || ( $value == "" ) ){
$value = "\t";
}else{
$value = str_replace( '"' , '""' , $value );
$value = '"' . $value . '"' . "\t";
}
$line .= $value;
}
$data .= trim( $line ) . "\n";
}
$data = str_replace( "\r" , "" , $data );
if ( $data == "" ){
$data = "\n(0) Records Found!\n";
}
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=emails.xls");
header("Pragma: no-cache");
header("Expires: 0");
print "$header\n$data";
?>
Can anyone help me out with this?
or if there is a simpler way that would be great.
Cheers
You are mixing PDO methods with sqlite_* functions; try using one or the other:
$db = new PDO("sqlite:../ccm.sqlite");
$query = $db->query("select * from emails");
$first_row = true;
while ($row = $query->fetch(PDO::FETCH_ASSOC))
{
if ($first_row)
{
// I'm not sure how to get the field names using a PDO method but
// we can use the first row's (or any row's) key values as these
// are the field names.
$first_row = false;
$number_of_fields = count($row);
$field_names = array_keys($row);
$first_field_name = $field_names[0];
}
// do stuff here with the row
print_r($row);
}
or
$db = sqlite_open("../cmm.sqlite");
$query = sqlite_query($db, "select * from emails");
$number_of_fields = sqlite_num_fields($query);
$first_field_name = sqlite_field_name($query, 0);
while ($row = sqlite_fetch_array($query))
{
// do stuff here with the row.
print_r($row);
}
I'm not 100% sure but I think PDO works with sqlite3 databases and sqlite_* functions works with sqlite2 databases.
If I need to quickly get data out of a sqlite3 database as CSV files, I use the sqlite3 CLI:
$ sqlite3 ccm.sqlite
sqlite> .mode csv
sqlite> .output emails.csv
sqlite> .headers on
sqlite> select * from emails
sqlite> .output stdout
sqlite> .quit
$ cat emails.csv
This starts the sqlite3 CLI opening the ccm.sqlite database, sets the output mode to csv (the format of select statements), sets output to the file named emails.csv, turns select column headers on (optional), selects all the data in the emails table, sets output to standard out (closing the emails.csv file), quits the CLI and checks the output by sending it to standard out.
There are other formats you can output, type .help at the sqlite3 CLI prompt:
.mode MODE ?TABLE? Set output mode where MODE is one of:
csv Comma-separated values
column Left-aligned columns. (See .width)
html HTML <table> code
insert SQL insert statements for TABLE
line One value per line
list Values delimited by .separator string
tabs Tab-separated values
tcl TCL list elements
I've improved upon Stacey's answer, and thought I'll share it here.
I've added headers to make the browser download the output as a CSV file.
<?
// Set headers to make the browser download the results as a csv file
header("Content-type: text/csv");
header("Content-Disposition: attachment; filename=filename.csv");
header("Pragma: no-cache");
header("Expires: 0");
// Connect to DB
$conn = new PDO('sqlite:db_name.db');
// Query
$query = $conn->query("SELECT * FROM some_table");
// Fetch the first row
$row = $query->fetch(PDO::FETCH_ASSOC);
// If no results are found, echo a message and stop
if ($row == false){
echo "No results";
exit;
}
// Print the titles using the first line
print_titles($row);
// Iterate over the results and print each one in a line
while ($row != false) {
// Print the line
echo implode(array_values($row), ",") . "\n";
// Fetch the next line
$row = $query->fetch(PDO::FETCH_ASSOC);
}
// Prints the column names
function print_titles($row){
echo implode(array_keys($row), ",") . "\n";
}
If you need to send a CSV file directly to the browser, without writing in an external file, you can open the output and use fputcsv on it.
<?php
$out = fopen('php://output', 'w');
// print column header
fputcsv($out, array_keys($row)));
//or print content directly
fputcsv($out, array_values($row)));
fclose($out);
?>
Related
I try to export an Excel file from a WordPress database users table. It works in general. But I also need to add all user_meta data into this file. How could I combine this?
My code:
<?php
//Include the wp-load.php file
include('../../../../wp-load.php');
//As this is external file, we aren't using the WP theme here. So setting this as false
define('WP_USE_THEMES', false);
global $wpdb;
$table_name = $wpdb->prefix . 'users';
$file = 'email_csv'; // ?? not defined in original code
$results = $wpdb->get_results("SELECT * FROM $table_name", ARRAY_A);
if (empty($results)) {
return;
}
$csv_output = '"'.implode('";"',array_keys($results[0])).'";'."\n";;
foreach ($results as $row) {
$csv_output .= '"'.implode('";"',$row).'";'."\n";
}
$csv_output .= "\n";
$filename = $file."_".date("Y-m-d_H-i",time());
header("Content-type: application/vnd.ms-excel");
header("Content-disposition: csv" . date("Y-m-d") . ".csv");
header( "Content-disposition: filename=".$filename.".csv");
print $csv_output;
exit;
For your custom list of meta_keys (company, firstname, address) you can define an array containing these, and add them to the CSV as trailing columns like so:
global $wpdb;
// Define your custom meta keys you want to add as columns HERE:
$meta_keys = ['company', 'firstname', `address`]; // can contain as many as you want
// This function will load the desired keys as an associative array
// in the form: [$meta_key_1 => $meta_value_1, ..., $meta_key_n => $meta_value_n]
function load_user_meta($user_id, $keys) {
$meta_row = [];
foreach ($keys as $meta_key) {
$value = get_user_meta($user_id, $meta_key, true);
$meta_row[$meta_key] = $value;
}
return $meta_row;
}
$table_name = $wpdb->prefix . 'users';
$results = $wpdb->get_results("SELECT * FROM $table_name", ARRAY_A);
if (empty($results)) {
return;
}
// Merge the result's keys with the list of custom meta keys:
$csv_output = '"'.implode('";"',array_merge(array_keys($results[0]), $meta_keys )).'";'."\n";
foreach ($results as $row) {
// load the custom meta for this user's ID:
$custom_meta_row = load_user_meta($row['ID'], $meta_keys);
// merge the acquired user meta into the row output:
$csv_output .= '"'.implode('";"',array_merge($row, $custom_meta_row)).'";'."\n";
}
$csv_output .= "\n";
If a certain meta_key does not exist for all users, this still works since get_user_meta will produce an empty string for these cases.
Additional note: it's generally not a good idea to produce CSV output the way you do. This works as long as there are no " and ; characters anywhere in your user_meta - those characters would have to be escaped with a certain escape character. Therefore, it is better to use fputcsv on the output stream ( $outstream = fopen("php://output", 'w');).
I am working on Export to CSV in PHP. I have code that works fine it gives me output in ExcelSheet as I want.
Code snippet:
public function generate_csv() {
$data_rows = array();
$table = 'ProductDetails';
$data_rows = array();
global $wpdb, $bp;
$data= $wpdb->get_results("SELECT * FROM " . $table . "");
$fh = #fopen( 'php://output', 'w' );
foreach ($data as $u ) {
$row = array();
$row[0] = $u->productCode;
$row[1] = $u->productTitle;
$row[2] = $u->productDescription;
$row[3] = $u->specification;
$row[4] = $u->whereToBuy;
$data_rows[] = $row;
}
header("Pragma: public");
... Some more header ...
header("Content-Transfer-Encoding: binary");
fputcsv( $fh, $header_row );
foreach ( $data_rows as $data_row ) {
fputcsv( $fh, $data_row );
}
fclose( $fh );
die();
}
As you can see in code I am hard coding all column names and creating array. The problem is if phpMyAdmin add/remove column in database then to get perfect ExcelSheet necessary changes need to make in this code also. Can any one please help me to make this code dynamic.? Like what should be instead of $row[0], $row[1], $row[2].... ??
Thank You
More global approach is to use double foreaches
$data_rows=array();
foreach ($data as $u ) {
$row = array();
foreach ($u as $field)
{
$row[] = $field; // collect dynamic row fields
}
$data_rows[] = $row; // each row will have own array of fields
}
/// EDITED
public function generate_csv($table) // better to have table name here
{
$data_rows = array();
$data_rows = array();
global $wpdb, $bp;
$sql = "SELECT * FROM " . $table . "";
$data= $wpdb->get_results($sql);
$fh = #fopen( 'php://output', 'w' );
//following the example from: https://stackoverflow.com/a/31068464/1171074
$header_data=array();
foreach ( $wpdb->get_col( "DESC " . $table, 0 ) as $column_name ) {
$header_data[] = $column_name;
}
array_push($data_rows,$header_data); // first array will be columns names
foreach ($data as $u ) {
$row = array();
foreach ($u as $field)
{
$row[] = $field; // collect dynamic row fields
}
$data_rows[] = $row; // each row will have own array of fields
}
............ // rest of the code
}
You can use the virtual INFORMATION_SCHEMA.COLUMNS table to get the column names, like so:
"SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = {$table}"
This should get you pretty close, if not all the way there. It will query the table, build a headers row for the csv, then it will assemble each data row. You shouldn't need to know the row name, if you iterate the response row as value..
I apologize up front if it's a little buggy, since I don't have a PHP box handy where I'm at to verify the precise syntax.
public function generate_csv() {
global $wpdb;
global $bp;
$headers = array();
$data_rows = array();
$table = 'ProductDetails';
$data_rows = array();
$header_row;
# determine table field names
$table_sql = sprintf("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '%s'",$table);
# this will run the query and stuff field names into
$resp = $wpdb->get_results($table_sql);
foreach($resp as $row){
array_push($headers,$row[0]);
}
# get the records from the datbase
$data= $wpdb->get_results(sprintf("SELECT * FROM %s",$table));
# open output handle
$fh = #fopen( 'php://output', 'w' );
foreach ($data as $record ) {
$row = array();
foreach($record as $value){
array_push($row,$value);
}
array_push($data_rows,$row);
}
header("Pragma: public");
... Some more header ...
header("Content-Transfer-Encoding: binary");
fputcsv( $fh, $headers );
foreach ( $data_rows as $data_row ) {
fputcsv( $fh, $data_row );
}
fclose( $fh );
return;
}
I'm using PHP to create an excel document with the data I'm pulling from a MySQL Database.
While cycling through the rows at the end and printing out my data to each cell, I want to replace each cell that has the string/int equivical of '-1' to '0'.
Here's my code so far,
header('Content-Type: text/csv');
header('Content-Disposition: attachment;filename=exported-data.csv');
$sql = "SELECT * FROM db_table";
$sth = $db->prepare($sql);
$sth->execute();
$filename = date('d.m.Y').'.csv';
$data = fopen($filename, 'w');
while ($row = $sth->fetch(PDO::FETCH_ASSOC)) {
$csv = implode(',', $row) . "\n";
fwrite($data, $csv);
print_r($csv);
}
echo "\r\n";
This works efficiently with getting the data from the db and outputting to an excel spreadsheet but how would I check each record pulled and replace it with a 0 if the record is -1?
So visually, if my database looked like this:
id mon tues wed
85 -1 -1 75
36 -1 12 -1
The excel spreadsheet would pop out like so:
85 0 0 75
36 0 12 0
I agree with u_mulder about replacing the -1 results with 0. I would build upon that with some error checking, cache busting, and I would use PHP's fputcsv function to stream the file directly to STDOUT. This will reduce memory usage, increase performance, and ensure that field values containing double quotes or commas are correctly parsed.
<?php
header('Content-Type: text/csv');
header('Content-Disposition: attachment;filename=exported-data.csv');
header("Pragma: no-cache");
header("Expires: 0");
$sql = "SELECT * FROM db_table";
$sth = $db->prepare($sql);
$sth->execute();
$file = fopen('php://output', 'w');
if(false === $file) {
throw new Exception("Failed to create output stream resource.");
}
while ($row = $sth->fetch(PDO::FETCH_ASSOC)) {
foreach($row as &$field) {
if("-1" == strval($field)) {
$field = "0";
}
}
if(false === fputcsv($file, $row)) {
throw new Exception("Failed to write row to CSV file.");
}
}
fclose($file);
I suggest you to do this:
while ($row = $sth->fetch(PDO::FETCH_ASSOC)) {
// check every key of $row
// use & to pass $value by reference
foreach ($row as &$value) {
// use strval to get string representation of a $value
if (strval($value) == '-1') {
$value = '0';
}
}
$csv = implode(',', $row) . "\n";
fwrite($data, $csv);
print_r($csv);
}
Doing this at the SQL level will be much faster then analyzing each row individually with PHP especially as your database gets larger. Use CASE.
header('Content-Type: text/csv');
header('Content-Disposition: attachment;filename=exported-data.csv');
$sql = "
SELECT
id
,CASE WHEN monday = -1 THEN 0 ELSE monday END AS monday
,CASE WHEN tuesday = -1 THEN 0 ELSE tuesday END AS tuesday
,CASE WHEN wednesday = -1 THEN 0 ELSE wednesday END AS wednesday
FROM db_table";
$sth = $db->prepare($sql);
$sth->execute();
$filename = date('d.m.Y').'.csv';
$data = fopen($filename, 'w');
while ($row = $sth->fetch(PDO::FETCH_ASSOC)) {
$csv = implode(',', $row) . "\n";
fwrite($data, $csv);
print_r($csv);
}
echo "\r\n";
Filter $row to replace negative values by 0:
$row = array_map(function ($val) { return $val > 0 ? $val : 0; }, $row);
Also, consider using fputcsv() to generate valid CSV files instead of trying to do it yourself. Simply separating values by , may work when you are dealing only with numbers but this may create problems with strings.
$output = fopen('php://output', 'w');
while ($row = $sth->fetch(PDO::FETCH_ASSOC))
{
$row = array_map(function ($val) { return $val > 0 ? $val : 0; }, $row);
fputcsv($data, $row);
fputcsv($output, $row);
}
Another problem that you may face when generating CSV files to be opened with Excel is localization. Excel expects the CSV files it opens to be formatted according to the local system localization settings. A record such as 1,2,3,1.23 may work in English, having each number separated in a column and having 1.23 with its decimals interpreted correctly, but will not work on many others languages, specially when , is used as decimal separator instead of ..
With that in mind you may want to implement localization to your CSV aswell, and your best guess is to use the client's browser language settings:
$locale = isset($_COOKIE['locale']) ? $_COOKIE['locale'] : $_SERVER['HTTP_ACCEPT_LANGUAGE'];
$locale = preg_split('/[,;]/', $locale);
setlocale(LC_ALL, $locale[0]);
$locale = localeconv();
$output = fopen('php://output', 'w');
while ($row = $sth->fetch(PDO::FETCH_ASSOC))
{
$row = array_map(function ($val) { return $val > 0 ? $val : 0; }, $row);
fputcsv($data, $row, $locale['decimal_point'] == ',' ? ';' : ',');
fputcsv($output, $row, $locale['decimal_point'] == ',' ? ';' : ',');
}
Now, if you don't want to have this complication, you can instead generate real Excel .XLSX files using a library such as PHPExcel.
I need to export the data from the Mysql table “tblinfoaanvraag” (see here for picture of the table: http://s29.postimg.org/qeqp43z4n/mysql.png)
I have a working code with the correct query and it triggers an Excel download and the data is in the file. However, The data inside the Excel file is still formatted as an sql query result and the headers (field names) are only shown as “Array”.
So there are two things I’m struggling with at this point: format the sql-results as cells in the .csv file and the headers/table field names should be shown correctly instead of just “Array”.
Here is a screenshot of the downloaded Excel-file: http://s13.postimg.org/p0rcehehj/excel1.png
The code:
<?php
if(isset($_POST['InfoaanvragenDownloaden']))
{
try
{
// Variables for later use
$header="";
$data="";
//connection
$sHost = "localhost";
$sUser = "root";
$sPassword = "";
$sDatabase = "corbati";
$link = #mysqli_connect($sHost, $sUser, $sPassword, $sDatabase) or die("Oop, dbase is gone!");
//create query to select as data from your table
$select = "select * from tblinfoaanvraag ORDER BY PK_Infoaanvraag DESC";
//run mysql query and then count number of fields
$export = mysqli_query ( $link, $select )
or die ( "Sql error : " . mysql_error( ) );
$fields = mysqli_num_fields ( $export );
//create csv header row, to contain table headers
//with database field names
for ( $i = 0; $i < $fields; $i++ ) {
$header .= mysqli_fetch_fields( $export ) . ",";
}
//this is where most of the work is done.
//Loop through the query results, and create
//a row for each
while( $row = mysqli_fetch_row( $export ) ) {
$line = '';
//for each field in the row
foreach( $row as $value ) {
//if null, create blank field
if ( ( !isset( $value ) ) || ( $value == "" ) ){
$value = ",";
}
//else, assign field value to our data
else {
$value = str_replace( '"' , '""' , $value );
$value = '"' . $value . '"' . ",";
}
//add this field value to our row
$line .= $value;
}
//trim whitespace from each row
$data .= trim( $line ) . "\n";
}
//remove all carriage returns from the data
$data = str_replace( "\r" , "" , $data );
//create a file and send to browser for user to download
header("Content-type: application/vnd.ms-excel");
header( "Content-disposition: filename=Infoaanvragen.csv");
print "$header\n$data";
exit;
}
catch (Exception $e)
{
$feedback = $e->getMessage();
}
}
?>
http://php.net/manual/en/function.fputcsv.php
You can pass it a file handle and your data for each row, and it formats it as a CSV line, with correct escapings. It uses a file, though you can use an in memory file stream to avoid hitting the disk
$filename = "php://memory";
$fp = fopen($filename, "w+b");
$rowNum = 1;
while( $row = mysqli_fetch_row( $export ) ) {
if ($rowNum == 1){
fputcsv($fp, array_keys($row)); // Headers
}
fputcsv($fp, $row) // Data
$rowNum++;
}
rewind($fp);
var_dump(stream_get_contents($fp));
You would use the array keys of a row for first CSV row, and array values of each row for data.
Use ';' as delimiter (fputcsv has a parameter for that and it's ',' by default) and set the end of lines in DOS format. At least it's what phpMyAdmin does when doing an export in the "CSV for MS Excel" format.
I'm trying to export an array of arrays to excel. I have it set up to be a header variable, and a data variable that basically builds a giant string to be executed in the export. However, only the header variable is going through. Let me show some code:
This is setting the parameters:
str_replace(" ", "_", $getData['name']);
$filename = $getData['name']."_summary.xls";
header("Content-Type: application/x-msdownload");
header("Content-Disposition: attachment; filename=\"$filename\"");
header("Pragma: no-cache");
header("Expires: 0");
Which goes to a function to get the information:
foreach($tempRS as $key=>$value)
{
foreach($value as $iKey=>$iValue)
{
if($count == 6)
{
$iValue = str_replace('"', '""', $iValue);
$iValue = '"'.$iValue.'"'."\n";
$data .= trim($iValue);
$count = 0;
}
else
{
$iValue = str_replace('"', '""', $iValue);
$iValue = '"'.$iValue.'"'."\t";
$data .= trim($iValue);
$count++;
}
}
}
$header = "ROW HEADER 1\tROW HEADER 2\tROW HEADER 3\tROW HEADER 4\tROW HEADER 5\tROW HEADER 6\n";
print "$header\n$data";
I can't seem to figure out why i'm losing the $data variable on the export.
Why not just fputcsv() to generate that CSV data for you? Or better yet, instead of making a .csv masquerade as an Excel file, you can use PHPExcel to output a native .xls/.xlsx and actually use formatting and formulae in the generated spreadsheet.
first of all, use echo instead of print. Print causes loads of overhead as it does both return and echo the data.
Secondly, don't put the variables within quotes, use
echo $header ."\n".$data;
To get to your question, does the foreach loops actually loop? Have you checked the $data if it contains any data?
A better solution might be this:
$header = '';
echo $header;
foreach() loop here {
//echo the data here instead of putting it in a variable
}
Or maybe better, use http://nl.php.net/fputcsv
I tested your code and it seems that your trim() method is trimming your \n and \t.
If you remove it, your code should be fine.
Here's my code to export a array of product in excel.
Only one little problem with this code : Excel doesn't want to open it because of a format problem, but if you click "yes" when it promps an error message, you'll be ok...
No problem with open office though
Working on a fix...
$filename = "products_exports " . date("Y-m-d H_i_s") . ".xls";
/**
* Tell the browser to download an excel file.
*/
header("Content-Type: application/x-msdownload; charset=utf-8");
header("Content-Disposition: attachment; filename=\"$filename\"");
header("Pragma: no-cache");
header("Expires: 0");
/**
* The header of the table
* #var string
*/
$header = "";
/**
* All the data of the table in a formatted string
* #var string
*/
$data = "";
//We fill in the header
foreach ($productArray as $i => $product) {
$count = 0;
foreach ($product as $key => $value) {
if($count == count((array)new Product("")) - 1){
$header.= $key;
}
else{
$header.= $key . "\t";
$count++;
}
}
break; /*One loop is enough to get the header !*/
}
//And then the data by the product and all the categories
/*Where $productArray = This can be your custom array of object. eg.
array[0] = new YouCustomObject(your params...);
*/
foreach ($productArray as $i => $product) {
$count = 0;
foreach ($product as $key => $value) {
if($count == count((array)new Product("")) - 1){
$value = str_replace('"', '""', $value);
$value = '"' . $value . '"' . "\n";
$data .= $value;
$count = 0;
}
else{
$value = str_replace('"', '""', $value);
$value = '"' . $value . '"' . "\t";
$data .= $value;
$count++;
}
}
}
echo $header ."\n". $data;