I have been using stack overflow for a good couple of years but only now made an account because I have never become so stuck that I needed to ask a question (not because I'm smart, because my code is simple!), anyway on to my question;
I am exporting a table in .xls format via PHP with information from a few tables in my MYSQL table. all the information and styling works perfectly. The only problem is that when it opens in office 2007 i get this error message:
"the file you are trying to open, 'export.xls', is a different format than specified by the file extension. Verify that the file is not corrupted and is from a trusted source before opening the file. Are you sure you want to view this file?"
So to sum up, all information is pulled from DB successful and all the styling works - I know this to be true because when I click 'yes' on the dialog box that pops up I see everything laid-out perfectly.
Below is the Excel exporter class:
/**
* Class for generating xml with multiple spreadsheets
* #author Marin Crnković
* #version 0.9
* #update_date 21.01.2009
*/
class excel_xml {
var $xml_data;
var $nl;
var $tab;
var $cols;
var $rows;
var $worksheets;
var $counters;
var $xml;
/**
* Constructor
*/
function excel_xml(){
$this->column_width = 150;
$this->debug = false;
$this->cols = array();
$this->row_array = array();
$this->rows = array();
$this->worksheets = array();
$this->counters = array();
$this->nl = "\n";
$this->tab = "\t";
}
/**
* Set debug
*/
function debug() {
$this->debug = true;
}
/**
* Generate xml
* #returns string
*/
function generate() {
// Create header
$xml = $this->create_header().$this->nl;
// Put all worksheets
$xml .= join('', $this->worksheets).$this->nl;
// Finish with a footer
$xml .= $this->create_footer();
$this->xml = $xml;
return $this->xml;
}
/**
* Create worksheet
* Uppon creating a worksheet, delete counters
* #param string $worksheet_name: name of the worksheet
*/
function create_worksheet($worksheet_name) {
$worksheet = '<Worksheet ss:Name="'.$worksheet_name.'">';
$worksheet .= $this->create_table();
$worksheet .= '<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</Worksheet>';
// Unset the counters and rows so you can generate another worksheet table
$this->counters = array();
$this->row_array = array();
$this->rows = '';
// Add generated worksheet to the worksheets array
$this->worksheets[] = $worksheet;
}
/**
* Create table
* #returns string
*/
function create_table() {
// Create rows with the method that automaticaly sets counters for number of columns and rows
$rows = $this->create_rows();
// Table header
$table = '<Table ss:ExpandedColumnCount="'.$this->counters['cols'].'" ss:ExpandedRowCount="'.$this->counters['rows'].'" x:FullColumns="1" x:FullRows="1">'.$this->nl;
// Columns data (width mainly)
for($i = 1; $i <= $this->counters['cols']; $i++) {
$table .= '<Column ss:Index="'.$i.'" ss:Width="'.$this->column_width.'" />'.$this->nl;
}
// Insert all rows
$table .= join('', $rows);
// End table
$table .= '</Table>'.$this->nl;
return $table;
}
/**
* Add another row into the array
* #param mixed $array: array with row cells
* #param mixed $style: default null, if set, adds style to the array
*/
function add_row($array, $style = null) {
if(!is_array($array)) {
// Asume the delimiter is , or ;
$array = str_replace(',', ';', $array);
$array = explode(';', $array);
}
if(!is_null($style)) {
$style_array = array('attach_style' => $style);
$array = array_merge($array, $style_array);
}
$this->row_array[] = $array;
}
/**
* Create rows
* #returns array
*/
function create_rows() {
$row_array = $this->row_array;
if(!is_array($row_array)) return;
$cnt = 0;
$row_cell = array();
foreach($row_array as $row_data) {
$cnt++;
// See if there are styles attached
$style = null;
if($row_data['attach_style']) {
$style = $row_data['attach_style'];
unset($row_data['attach_style']);
}
// Store the counter of rows
$this->counters['rows'] = $cnt;
$cells = '';
$cell_cnt = 0;
foreach($row_data as $key => $cell_data) {
$cell_cnt++;
$cells .= $this->nl.$this->prepare_cell($cell_data, $style);
}
// Store the number of cells in row
$row_cell[$cnt][] = $cell_cnt;
$this->rows[] = '<Row>'.$cells.$this->nl.'</Row>'.$this->nl;
}
// Find out max cells in all rows
$max_cells = max($row_cell);
$this->counters['cols'] = $max_cells[0];
return $this->rows;
}
/**
* Prepare cell
* #param string $cell_data: string for a row cell
* #returns string
*/
function prepare_cell($cell_data, $style = null) {
$str = str_replace("\t", " ", $cell_data); // replace tabs with spaces
$str = str_replace("\r\n", "\n", $str); // replace windows-like new-lines with unix-like
$str = str_replace('"', '""', $str); // escape quotes so we support multiline cells now
preg_match('#\"\"#', $str) ? $str = '"'.$str.'"' : $str; // If there are double doublequotes, encapsulate str in doublequotes
// Formating: bold
if(!is_null($style)) {
$style = ' ss:StyleID="'.$style.'"';
} elseif (preg_match('/^\*([^\*]+)\*$/', $str, $out)) {
$style = ' ss:StyleID="bold"';
$str = $out[1];
}
if (preg_match('/\|([\d]+)$/', $str, $out)) {
$merge = ' ss:MergeAcross="'.$out[1].'"';
$str = str_replace($out[0], '', $str);
}
// Get type
$type = preg_match('/^([\d]+)$/', $str) ? 'Number' : 'String';
return '<Cell'.$style.$merge.'><Data ss:Type="'.$type.'">'.$str.'</Data></Cell>';
}
/**
* Create header
* #returns string
*/
function create_header() {
if (is_array($this->styles)) {
$styles = join('', $this->styles);
}
$header = <<<EOF
<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
<OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office">
<DownloadComponents/>
<LocationOfComponents HRef="file:///\\"/>
</OfficeDocumentSettings>
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
<WindowHeight>12525</WindowHeight>
<WindowWidth>15195</WindowWidth>
<WindowTopX>480</WindowTopX>
<WindowTopY>120</WindowTopY>
<ActiveSheet>0</ActiveSheet>
<ProtectStructure>False</ProtectStructure>
<ProtectWindows>False</ProtectWindows>
</ExcelWorkbook>
<Styles>
<Style ss:ID="Default" ss:Name="Normal">
<Alignment ss:Vertical="Bottom"/>
<Borders/>
<Font/>
<Interior/>
<NumberFormat/>
<Protection/>
</Style>
<Style ss:ID="bold">
<Font ss:Bold="1" />
</Style>
$styles
</Styles>
EOF;
return $header;
}
/**
* Add style to the header
* #param string $style_id: id of the style the cells will reference to
* #param array $parameters: array with parameters
*/
function add_style($style_id, $parameters) {
foreach($parameters as $param => $data) {
switch($param) {
case 'size':
$font['ss:Size'] = $data;
break;
case 'font':
$font['ss:FontName'] = $data;
break;
case 'color':
case 'colour':
$font['ss:Color'] = $data;
break;
case 'bgcolor':
$interior['ss:Color'] = $data;
break;
case 'bold':
$font['ss:Bold'] = $data;
break;
case 'italic':
$font['ss:Italic'] = $data;
break;
case 'strike':
$font['ss:StrikeThrough'] = $data;
break;
}
}
if(is_array($interior)) {
foreach($interior as $param => $value) {
$interiors .= ' '.$param.'="'.$value.'"';
}
$interior = '<Interior ss:Pattern="Solid"'.$interiors.' />'.$this->nl;
}
if(is_array($font)) {
foreach($font as $param => $value) {
$fonts .= ' '.$param.'="'.$value.'"';
}
$font = '<Font'.$fonts.' />'.$this->nl;
}
$this->styles[] = '
<Style ss:ID="'.$style_id.'">
'.$interior.$font.'
</Style>';
}
/**
* Create footer
* #returns string
*/
function create_footer() {
return '</Workbook>';
}
/**
* Output as download
*/
function download($filename) {
if(!strlen($this->xml)) $this->generate();
header("Cache-Control: public, must-revalidate");
header("Pragma: no-cache");
header("Content-Length: " .strlen($this->xml) );
header("Content-Type: application/vnd.ms-excel");
if(!$this->debug){
header('Content-Disposition: attachment; filename="'.$filename.'"');
header("Content-Transfer-Encoding: binary");
} else {
header("Content-Type: text/plain");
}
print $this->xml;
exit;
}
}
And this is my implementation with sensitive information censored;
$excel = new excel_xml();
$header_style = array(
'bold' => 1,
'size' => '14',
'color' => '#FFFFFF',
'bgcolor' => '#4F81BD'
);
$excel->add_style('header', $header_style);
$header_style2 = array(
'bold' => 1,
'color' => '#FFFFFF',
'bgcolor' => '#92d050'
);
$excel->add_style('green', $header_style2);
$header_style3 = array(
'bold' => 1,
'color' => '#FFFFFF',
'bgcolor' => '#c00000'
);
$excel->add_style('error', $header_style3);
$header_style4 = array(
'bold' => 1,
'color' => '#FFFFFF',
'bgcolor' => '#e46d0a'
);
$excel->add_style('orange', $header_style4);
$header_style5 = array(
'bold' => 1,
'color' => '#FFFFFF',
'bgcolor' => '#c00000'
);
$excel->add_style('red', $header_style5);
/**
* Add row and attach the style "header" to it
*/
$excel->add_row(array(
'col1',
'col2',
'col3',
'col4',
'col5'
), 'header');
/**
* Add some rows, if you encapsulate the string inside asterisks,
* they will get bold using the predefined style "bold"
* If you append "|x" where x is a number, that cell will be
* merged with the x following cells
*/
$excel->add_row(array(
$Queried_Info_From_DB1,
$Queried_Info_From_DB2,
$Queried_Info_From_DB3,
$Queried_Info_From_DB4,
$Queried_Info_From_DB5
), 'red');
if(mysql_num_rows($result) == 0){
$excel->add_row(array(
'You have no info to display!|4'
), 'error');
}
/**
* Tell the object to create the worksheet.
* The passed string is the name of the worksheet
*/
$excel->create_worksheet('Your info');
/**
* If you invoke the generate method, you will get the
* XML returned or...
*/
$xml = $excel->generate();
/**
* ... you can pass the whole thing for download with
* the passed string as the filename
*/
$excel->download('Export');
You're writing a file that's spreadsheetML format, not BIFF (.xls) format, so MS Excel will complain at this discrepancy. Try saving it with a file extension of .xml (because that's what you're actually creating)
Related
I have a form that user can enter following
Shape = Round, Triangle, Square, Rectangle, Rhombus, Kite, Decagon
Color = Red, Black, Green, Yellow, Blue, White
Size = 1, 2, 3 … 11
And in the databases, there are multiple items with above characteristics
Example red color round with size 5 and another round with black color size 1 so on.
User can select just one or all 3 characteristics and submit the form and I want to show founded results.
Example: if user selected only color results should display all items from selected color no matter the shape or size. And if user select shape and color all items that have selected shape and color.
My question is how can create a query to do this?
Code that I try
if (!empty($_POST["shape"])):
$shape = trim($_POST["shape"]);
else:
$shape = "";
endif;
if (!empty($_POST["color"])):
$color = strtolower(trim($_POST["color"]));
else:
$color = "";
endif;
if (!empty($_POST["size"])):
$size = trim($_POST["size"]);
else:
$size = "";
endif;
SQL = SELECT * FROM items WHERE item_shape = $shape && item_color = $color && item_size = $size
Results always 0 unless I use only one WHERE clause it works like only shape and remove others from the command.
Also, I try changing like this
if (!empty($_POST["shape"])):
$shape = trim($_POST["shape"]);
else:
$shape = " Round, Triangle, Square, Rectangle, Rhombus, Kite, Decagon";
endif;
// changed all post parameters sane wat u did with shape
SQL = SELECT * FROM items WHERE item_shape in ($shape) && item_color in ($color) && item_size = ($size)
How can i achieve this? Appreciate your time.
You can try something like this:
// add as many features as you like to filter in this array
$features = array();
if (!empty($_POST["shape"])):
$features['shape'] = trim($_POST["shape"]);
endif;
if (!empty($_POST["color"])):
$features['color'] = strtolower(trim($_POST["color"]));
endif;
if (!empty($_POST["size"])):
$features['size'] = trim($_POST["size"]);
endif;
$sql = "SELECT * FROM items";
// if there is any feature in the array
if ( ! is_null($features))
{
$i = 0;
$len = count($features);
// check each one of the features
foreach ($features as $feature => $feature_value) {
if ($i == 0)
{
// if the first item, use WHERE
$sql .= ' WHERE ';
} else
{
// else, use &&
$sql .= ' && ';
}
$sql .= 'item_' . $feature . ' = ' . $feature_item;
$i++;
}
}
You could build a dynamic query, mapping the columns names of database with the names sent by form. After use a foreach to check if every element has or not a value if positive create a new element in $new. At last make the WHERE clause with implode() it will glue which element of array with AND key-word.
$fakePost = array('Shape' => '', 'Color' => '', 'Size' =>'2');
$fieldsName = ['Shape' => 'shape_list', 'Round' => 'round_list', 'Size' => 'size_list', 'Color' => 'color_list'];
$new = [];
foreach($fakePost as $k => $v){
if(!empty($v)){
$new[] = $fieldsName[$k] . " = '$v'";
}
}
if(!empty($new)){
echo ' WHERE '. implode(' AND ', $new);
}else{
echo 'please select some value';
}
Output:
WHERE size_list = '2'
or:
WHERE shape_list = 'green' AND size_list = '2'
As i understand your problem below query will give the exact result what you want
$shape = $_POST['shape'])??trim($_POST['shape']) ;
$color = $_POST['color'])??trim($_POST['color']) ;
$size = $_POST['color'])??trim($_POST['color']) ;
$where = array();
if (!empty($shape)) {
$shape_arr = explode(',', $shape);
$temp_shape = '';
foreach ($shape_arr as $key => $value) {
$temp_shape .= "'".$value."',";
}
$temp_shape = rtrim($temp_shape,',');
$where[] = " item_shape IN(".$temp_shape.") ";
}
if (!empty($color)) {
$color_arr = explode(',', $color);
$temp_color = '';
foreach ($color_arr as $key => $value) {
$temp_color .= "'".$value."',";
}
$temp_color = rtrim($temp_color,',');
$where[] = " item_color IN(".$temp_color.") ";
}
if (!empty($size)) {
$where[] = " item_size IN(".$size.") ";
}
$sql = "SELECT * FROM items ";
if(count($where)>0){
$sql .= " WHERE ". implode(" AND ", $where) ;
}
Here would be my version:
getItems.php: Fetch the posted values and call a function for fetching the items based on them (getItems()).
itemsFunctions.php: All functions for handling items could be found in a separate file for reuse.
getItems.php
<?php
require_once 'itemsFunctions.php';
$shape = isset($_POST['shape']) ? trim($_POST['shape']) : '';
$color = isset($_POST['color']) ? strtolower(trim($_POST['color'])) : '';
$size = isset($_POST['size']) ? trim($_POST['size']) : 0;
// Get items.
$items = getItems($shape, $color, $size);
// Do something with the fetched items
// (like display them in a table/grid).
itemsFunctions.php
/**
* Fetch items from items table.
*
* #param string $shape [optional] Item shape.
* #param string $color [optional] Item color.
* #param integer $size [optional] Item size.
* #return array Fetched items.
*/
function getItems($shape = '', $color = '', $size = 0) {
// Array containing the WHERE conditions.
$where = array();
// Add WHERE conditions to array based on the given values.
if (!empty($shape)) {
$where[] = 'item_shape = ' . $shape;
}
if (!empty($color)) {
$where[] = 'item_color = ' . $color;
}
if ($size > 0) {
$where[] = 'item_size = ' . $size;
}
// Build the sql statement.
$sql = sprintf('SELECT * FROM items %s'
, count($where) > 0 ? ' WHERE ' . implode(' AND ', $where) : ''
);
// Run query for fetching items by using the sql statement...
// Fetched items as array.
$items = array(
array(
'item_shape' => 'round',
'item_color' => 'red',
'item_size' => '45',
),
array(
'item_shape' => 'square',
'item_color' => 'blue',
'item_size' => '1258',
),
);
return $items;
}
/**
* Add item to items table.
*
* #param string $shape [optional] Item shape.
* #param string $color [optional] Item color.
* #param integer $size [optional] Item size.
* #return integer Last insert id.
*/
function addItem($shape = '', $color = '', $size = 0) {
//...
}
/**
* Update item in items table.
*
* #param integer $id Item ID.
* #param string $shape [optional] Item shape.
* #param string $color [optional] Item color.
* #param integer $size [optional] Item size.
* #return bool TRUE if updated, FALSE otherwise.
*/
function updateItem($id, $shape = '', $color = '', $size = 0) {
// Validate item ID...
//...
}
/**
* Remove item from items table.
*
* #param integer $id Item ID.
* #return bool TRUE if deleted, FALSE otherwise.
*/
function deleteItem($id) {
// Validate item ID...
//...
}
Notes:
Size should be integer.
I used the function sprintf(). It prints as echo() but it
allows the use of placeholders (%s) as well. I use it a lot in
building complex sql statements.
Recommendation: Use prepared statements in your PHP codes in order to avoid MySQL injection.
Good luck!
I am working on exporting data from a MySQL database into an Excel spreadsheet. I have found code for doing this before and it works quite well. It does not format the spreadsheet. It was also the first PHP/MySQL site I created and the data didn't need to be pretty. The current project requires formatted data.
Yesterday, I found an article that may have allowed me to do what I need to do. Like an idiot, I didn't copy the link down. I can't find it today.
Here's my code -
<?php
require_once("includes/connection.php");
require_once("includes/functions.php");
// set $closed to 0 for development
$closed = 0;
//create a sting to allow the user to see if s/he is looking at open or closed items
if ($closed) {
$filename = FILENAME."_closed";
} else {
$filename = FILENAME."_open";
}
// $data will hold the result
$data = '<table>';
// is the row a header?
$th = FALSE;
// define the separator character
$sep = '\t';
// array for keys
$thKey = array();
// are we in the first row?
$firstRow = TRUE;
// create the query
$query = "SELECT ";
$query .= "training_requirements.Training, mechanism.mechName, location.locationName, impacted_employees.groupName, ";
$query .= "training_requirements.DateReceived, training_requirements.DateStart, training_requirements.DateDue, ";
$query .= "requester.lastName, requester.firstName, impact.impactName, training_requirements.TimeNeeded, ";
$query .= "priority.priority, training_requirements.Notes ";
$query .= "FROM ";
$query .= "training_requirements, impact, impacted_employees, location, mechanism, requester, priority ";
$query .= "WHERE impact.impactId = training_requirements.impactId ";
$query .= "AND impacted_employees.groupId = training_requirements.impEmpId ";
$query .= "AND location.locationId = training_requirements.trainLocId ";
$query .= "AND mechanism.mechId = training_requirements.mechId ";
$query .= "AND requester.requesterId = training_requirements.requesterId ";
$query .= "AND priority.id = training_requirements.Priority ";
$query .= "AND training_requirements.Closed = $closed ";
$query .= "AND training_requirements.Deleted = 0";
// run the query
$result = executeQuery($connection, $query);
// process the query
if (mysqli_num_rows($result) > 0) {
while ($resource = mysqli_fetch_assoc($result)) {
if (empty($thKey)) {
foreach($resource as $key => $value) {
$thKey[] = $key;
}
}
$data .= '<tr>';
for ($i = 0; $i < count($resource); $i++) {
if ($firstRow) {
// create the header
for ($j = 0; $j < count($resource); $j++) {
$data .= '<th>';
$data .= $thKey[$j];
$data .= '</th>';
}
$data .= '</tr><tr>';
$firstRow = FALSE;
}
$data .= '<td>';
if (isset($resource[$thKey[$i]])) {
$data .= $resource[$thKey[$i]];
} else {
$data .= ' ';
}
$data .= '</td>';
}
$data .= '</tr>';
}
$data .= '</table>';
echo $data;
}
//header('Content-type: application/excel');
//header("Content-Disposition: attachment; filename={$filename}.xls");
//header("Pragma: no-cache");
//header("Expires: 0");
?>
The code continues on to allow me to display the results in a browser. I get a proper looking table in Firefox. When I un-comment the header statements at the bottom, I get a blank Excel file. No cells, no nothing.
Using Excel 2007(12.0.6715.5000) SP3 MSO (12.0.6721.5000), PHP 5.4.24, and MySQL 5.5.40. Using plugins and libraries is not an option.
Vern
your code is just fech data from MySQL and not make any excel file .
here you are a great class for making execl file
with pure XML code without any extension
<?php
/********************************/
/* Code By Mr Korosh Raoufi */
/* WwW.k2-4u.CoM */
/********************************/
/**
* Simple excel generating from PHP5
*
* #package Utilities
* #license http://www.opensource.org/licenses/mit-license.php
* #author Oliver Schwarz <oliver.schwarz#gmail.com>
* #version 1.0
*/
/**
* Generating excel documents on-the-fly from PHP5
*
* Uses the excel XML-specification to generate a native
* XML document, readable/processable by excel.
*
* #package Utilities
* #subpackage Excel
* #author Oliver Schwarz <oliver.schwarz#vaicon.de>
* #version 1.1
*
* #todo Issue #4: Internet Explorer 7 does not work well with the given header
* #todo Add option to give out first line as header (bold text)
* #todo Add option to give out last line as footer (bold text)
* #todo Add option to write to file
*/
class Excel_XML
{
/**
* Header (of document)
* #var string
*/
private $header = "<?xml version=\"1.0\" encoding=\"%s\"?\>\n<Workbook xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\" xmlns:x=\"urn:schemas-microsoft-com:office:excel\" xmlns:ss=\"urn:schemas-microsoft-com:office:spreadsheet\" xmlns:html=\"http://www.w3.org/TR/REC-html40\">";
/**
* Footer (of document)
* #var string
*/
private $footer = "</Workbook>";
/**
* Lines to output in the excel document
* #var array
*/
private $lines = array();
/**
* Used encoding
* #var string
*/
private $sEncoding;
/**
* Convert variable types
* #var boolean
*/
private $bConvertTypes;
/**
* Worksheet title
* #var string
*/
private $sWorksheetTitle;
/**
* Constructor
*
* The constructor allows the setting of some additional
* parameters so that the library may be configured to
* one's needs.
*
* On converting types:
* When set to true, the library tries to identify the type of
* the variable value and set the field specification for Excel
* accordingly. Be careful with article numbers or postcodes
* starting with a '0' (zero)!
*
* #param string $sEncoding Encoding to be used (defaults to UTF-8)
* #param boolean $bConvertTypes Convert variables to field specification
* #param string $sWorksheetTitle Title for the worksheet
*/
public function __construct($sEncoding = 'UTF-8', $bConvertTypes = false, $sWorksheetTitle = 'Table1')
{
$this->bConvertTypes = $bConvertTypes;
$this->setEncoding($sEncoding);
$this->setWorksheetTitle($sWorksheetTitle);
}
/**
* Set encoding
* #param string Encoding type to set
*/
public function setEncoding($sEncoding)
{
$this->sEncoding = $sEncoding;
}
/**
* Set worksheet title
*
* Strips out not allowed characters and trims the
* title to a maximum length of 31.
*
* #param string $title Title for worksheet
*/
public function setWorksheetTitle ($title)
{
$title = preg_replace ("/[\\\|:|\/|\?|\*|\[|\]]/", "", $title);
$title = substr ($title, 0, 31);
$this->sWorksheetTitle = $title;
}
/**
* Add row
*
* Adds a single row to the document. If set to true, self::bConvertTypes
* checks the type of variable and returns the specific field settings
* for the cell.
*
* #param array $array One-dimensional array with row content
*/
private function addRow ($array)
{
$cells = "";
foreach ($array as $k => $v):
$type = 'String';
if ($this->bConvertTypes === true && is_numeric($v)):
$type = 'Number';
endif;
$v = htmlentities($v, ENT_COMPAT, $this->sEncoding);
$cells .= "<Cell><Data ss:Type=\"$type\">" . $v . "</Data></Cell>\n";
endforeach;
$this->lines[] = "<Row>\n" . $cells . "</Row>\n";
}
/**
* Add an array to the document
* #param array 2-dimensional array
*/
public function addArray ($array)
{
foreach ($array as $k => $v)
$this->addRow ($v);
}
/**
* Generate the excel file
* #param string $filename Name of excel file to generate (...xls)
*/
public function generateXML ($filename = 'excel-export')
{
// correct/validate filename
$filename = preg_replace('/[^aA-zZ0-9\_\-]/', '', $filename);
// deliver header (as recommended in php manual)
header("Content-Type: application/vnd.ms-excel; charset=" . $this->sEncoding);
header("Content-Disposition: inline; filename=\"" . $filename . ".xls\"");
// print out document to the browser
// need to use stripslashes for the damn ">"
echo stripslashes (sprintf($this->header, $this->sEncoding));
echo "\n<Worksheet ss:Name=\"" . $this->sWorksheetTitle . "\">\n<Table>\n";
foreach ($this->lines as $line)
echo $line;
echo "</Table>\n</Worksheet>\n";
echo $this->footer;
}
}
?>
usage:
$xls = new Excel_XML('UTF-8', false, 'title text');
$data = array(
1 => array ('column1 text', 'coloumn2 text'),
1 => array ('column1 text', 'coloumn2 text'),
1 => array ('column1 text', 'coloumn2 text'),
);
$xls -> addArray($data);
$xls -> generateXML('file Name'); // its print code to browser use requred header to download
I am using (trying to use) PHPExcel to pass an array to excel, I have defined the headings and i want every array in the array to in a separate row.
However, this only puts the headings in the excel file and not the data from the array. What am i doing wrong?How can I get this to work?
Script:
<?php
$databasehost = "localhost";
$databasename = "dummydata";
$databasetable = "import1";
$databasetable2 = "data1";
$databaseusername ="dummydata";
$databasepassword = "dummydata";
$con = #mysql_connect($databasehost,$databaseusername,$databasepassword) or die(mysql_error());
#mysql_select_db($databasename) or die(mysql_error());
$query = mysql_query("SELECT * from $databasetable;");
$data = array();
$index = 0;
while($row = mysql_fetch_assoc($query))
{
$data[$index] = $row;
$index++;
}
foreach ($data as $key) {
$url = 'http://maps.googleapis.com/maps/api/geocode/json?latlng='.$key['latitude'].','.$key['longitude'].'&sensor=true';
$json = file_get_contents($url);
$dataReceived = json_decode($json, TRUE);
//echo '<pre>'; print_r($dataReceived['results']); echo '</pre>';
$compiled = array();
$index = 0;
foreach ($dataReceived['results'] as $value) {
$compiled[$index] = array(
'ref' => $key['id']);
foreach ($value['address_components'] as $value2)
{
$compiled[$index][$value2['types'][0]] = $value2['long_name'];
}
$index++;
}
$sortedData = array();
$index = 0;
foreach ($compiled as $value) {
//echo '<pre>'; print_r($value); echo '</pre>';
$sortedData[$index] = array(
'ref' => $value['ref'],
'lat' => $key['latitude'],
'long' => $key['longitude'],
'route' => $value['route'],
'locality' => $value['locality'],
'administrative_area_level_2' => $value['administrative_area_level_2'],
'administrative_area_level_1' => $value['administrative_area_level_1'],
'country' => $value['country'],
'postal_code_prefix' => $value['postal_code_prefix'],
'postal_town' => $value['postal_town'],
'postal_code' => $value['postal_code'],
'administrative_area_level_3' => $value['administrative_area_level_3'],
'street_number' => $value['street_number'],
'establishment' => $value['establishment'],
);
$index++;
}
echo '<pre>';print_r($sortedData);echo "</pre>";
/*$query = mysql_query("INSERT INTO $databasetable2
ref, lat, long, route, locality, administrative_area_level_2, administrative_area_level_1, country, postal_code_prefix, postal_town)
VALUES
()");*/
}
#mysql_close($con);
/**
* PHPExcel
*
* Copyright (C) 2006 - 2011 PHPExcel
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* #category PHPExcel
* #package PHPExcel
* #copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
* #license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
* #version ##VERSION##, ##DATE##
*/
/** Error reporting */
error_reporting(E_ALL);
ini_set('display_errors', '1');
date_default_timezone_set('Europe/London');
/** PHPExcel */
require_once 'Classes/PHPExcel.php';
// Create new PHPExcel object
//echo date('H:i:s') . " Create new PHPExcel object\n";
$objPHPExcel = new PHPExcel();
// Set properties
//echo date('H:i:s') . " Set properties\n";
$objPHPExcel->getProperties()->setCreator("Anon")
->setLastModifiedBy("Anon")
->setTitle("Crawler Data");
// Add some data
//echo date('H:i:s') . " Add some data\n";
$objPHPExcel->setActiveSheetIndex(0)
->setCellValue('A1', 'ref')
->setCellValue('B1', 'latitude')
->setCellValue('C1', 'longitude')
->setCellValue('D1', 'route')
->setCellValue('E1', 'locality')
->setCellValue('F1', 'administrative_area_level_2')
->setCellValue('G1', 'administrative_area_level_1')
->setCellValue('H1', 'country')
->setCellValue('I1', 'postal_code_prefix')
->setCellValue('J1', 'postal_town')
->setCellValue('K1', 'postal_code')
->setCellValue('L1', 'administrative_area_level_3')
->setCellValue('M1', 'street_number')
->setCellValue('N1', 'establishment');
//$objPHPExcel->getActiveSheet()->fromArray($sortedData, null, 'A2');
// Set active sheet index to the first sheet, so Excel opens this as the first sheet
$objPHPExcel->setActiveSheetIndex(0);
// Save Excel 2007 file
//echo date('H:i:s') . " Write to Excel2007 format\n";
//!!!!!!!!!!!!!!!!!!!-------- I Change 'Excel2007' to 'Excel5' ------!!!!!!!!!!!!!!!!!!!!!!!!
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
//!!!!!!!!!!!!!!!!!!!-------- I Change '.xlsx' to '.xls' ------!!!!!!!!!!!!!!!!!!!!!!!!
$objWriter->save(str_replace('.php', '.xls', __FILE__));
// Echo memory peak usage
//echo date('H:i:s') . " Peak memory usage: " . (memory_get_peak_usage(true) / 1024 / 1024) . " MB\r\n";
// Echo done
//echo date('H:i:s') . " Done writing file.\r\n";
?>
file now looks like:
<?php
require_once 'Classes/PHPExcel.php';
date_default_timezone_set('Europe/London');
$databasehost = "localhost";
$databasename = "ryansmur_crawler";
$databasetable = "import1";
$databasetable2 = "data1";
$databaseusername ="ryansmur_admin";
$databasepassword = "Penelope1";
$con = #mysql_connect($databasehost,$databaseusername,$databasepassword) or die(mysql_error());
#mysql_select_db($databasename) or die(mysql_error());
$query = mysql_query("SELECT * from $databasetable;");
$data = array();
$index = 0;
while($row = mysql_fetch_assoc($query))
{
$data[$index] = $row;
$index++;
}
$headers = array(
'ref', 'lat', 'long', 'route', 'locality', 'administrative_area_level_2',
'administrative_area_level_1', 'country', 'postal_code_prefix',
'postal_town', 'postal_code', 'administrative_area_level_3',
'street_number', 'establishment',
);
$addRowCreate = function(PHPExcel_Worksheet $sheet, $col = 'A', $row = NULL) {
return function(array $data) use ($sheet, $col, &$row) {
if ($row === NULL) {
$row = $sheet->getHighestRow() + 1;
}
$sheet->fromArray(array($data), NULL, "$col$row");
$row++;
};
};
$doc = new PHPExcel();
$doc->getProperties()->setCreator("Anon")
->setLastModifiedBy("Anon")
->setTitle("Crawler Data");
$sheet = $doc->setActiveSheetIndex(0);
$sheet->fromArray($headers);
$addRow = $addRowCreate($sheet);
foreach ($data as $key) {
$url = 'http://maps.googleapis.com/maps/api/geocode/json?latlng='.$key['latitude'].','.$key['longitude'].'&sensor=true';
$json = file_get_contents($url);
$dataReceived = json_decode($json, TRUE);
$compiled = array();
$index = 0;
foreach ($dataReceived['results'] as $value) {
$compiled[$index] = array(
'ref' => $key['id']);
foreach ($value['address_components'] as $value2)
{
$compiled[$index][$value2['types'][0]] = $value2['long_name'];
}
$index++;
}
$sortedData = array();
$index = 0;
foreach ($compiled as $value) {
$addRow(array(
'ref' => $value['ref'],
'lat' => $key['latitude'],
'long' => $key['longitude'],
'route' => $value['route'],
'locality' => $value['locality'],
'administrative_area_level_2' => $value['administrative_area_level_2'],
'administrative_area_level_1' => $value['administrative_area_level_1'],
'country' => $value['country'],
'postal_code_prefix' => $value['postal_code_prefix'],
'postal_town' => $value['postal_town'],
'postal_code' => $value['postal_code'],
'administrative_area_level_3' => $value['administrative_area_level_3'],
'street_number' => $value['street_number'],
'establishment' => $value['establishment'],
));
$index++;
}
}
#mysql_close($con);
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
$objWriter->save(str_replace('.php', '.xls', __FILE__));
echo date('H:i:s') . " Done writing file.\r\n";
?>
Just re-reading your code and it looks rather chaotic. I think it can be improved in many areas, however with the least changes I suggest you do the following:
Instead of first creating multiple arrays of rows you want to add, add a new row each time you have created it. For that you do not even need to name the keys. So before you iterate through the database results, first create the headers (I named it $headers):
$headers = array(
'ref', 'lat', 'long', 'route', 'locality', 'administrative_area_level_2',
'administrative_area_level_1', 'country', 'postal_code_prefix',
'postal_town', 'postal_code', 'administrative_area_level_3',
'street_number', 'establishment',
);
Also before the database iteration, create a helper-function:
$addRowCreate = function(PHPExcel_Worksheet $sheet, $col = 'A', $row = NULL) {
return function(array $data) use ($sheet, $col, &$row) {
if ($row === NULL) {
$row = $sheet->getHighestRow() + 1;
}
$sheet->fromArray(array($data), NULL, "$col$row");
$row++;
};
};
This $addRowCreate helper function will allow you to create a add-row-function later on, like in just a second. Also before the database iteration, create the excel document (memory) and set it's properties. Also add the headers in the first row:
$doc = new PHPExcel();
$doc->getProperties()->setCreator("Anon")
->setLastModifiedBy("Anon")
->setTitle("Crawler Data");
$sheet = $doc->setActiveSheetIndex(0);
$sheet->fromArray($headers);
The next step is to create the add-row-function, which is very easy thanks to the helper above:
$addRow = $addRowCreate($sheet);
You now can use one row after the other by calling it once per row array. For testing purposes, just add another row and save it to disk:
$addRow($headers);
$writer = PHPExcel_IOFactory::createWriter($doc, 'Excel5');
$writer->save(basename(__FILE__, '.php') . '.xls');
die('test finished.');
You should now have create the xls file with two rows. You can then remove the test again and inside your loops use the $addRow function:
$addRow(array(
'ref' => $value['ref'],
'lat' => $key['latitude'],
'long' => $key['longitude'],
'route' => $value['route'],
'locality' => $value['locality'],
'administrative_area_level_2' => $value['administrative_area_level_2'],
'administrative_area_level_1' => $value['administrative_area_level_1'],
'country' => $value['country'],
'postal_code_prefix' => $value['postal_code_prefix'],
'postal_town' => $value['postal_town'],
'postal_code' => $value['postal_code'],
'administrative_area_level_3' => $value['administrative_area_level_3'],
'street_number' => $value['street_number'],
'establishment' => $value['establishment'],
));
Technically you can remove the string-array-keys, however I've kept them in so that you can better find the place where you need to change your code as the array already exists there-in.
After you've put this to the work, you can safely remove all the not-any-more-needed temporary arrays and counters.
The full usage-example (test):
require_once 'Classes/PHPExcel.php'; /* PHPExcel <http://phpexcel.codeplex.com/> */
$headers = array(
'ref', 'lat', 'long', 'route', 'locality', 'administrative_area_level_2',
'administrative_area_level_1', 'country', 'postal_code_prefix',
'postal_town', 'postal_code', 'administrative_area_level_3',
'street_number', 'establishment',
);
$addRowCreate = function(PHPExcel_Worksheet $sheet, $col = 'A', $row = NULL) {
return function(array $data) use ($sheet, $col, &$row) {
if ($row === NULL) {
$row = $sheet->getHighestRow() + 1;
}
$sheet->fromArray(array($data), NULL, "$col$row");
$row++;
};
};
$doc = new PHPExcel();
$doc->getProperties()->setCreator("Anon")
->setLastModifiedBy("Anon")
->setTitle("Crawler Data");
$sheet = $doc->setActiveSheetIndex(0);
$sheet->fromArray($headers);
$addRow = $addRowCreate($sheet);
$addRow($headers);
$writer = PHPExcel_IOFactory::createWriter($doc, 'Excel5');
$writer->save(basename(__FILE__, '.php') . '.xls');
die('test finished.');
Old Answer:
However, this only puts the headings in the excel file and not the data from the array. What am i doing wrong?
You are actually only storing the headings into the file. You do not store any data.
How can I get this to work?
Bring the array in the right format and uncomment the following line in your code:
//$objPHPExcel->getActiveSheet()->fromArray($sortedData, null, 'A2');
Take care that $sortedData is the needed 2D array, see the examples in this dicsussion:
Array
(
[0] => Array
(
[0] => Relative CellA1
[1] => Relative CellB1
[2] => Relative CellC1
)
[1] => Array
(
[0] => Relative CellA2
[1] => Relative CellB2
[2] => Relative CellC2
)
)
Unless you don't get the array into that kind of 2D format, the function will not work in your favor.
Please let me know if you've got any more questions.
PHPExcel write data to the cell and you must define it position. Just like then you define headers. The principle is that you fill out the document line by line.
So I write example code to show the idea
$alphas = range('A', 'Z'); // A, B, C, D, E...
$sheet = $excel->getActiveSheet();
//headers
$sheet
->setCellValue($alphas[0].'1', 'Title1')
->setCellValue($alphas[1].'1', 'Title2')
->setCellValue($alphas[2].'1', 'Title3')
->setCellValue($alphas[3].'1', 'Title4')
;
$sheet->getColumnDimension($alphas[0])->setWidth(40);
$sheet->getColumnDimension($alphas[1])->setWidth(9);
$sheet->getColumnDimension($alphas[2])->setWidth(60);
$sheet->getColumnDimension($alphas[3])->setWidth(30);
$items = ...;// <--- your data
$row_num = 2; // start from 2 row
foreach($items as $item) {
$sheet->setCellValue($alphas[0].$row_num, $item['key1']);
$sheet->setCellValue($alphas[1].$row_num, $item['key2']);
$sheet->setCellValue($alphas[2].$row_num, $item['key3']);
$sheet->setCellValue($alphas[3].$row_num, $item['key4']);
$row_num++;
}
You can create a generic function to get excel content from any 2D arrays.
PHP array2xlsx function
/**
* This function returns xlsx content from an associative array.
*
* Warning: one cell = about 1k memory, so this function does not work
* if your array is too large.
*
* #param array $array
* #param string $title
* #param string $author
* #return string
*/
function array2xlsx(array &$array, $title = 'New Document', $author = null)
{
// Basic checks
if (count($array) == 0)
{
return null;
}
// Putting meta-data into a new excel file
$ex = new PHPExcel();
$ex->getProperties()->setLastModifiedBy($title);
$ex->getProperties()->setTitle($title);
$ex->getProperties()->setSubject($title);
$ex->getProperties()->setDescription($title);
$ex->getProperties()->setCreator($author);
// Select first page on the excel document
$ex->setActiveSheetIndex(0);
$sheet = $ex->getActiveSheet();
// Writes column titles on row 1 (assuming column names are array keys)
$column_names = array_keys(reset($array));
foreach ($column_names as $column_number => $column_name)
{
$azNumber = PHPExcel_Cell::stringFromColumnIndex($column_number);
$sheet->SetCellValue($azNumber . "1", $column_name);
}
// Writes document content
foreach ($array as $row_number => $row)
{
foreach (array_values($row) as $column_number => $cell_content)
{
// Converts column numbers to alphabetic numbering
$azNumber = PHPExcel_Cell::stringFromColumnIndex($column_number);
$sheet->SetCellValue($azNumber . ($row_number + 2), $cell_content);
}
}
// Creates file contents
$writer = new PHPExcel_Writer_Excel2007($ex);
ob_start();
$writer->save("php://output");
$content = ob_get_contents();
ob_end_clean();
return $content;
}
And send it directly to your user, by sending proper headers.
PHP download_send_header function
function download_send_headers($filename) {
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header("Content-Disposition: attachment;filename={$filename}");
header("Content-Transfer-Encoding: binary");
}
PHP Usage example
// We simulate your array
$array = array();
for ($i = 0; ($i < 50); $i++)
{
$array[$i] = array(
'ref' => "ref {$i}",
'lat' => "lat {$i}",
'long' => "long {$i}",
'route' => "route {$i}",
'locality' => "locality {$i}",
'administrative_area_level_2' => "administrative area level 2 {$i}",
'administrative_area_level_1' => "administrative area level 1 {$i}",
'country' => "country {$i}",
'postal_code_prefix' => "postal_code_prefix {$i}",
'postal_town' => "postal_town {$i}",
'postal_code' => "postal code {$i}",
'administrative_area_level_3' => "administrative area level 3 {$i}",
'street_number' => "street number {$i}",
'establishment' => "establishment {$i}",
);
}
// We send headers and excel content from your array
download_send_headers("my_test.xlsx");
echo array2xlsx($array);
Result
I have a function that updates fine with a single dimensional array, but with a multidimensional array (or nested array) it will not update. the document data, the BSONfield (acts as the find key), and the collection are imputed. Any Idea what i am doing wrong?
Public Static function updateDocument($collection, $BSONfield, $document){
$dbcollection = $db->selectCollection($collection);
$sdata = $document[$BSONfield];
$secureInnerDocument = array();
$secureDocument = array();
if($BSONfield == "_id"){
$sdata = new MongoID($sdata);
unset($document["_id"]);
}
$filter = array($BSONfield=>$sdata);
foreach ($document as $k => $v) {
if (is_array($v)) {
foreach ($v as $sk => $sv) {
$secureInnerDocument[$sk] = Security::secureQuery($sv);
}
$secureDocument[$k] = $secureInnerDocument;
}else{
$secureDocument[$k] = Security::secureQuery($v);
}
}
$dbcollection->update($filter,array('$set'=>$secureDocument));
$objid = (string) $secureDocument['_id'];
return $objid;
}
It translates fairly directly:
db.collection.update(
{fieldNameFilter:'filterValue'},
{$set: {'stringFieldName' : 'newValue'}}
);
Translates to:
$collection->update(
array('fieldNameFilter'=>'filterValue'),
array($set => array('stringFieldName'=>$value))
);
Then there are some flags for multi-row updates, etc. which I'm not showing here, but which are in the PHP and Mongo docs.
You might also want to look at: MongoDB - help with a PHP query
So after fiddling around with is my solution ended up being kind of janky, I deleted the Document then re-create it. Here is the code in case anyone is looking:
/**
* updates document in the collection.
* This function secures the data
*
* #return object ID
* #param string $collection The name of the collection
* #param string $BSONfield The $BSON Field you want to index by
* #param string $document The document contents as an array
*/
Public Static function updateDocument($collection, $BSONfield, $document){
$db = Database::dbConnect();
$collection = Security::secureQuery($collection);
$BSONfield = Security::secureQuery($BSONfield);
$dbcollection = $db->selectCollection($collection);
if(array_key_exists('_id', $document)){
$document["_id"] = new MongoID($document["_id"]);
}
Database::deleteDocument($collection, $BSONfield, $document);
$objid = Database::createDocument($collection, $document);
return $objid;
}
/**
* Deletes a document in the collection.
* This function secures the data
*
* #return Boolean True - if successfully deleted, False if document not found
* #param string $collection The name of the collection
* #param string $BSONfield The $BSON Field you want to index by
* #param string $document The document contents as an array
*/
Public Static function deleteDocument($collection, $BSONfield, $document){
$db = Database::dbConnect();
$collection = Security::secureQuery($collection);
$BSONfield = Security::secureQuery($BSONfield);
$exists = False;
$dbcollection = $db->selectCollection($collection);
$documentList = $dbcollection->find();
$sdata = $document[$BSONfield];
if($BSONfield == "_id"){
$sdata = new MongoID($sdata);
}
foreach ($documentList as $doc) {
$documentID = $doc[$BSONfield];
if ($documentID == $sdata){
$exists = True;
}
}
if ($exists){
$deleted = True;
$filter = array($BSONfield=>$sdata);
$dbcollection->remove($filter,true);
}else{
$deleted = False;
}
return $deleted;
}
/**
* Inserts document into the collection.
* This function secures the data
*
* #return object ID.
* #param string $collection The name of the collection
* #param string $document The document contents as an array
*/
Public Static function createDocument($collection, $document){
$db = Database::dbConnect();
$collection = Security::secureQuery($collection);
$dbcollection = $db->selectCollection($collection);
$secureDocument = array();
$secureInnerDocument = array();
foreach ($document as $k => $v) {
if (is_array($v)) {
foreach ($v as $sk => $sv) {
$secureInnerDocument[$sk] = Security::secureQuery($sv);
}
$secureDocument[$k] = $secureInnerDocument;
}else{
if ($k == '_id'){
$secureDocument[$k] = $v;
}else{
$secureDocument[$k] = Security::secureQuery($v);
}
}
}
$dbcollection->insert($secureDocument);
$objid = (string) $secureDocument['_id'];
return $objid;
}
and how i am securing all the data from injections:
/**
* Secures string to be inputed into a database.
*
* #return Retuns secure string
* #param String $string String to be secured
*/
Public Static Function secureQuery($string){
$secureString = strtr($string, array(
"'" => "0x27",
"\"" => "0x22",
"\\" => "0x5C",
"<" => "0x3C",
">" => "0x3E",
"=" => "0x3D",
"+" => "0x2B",
"&" => "0x26",
"{" => "0x7B",
"}" => "0x7D",
));
return $secureString;
}
/**
* Un-Secures string to be inputed into a database.
*
* #return Retuns unsecure string
* #param String $string String to be un-secured
*/
Public Static Function unsecureQuery($string){
$secureString = strtr($string, array(
"0x27" => "'",
"0x22" => "\"",
"0x5C" => "\\",
"0x3C" => "<",
"0x3E" => ">",
"0x3D" => "=",
"0x2B" => "+",
"0x26" => "&",
"0x7B" => "{",
"0x7D" => "}",
));
return $secureString;
}
enjoy!
You don't seem to be using the $set operator correctly. As per the MongoDB docs, you need to format your update document like so;
{ $set : { field : value } }
If you're running a $set on nested keys, you need to use dot notation to get to them. For example;
{ $set : { field.nest : value } }
I am using this code to export selected data from MySQL to CSV using PHP, I am facing a little problem that when data exported to the csv file it looks like below:
First line in its correct place, but starting from the second row data shifts to the right one space, if I open the csv file in Excel, I can see the most left cell after the first row is empty.
parts destination
===================
1 9.71504E+11
1 9.71504E+11
1 96656587662
1 9.71504E+11
This is my code :
$values =mysql_query( "SELECT parts,destination from log");
$rown = 0;
$row = array();
$row[] = 'parts';
$row[] = 'destination'."\n";
$data .= join(',', $row)."\n";
while( $row_select = mysql_fetch_assoc($values) ) {
if($rown++==0)
$row = array();
$row[] = $row_select['parts'];
$row[] = $row_select['destination']."\n";
}
$data .= join(',', $row)."\n";
$filename = $file."_".date("Y-m-d_H-i",time());
header("Content-type: text/csv");
header("Content-disposition: csv" . date("Y-m-d") . ".csv");
header( "Content-disposition: filename=".$filename.".csv");
print $data;
exit();
Would you please help?
Regards,
First line in its correct place, but starting from the second row data shifts to the right one space, if I open the csv file in Excel, I can see the most left cell after the first row is empty.
I've found out the hard way that writing CSV is more complex than one would imagine. Take, for example, escaping the values so that the delimiter is properly escaped inside values. I've created a simple class that utilises fwritecsv( ) instead of trying to render CSV myself:
EDIT: I've changed the example to your usage scenario.
<?php
/**
* Simple class to write CSV files with.
*
* #author Berry Langerak <berry#ayavo.nl>
*/
class CsvWriter {
/**
* The delimiter used. Default is semi-colon, because Microsoft Excel is an asshole.
*
* #var string
*/
protected $delimiter = ";";
/**
* Enclose values in the following character, if necessary.
*
* #var string
*/
protected $enclosure = '"';
/**
* Constructs the CsvWriter.
*/
public function __construct( ) {
$this->buffer = fopen( 'php://temp', 'w+' );
}
/**
* Writes the values of $line to the CSV file.
*
* #param array $line
* #return CsvWriter $this
*/
public function write( array $line ) {
fputcsv( $this->buffer, $line, $this->delimiter, $this->enclosure );
return $this;
}
/**
* Returns the parsed CSV.
*
* #return string
*/
public function output( ) {
rewind( $this->buffer );
$output = $this->readBuffer( );
fclose( $this->buffer );
return $output;
}
/**
* Reads the buffer.
* #return type
*/
protected function readBuffer( ) {
$output = '';
while( ( $line = fgets( $this->buffer ) ) !== false ) {
$output .= $line;
}
return $output;
}
}
/**
* Example usage, in your scenario:
*/
$values = mysql_query( "SELECT parts,destination from log" );
$csv = new CsvWriter( );
$csv->write( array( 'parts', 'destination' ) ); // write header.
while( $line = mysql_fetch_assoc( $values ) ) {
$csv->write( $line );
}
$filename = $file."_".date("Y-m-d_H-i",time());
header("Content-type: text/csv");
header("Content-disposition: csv" . date("Y-m-d") . ".csv");
header( "Content-disposition: filename=".$filename.".csv");
print $csv->output( );
exit();
Like #ChrisPatrick points out, the line
$data .= join(',', $row)."\n";
is causing the problem, you should move this to inside the while loop and then you'll get rid of the cell skipping.
The problem is in the following line
$data .= join(',', $row)."\n";
You're concatenating all the elements in $row with commas. So the destination of one row is concatenated with the parts of the next row with a comma in between, so you get something like this:
$data = $row_select['parts'] . ',' . $row_select['destination']."\n" . ',' . $row_select['parts'] etc...
The comma after the newline creates an empty cell at the beginning of the row.
UPDATE It should work with the following
while( $row_select = mysql_fetch_assoc($values)){
$row = array();
$row[] = $row_select['parts'];
$row[] = $row_select['destination']."\n";
$data .= join(',', $row);
}