XLS (BIFF5) and HTM support
This commit is contained in:
parent
3dd4c4ecce
commit
de1d1c8397
@ -10,4 +10,6 @@ abstract class Type
|
||||
{
|
||||
const CSV = "csv";
|
||||
const XLSX = "xlsx";
|
||||
const XLS = "xls";
|
||||
const HTM = "htm";
|
||||
}
|
||||
|
103
src/Spout/Writer/HTM.php
Normal file
103
src/Spout/Writer/HTM.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace Box\Spout\Writer;
|
||||
|
||||
use Box\Spout\Common\Exception\IOException;
|
||||
|
||||
/**
|
||||
* Class HTM
|
||||
* This class provides support to write data to HTM files
|
||||
*
|
||||
* @package Box\Spout\Writer
|
||||
*/
|
||||
class HTM extends AbstractWriter
|
||||
{
|
||||
/** Number of rows to write before flushing */
|
||||
const FLUSH_THRESHOLD = 500;
|
||||
|
||||
/** @var string Content-Type value for the header */
|
||||
protected static $headerContentType = 'text/html; charset=UTF-8';
|
||||
|
||||
/** @var int */
|
||||
protected $lastWrittenRowIndex = 0;
|
||||
|
||||
/**
|
||||
* Opens the HTM streamer and makes it ready to accept data.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function openWriter()
|
||||
{
|
||||
fwrite($this->filePointer, "<html>\n");
|
||||
fwrite($this->filePointer, "<head>\n");
|
||||
fwrite($this->filePointer, "<title>" . htmlentities(basename(basename($this->outputFilePath, '.html'), '.htm')) . "</title>\n");
|
||||
fwrite($this->filePointer, "</head>\n");
|
||||
fwrite($this->filePointer, "<body>\n");
|
||||
fwrite($this->filePointer, "<table cellspacing=\"3\" cellpadding=\"3\" border=\"1\">\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds data to the currently opened writer.
|
||||
*
|
||||
* @param array $dataRow Array containing data to be written.
|
||||
* Example $dataRow = ['data1', 1234, null, '', 'data5'];
|
||||
* @return void
|
||||
* @throws \Box\Spout\Common\Exception\IOException If unable to write data
|
||||
*/
|
||||
protected function addRowToWriter(array $dataRow)
|
||||
{
|
||||
$wasWriteSuccessful = true;
|
||||
if ($this->lastWrittenRowIndex == 0) {
|
||||
$wasWriteSuccessful = $wasWriteSuccessful && fwrite($this->filePointer, "<thead>\n");
|
||||
}
|
||||
if ($this->lastWrittenRowIndex == 1) {
|
||||
$wasWriteSuccessful = $wasWriteSuccessful && fwrite($this->filePointer, "<tbody>\n");
|
||||
}
|
||||
$wasWriteSuccessful = $wasWriteSuccessful && fwrite($this->filePointer, "<tr>\n");
|
||||
foreach ($dataRow as $cell) {
|
||||
$cell = nl2br(htmlentities($cell));
|
||||
|
||||
if ($this->lastWrittenRowIndex == 0) {
|
||||
$wasWriteSuccessful = $wasWriteSuccessful && fwrite($this->filePointer, "\t<th>{$cell}</th>\n");
|
||||
} else
|
||||
{
|
||||
$wasWriteSuccessful = $wasWriteSuccessful && fwrite($this->filePointer, "\t<td>{$cell}</td>\n");
|
||||
}
|
||||
}
|
||||
$wasWriteSuccessful = $wasWriteSuccessful && fwrite($this->filePointer, "</tr>\n");
|
||||
if ($this->lastWrittenRowIndex == 0) {
|
||||
$wasWriteSuccessful = $wasWriteSuccessful && fwrite($this->filePointer, "</thead>\n");
|
||||
}
|
||||
|
||||
if ($wasWriteSuccessful === false) {
|
||||
throw new IOException('Unable to write data');
|
||||
}
|
||||
|
||||
$this->lastWrittenRowIndex++;
|
||||
if ($this->lastWrittenRowIndex % self::FLUSH_THRESHOLD === 0) {
|
||||
$this->globalFunctionsHelper->fflush($this->filePointer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the HTM streamer, preventing any additional writing.
|
||||
* If set, sets the headers and redirects output to the browser.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function closeWriter()
|
||||
{
|
||||
if ($this->filePointer) {
|
||||
if ($this->lastWrittenRowIndex >= 1) {
|
||||
fwrite($this->filePointer, "</tbody>\n");
|
||||
}
|
||||
fwrite($this->filePointer, "</table>\n");
|
||||
fwrite($this->filePointer, "</body>\n");
|
||||
fwrite($this->filePointer, "</html>\n");
|
||||
|
||||
$this->globalFunctionsHelper->fclose($this->filePointer);
|
||||
}
|
||||
|
||||
$this->lastWrittenRowIndex = 0;
|
||||
}
|
||||
}
|
@ -33,6 +33,12 @@ class WriterFactory
|
||||
case Type::XLSX:
|
||||
$writer = new XLSX();
|
||||
break;
|
||||
case Type::XLS:
|
||||
$writer = new XLS();
|
||||
break;
|
||||
case Type::HTM:
|
||||
$writer = new HTM();
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedTypeException('No writers supporting the given type: ' . $writerType);
|
||||
}
|
||||
|
193
src/Spout/Writer/XLS.php
Normal file
193
src/Spout/Writer/XLS.php
Normal file
@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
namespace Box\Spout\Writer;
|
||||
|
||||
use Box\Spout\Common\Exception\IOException;
|
||||
|
||||
// Based on https://gist.github.com/ihumanable/929039
|
||||
// ... with some bug fixes by Chris Graham, ocProducts.
|
||||
|
||||
/**
|
||||
* Class XLS
|
||||
* This class provides support to write data to XLS files
|
||||
*
|
||||
* @package Box\Spout\Writer
|
||||
*/
|
||||
class XLS extends AbstractWriter
|
||||
{
|
||||
/** Number of rows to write before flushing */
|
||||
const FLUSH_THRESHOLD = 500;
|
||||
|
||||
/** @var string Content-Type value for the header */
|
||||
protected static $headerContentType = 'application/vnd.ms-excel; charset=UTF-8';
|
||||
|
||||
/** @var int */
|
||||
private $col;
|
||||
|
||||
/** @var int */
|
||||
private $row;
|
||||
|
||||
/**
|
||||
* Opens the XLS streamer and makes it ready to accept data.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function openWriter()
|
||||
{
|
||||
$this->col = 0;
|
||||
$this->row = 0;
|
||||
$this->bofMarker();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the Excel Beginning of File marker
|
||||
*
|
||||
* @see pack()
|
||||
* @return nothing
|
||||
*/
|
||||
private function bofMarker()
|
||||
{
|
||||
fwrite($this->filePointer, pack("ssssss", 0x809, 0x8, 0x0, 0x10, 0x0, 0x0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves internal cursor all the way left, col = 0
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function home()
|
||||
{
|
||||
$this->col = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves internal cursor right by the amount specified
|
||||
*
|
||||
* @param optional integer $amount The amount to move right by, defaults to 1
|
||||
* @return integer The current column after the move
|
||||
*/
|
||||
function right($amount = 1)
|
||||
{
|
||||
$this->col += $amount;
|
||||
return $this->col;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves internal cursor down by amount
|
||||
*
|
||||
* @param optional integer $amount The amount to move down by, defaults to 1
|
||||
* @return integer The current row after the move
|
||||
*/
|
||||
function down($amount = 1)
|
||||
{
|
||||
$this->row += $amount;
|
||||
return $this->row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a number to the Excel Spreadsheet
|
||||
*
|
||||
* @see pack()
|
||||
* @param integer $value The value to write out
|
||||
* @return boolean Success status
|
||||
*/
|
||||
function number($value)
|
||||
{
|
||||
$wasWriteSuccessful = true;
|
||||
$wasWriteSuccessful = $wasWriteSuccessful && fwrite($this->filePointer, pack("sssss", 0x203, 14, $this->row, $this->col, 0x0));
|
||||
$wasWriteSuccessful = $wasWriteSuccessful && fwrite($this->filePointer, pack("d", $value));
|
||||
return $wasWriteSuccessful;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a string (or label) to the Excel Spreadsheet
|
||||
*
|
||||
* @see pack()
|
||||
* @param string $value The value to write out
|
||||
* @return boolean Success status
|
||||
*/
|
||||
function label($value)
|
||||
{
|
||||
$value = str_replace(array("\r\n", "\r"), "\n", $value);
|
||||
|
||||
// We're doing BIFF5, not BIFF8 - meaning a 255 char limit. If you want something good, use XLSX, else XLS for compatibility.
|
||||
if (strlen($value) >= 255) {
|
||||
$value = substr($value, 0, 255);
|
||||
}
|
||||
|
||||
$length = strlen($value);
|
||||
$wasWriteSuccessful = true;
|
||||
$wasWriteSuccessful = $wasWriteSuccessful && fwrite($this->filePointer, pack("ssssss", 0x204, 8 + $length, $this->row, $this->col, 0x0, $length));
|
||||
if ($value !='') {
|
||||
$wasWriteSuccessful = $wasWriteSuccessful && fwrite($this->filePointer, $value);
|
||||
}
|
||||
return $wasWriteSuccessful;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds data to the currently opened writer.
|
||||
*
|
||||
* @param array $dataRow Array containing data to be written.
|
||||
* Example $dataRow = ['data1', 1234, null, '', 'data5'];
|
||||
* @return void
|
||||
* @throws \Box\Spout\Common\Exception\IOException If unable to write data
|
||||
*/
|
||||
protected function addRowToWriter(array $dataRow)
|
||||
{
|
||||
if ($this->row == 65536) {
|
||||
// Hit the limit. You should have chosen XLSX
|
||||
return;
|
||||
}
|
||||
|
||||
$wasWriteSuccessful = true;
|
||||
|
||||
$this->home();
|
||||
foreach ($dataRow as $cell) {
|
||||
if (is_integer($cell)) {
|
||||
$wasWriteSuccessful = $wasWriteSuccessful && $this->number($cell);
|
||||
} else
|
||||
{
|
||||
$wasWriteSuccessful = $wasWriteSuccessful && $this->label($cell);
|
||||
}
|
||||
$this->right();
|
||||
}
|
||||
$this->down();
|
||||
|
||||
if ($wasWriteSuccessful === false) {
|
||||
throw new IOException('Unable to write data');
|
||||
}
|
||||
|
||||
if ($this->row % self::FLUSH_THRESHOLD === 0) {
|
||||
$this->globalFunctionsHelper->fflush($this->filePointer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the Excel End of File marker
|
||||
*
|
||||
* @see pack()
|
||||
* @return nothing
|
||||
*/
|
||||
private function eofMarker()
|
||||
{
|
||||
fwrite($this->filePointer, pack("ss", 0x0A, 0x00));
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the XLS streamer, preventing any additional writing.
|
||||
* If set, sets the headers and redirects output to the browser.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function closeWriter()
|
||||
{
|
||||
if ($this->filePointer) {
|
||||
$this->eofMarker();
|
||||
|
||||
$this->globalFunctionsHelper->fclose($this->filePointer);
|
||||
}
|
||||
|
||||
$this->row = 0;
|
||||
$this->col = 0;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user