xls_export/vendor/xls_export.php

1415 lines
60 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
require_once "fat.php";
define("CELL_STRING",1);
define("CELL_FLOAT",2);
define("CELL_PICTURE",3);
define("XLSFILE_DEFAULT_FONTNAME","Albany");
define("XLSFILE_DEFAULT_FONTHEIGHT",0x00c8);
define("XLSFILE_DEFAULT_FGCOLOR",0x0008);
define("XLSFILE_DEFAULT_ROWHEIGHT",0x012c);
define("XLSFILE_DEFAULT_COLWIDTH",0x0924);
define("XLSFILE_CHARACTERSET",0x00); // = LATIN , see values in font.php XLSFONT_CHARACTERSET_*
define("XLSCELLHALLIGN_LEFT",0);
define("XLSCELLHALLIGN_RIGHT",1);
define("XLSCELLHALLIGN_CENTER",2);
define("FILE_HEADER_NUMBEROFFATSECTORS",0x2c);
define("FILE_HEADER_DIRECTORYSTART",0x30);
define("FILE_HEADER_MINIFATSTART",0x3c);
define("FILE_HEADER_DIFCHAINSTART",0x40);
define("FILE_HEADER_DIFSECTORSCOUNT",0x44);
define("FILE_HEADER_FIRSTFATENTRY",0x4c);
require_once "biff.php";
require_once "palette.php";
require_once "font.php";
require_once "xf.php";
require_once "picture.php";
require_once "mergedcells.php";
class xlsexport {
protected $default_cell_allign = XLSCELLHALLIGN_LEFT;
var $page_header = "&L&C&[TAB]&R";
var $page_footer = "&L&CPage &[PAGE]&R";
// $xlsdocument struct
// "worksheetid" => index of $worksheets
// "worksheetname" => data
//
// data struct
// array of $rows
//
// rows struct
// array of $cells
//
// cell struct
// $data,
// type : *xls_string/xls_int/xls_float/xls_expression,
// format,
// font-index : *,
// xf-index : *
var $xlsfilehandle = null;
var $file_header = null;
var $xlsdocument = null;
var $xlsstreamsize = null;
var $rootstorageoffset = null;
var $xls_bof = null;
var $palette = null;
var $xf = null;
var $xls_bofstart = -1;
var $sheetinformationpos = -1;
var $objectcounter = 1;
// array struct
// (sheetname, first_row, last_row, first_col, last_col, sheetinfopos, fileoffset, colwidths, rowheights, defcolwidthoffset, rowrecordsoffset)
var $worksheets = null;
public function __construct() {
$this->xlsdocument = array();
$this->xls_bof = new xls_bof(0);
$this->palette = new xls_palette();
$this->font = new xls_font(0);
$this->xf = new xls_xf(0);
}
public function addworksheet($sheetname) {
if (isset($this->worksheets[$sheetname])) { return false; }
$this->xlsdocument[$sheetname]["document"] = array();
$this->xlsdocument[$sheetname]["worksheetid"] = count($this->worksheets);
$this->worksheets[] = array("sheetname" => $sheetname,
"first_row" => 0xffffffff,
"last_row" => 0,
"first_col" => 0xffffffff,
"last_col" => 0,
"sheetinfopos" => -1,
"fileoffset" => -1,
"colwidths" => array(),
"rowheights" => array(),
"defcolwidthoffset" => 0xffffffff,
"rowrecordsoffset" => 0xffffffff);
return true;
}
public function setcolwidth($sheetname, $acolidx, $awidth) {
$sheetid = $this->xlsdocument[$sheetname]["worksheetid"];
$this->worksheets[$sheetid]["colwidths"][$acolidx] = $awidth;
}
public function setrowheight($sheetname, $arowidx, $aheight) {
$sheetid = $this->xlsdocument[$sheetname]["worksheetid"];
$this->worksheets[$sheetid]["rowheights"][$arowidx] = $aheight;
}
public function merge_cells($sheetname, $firstrow, $lastrow, $firstcol, $lastcol) {
if (defined("MERGEDEBUG")) {
echo "merge cells , sheet : $sheetname , (fr,lr) : (fc,lc) = ($firstrow,$lastrow) : ($firstcol,$lastcol)<br>\n";
}
if (!isset($this->xlsdocument[$sheetname]["mergedcells"])) {
$this->xlsdocument[$sheetname]["mergedcells"] = new xls_mergedcells();
}
$this->xlsdocument[$sheetname]["mergedcells"]->merge_cells($firstrow, $lastrow, $firstcol, $lastcol);
if (defined("MERGEDEBUG")) {
print_r($this->xlsdocument[$sheetname]["mergedcells"]);
}
}
public function setcell($args) {
if (($this->worksheets==null) || (count($this->worksheets)==0)) { return false; }
if (!isset($args["data"])) { return false; }
$sheetname = (isset($args["sheetname"]) ? $args["sheetname"] : $this->worksheets[0]["sheetname"]);
if (isset($args["row"])) { $row = $args["row"]; }
else {
if (count($this->xlsdocument[$sheetname]["document"])<1) {
$row = 0;
$col = 0;
}
else { $row = count($this->xlsdocument[$sheetname]["document"]); }
}
if (isset($args["col"]) && (!isset($col))) { $col = $args["col"]; }
else {
if (isset($this->xlsdocument[$sheetname]["document"][$row])) { $col = count($this->xlsdocument[$sheetname]["document"][$row]); }
else { $col=0; }
}
/*
if (!isset($this->worksheets[$this->xlsdocument[$sheetname]["worksheetid"]]["colwidths"][$col])) {
$this->setcolwidth($sheetname,$col,XLSFILE_DEFAULT_COLWIDTH);
}
if (!isset($this->worksheets[$this->xlsdocument[$sheetname]["worksheetid"]]["rowheights"][$row])) {
$this->setrowheight($sheetname,$row,XLSFILE_DEFAULT_ROWHEIGHT);
}
*/
if (isset($this->xlsdocument[$sheetname]["mergedcells"])) {
$pos = $this->xlsdocument[$sheetname]["mergedcells"]->findpos($row,$col);
if ($pos!==false) {
if (($pos["row"]!=$row) || ($pos["col"]!=$col)) { return false; }
}
}
$cell = array("type" => CELL_STRING, "xfindex" => -1);
$xfrec = array();
$fontrec = array();
foreach ($args as $key => $param) {
switch ($key) {
case "data" :
case "type" : $cell[$key] = $param;
break;
case "bgcolor" :
case "backgroundcolor" :
case "background-color" : $xfrec["patternbgcolor"]=$param;
break;
case "textrotate" : $xfrec["rotate"]=$param;
break;
case "textwrap" :
case "hallign" :
case "vallign" :
case "bordertop" :
case "borderleft" :
case "borderright" :
case "borderbottom" :
case "bordertopcolor" :
case "borderleftcolor" :
case "borderrightcolor" :
case "borderbottomcolor" :
case "bordercolor" :
case "border" : $xfrec[$key] = $param;
break;
case "fontname" : $fontrec["name"] = $param;
break;
case "fontheight" :
case "fontsize" : $fontrec["height"] = $param;
break;
case "fontweight" : $fontrec["weight"] = $param;
break;
case "color" :
case "fgcolor" :
case "fontcolor" : $fontrec["color"] = $param;
break;
case "fontstyle" : $fontrec["style"] = $param;
break;
case "fontfamily" : $fontrec["family"] = $param;
break;
case "fontescape" : $fontrec["escape"] = $param;
break;
case "underline" : $fontrec["underline"] = $param;
break;
}
}
if (($cell["type"]==CELL_PICTURE) && (isset($fontrec["color"]))) {
$cell["color"]=$this->palette->getcoloridx($fontrec["color"]);
$cell["xfindex"] = $this->xf->defaultxf;
}
else if ((count($xfrec)>0) || (count($fontrec)>0)) {
$xfcheck = array("patternbgcolor","bordertopcolor","borderleftcolor","borderrightcolor","borderbottomcolor","bordercolor");
foreach ($xfcheck as $key) {
if (isset($xfrec[$key])) {
$xfrec[$key] = $this->palette->getcoloridx($xfrec[$key]);
}
}
if (isset($fontrec["color"])) { $fontrec["color"] = $this->palette->getcoloridx($fontrec["color"]); }
$fontindex = $this->font->append($fontrec);
if (defined("FONTDEBUG")) {
if (count($fontrec)>0) {
echo "fontrec :\n";
print_r($fontrec);
echo "fontindex : $fontindex\n";
}
}
if ($fontindex!=0) {
$xfrec["fontindex"] = $fontindex;
}
$xfindex = $this->xf->append($xfrec);
$cell["xfindex"] = $xfindex;
if (defined("CELLINSERTDEBUG")) {
print_r($cell);
}
}
else {
$cell["xfindex"] = $this->xf->defaultxf;
}
$this->xlsdocument[$sheetname]["document"][$row][$col] = $cell;
$this->worksheets[$this->xlsdocument[$sheetname]["worksheetid"]]["first_row"] = min($row,$this->worksheets[$this->xlsdocument[$sheetname]["worksheetid"]]["first_row"]);
$this->worksheets[$this->xlsdocument[$sheetname]["worksheetid"]]["last_row"] = max($row,$this->worksheets[$this->xlsdocument[$sheetname]["worksheetid"]]["last_row"]);
$this->worksheets[$this->xlsdocument[$sheetname]["worksheetid"]]["first_col"] = min($col,$this->worksheets[$this->xlsdocument[$sheetname]["worksheetid"]]["first_col"]);
$this->worksheets[$this->xlsdocument[$sheetname]["worksheetid"]]["last_col"] = max($col,$this->worksheets[$this->xlsdocument[$sheetname]["worksheetid"]]["last_col"]);
return true;
}
public function savefile($afilename) {
if (file_exists($afilename)) {
unlink($afilename);
}
$this->xlsfilehandle = fopen($afilename,"x+");
$this->file_headerinit();
$this->xls_bofstart = ftell($this->xlsfilehandle);
$this->xls_bof->clear(XLS_BIFF5);
$this->xls_bof->append(XLSDATA_SHORT,0x0500);
$this->xls_bof->append(XLSDATA_SHORT,BIFF_WORKBOOKGLOBALS);
$this->xls_bof->append(XLSDATA_SHORT,0x096c); // build identifier
$this->xls_bof->append(XLSDATA_SHORT,0x07c9); // build year = 1993
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_INTERFACEHEADER);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_MENURECORDGROUP);
$this->xls_bof->append(XLSDATA_BYTE,0);
$this->xls_bof->append(XLSDATA_BYTE,0);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_TOOLBARHEADER);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_TOOLBAREND);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_INTERFACEEND);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_WRITEACCESS);
$s = $this->xls_strpad("APACHE2/PHP-XLS Generator",31);
$this->xls_bof->append(XLSDATA_STRING1,$s);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_CODEPAGE);
$this->xls_bof->append(XLSDATA_SHORT,0x04e4);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_FUNCTIONGROUPCOUNT);
$this->xls_bof->append(XLSDATA_SHORT,0x000e);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_writeexterninfo();
foreach ($this->worksheets as $key => $sheetdata) {
$this->xls_bof->clear(BIFF_DEFINEDNAME);
$this->xls_bof->append(XLSDATA_SHORT,0x0020); // built-in-name
$this->xls_bof->append(XLSDATA_BYTE,0x00); // keyboard shortcut
$this->xls_bof->append(XLSDATA_BYTE,0x01);
$this->xls_bof->append(XLSDATA_SHORT,strlen($sheetdata["sheetname"])+2);
$this->xls_bof->append(XLSDATA_SHORT,$key+1);
$this->xls_bof->append(XLSDATA_SHORT,$key+1);
$this->xls_bof->append(XLSDATA_BYTE,0x00); // length of menu text
$this->xls_bof->append(XLSDATA_BYTE,0x00); // length of description text
$this->xls_bof->append(XLSDATA_BYTE,0x00); // length of help topic text
$this->xls_bof->append(XLSDATA_BYTE,0x00); // length of status bar text
$this->xls_bof->append(XLSDATA_BYTE,0x0c); // ?
$this->xls_bof->append(XLSDATA_BYTE,0x17); // ?
$this->xls_bof->append(XLSDATA_STRING,$sheetdata["sheetname"]);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_DEFINEDNAME);
$this->xls_bof->append(XLSDATA_SHORT,0x0020); // built-in-name
$this->xls_bof->append(XLSDATA_BYTE,0x00); // keyboard shortcut
$this->xls_bof->append(XLSDATA_BYTE,0x01);
$this->xls_bof->append(XLSDATA_SHORT,0x0015);
$this->xls_bof->append(XLSDATA_SHORT,$key+1);
$this->xls_bof->append(XLSDATA_SHORT,$key+1);
$this->xls_bof->append(XLSDATA_BYTE,0x00); // length of menu text
$this->xls_bof->append(XLSDATA_BYTE,0x00); // length of description text
$this->xls_bof->append(XLSDATA_BYTE,0x00); // length of help topic text
$this->xls_bof->append(XLSDATA_BYTE,0x00); // length of status bar text
$this->xls_bof->append(XLSDATA_BYTE,0x06); // ?
$this->xls_bof->append(XLSDATA_BYTE,0x3b); // ?
$this->xls_bof->append(XLSDATA_SHORT,0xffff-$key); // ?
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // ?
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // ?
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // ?
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // ?
$this->xls_bof->append(XLSDATA_SHORT,$key);
$this->xls_bof->append(XLSDATA_SHORT,$key);
$this->xls_bof->append(XLSDATA_LONG,0xffff0000); // ?
$this->xls_bof->append(XLSDATA_SHORT,0xff00); // ?
$this->xls_bof->save($this->xlsfilehandle);
}
$this->xls_bof->clear(BIFF_WINDOWPROTECT);
$this->xls_bof->append(XLSDATA_SHORT,0x0000);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_PROTECT);
$this->xls_bof->append(XLSDATA_SHORT,0x0000);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_PASSWORD);
$this->xls_bof->append(XLSDATA_SHORT,0x0000);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_WINDOW1);
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // Horizontal position of the document window
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // Vertical position of the document window
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // Width of the document window
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // Height of the document window
$this->xls_bof->append(XLSDATA_SHORT,0x0038); // Horz/vert scrollbars + Worksheet tab bar visible
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // active tab bar
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // Index of first visible tab in the worksheet tab bar
$this->xls_bof->append(XLSDATA_SHORT,0x0001); // Number of selected worksheets
$this->xls_bof->append(XLSDATA_SHORT,0x0258); // Width of worksheet tab bar (in 1/1000 of window width).
// The remaining space is used by the horizontal scrollbar.
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_BACKUP);
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // =1 if Excel should save a backup version of the file
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_OBJECTDISPLAYOPTIONS);
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // show all
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_DATEMODE);
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // 0 = Base date is 1899-Dec-31 (the cell value 1 represents 1900-Jan-01)
// 1 = Base date is 1904-Jan-01 (the cell value 1 represents 1904-Jan-02)
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_PRECISION);
$this->xls_bof->append(XLSDATA_SHORT,0x0001); // 0 = Use displayed values; 1 = Use real cell values
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_REFRESHALL);
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // =1 then Refresh All should be done on all external data ranges and PivotTables when loading the workbook (the default is =0)
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_BOOKBOOL);
$this->xls_bof->append(XLSDATA_SHORT,0x0000);
$this->xls_bof->save($this->xlsfilehandle);
$this->font->save($this->xlsfilehandle,$this->xls_bof);
$this->xls_workbookformat();
$this->xf->save($this->xlsfilehandle,$this->xls_bof);
//$this->xls_bof->workbookxfrecords($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_STYLEINFORMATION);
$this->xls_bof->append(XLSDATA_SHORT,0x8010);
$this->xls_bof->append(XLSDATA_BYTE,0x03);
$this->xls_bof->append(XLSDATA_BYTE,0xff);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_STYLEINFORMATION);
$this->xls_bof->append(XLSDATA_SHORT,0x8011);
$this->xls_bof->append(XLSDATA_BYTE,0x06);
$this->xls_bof->append(XLSDATA_BYTE,0xff);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_STYLEINFORMATION);
$this->xls_bof->append(XLSDATA_SHORT,0x8012);
$this->xls_bof->append(XLSDATA_BYTE,0x04);
$this->xls_bof->append(XLSDATA_BYTE,0xff);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_STYLEINFORMATION);
$this->xls_bof->append(XLSDATA_SHORT,0x8013);
$this->xls_bof->append(XLSDATA_BYTE,0x07);
$this->xls_bof->append(XLSDATA_BYTE,0xff);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_STYLEINFORMATION);
$this->xls_bof->append(XLSDATA_SHORT,0x8000);
$this->xls_bof->append(XLSDATA_BYTE,0x00);
$this->xls_bof->append(XLSDATA_BYTE,0xff);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_STYLEINFORMATION);
$this->xls_bof->append(XLSDATA_SHORT,0x8014);
$this->xls_bof->append(XLSDATA_BYTE,0x05);
$this->xls_bof->append(XLSDATA_BYTE,0xff);
$this->xls_bof->save($this->xlsfilehandle);
$this->palette->save($this->xlsfilehandle,$this->xls_bof);
$this->sheetinformationpos = ftell($this->xlsfilehandle);
$this->xls_writesheetinformationlist();
$this->xls_bof->clear(XLS_BIFF_EOF);
$this->xls_bof->save($this->xlsfilehandle);
foreach ($this->worksheets as $sheetkey => $data) {
$this->xls_writesheetdata($sheetkey);
}
$this->xlsstreamsize = ftell($this->xlsfilehandle)-0x0200;
if ($this->xlsstreamsize>=0x1000) {
$fsize = ftell($this->xlsfilehandle) & 0x01ff;
$reqbytes = 0x0200 - $fsize;
}
else {
$fsize = ftell($this->xlsfilehandle) & 0x003f;
$reqbytes = 0x0040 - $fsize;
}
if ($reqbytes>0) {
$s = str_repeat(chr(0),$reqbytes);
fwrite($this->xlsfilehandle,$s,$reqbytes);
}
$this->rootstorageoffset=ftell($this->xlsfilehandle);
$this->xls_writerootstorage();
if ((ftell($this->xlsfilehandle) & 0x01ff)!=0) {
$fsize = ftell($this->xlsfilehandle) & 0x01ff;
$reqbytes = 0x0200 - $fsize;
if ($reqbytes>0) {
$s = str_repeat(chr(0),$reqbytes);
fwrite($this->xlsfilehandle,$s,$reqbytes);
}
}
if ($this->xlsstreamsize>=0x1000) {
$rootsecid = $this->rootstorageoffset;
$rootsecid = $rootsecid-0x200;
$rootsecid = $rootsecid>>9;
$rootminisecid = 0;
}
else {
$rootsecid = 0;
$rootminisecid = ($this->rootstorageoffset-0x0200) >> 6;
};
$this->xls_writeminifat();
$dirsecid = ftell($this->xlsfilehandle);
$dirsecid = $dirsecid-0x0200;
$dirsecid = $dirsecid>>9;
$this->xls_writedirentry("Root Entry",5,1,0xffffffff,$rootsecid,(($this->xlsstreamsize<0x1000) ? $this->rootstorageoffset-0x0100 : 0x0100));
$this->xls_writedirentry("Book",2,1,3,0,$this->xlsstreamsize);
$this->xls_writedirentry(chr(5)."DocumentSummaryInformation",2,1,0xffffffff,$rootminisecid,0x48);
$this->xls_writedirentry(chr(5)."SummaryInformation",2,1,2,$rootminisecid+2,0x48);
$fatsecid = ftell($this->xlsfilehandle);
$fatsecid = $fatsecid-0x0200;
$fatsecid = $fatsecid>>9;
fseek($this->xlsfilehandle,FILE_HEADER_DIRECTORYSTART,SEEK_SET);
fwrite($this->xlsfilehandle,pack("V",$dirsecid),4);
fseek($this->xlsfilehandle,0,SEEK_END);
$fat = new fat_class($this->xlsfilehandle, $this->xlsstreamsize, $this->rootstorageoffset);
fseek($this->xlsfilehandle,FILE_HEADER_NUMBEROFFATSECTORS,SEEK_SET);
$fatsectorcount = $fat->fatsectorcount;
fwrite($this->xlsfilehandle,pack("V",$fatsectorcount),4);
fseek($this->xlsfilehandle,FILE_HEADER_FIRSTFATENTRY,SEEK_SET);
while ($fatsectorcount>0) {
fwrite($this->xlsfilehandle,pack("V",$fatsecid),4);
$fatsecid++;
$fatsectorcount--;
}
fclose($this->xlsfilehandle);
}
private function file_headerinit() {
// signature
$this->file_header = pack("c*",0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1);
// clsid
$this->file_header .= pack("c*",0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
// minor.ver
$this->file_header .= pack("v",0x003e);
// major.ver
$this->file_header .= pack("v",0x0003);
// byteorder
$this->file_header .= pack("v",0xfffe);
// sectorshift
$this->file_header .= pack("v",0x0009);
// minisectorsh
$this->file_header .= pack("v",0x0006);
// reserved
$this->file_header .= pack("vvvvv",0x0000,0x0000,0x0000,0x0000,0x0000);
// fatsectors
$this->file_header .= pack("V",0x00000001);
// dirsectors
$this->file_header .= pack("V",0x00000000);
// signature
$this->file_header .= pack("V",0x00000000);
// ministrm.size
$this->file_header .= pack("V",0x00001000);
// first minifat sector
$this->file_header .= pack("V",0x00000000);
// minifat sectors
$this->file_header .= pack("V",0x00000001);
// dif sectors start
$this->file_header .= pack("V",0xfffffffe);
// dif sectors count
$this->file_header .= pack("V",0x00000000);
// first109fat
$this->file_header .= str_repeat(chr(0xff),436);
fwrite($this->xlsfilehandle, $this->file_header);
}
function xls_strpad($astr,$asize) {
$strlength = strlen($astr);
$output = chr($strlength).$astr;
while (strlen($output)!=$asize) { $output .= " "; }
return $output;
}
private function xls_workbookformat() {
$s = pack("C*",0x1e,0x04,0x14,0x00,0x05,0x00,0x11,0x24,0x23,0x2c,0x23,0x23,0x30);
$s.= pack("C*",0x5f,0x29,0x3b,0x28,0x24,0x23,0x2c,0x23,0x23,0x30,0x29,0x1e,0x04,0x19,0x00,0x06);
$s.= pack("C*",0x00,0x16,0x24,0x23,0x2c,0x23,0x23,0x30,0x5f,0x29,0x3b,0x5b,0x52,0x65,0x64,0x5d);
$s.= pack("C*",0x28,0x24,0x23,0x2c,0x23,0x23,0x30,0x29,0x1e,0x04,0x1a,0x00,0x07,0x00,0x17,0x24);
$s.= pack("C*",0x23,0x2c,0x23,0x23,0x30,0x2e,0x30,0x30,0x5f,0x29,0x3b,0x28,0x24,0x23,0x2c,0x23);
$s.= pack("C*",0x23,0x30,0x2e,0x30,0x30,0x29,0x1e,0x04,0x1f,0x00,0x08,0x00,0x1c,0x24,0x23,0x2c);
$s.= pack("C*",0x23,0x23,0x30,0x2e,0x30,0x30,0x5f,0x29,0x3b,0x5b,0x52,0x65,0x64,0x5d,0x28,0x24);
$s.= pack("C*",0x23,0x2c,0x23,0x23,0x30,0x2e,0x30,0x30,0x29,0x1e,0x04,0x2d,0x00,0x2a,0x00,0x2a);
$s.= pack("C*",0x5f,0x28,0x24,0x2a,0x20,0x23,0x2c,0x23,0x23,0x30,0x5f,0x29,0x3b,0x5f,0x28,0x24);
$s.= pack("C*",0x2a,0x20,0x28,0x23,0x2c,0x23,0x23,0x30,0x29,0x3b,0x5f,0x28,0x24,0x2a,0x20,0x22);
$s.= pack("C*",0x2d,0x22,0x5f,0x29,0x3b,0x5f,0x28,0x40,0x5f,0x29,0x1e,0x04,0x2a,0x00,0x29,0x00);
$s.= pack("C*",0x27,0x5f,0x28,0x2a,0x20,0x23,0x2c,0x23,0x23,0x30,0x5f,0x29,0x3b,0x5f,0x28,0x2a);
$s.= pack("C*",0x20,0x28,0x23,0x2c,0x23,0x23,0x30,0x29,0x3b,0x5f,0x28,0x2a,0x20,0x22,0x2d,0x22);
$s.= pack("C*",0x5f,0x29,0x3b,0x5f,0x28,0x40,0x5f,0x29,0x1e,0x04,0x35,0x00,0x2c,0x00,0x32,0x5f);
$s.= pack("C*",0x28,0x24,0x2a,0x20,0x23,0x2c,0x23,0x23,0x30,0x2e,0x30,0x30,0x5f,0x29,0x3b,0x5f);
$s.= pack("C*",0x28,0x24,0x2a,0x20,0x28,0x23,0x2c,0x23,0x23,0x30,0x2e,0x30,0x30,0x29,0x3b,0x5f);
$s.= pack("C*",0x28,0x24,0x2a,0x20,0x22,0x2d,0x22,0x3f,0x3f,0x5f,0x29,0x3b,0x5f,0x28,0x40,0x5f);
$s.= pack("C*",0x29,0x1e,0x04,0x32,0x00,0x2b,0x00,0x2f,0x5f,0x28,0x2a,0x20,0x23,0x2c,0x23,0x23);
$s.= pack("C*",0x30,0x2e,0x30,0x30,0x5f,0x29,0x3b,0x5f,0x28,0x2a,0x20,0x28,0x23,0x2c,0x23,0x23);
$s.= pack("C*",0x30,0x2e,0x30,0x30,0x29,0x3b,0x5f,0x28,0x2a,0x20,0x22,0x2d,0x22,0x3f,0x3f,0x5f);
$s.= pack("C*",0x29,0x3b,0x5f,0x28,0x40,0x5f,0x29);
fwrite($this->xlsfilehandle,$s);
}
private function xls_writesheetinformationlist() {
foreach ($this->worksheets as $key => $data) {
$this->xls_writeonesheetinformation($key);
}
}
private function xls_writeonesheetinformation($sheetid) {
$fpos = ftell($this->xlsfilehandle);
if ($this->worksheets[$sheetid]["sheetinfopos"]!=-1) {
fseek($this->xlsfilehandle,$this->worksheets[$sheetid]["sheetinfopos"],SEEK_SET);
}
$this->xls_bof->clear(BIFF_BOUNDSHEET);
$this->xls_bof->append(XLSDATA_LONG,$this->worksheets[$sheetid]["fileoffset"]);
$this->xls_bof->append(XLSDATA_SHORT,0x0000);
$this->xls_bof->append(XLSDATA_STRING,$this->worksheets[$sheetid]["sheetname"]);
$this->xls_bof->save($this->xlsfilehandle);
if ($this->worksheets[$sheetid]["sheetinfopos"]!=-1) {
fseek($this->xlsfilehandle,$fpos,SEEK_SET);
}
else { $this->worksheets[$sheetid]["sheetinfopos"]=$fpos; }
}
private function xls_writeexterninfo() {
$this->xls_bof->clear(BIFF_EXTERNALREFERENCESCOUNT);
$this->xls_bof->append(XLSDATA_SHORT,count($this->worksheets)+2); // = sheetcount+2
$this->xls_bof->save($this->xlsfilehandle);
foreach ($this->worksheets as $key => $sheetdata) {
$this->xls_bof->clear(BIFF_EXTERNSHEET);
$this->xls_bof->append(XLSDATA_BYTE,strlen($sheetdata["sheetname"]));
$this->xls_bof->append(XLSDATA_BYTE,3);
$this->xls_bof->append(XLSDATA_STRING1,$sheetdata["sheetname"]);
$this->xls_bof->save($this->xlsfilehandle);
}
$this->xls_bof->clear(BIFF_EXTERNSHEET);
$this->xls_bof->append(XLSDATA_BYTE,0x01);
$this->xls_bof->append(XLSDATA_BYTE,0x3a);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_EXTERNSHEET);
$this->xls_bof->append(XLSDATA_BYTE,0x01);
$this->xls_bof->append(XLSDATA_BYTE,0x04);
$this->xls_bof->save($this->xlsfilehandle);
}
public function xls_picturecallback() {
die("done.");
}
private function xls_writesheetdata($sheetid) {
if (defined("DEBUG")) {
echo "writesheet : $sheetid<br>";
}
$rowrecord_filepos = array();
$rowpos = array();
$this->worksheets[$sheetid]["fileoffset"] = ftell($this->xlsfilehandle)-0x0200;
$this->xls_writeonesheetinformation($sheetid);
$this->xls_bof->clear(XLS_BIFF5);
$this->xls_bof->append(XLSDATA_SHORT,0x0500);
$this->xls_bof->append(XLSDATA_SHORT,WORKBOOK_SHEET);
$this->xls_bof->append(XLSDATA_SHORT,0x096c); // build identifier
$this->xls_bof->append(XLSDATA_SHORT,0x07c9); // build year = 1993
$this->xls_bof->save($this->xlsfilehandle);
$this->worksheets[$sheetid]["rowrecordsoffset"] = ftell($this->xlsfilehandle)+2+2+4+2+2+4;
$rowcount = $this->worksheets[$sheetid]["last_row"]-$this->worksheets[$sheetid]["first_row"];
$dbcellcount = ($rowcount >> 5)+1;
$this->xls_bof->clear(BIFF_INDEX);
$this->xls_bof->append(XLSDATA_LONG,0x00000000); // unused var.
$this->xls_bof->append(XLSDATA_SHORT,$this->worksheets[$sheetid]["first_row"]);
$this->xls_bof->append(XLSDATA_SHORT,$this->worksheets[$sheetid]["last_row"]+1);
$this->xls_bof->append(XLSDATA_LONG,0x00000000);
$i=0;
while ($i!=$dbcellcount) {
$this->xls_bof->append(XLSDATA_LONG,0xffffffff);
$rowrecord_filepos[$i]=ftell($this->xlsfilehandle)+16+($i<<2);
$i++;
}
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_CALCMODE);
$this->xls_bof->append(XLSDATA_SHORT,0x0001);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_CALCCOUNT);
$this->xls_bof->append(XLSDATA_SHORT,0x0064);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_REFMODE);
$this->xls_bof->append(XLSDATA_SHORT,0x0001);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_ITERATION);
$this->xls_bof->append(XLSDATA_SHORT,0x0001);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_DELTA);
$this->xls_bof->append(XLSDATA_BYTE,0xfc);
$this->xls_bof->append(XLSDATA_BYTE,0xa9);
$this->xls_bof->append(XLSDATA_BYTE,0xf1);
$this->xls_bof->append(XLSDATA_BYTE,0xd2);
$this->xls_bof->append(XLSDATA_BYTE,0x4d);
$this->xls_bof->append(XLSDATA_BYTE,0x62);
$this->xls_bof->append(XLSDATA_BYTE,0x50);
$this->xls_bof->append(XLSDATA_BYTE,0x3f);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_SAVERECALC);
$this->xls_bof->append(XLSDATA_SHORT,0x0001);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_PRINTHEADERS);
$this->xls_bof->append(XLSDATA_SHORT,0x0000);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_PRINTGRIDLINES);
$this->xls_bof->append(XLSDATA_SHORT,0x0000);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_GRIDSET);
$this->xls_bof->append(XLSDATA_SHORT,0x0001);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_GUTS);
$this->xls_bof->append(XLSDATA_SHORT,0x0000);
$this->xls_bof->append(XLSDATA_SHORT,0x0000);
$this->xls_bof->append(XLSDATA_SHORT,0x0000);
$this->xls_bof->append(XLSDATA_SHORT,0x0000);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_DEFAULTROWHEIGHT);
$this->xls_bof->append(XLSDATA_SHORT,0x0000);
$this->xls_bof->append(XLSDATA_SHORT,0x012c);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_COUNTRY);
$this->xls_bof->append(XLSDATA_SHORT,0x0001); // Windows country identifier of the user interface language of Excel
$this->xls_bof->append(XLSDATA_SHORT,0x0001); // Windows country identifier of the system regional settings
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_SHEETPR);
$this->xls_bof->append(XLSDATA_SHORT,0x04c1); /* 0 0001H 0 = Do not show automatic page breaks
1 = Show automatic page breaks
4 0010H 0 = Standard sheet
1 = Dialogue sheet (BIFF5-BIFF8)
5 0020H 0 = No automatic styles in outlines
1 = Apply automatic styles to outlines
6 0040H 0 = Outline buttons above outline group
1 = Outline buttons below outline group
7 0080H 0 = Outline buttons left of outline group
1 = Outline buttons right of outline group
8 0100H 0 = Scale printout in percent
1 = Fit printout to number of pages
9 0200H 0 = Save external linked values (BIFF3-BIFF4 only)
1 = Do not save external linked values (BIFF3-BIFF4 only)
10 0400H 0 = Do not show row outline symbols 1 = Show row outline symbols
11 0800H 0 = Do not show column outline symbols
1 = Show column outline symbols
13-12 3000H These flags specify the arrangement of windows. They are stored in BIFF4 only.
002 = Arrange windows tiled
012 = Arrange windows horizontal
102 = Arrange windows vertical
112 = Arrange windows cascaded
The following flags are valid for BIFF4-BIFF8 only:
14 4000H 0 = Excel like expression evaluation
1 = Lotus like expression evaluation
15 8000H 0 = Excel like formula editing
1 = Lotus like formula editing
*/
$this->xls_bof->save($this->xlsfilehandle);
/*
$this->xls_bof->clear(BIFF_PAGEHEADER);
$this->xls_bof->append(XLSDATA_LSTRING,$this->page_header);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_PAGEFOOTER);
$this->xls_bof->append(XLSDATA_LSTRING,$this->page_footer);
$this->xls_bof->save($this->xlsfilehandle);
*/
/*
$this->xls_bof->clear(BIFF_PAGEHEADER);
$this->xls_bof->append(XLSDATA_LSTRING,"");
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_PAGEFOOTER);
$this->xls_bof->append(XLSDATA_LSTRING,"");
$this->xls_bof->save($this->xlsfilehandle);
*/
$this->xls_bof->clear(BIFF_HCENTER);
$this->xls_bof->append(XLSDATA_SHORT,0x0000);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_VCENTER);
$this->xls_bof->append(XLSDATA_SHORT,0x0000);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_LEFTMARGIN);
$this->xls_bof->append(XLSDATA_BYTE,0x00);
$this->xls_bof->append(XLSDATA_BYTE,0x00);
$this->xls_bof->append(XLSDATA_BYTE,0x00);
$this->xls_bof->append(XLSDATA_BYTE,0x00);
$this->xls_bof->append(XLSDATA_BYTE,0x00);
$this->xls_bof->append(XLSDATA_BYTE,0x00);
$this->xls_bof->append(XLSDATA_BYTE,0xf0);
$this->xls_bof->append(XLSDATA_BYTE,0x3f);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_RIGHTMARGIN);
$this->xls_bof->append(XLSDATA_BYTE,0x00);
$this->xls_bof->append(XLSDATA_BYTE,0x00);
$this->xls_bof->append(XLSDATA_BYTE,0x00);
$this->xls_bof->append(XLSDATA_BYTE,0x00);
$this->xls_bof->append(XLSDATA_BYTE,0x00);
$this->xls_bof->append(XLSDATA_BYTE,0x00);
$this->xls_bof->append(XLSDATA_BYTE,0xf0);
$this->xls_bof->append(XLSDATA_BYTE,0x3f);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_TOPMARGIN);
$this->xls_bof->append(XLSDATA_BYTE,0xab);
$this->xls_bof->append(XLSDATA_BYTE,0xaa);
$this->xls_bof->append(XLSDATA_BYTE,0xaa);
$this->xls_bof->append(XLSDATA_BYTE,0xaa);
$this->xls_bof->append(XLSDATA_BYTE,0xaa);
$this->xls_bof->append(XLSDATA_BYTE,0xaa);
$this->xls_bof->append(XLSDATA_BYTE,0xfa);
$this->xls_bof->append(XLSDATA_BYTE,0x3f);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_BOTTOMMARGIN);
$this->xls_bof->append(XLSDATA_BYTE,0xab);
$this->xls_bof->append(XLSDATA_BYTE,0xaa);
$this->xls_bof->append(XLSDATA_BYTE,0xaa);
$this->xls_bof->append(XLSDATA_BYTE,0xaa);
$this->xls_bof->append(XLSDATA_BYTE,0xaa);
$this->xls_bof->append(XLSDATA_BYTE,0xaa);
$this->xls_bof->append(XLSDATA_BYTE,0xfa);
$this->xls_bof->append(XLSDATA_BYTE,0x3f);
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_PAGESETUP);
$this->xls_bof->append(XLSDATA_SHORT,0x0000); /* Paper size
0 Undefined
1 Letter 81/2½ × 11½
2 Letter small 81/2½ × 11½
3 Tabloid 11½ × 17½
4 Ledger 17½ × 11½
5 Legal 81/2½ × 14½
6 Statement 51/2½ × 81/2½
7 Executive 71/4½ × 101/2½
8 A3 297mm × 420mm
9 A4 210mm × 297mm
10 A4 small 210mm × 297mm
11 A5 148mm × 210mm
12 B4 (JIS) 257mm × 364mm
13 B5 (JIS) 182mm × 257mm
14 Folio 81/2½ × 13½
15 Quarto 215mm × 275mm
16 10×14 10½ × 14½
17 11×17 11½ × 17½
18 Note 81/2½ × 11½
19 Envelope #9 37/8½ × 87/8½
20 Envelope #10 41/8½ × 91/2½
21 Envelope #11 41/2½ × 103/8½
22 Envelope #12 43/4½ × 11½
23 Envelope #14 5½ × 111/2½
24 C 17½ × 22½
25 D 22½ × 34½
26 E 34½ × 44½
27 Envelope DL 110mm × 220mm
28 Envelope C5 162mm × 229mm
29 Envelope C3 324mm × 458mm
30 Envelope C4 229mm × 324mm
31 Envelope C6 114mm × 162mm
32 Envelope C6/C5 114mm × 229mm
33 B4 (ISO) 250mm × 353mm
34 B5 (ISO) 176mm × 250mm
35 B6 (ISO) 125mm × 176mm
36 Envelope Italy 110mm × 230mm
37 Envelope Monarch 37/8½ × 71/2½
38 63/4 Envelope 35/8½ × 61/2½
39 US Standard Fanfold 147/8½ × 11½
40 German Std. Fanfold 81/2½ × 12½
41 German Legal Fanfold 81/2½ × 13½
42 B4 (ISO) 250mm × 353mm
43 Japanese Postcard 100mm × 148mm
44 9×11 9½ × 11½
45 10×11 10½ × 11½
46 15×11 15½ × 11½
47 Envelope Invite 220mm × 220mm
48 Undefined
49 Undefined
50 Letter Extra 91/2½ × 12½
51 Legal Extra 91/2½ × 15½
52 Tabloid Extra 1111/16½ × 18½
53 A4 Extra 235mm × 322mm
54 Letter Transverse 81/2½ × 11½
55 A4 Transverse 210mm × 297mm
56 Letter Extra Transv. 91/2½ × 12½
57 Super A/A4 227mm × 356mm
58 Super B/A3 305mm × 487mm
59 Letter Plus 812½ × 1211/16½
60 A4 Plus 210mm × 330mm
61 A5 Transverse 148mm × 210mm
62 B5 (JIS) Transverse 182mm × 257mm
63 A3 Extra 322mm × 445mm
64 A5 Extra 174mm × 235mm
65 B5 (ISO) Extra 201mm × 276mm
66 A2 420mm × 594mm
67 A3 Transverse 297mm × 420mm
68 A3 Extra Transverse 322mm × 445mm
69 Dbl. Japanese Postcard 200mm × 148mm
70 A6 105mm × 148mm
71
72
73
74
75 Letter Rotated 11½ × 81/2½
76 A3 Rotated 420mm × 297mm
77 A4 Rotated 297mm × 210mm
78 A5 Rotated 210mm × 148mm
79 B4 (JIS) Rotated 364mm × 257mm
80 B5 (JIS) Rotated 257mm × 182mm
81 Japanese Postcard Rot. 148mm × 100mm
82 Dbl. Jap. Postcard Rot. 148mm × 200mm
83 A6 Rotated 148mm × 105mm
84
85
86
87
88 B6 (JIS) 128mm × 182mm
89 B6 (JIS) Rotated 182mm × 128mm
90 12×11 12½ × 11½
*/
$this->xls_bof->append(XLSDATA_SHORT,0x0024); // scaling factor in percent
$this->xls_bof->append(XLSDATA_SHORT,0x0001); // start page number
$this->xls_bof->append(XLSDATA_SHORT,0x0001); // Fit worksheet width to this number of pages (0 = use as many as needed)
$this->xls_bof->append(XLSDATA_SHORT,0x0001); // Fit worksheet height to this number of pages (0 = use as many as needed)
$this->xls_bof->append(XLSDATA_SHORT,0x0146); /* Print options
bit mask
0 0001H 0 = Print pages in columns
1 = Print pages in rows
1 0002H 0 = Landscape
1 = Portrait
2 0004H 1 = Paper size, scaling factor, paper orientation (portrait/landscape),print resolution and number of copies are not initialised
3 0008H 0 = Print coloured
1 = Print black and white
4 0010H 0 = Default print quality
1 = Draft quality
5 0020H 0 = Do not print cell notes
1 = Print cell notes
6 0040H 0 = Use paper orientation (portrait/landscape) flag above1
1 = Use default paper orientation(landscape for chart sheets,portrait otherwise)
7 0080H 0 = Automatic page numbers
1 = Use start page number above The following flags are valid for BIFF8 only:
9 0200H 0 = Print notes as displayed
1 = Print notes at end of sheet
11-10 0C00H 002 = Print errors as displayed
012 = Do not print errors
102 = Print errors as ?--?
112 = Print errors as ?#N/A?
*/
$this->xls_bof->append(XLSDATA_SHORT,0x0033); // Print resolution in dpi
$this->xls_bof->append(XLSDATA_SHORT,0xff00); // Vertical print resolution in dpi
$this->xls_bof->append(XLSDATA_LONG,0x33333333); // Header margin
$this->xls_bof->append(XLSDATA_LONG,0x3fd33333); // Header margin
$this->xls_bof->append(XLSDATA_LONG,0x33333333); // Footer margin
$this->xls_bof->append(XLSDATA_LONG,0x3fd33333); // Footer margin
$this->xls_bof->append(XLSDATA_SHORT,0x00ff); // Number of copies to print
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_writeexterninfo();
$this->xls_bof->clear(BIFF_DEFCOLWIDTH);
$this->xls_bof->append(XLSDATA_SHORT,0x0008);
$this->xls_bof->save($this->xlsfilehandle);
$i=-1;
while ($i<$this->worksheets[$sheetid]["last_col"]) {
$i++;
if (isset($this->worksheets[$sheetid]["colwidths"][$i])) {
$this->xls_bof->clear(BIFF_COLINFO);
$this->xls_bof->append(XLSDATA_SHORT,$i); // Index to first column in the range
$this->xls_bof->append(XLSDATA_SHORT,$i); // Index to last column in the range
$this->xls_bof->append(XLSDATA_SHORT,$this->worksheets[$sheetid]["colwidths"][$i]); // Width of the columns in 1/256 of the width of the zero character, using default font (first FONT record in the file)
$this->xls_bof->append(XLSDATA_SHORT,$this->xf->defaultxf);
//$this->xls_bof->append(XLSDATA_SHORT,(($i<=$this->worksheets[$sheetid]["first_col"]) ? 0x0002 : 0x0000));
$this->xls_bof->append(XLSDATA_SHORT,0x0002);
/* Offset Bits Mask Option Name Contents
0 0 01h fHidden =1 if the column range is hidden
7-1 FEh (unused)
1 2-0 07h iOutLevel Outline level of column range
3 08h (Reserved) Reserved; must be 0 (zero)
4 10h fCollapsed =1 if the column range is collapsed in outlining
7-5 E0h (Reserved) Reserved; must be 0 (zero)
*/
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // Not used
$this->xls_bof->save($this->xlsfilehandle);
}
}
$this->xls_bof->clear(BIFF_DIMENSIONS);
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // first row
$this->xls_bof->append(XLSDATA_SHORT,$this->worksheets[$sheetid]["last_row"]+1); // last used row + 1
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // first col
$this->xls_bof->append(XLSDATA_SHORT,$this->worksheets[$sheetid]["last_col"]+1); // last used col + 1
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // not used
$this->xls_bof->save($this->xlsfilehandle);
$rowrecord_count = 0;
$i=0;
$sheetdata = &$this->xlsdocument[$this->worksheets[$sheetid]["sheetname"]]["document"];
if (count($sheetdata)>1) {
ksort ($sheetdata,SORT_NUMERIC);
}
while ($i<$this->worksheets[$sheetid]["last_row"]+1) {
$j=0;
$rowrecord_start = ftell($this->xlsfilehandle);
while (($j!=32) && ($i<$this->worksheets[$sheetid]["last_row"]+1)) {
if (isset($sheetdata[$i])) {
if (@isset($this->worksheets[$sheetid]["rowheights"][$i])) {
$this->xls_bof->clear(BIFF_ROW);
$this->xls_bof->append(XLSDATA_SHORT,$i); // row no.
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // first defined column
$this->xls_bof->append(XLSDATA_SHORT,$this->worksheets[$sheetid]["last_col"]+1); // last defined column +1
$this->xls_bof->append(XLSDATA_SHORT,$this->worksheets[$sheetid]["rowheights"][$i]); // row height
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // Used by Excel to optimize loading the file; if you are creating a BIFF file, set irwMac to 0.
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // reserved
$this->xls_bof->append(XLSDATA_BYTE,($this->worksheets[$sheetid]["rowheights"][$i]==0xff ? 0 : 0x40)); // see options @ offset 0
$this->xls_bof->append(XLSDATA_BYTE,0x01); /* options
Offset Bits Mask Name Contents
0 2?0 07h iOutLevel Outline level of the row
3 08h (Reserved)
4 10h fCollapsed =1 if the row is collapsed in outlining
5 20h fDyZero =1 if the row height is set to 0 (zero)
6 40h fUnsynced =1 if the font height and row height are not compatible
7 80h fGhostDirty =1 if the row has been formatted, even if it contains all blank cells
1 7?0 FFh (Reserved) ????
*/
$this->xls_bof->append(XLSDATA_SHORT,0x000f); /* If fGhostDirty=1 (see grbit field), this is the index to the XF record for the row.
Otherwise, this field is undefined.
Note: ixfe uses only the low-order 12 bits of the field (bits 11?0).
Bit 12 is fExAsc, bit 13 is fExDsc, and bits 14 and 15 are reserved.
fExAsc and fExDsc are set to true if the row has a thick border on top or on bottom,
respectively.
*/
$this->xls_bof->save($this->xlsfilehandle);
}
}
$i++;
$j++;
}
$i=$i-$j;
$j=0;
$rowpos = array();
while (($j!=32) && ($i<$this->worksheets[$sheetid]["last_row"]+1)) {
if (isset($sheetdata[$i])) {
$rowpos[]=ftell($this->xlsfilehandle);
$rowdata = &$sheetdata[$i];
if (count($rowdata)>1) {
ksort($rowdata,SORT_NUMERIC);
}
foreach ($rowdata as $cellid => $celldata) {
switch ($celldata["type"]) {
case CELL_STRING :
$this->xls_bof->clear(BIFF_LABEL);
$this->xls_bof->append(XLSDATA_SHORT,$i); // rowid.
$this->xls_bof->append(XLSDATA_SHORT,$cellid); // cellid
$this->xls_bof->append(XLSDATA_SHORT,$celldata["xfindex"]); // XF index.
$this->xls_bof->append(XLSDATA_LSTRING,$celldata["data"]);
$this->xls_bof->save($this->xlsfilehandle);
break;
case CELL_FLOAT :
$this->xls_bof->clear(BIFF_NUMBER);
$this->xls_bof->append(XLSDATA_SHORT,$i); // rowid.
$this->xls_bof->append(XLSDATA_SHORT,$cellid); // cellid
$this->xls_bof->append(XLSDATA_SHORT,$celldata["xfindex"]); // XF index.
$this->xls_bof->append(XLSDATA_FLOAT,floatval($celldata["data"]));
$this->xls_bof->save($this->xlsfilehandle);
break;
case CELL_PICTURE :
if (defined("PICTUREDEBUG")) {
echo "picture inserted<br>\n";
}
$bgcolor = (isset($celldata["bgcolor"]) ? $celldata["bgcolor"] : 9);
$fgcolor = (isset($celldata["color"]) ? $celldata["color"] : 9);
$bgcolorrgb = $this->palette->palette_array[$bgcolor-8];
$picture = new xls_picture($celldata["data"],$bgcolor,$fgcolor,$bgcolorrgb,$this->objectcounter,$i,$cellid);
$picture->loaddata();
$imageheight = ($picture->imageheight << 4)+$picture->imageheight;
$imagewidth = ($picture->imagewidth << 5)+$picture->imagewidth;
//$imageheight = intval(round($picture->imageheight*18));
//$imagewidth = intval(round($picture->imagewidth*36));
$picture->lastrow = $i;
$picture->lastcol = $cellid;
$rcnt = $i;
$ok = false;
if (defined("PICTUREDEBUG")) {
echo "calc. space<br>\n";
echo "start row : ".$picture->firstrow."<br>\n";
}
while (!$ok) {
$tmprowheight = (isset($this->worksheets[$sheetid]["rowheights"][$rcnt]) ? $this->worksheets[$sheetid]["rowheights"][$rcnt] : XLSFILE_DEFAULT_ROWHEIGHT);
if (defined("PICTUREDEBUG")) {
echo "?last row : ".$picture->lastrow." , picture height : $imageheight , tmpheight : $tmprowheight<br>\n";
}
if ($tmprowheight>=$imageheight) {
if (defined("PICTUREDEBUG")) {
echo "height calc. finish<br>\n";
}
$picture->imagebottom = $imageheight;
$ok=true;
continue;
}
else {
$picture->lastrow++;
$imageheight -= ($tmprowheight+18);
$rcnt++;
}
}
if (defined("PICTUREDEBUG")) {
echo "calc. space<br>\n";
echo "start row : ".$picture->firstcol."<br>\n";
}
$ccnt = $cellid;
$ok = false;
while (!$ok) {
$tmpcolwidth = (isset($this->worksheets[$sheetid]["colwidths"][$ccnt]) ? $this->worksheets[$sheetid]["colwidths"][$ccnt] : XLSFILE_DEFAULT_COLWIDTH);
if (defined("PICTUREDEBUG")) {
echo "?last row : ".$picture->lastcol." , picture width : $imagewidth , tmpwidth : $tmpcolwidth<br>\n";
}
if ($tmpcolwidth>=$imagewidth) {
if (defined("PICTUREDEBUG")) {
echo "width calc. finish<br>\n";
}
$ok=true;
$picture->imageright = $imagewidth;
}
else {
$picture->lastcol++;
$imagewidth -= ($tmpcolwidth+36);
$ccnt++;
}
}
/*
$picture->imagebottom = intval(round($imageheight*($tmprowheight/1024)));
$picture->imageright = intval(round($imagewidth*($tmpcolwidth/1024)));
*/
$picture->imagebottom = $imageheight / $tmprowheight * 256;
$picture->imageright = $imagewidth / $tmpcolwidth * 1024;
$picture->save($this->xlsfilehandle, $this->xls_bof);
unset($picture);
$this->objectcounter++;
break;
default : die("Unknown cell data type");
}
}
}
$i++;
$j++;
}
$filepos_backup = ftell($this->xlsfilehandle);
fseek($this->xlsfilehandle,$rowrecord_filepos[$rowrecord_count],SEEK_SET);
$s = pack("V",$filepos_backup-0x0200);
fwrite($this->xlsfilehandle,$s);
fseek($this->xlsfilehandle,$filepos_backup,SEEK_SET);
$this->xls_bof->clear(BIFF_DBCELL);
$this->xls_bof->append(XLSDATA_LONG,$filepos_backup-$rowrecord_start);
$this->xls_bof->append(XLSDATA_SHORT,($rowpos[0]-$rowrecord_start)-0x14);
foreach ($rowpos as $key => $data) {
if ($key==count($rowpos)-1) {
break;
}
$offset = $rowpos[0]-$data;
$this->xls_bof->append(XLSDATA_SHORT,$offset);
}
$this->xls_bof->save($this->xlsfilehandle);
unset($rowpos);
$rowrecord_count++;
}
$this->xls_bof->clear(BIFF_WINDOW2);
$sheetopt = ($sheetid==0 ? 0x06b6 : 0x00b6);
$this->xls_bof->append(XLSDATA_SHORT,$sheetopt); /* Bit Mask Contents
0 0001H 0 = Show formula results 1 = Show formulas
1 0002H 0 = Do not show grid lines 1 = Show grid lines
2 0004H 0 = Do not show sheet headers 1 = Show sheet headers
3 0008H 0 = Panes are not frozen 1 = Panes are frozen (freeze)
4 0010H 0 = Show zero values as empty cells 1 = Show zero values
5 0020H 0 = Manual grid line colour 1 = Automatic grid line colour
6 0040H 0 = Columns from left to right 1 = Columns from right to left
7 0080H 0 = Do not show outline symbols 1 = Show outline symbols
8 0100H 0 = Keep splits if pane freeze is removed 1 = Remove splits if pane freeze is removed
9 0200H 0 = Sheet not selected 1 = Sheet selected (BIFF5-BIFF8)
10 0400H 0 = Sheet not active 1 = Sheet active (BIFF5-BIFF8)
11 0800H 0 = Show in normal view 1 = Show in page break preview (BIFF8)
*/
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // Index to first visible row
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // Index to first visible column
$this->xls_bof->append(XLSDATA_LONG,0x00000040); // Grid line RGB colour
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(BIFF_SELECTION);
$this->xls_bof->append(XLSDATA_BYTE,0x03);
$this->xls_bof->append(XLSDATA_SHORT,$this->worksheets[$sheetid]["first_row"]); // Index to row of the active cell
$this->xls_bof->append(XLSDATA_SHORT,$this->worksheets[$sheetid]["first_col"]); // Index to column of the active cell
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // Index into the following cell range list to the entry that contains the active cell
$this->xls_bof->append(XLSDATA_SHORT,0x0001);
$this->xls_bof->append(XLSDATA_SHORT,0); // $this->worksheets[$sheetid]["first_row"]
$this->xls_bof->append(XLSDATA_SHORT,0); // $this->worksheets[$sheetid]["last_row"]
$this->xls_bof->append(XLSDATA_BYTE,0); // $this->worksheets[$sheetid]["last_col"]
$this->xls_bof->append(XLSDATA_BYTE,0); // $this->worksheets[$sheetid]["last_col"]
$this->xls_bof->save($this->xlsfilehandle);
if (isset($this->xlsdocument[$this->worksheets[$sheetid]["sheetname"]]["mergedcells"])) {
$this->xlsdocument[$this->worksheets[$sheetid]["sheetname"]]["mergedcells"]->save($this->xlsfilehandle, $this->xls_bof);
}
$this->xls_bof->clear(BIFF_SHEETPROTECTION);
$this->xls_bof->append(XLSDATA_SHORT,BIFF_SHEETPROTECTION);
$this->xls_bof->append(XLSDATA_BYTE,0x00); // not used
$this->xls_bof->append(XLSDATA_BYTE,0x00); // not used
$this->xls_bof->append(XLSDATA_BYTE,0x00); // not used
$this->xls_bof->append(XLSDATA_BYTE,0x00); // not used
$this->xls_bof->append(XLSDATA_BYTE,0x00); // not used
$this->xls_bof->append(XLSDATA_BYTE,0x00); // not used
$this->xls_bof->append(XLSDATA_BYTE,0x00); // not used
$this->xls_bof->append(XLSDATA_BYTE,0x00); // not used
$this->xls_bof->append(XLSDATA_BYTE,0x00); // not used
$this->xls_bof->append(XLSDATA_BYTE,0x00); // not used
$this->xls_bof->append(XLSDATA_BYTE,0x02); // unknown data
$this->xls_bof->append(XLSDATA_BYTE,0x00); // unknown data
$this->xls_bof->append(XLSDATA_BYTE,0x01); // unknown data
$this->xls_bof->append(XLSDATA_BYTE,0xff); // unknown data
$this->xls_bof->append(XLSDATA_BYTE,0xff); // unknown data
$this->xls_bof->append(XLSDATA_BYTE,0xff); // unknown data
$this->xls_bof->append(XLSDATA_BYTE,0xff); // unknown data
$this->xls_bof->append(XLSDATA_SHORT,0x4400); // ???
$this->xls_bof->append(XLSDATA_SHORT,0x0000); // not used
$this->xls_bof->save($this->xlsfilehandle);
$this->xls_bof->clear(XLS_BIFF_EOF);
$this->xls_bof->save($this->xlsfilehandle);
}
private function xls_writeminifat() {
$minifat_start = ftell($this->xlsfilehandle);
$minifat_sectorid = pack("V",($minifat_start-0x0200)/0x0200);
if ($this->xlsstreamsize>=0x1000) {
$s = pack("V",0x00000001);
$s .= pack("V",0xfffffffe);
$s .= pack("V",0x00000003);
$s .= pack("V",0xfffffffe);
$s = str_pad($s,512,chr(0xff));
fwrite($this->xlsfilehandle,$s,512);
}
else {
$s = "";
$scount = $this->xlsstreamsize >> 6;
$scount+= (($this->xlsstreamsize & 0x3f)>0 ? 1 : 0);
$scount--;
for ($i=0; $i!=$scount; $i++) {
$s .= pack ("V",$i+1);
}
$scount++;
$s .= pack("V",0xfffffffe);
$scount++;
$s .= pack("V",$scount);
$scount++;
$s .= pack("V",0xfffffffe);
$scount++;
$s .= pack("V",$scount);
$scount++;
$s .= pack("V",0xfffffffe);
$s = str_pad($s,512,chr(0xff));
fwrite($this->xlsfilehandle,$s,512);
}
$fpos = ftell($this->xlsfilehandle);
fseek($this->xlsfilehandle,0x003c,SEEK_SET);
fwrite($this->xlsfilehandle,$minifat_sectorid,4);
fseek($this->xlsfilehandle,$fpos,SEEK_SET);
}
private function xls_writerootstorage() {
$s="";
$s.=pack("C*",0xfe,0xff,0x00,0x00,0x04,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
$s.=pack("C*",0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0xd5,0xcd,0xd5);
$s.=pack("C*",0x9c,0x2e,0x1b,0x10,0x93,0x97,0x08,0x00,0x2b,0x2c,0xf9,0xae,0x30,0x00,0x00,0x00);
$s.=pack("C*",0x18,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x10,0x00,0x00,0x00);
$s.=pack("C*",0x02,0x00,0x00,0x00,0xe4,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
$s.=pack("C*",0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
$s.=pack("C*",0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
$s.=pack("C*",0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
$s.=pack("C*",0xfe,0xff,0x00,0x00,0x04,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
$s.=pack("C*",0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xe0,0x85,0x9f,0xf2);
$s.=pack("C*",0xf9,0x4f,0x68,0x10,0xab,0x91,0x08,0x00,0x2b,0x27,0xb3,0xd9,0x30,0x00,0x00,0x00);
$s.=pack("C*",0x18,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x10,0x00,0x00,0x00);
$s.=pack("C*",0x02,0x00,0x00,0x00,0xe4,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
$s.=pack("C*",0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
$s.=pack("C*",0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
$s.=pack("C*",0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
fwrite($this->xlsfilehandle,$s,256);
}
/*
struct StructuredStorageDirectoryEntry {
// [offset from start in bytes, length in bytes]
BYTE _ab[32*sizeof(WCHAR)]; // [000H,64] 64 bytes. The Element name in Unicode, padded with zeros to fill this byte array
WORD _cb; // [040H,02] Length of the Element name in characters, not bytes
BYTE _mse; // [042H,01] Type of object: value taken from the STGTY enumeration
STGTY_INVALID = 0,
STGTY_STORAGE = 1,
STGTY_STREAM = 2,
STGTY_LOCKBYTES = 3,
STGTY_PROPERTY = 4,
STGTY_ROOT = 5,
BYTE _bflags; // [043H,01] Value taken from DECOLOR enumeration.
DE_RED = 0,
DE_BLACK = 1,
SID _sidLeftSib; // [044H,04] SID of the left-sibling of this entry in the directory tree
SID _sidRightSib; // [048H,04] SID of the right-sibling of this entry in the directory tree
SID _sidChild; // [04CH,04] SID of the child acting as the root of all the children of this element (if _mse=STGTY_STORAGE)
GUID _clsId; // [050H,16] CLSID of this storage (if _mse=STGTY_STORAGE)
DWORD _dwUserFlags; // [060H,04] User flags of this storage (if _mse=STGTY_STORAGE)
TIME_T _time[2]; // [064H,16] Create/Modify time-stamps (if _mse=STGTY_STORAGE)
SECT _sectStart; // [074H,04] starting SECT of the stream (if _mse=STGTY_STREAM)
ULONG _ulSize; // [078H,04] size of stream in bytes (if _mse=STGTY_STREAM)
DFPROPTYPE _dptPropType; // [07CH,02] Reserved for future use. Must be zero.
};
*/
private function xls_writedirentry($adirname,$adirtype,$adecolor,$arightchild,$asectorid,$asize) {
$dirname = "";
for ($i=0; $i<strlen($adirname); $i++) {
$dirname .= $adirname{$i}.chr(0);
}
$dirname = str_pad($dirname,64,chr(0));
$namelen = (strlen($adirname)*2)+2;
fwrite($this->xlsfilehandle,$dirname,64);
fwrite($this->xlsfilehandle,pack("v",$namelen));
fwrite($this->xlsfilehandle,pack("C",$adirtype));
fwrite($this->xlsfilehandle,pack("C",$adecolor));
fwrite($this->xlsfilehandle,pack("V",0xffffffff));
fwrite($this->xlsfilehandle,pack("V",$arightchild));
fwrite($this->xlsfilehandle,pack("V",($adirname=="Root Entry" ? 0x00000001 : 0xffffffff)));
$s = str_repeat(chr(0),16);
fwrite($this->xlsfilehandle,$s,16);
fwrite($this->xlsfilehandle,pack("V",0x00000000));
fwrite($this->xlsfilehandle,$s,16);
fwrite($this->xlsfilehandle,pack("V",$asectorid));
fwrite($this->xlsfilehandle,pack("V",$asize));
fwrite($this->xlsfilehandle,pack("v",0x0000));
fwrite($this->xlsfilehandle,pack("v",0x0000));
}
public function sendfile($afilename) {
// 2009-10-22 - modified by Helmut Schottmüller
// Change path to TYPOlight temp dir
$currentdir = getcwd();
chdir(TL_ROOT . '/system/tmp');
// 2009-10-22 - end modification
$tmpname = "tmp".date("YmdHi").".xls";
$this->savefile($tmpname);
header("Content-Type:application/force-download");
$headerfilename=sprintf("Content-Disposition: attachment; filename=%s",$afilename);
header($headerfilename);
header("Content-Transfer-Encoding: binary");
$dlfilesize = filesize($tmpname);
header("Content-Length: ".$dlfilesize);
@readfile($tmpname,$afilename);
unlink($tmpname);
// 2009-10-22 - modified by Helmut Schottmüller
// Change path back to current dir
chdir($currentdir);
// 2009-10-22 - end modification
}
// additional getters
// 2010-02-02 - modified by Helmut Schottmüller, methods by Georg Rehfeld
/**
* Returns the width of the given column.
*
* The return value is in terms of 256 times the width of the 0 (zero) character in
* the default font (the first one defined). When devided by 256 it is
* roughly comparable to CSS 'en' units.
*/
public function getcolwidth($sheetname, $acolidx) {
$sheetid = $this->xlsdocument[$sheetname]["worksheetid"];
if (isset($this->worksheets[$sheetid]["colwidths"][$acolidx]))
{
return $this->worksheets[$sheetid]["colwidths"][$acolidx];
}
return XLSFILE_DEFAULT_COLWIDTH; // 0x0924 = 2340 = 9.14 en ?
}
/**
* Returns the height of the given row.
*
* The return value is in terms of 256 times the width of the 0 (zero) character in
* the default font (the first one defined). When devided by 256 it is
* roughly comparable to CSS 'en' units.
*
* @TODO: there seems to be a need for some scale factor, when used with cw/ccw text?
*/
public function getrowheight($sheetname, $arowidx) {
$sheetid = $this->xlsdocument[$sheetname]["worksheetid"];
if (isset($this->worksheets[$sheetid]["rowheights"][$arowidx]))
{
return $this->worksheets[$sheetid]["rowheights"][$arowidx];
}
return XLSFILE_DEFAULT_ROWHEIGHT; // 0x012c = 300 = 1.17 en ?
}
// 2010-02-02 - end modification
}
?>