00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 require_once(dirname(__FILE__) . '/KjwObject.php');
00033
00034 class KjwSimpleXmlWorkbook extends KjwObject {
00035 var $_null = null;
00036
00037 function KjwSimpleXmlWorkbook() {
00038 $this->_initEmpty();
00039 }
00040
00041 function _initEmpty() {
00042 $this->_encoding = 'UTF-8';
00043 $this->_author = 'KjwSimpleXmlWorkbook.php';
00044 $this->_company = 'All4students / KjwLib';
00045 $this->_data = array();
00046 $this->_createDate = strftime('%Y-%m%dT%H:%M:%SZ');
00047 $this->_currentWorksheet = null;
00048 }
00049
00050 function &newWorkbook() {
00051 $this->_initEmpty();
00052 return $this;
00053 }
00054
00058 function &newWorksheet($sheetName) {
00059 if (($sheet = $this->_getWorksheet($sheetName)) !== null)
00060 return false;
00061 array_push($this->_data, array('_TAG' => 'Worksheet', 'Name' => $sheetName, '_DATA' => array()));
00062 $this->_currentWorksheet = &$this->_getWorksheet($sheetName);
00063 return $this;
00064 }
00065
00066 function &newWorksheetFromResultSet(&$result, $sheetName) {
00067 $this->newWorksheet($sheetName);
00068 $at = $result->at();
00069 $result->seekAbs(0);
00070 while (($row = $result->getNext())) {
00071 if ($result->at() == 1)
00072 $this->addHeaderRow(array_keys($row));
00073 $this->addRow($row);
00074 }
00075 $result->seekAbs($at);
00076 return $this;
00077 }
00078
00082 function &_getWorksheet($sheetName) {
00083 foreach ($this->_data as $key => $value) {
00084 if ($value['Name'] == $sheetName)
00085 return $this->_data[$key];
00086 }
00087 return $this->_null;
00088 }
00089
00090 function setAuthor($author) {
00091 $this->_author = $author;
00092 }
00093
00094 function setCompany($company) {
00095 $this->_company = $company;
00096 }
00097
00098 function _toCellData($value, $styleId = null) {
00099 assert(!is_object($value) && !is_array($value));
00100 $valueType = 'String';
00101 if (is_double($value) || is_float($value) || is_integer($value)) {
00102 $valueType = 'Number';
00103 } elseif (is_bool($value)) {
00104 $valueType = 'Boolean';
00105 $value = (int)$value;
00106 } elseif (preg_match('/^([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})$/', $value, $m)) {
00107 if ($styleId === null)
00108 $styleId = 'Date';
00109 $valueType = 'DateTime';
00110 $value = sprintf("%04d-%02d-%02dT00:00:00.000", $m[1], $m[2], $m[3]);
00111 } elseif (preg_match('/^([0-9]{4})-([0-9]{1,2})-([0-9]{1,2}) ([0-9]{1,2}):([0-9]{2})/', $value, $m)) {
00112 if ($styleId === null)
00113 $styleId = 'DateTime';
00114 $valueType = 'DateTime';
00115 $value = sprintf("%04d-%02d-%02dT%02d:%02d:00.000", $m[1], $m[2], $m[3], $m[4], $m[5]);
00116 } elseif (preg_match('/^([0-9]{1,2}):([0-9]{2})/', $value, $m)) {
00117 if ($styleId === null)
00118 $styleId = 'Time';
00119 $valueType = 'DateTime';
00120 $value = sprintf("1899-12-31T%02d:%02d:00.000", $m[1], $m[2]);
00121 }
00122
00123 $cell = array('_TAG' => 'Cell', '_DATA' => array(
00124 '_TAG' => 'Data', 'ss:Type' => $valueType, '_DATA' => $value));
00125 if ($styleId !== null)
00126 $cell['ss:StyleID'] = $styleId;
00127 return $cell;
00128 }
00129
00130 function addRow($row) {
00131 $newCells = array();
00132 foreach ($row as $value)
00133 array_push($newCells, $this->_toCellData($value));
00134 array_push($this->_currentWorksheet['_DATA'], array('_TAG' => 'Row', '_DATA' => $newCells));
00135 }
00136
00137 function addHeaderRow($row) {
00138 $newCells = array();
00139 foreach ($row as $value)
00140 array_push($newCells, $this->_toCellData($value, 'Head'));
00141 array_push($this->_currentWorksheet['_DATA'], array('_TAG' => 'Row', '_DATA' => $newCells));
00142 }
00143
00144 function _countRowColumnStats($worksheet) {
00145 $rowCount = 0;
00146 $columnCount = 0;
00147 $columnSizes = array();
00148 foreach ($worksheet['_DATA'] as $row) {
00149 ++$rowCount;
00150 $columnCount = max($columnCount, sizeof($row['_DATA']));
00151 for ($i = 0; $i < sizeof($row['_DATA']); ++$i) {
00152 $columnSizes[$i] = max((int)@$columnSizes[$i], 2);
00153 if (@$row['_DATA'][$i]['ss:StyleID'] != 'Head') {
00154 if (isset($row['_DATA'][$i]['_DATA'])
00155 && is_array($row['_DATA'][$i]['_DATA'])
00156 && $row['_DATA'][$i]['_DATA']['_TAG'] == 'Data') {
00157 $columnSizes[$i] = max($columnSizes[$i],
00158 strlen(@$row['_DATA'][$i]['_DATA']['_DATA']));
00159 }
00160 }
00161 }
00162 }
00163 return array($rowCount, $columnCount, $columnSizes);
00164 }
00165
00166 function _xmlToString($data, $indent, $noIndent = false) {
00167 assert(!is_string($data));
00168 $output = '';
00169
00170 if (is_array($data) && isset($data['_TAG'])) {
00171 $output = ($noIndent ? '' : str_repeat(' ', $indent)) . '<' . $data['_TAG'];
00172 foreach ($data as $key => $value) {
00173 if ($key[0] != '_')
00174 $output .= " $key=\"" . htmlentities($value, ENT_COMPAT, $this->_encoding) . '"';;
00175 }
00176 if (!isset($data['_DATA'])) {
00177 $output .= "/>" . ($noIndent ? '' : "\n");
00178 return $output;
00179 }
00180
00181 if (!is_array($data['_DATA'])) {
00182 $output .= '>' . htmlentities($data['_DATA'], ENT_COMPAT, $this->_encoding) . "</$data[_TAG]>"
00183 . ($noIndent ? '' : "\n");
00184 return $output;
00185 }
00186
00187 if ($data['_TAG'] == 'Cell') {
00188 $output .= ">" . $this->_xmlToString($data['_DATA'], $indent + 1, true) . "</$data[_TAG]>\n";
00189 } else {
00190 $output .= ">\n"
00191 . $this->_xmlToString($data['_DATA'], $indent + 1)
00192 . str_repeat(' ', $indent) . "</$data[_TAG]>" . ($noIndent ? '' : "\n");
00193 }
00194
00195 } elseif (is_array($data)) {
00196 foreach ($data as $value) {
00197 $output .= $this->_xmlToString($value, $indent);
00198 }
00199
00200 } else {
00201 assert(0);
00202 }
00203 return $output;
00204 }
00205
00206 function toString() {
00207 $author = htmlentities($this->_author, ENT_COMPAT, 'UTF-8');
00208 $company = htmlentities($this->_company, ENT_COMPAT, 'UTF-8');
00209 $createDate = htmlentities($this->_createDate);
00210
00211 $output = <<<__EOF__
00212 <?xml version="1.0"?>
00213 <?mso-application progid="Excel.Sheet"?>
00214 <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
00215 xmlns:o="urn:schemas-microsoft-com:office:office"
00216 xmlns:x="urn:schemas-microsoft-com:office:excel"
00217 xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
00218 xmlns:html="http://www.w3.org/TR/REC-html40">
00219 <DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
00220 <Author>$author</Author>
00221 <LastAuthor>$author</LastAuthor>
00222 <Created>$createDate</Created>
00223 <Company>$company</Company>
00224 <Version>11.5606</Version>
00225 </DocumentProperties>
00226 <ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
00227 <WindowHeight>12465</WindowHeight>
00228 <WindowWidth>13020</WindowWidth>
00229 <WindowTopX>600</WindowTopX>
00230 <WindowTopY>240</WindowTopY>
00231 <ProtectStructure>False</ProtectStructure>
00232 <ProtectWindows>False</ProtectWindows>
00233 </ExcelWorkbook>
00234 <Styles>
00235 <Style ss:ID="Default" ss:Name="Normal">
00236 <Alignment ss:Vertical="Bottom"/>
00237 <Borders/>
00238 <Font/>
00239 <Interior/>
00240 <NumberFormat/>
00241 <Protection/>
00242 </Style>
00243 <Style ss:ID="Head">
00244 <Font x:Family="Swiss" ss:Bold="1"/>
00245 </Style>
00246 <Style ss:ID="Time">
00247 <NumberFormat ss:Format="Short Time"/>
00248 </Style>
00249 <Style ss:ID="Date">
00250 <NumberFormat ss:Format="Short Date"/>
00251 </Style>
00252 <Style ss:ID="DateTime">
00253 <NumberFormat ss:Format="General Date"/>
00254 </Style>
00255 </Styles>
00256 __EOF__;
00257 foreach ($this->_data as $worksheet) {
00258 $worksheetName = htmlentities($worksheet['Name'], ENT_COMPAT, $this->_encoding);
00259 list($rowCount, $columnCount, $columnSizes) = $this->_countRowColumnStats($worksheet);
00260 $output .= <<<__EOF__
00261
00262 <Worksheet ss:Name="$worksheetName">
00263 <Table ss:ExpandedColumnCount="$columnCount" ss:ExpandedRowCount="$rowCount" x:FullColumns="1" x:FullRows="1">
00264
00265 __EOF__;
00266 for ($i = 0; $i < sizeof($columnSizes); ++$i) {
00267 $output .= " <Column ss:Index=\"" . ($i + 1) . "\" ss:AutoFitWidth=\"0\""
00268 . " ss:Width=\"" . min($columnSizes[$i] * 7, 200) . "\"/>\n";
00269 }
00270 foreach ($worksheet['_DATA'] as $row) {
00271 $output .= $this->_xmlToString($row, 3);
00272 }
00273
00274 $output .= <<<__EOF__
00275 </Table>
00276 <WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
00277 <Selected/>
00278 <ProtectObjects>False</ProtectObjects>
00279 <ProtectScenarios>False</ProtectScenarios>
00280 </WorksheetOptions>
00281 </Worksheet>
00282 __EOF__;
00283 }
00284 $output .= <<<__EOF__
00285
00286 </Workbook>
00287 __EOF__;
00288
00289 return $output;
00290 }
00291
00292 function offerAsDownload($filename = 'data.xls') {
00293 header("Content-Disposition: attachment; filename=\"" . urlencode($filename) . "\"");
00294 header('Content-Type: application/vnd.ms-excel; charset=UTF-8');
00295 echo $this->toString();
00296 }
00297 }
00298
00299 ?>