438 lines
No EOL
11 KiB
PHP
438 lines
No EOL
11 KiB
PHP
<?php
|
|
|
|
class Excel_Number
|
|
{
|
|
public $value;
|
|
|
|
function __construct($value)
|
|
{
|
|
$this->value = $value;
|
|
}
|
|
|
|
function getString()
|
|
{
|
|
return $this->value;
|
|
}
|
|
}
|
|
|
|
class Excel_DateTime
|
|
{
|
|
public $value;
|
|
|
|
function __construct($value)
|
|
{
|
|
$this->value = intval($value);
|
|
}
|
|
|
|
function getString()
|
|
{
|
|
return date('Y-m-d\TH:i:s.u', $this->value);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Êëåòêà òàáëèöû
|
|
*/
|
|
class TableCell
|
|
{
|
|
public $style = false;
|
|
public $value;
|
|
public $merge = false;
|
|
|
|
function __construct ($value)
|
|
{
|
|
$this->value = $value;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Ðÿä òàáëèöû
|
|
*/
|
|
class TableRow
|
|
{
|
|
public $style = false;
|
|
public $cells = array();
|
|
public $height = false;
|
|
|
|
function setCell($y, $value)
|
|
{
|
|
$this->cells[$y] = new TableCell($value);
|
|
}
|
|
|
|
function setCellStyle($y, $name)
|
|
{
|
|
$this->cells[$y]->style = $name;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Òàáëèöà
|
|
*/
|
|
class ExcelTable
|
|
{
|
|
static $index;
|
|
private $name;
|
|
private $style;
|
|
protected $rows = array();
|
|
|
|
protected $splitVertical = false;
|
|
protected $splitHorizontal = false;
|
|
|
|
function __construct()
|
|
{
|
|
$this->name = "Page " . intval(self::$index ++);
|
|
}
|
|
|
|
/**
|
|
* Çàïèñàòü çíà÷åíèå â êëåòêó ñ çàäàííûìè êîîðäèíàòàìè
|
|
*/
|
|
function setCell($x, $y, $value)
|
|
{
|
|
assert(is_numeric($x) && $x > 0);
|
|
assert(is_numeric($y) && $y > 0);
|
|
|
|
if(! isset($this->rows[$x])) {
|
|
$this->rows[$x] = new TableRow();
|
|
}
|
|
$this->rows[$x]->setCell($y, $value);
|
|
}
|
|
|
|
/**
|
|
* Çàïîëíÿåò ðÿä íà÷èíàÿ ñ óêàçàííîãî ñòîëáöà çíà÷åíèÿìè èç ìàññèâà
|
|
*/
|
|
function setRow($row, $index, array $data)
|
|
{
|
|
assert(is_numeric($index) && $index > 0);
|
|
assert(is_numeric($row) && $row > 0);
|
|
|
|
reset($data);
|
|
for ($i = $index; $i < $index + count($data); $i++) {
|
|
$this->setCell($row, $i, current($data));
|
|
next($data);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Óñòàíàâëèâàåò âûñîòó ðÿäà
|
|
* @param $row integer Íîìåð ðÿäà
|
|
* @parma $value real Âûñîòà ðÿäà
|
|
*/
|
|
function setRowHeight ($row, $value)
|
|
{
|
|
assert(is_numeric($row) && $row > 0);
|
|
|
|
$this->rows[$row]->height = $value;
|
|
}
|
|
|
|
/**
|
|
* Óñòàíàâëèâàåò ñòèëü ðÿäà
|
|
* @param $row integer Íîìåð ðÿäà
|
|
* @parma $name string Èìÿ ñòèëÿ
|
|
*/
|
|
function setRowStyle ($row, $name)
|
|
{
|
|
assert(is_numeric($row) && $row > 0);
|
|
|
|
$this->rows[$row]->style = $name;
|
|
}
|
|
|
|
/**
|
|
* Îáüåäèíÿåò êëåòêè â ñòðîêå
|
|
* @param $row Íîìåð ðÿäà
|
|
* @param $cell Íîìåð ñòîëáöà
|
|
* @param $merge Êîëè÷åñòâî êëåòîê äëÿ îáüåäèíåíèÿ
|
|
*/
|
|
function setCellMerge ($row, $cell, $merge)
|
|
{
|
|
assert(is_numeric($row) && $row > 0);
|
|
assert(is_numeric($cell) && $cell > 0);
|
|
|
|
$this->rows[$row]->cells[$cell]->merge = $merge;
|
|
}
|
|
|
|
/**
|
|
* Óñòàíàâëèâàåò ñòèëü äëÿ êëåòîê ðÿäà
|
|
* @param $row integer Íîìåð ðÿäà
|
|
* @param $y integer Íîìåð ñòîëáöà
|
|
* @parma $name string Èìÿ ñòèëÿ
|
|
*/
|
|
function setCellStyle ($row, $y, $name)
|
|
{
|
|
if (isset($this->rows[$row]))
|
|
$this->rows[$row]->setCellStyle($y, $name);
|
|
}
|
|
|
|
/**
|
|
* Äîáàâëÿåò ñòðîêó ê òàáëèöå
|
|
*/
|
|
function addRow($index = 1, array $data = array(""))
|
|
{
|
|
assert(is_numeric($index) && $index > 0);
|
|
$offset = $this->getRows() + 1;
|
|
|
|
$this->setRow($offset, $index, $data);
|
|
return $offset;
|
|
}
|
|
|
|
/**
|
|
* Êîëè÷åñòâî ñòðîê â òàáëèöå
|
|
*
|
|
* @return int
|
|
*/
|
|
function getRows()
|
|
{
|
|
return max(array_keys($this->rows));
|
|
}
|
|
|
|
/**
|
|
* Êîëè÷åñòâî ñòîëáöîâ â ñòðîêå
|
|
*
|
|
* @return int
|
|
*/
|
|
function getRowCells($row)
|
|
{
|
|
return max(array_keys($row->cells));
|
|
}
|
|
|
|
/**
|
|
* Ðàçäåëÿåò òàáëèöó íà äâå ÷àñòè ïî âåðòèêàëè
|
|
* @param $n integer Êîëè÷åñòâî ñòîëáöîâ ñëåâà
|
|
*/
|
|
function splitVertical($n)
|
|
{
|
|
$this->splitVertical = $n;
|
|
}
|
|
|
|
/**
|
|
* Ðàçäåëÿåò òàáëèöó íà äâå ÷àñòè ïî ãîðèçîíòàëè
|
|
* @param $n integer Êîëè÷åñòâî ñòîëáöîâ ñâåðõó
|
|
*/
|
|
function splitHorizontal($n)
|
|
{
|
|
$this->splitHorizontal = $n;
|
|
}
|
|
|
|
|
|
/**
|
|
* Êîëè÷åñòâî ñòîëáöîâ â òàáëèöå
|
|
*
|
|
* @return int
|
|
*/
|
|
function getColumns()
|
|
{
|
|
return max(array_map(array($this, 'getRowCells'), $this->rows));
|
|
}
|
|
|
|
function encode($s)
|
|
{
|
|
return iconv("WINDOWS-1251", "UTF-8", $s);
|
|
}
|
|
|
|
/**
|
|
* Ãåíåðàöèÿ êëåòêè òàáëèöû (Ïåðåðàáîòàòü)
|
|
*/
|
|
function createCell ($ncell, XMLWriter $doc, $j, $value, $setIndex) {
|
|
$doc->startElement("Cell");
|
|
|
|
if ($ncell->style) {
|
|
$doc->writeAttribute('ss:StyleID', $ncell->style);
|
|
}
|
|
|
|
if ($ncell->merge) {
|
|
$doc->writeAttribute('ss:MergeAcross', $ncell->merge);
|
|
}
|
|
|
|
if ($setIndex) {
|
|
$doc->writeAttribute('ss:Index', $j);
|
|
}
|
|
|
|
$doc->startElement("Data");
|
|
if ($value instanceof Excel_DateTime) {
|
|
$doc->writeAttribute('ss:Type', "DateTime");
|
|
$doc->text($value->getString());
|
|
} else if ($value instanceof Excel_Number) {
|
|
$doc->writeAttribute('ss:Type', "Number");
|
|
$doc->text($value->getString());
|
|
} else {
|
|
if (is_string($value)) {
|
|
$doc->writeAttribute('ss:Type', "String");
|
|
} else {
|
|
$doc->writeAttribute('ss:Type', "Number");
|
|
}
|
|
$doc->writeCData($this->encode($value));
|
|
}
|
|
$doc->endElement();
|
|
$doc->endElement();
|
|
}
|
|
|
|
/**
|
|
* Ãåíåðàöèÿ òàáëèöû
|
|
*/
|
|
public function createTable (XMLWriter $doc) {
|
|
$doc->startElement('Worksheet');
|
|
$doc->writeAttribute('ss:Name', $this->name);
|
|
|
|
$columns = $this->getColumns();
|
|
$rows = $this->getRows();
|
|
|
|
$doc->startElement('Table');
|
|
$doc->writeAttribute('ss:ExpandedColumnCount', $columns);
|
|
$doc->writeAttribute('ss:ExpandedRowCount', $rows);
|
|
|
|
// Ïåðåïèñàòü öûêë !!!!!!!
|
|
for ($i = 1; $i <= $rows; $i++) {
|
|
$doc->startElement('Row');
|
|
if (isset($this->rows[$i])) {
|
|
if ($this->rows[$i]->style) {
|
|
$doc->writeAttribute('ss:StyleID', $this->rows[$i]->style);
|
|
}
|
|
|
|
if ($this->rows[$i]->height) {
|
|
$doc->writeAttribute('ss:Height', $this->rows[$i]->height);
|
|
}
|
|
|
|
$nrow = $this->rows[$i];
|
|
// Ôëàã èíäèêàòîð ïîäñòàíîâêè íîìåðà ñòîëáöà
|
|
$setIndex = false;
|
|
for ($j = 1; $j <= $columns; $j++) {
|
|
|
|
$value = null;
|
|
if (isset($nrow->cells[$j])) {
|
|
$value = $nrow->cells[$j]->value;
|
|
}
|
|
|
|
if (!empty($value)) {
|
|
$this->createCell($nrow->cells[$j], $doc, $j, $value, $setIndex);
|
|
$setIndex = false;
|
|
} else {
|
|
$setIndex = true;
|
|
}
|
|
}
|
|
}
|
|
$doc->endElement();
|
|
}
|
|
$doc->endElement();
|
|
$this->splitPane ($doc);
|
|
$doc->endElement();
|
|
}
|
|
|
|
protected function splitPane (XMLWriter $doc) {
|
|
$doc->startElement('WorksheetOptions');
|
|
$doc->writeAttribute('xmlns', 'urn:schemas-microsoft-com:office:excel');
|
|
|
|
$doc->writeElement('FrozenNoSplit');
|
|
if ($this->splitVertical) {
|
|
$doc->writeElement('SplitVertical', $this->splitVertical);
|
|
$doc->writeElement('LeftColumnRightPane', $this->splitVertical);
|
|
}
|
|
if ($this->splitHorizontal) {
|
|
$doc->writeElement('SplitHorizontal', $this->splitHorizontal);
|
|
$doc->writeElement('TopRowBottomPane', $this->splitHorizontal);
|
|
}
|
|
if ($this->splitHorizontal && $this->splitVertical) {
|
|
$doc->writeElement('ActivePane', 0);
|
|
} else if($this->splitHorizontal) {
|
|
$doc->writeElement('ActivePane', 2);
|
|
}
|
|
$doc->endElement();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Äîêóìåíò
|
|
*/
|
|
class ExcelDocument {
|
|
static $ns = "urn:schemas-microsoft-com:office:spreadsheet";
|
|
private $table = array ();
|
|
protected $styles = array();
|
|
|
|
function addTable($table) {
|
|
$this->table [] = $table;
|
|
}
|
|
|
|
/**
|
|
* Äîáàâëåíèå ñòèëÿ ê äîêóìåíòó
|
|
* @param $name string Èìÿ ñòèëÿ
|
|
* @param $values array Ïàðàìåòðû ñòèëÿ
|
|
* @param $type Òèï ñòèëÿ
|
|
*/
|
|
function setStyle ($name, array $values, $type = 'Interior')
|
|
{
|
|
if(!isset($this->styles[$name])) {
|
|
$this->styles[$name] = array();
|
|
}
|
|
$this->styles[$name][$type] = $values;
|
|
}
|
|
|
|
/**
|
|
* Ãåíåðàöèÿ ñòèëåé
|
|
*/
|
|
private function createStyles (XMLWriter $doc) {
|
|
$doc->startElement('Styles');
|
|
foreach ($this->styles as $name => $sn) {
|
|
$doc->startElement('Style');
|
|
$doc->writeAttribute('ss:ID', $name);
|
|
foreach ($sn as $type => $s) {
|
|
// Ñòèëü Borders - ñîñòàâíîé
|
|
if ($type == 'Borders') {
|
|
$doc->startElement('Borders');
|
|
foreach ($s as $border) {
|
|
$doc->startElement('Border');
|
|
foreach ($border as $key => $value) {
|
|
$doc->writeAttribute('ss:' . $key, $value);
|
|
}
|
|
$doc->endElement();
|
|
}
|
|
$doc->endElement();
|
|
} else {
|
|
$doc->startElement($type);
|
|
foreach ($s as $key => $value) {
|
|
$doc->writeAttribute('ss:' . $key, $value);
|
|
}
|
|
$doc->endElement();
|
|
}
|
|
}
|
|
$doc->endElement();
|
|
}
|
|
$doc->endElement();
|
|
}
|
|
|
|
/**
|
|
* Ïðåîáðàçóåò ïåðåâîäû ñòðîêè â ñïåö ñèìâîëû
|
|
*/
|
|
function clean ($s) {
|
|
assert(is_string($s));
|
|
|
|
return strtr($s, array ("\n" => ' '));
|
|
}
|
|
|
|
/**
|
|
* Ñîõðàíÿåò òàáëèöó â ôîðìàòå Office 2003 XML
|
|
* http://en.wikipedia.org/wiki/Microsoft_Office_XML_formats
|
|
*/
|
|
function save($filename)
|
|
{
|
|
$doc = new xmlWriter();
|
|
$doc->openURI($filename);
|
|
$doc->setIndent(false);
|
|
$doc->startDocument('1.0','windows-1251');
|
|
$doc->startElement('Workbook');
|
|
$doc->writeAttribute('xmlns', self::$ns);
|
|
$doc->writeAttribute('xmlns:ss', self::$ns);
|
|
|
|
$this->createStyles($doc);
|
|
|
|
foreach ($this->table as $table) {
|
|
if ($table instanceof ExcelTable) {
|
|
$table->createTable($doc);
|
|
} else {
|
|
$table_data = call_user_func($table);
|
|
$table_data->createTable($doc);
|
|
unset($table_data);
|
|
}
|
|
}
|
|
$doc->endElement();
|
|
}
|
|
}
|
|
|
|
?>
|