PageRenderTime 46ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/inc/excel.php

https://github.com/toxik/SportsNews
PHP | 235 lines | 135 code | 20 blank | 80 comment | 15 complexity | 15d6dd5e231ff401392eb9e04935218b MD5 | raw file
  1. <?php
  2. /**
  3. * MS-Excel stream handler
  4. * This class read/writes a data stream directly
  5. * from/to a Microsoft Excel spreadsheet
  6. * opened with the xlsfile:// protocol
  7. * This is used to export associative array data directly to MS-Excel
  8. * @requires PHP 4 >= 4.3.2
  9. * @author Ignatius Teo <ignatius@act28.com>
  10. * @copyright (C)2004 act28.com <http://act28.com>
  11. * @version 0.3
  12. * @date 20 Jan 2005
  13. * $Id: excel.php,v 1.3 2005/01/20 09:58:58 Owner Exp $
  14. */
  15. class xlsStream
  16. {
  17. /* private */
  18. var $position = 0; // stream pointer
  19. var $mode = "rb"; // default stream open mode
  20. var $xlsfilename = null; // stream name
  21. var $fp = null; // internal stream pointer to physical file
  22. var $buffer = null; // internal write buffer
  23. var $endian = "unknown"; // little | unknown | big endian mode
  24. var $bin = array(
  25. "big" => "v",
  26. "little" => "s",
  27. "unknown" => "s",
  28. );
  29. /**
  30. * detect server endian mode
  31. * thanks to Charles Turner for picking this one up
  32. * @access private
  33. * @params void
  34. * @returns void
  35. * @see http://www.phpdig.net/ref/rn45re877.html
  36. */
  37. function _detect()
  38. {
  39. // A hex number that may represent 'abyz'
  40. $abyz = 0x6162797A;
  41. // Convert $abyz to a binary string containing 32 bits
  42. // Do the conversion the way that the system architecture wants to
  43. switch (pack ('L', $abyz))
  44. {
  45. // Compare the value to the same value converted in a Little-Endian fashion
  46. case pack ('V', $abyz):
  47. $this->endian = "little";
  48. break;
  49. // Compare the value to the same value converted in a Big-Endian fashion
  50. case pack ('N', $abyz):
  51. $this->endian = "big";
  52. break;
  53. default:
  54. $this->endian = "unknown";
  55. break;
  56. }
  57. }
  58. /**
  59. * called by fopen() to the stream
  60. * @param (string) $path file path
  61. * @param (string) $mode stream open mode
  62. * @param (int) $options stream options (STREAM_USE_PATH |
  63. * STREAM_REPORT_ERRORS)
  64. * @param (string) $opened_path stream opened path
  65. */
  66. function stream_open($path, $mode, $options, &$opened_path)
  67. {
  68. $url = parse_url($path);
  69. $this->xlsfilename = '/' . $url['host'] . $url['path'];
  70. $this->position = 0;
  71. $this->mode = $mode;
  72. $this->_detect(); // detect endian mode
  73. //@TODO: test for invalid mode and trigger error if required
  74. // open underlying resource
  75. $this->fp = @fopen($this->xlsfilename, $this->mode);
  76. if (is_resource($this->fp))
  77. {
  78. // empty the buffer
  79. $this->buffer = "";
  80. if (preg_match("/^w|x/", $this->mode))
  81. {
  82. // write an Excel stream header
  83. $str = pack(str_repeat($this->bin[$this->endian], 6), 0x809, 0x8, 0x0, 0x10, 0x0, 0x0);
  84. fwrite($this->fp, $str);
  85. $opened_path = $this->xlsfilename;
  86. $this->position = strlen($str);
  87. }
  88. }
  89. return is_resource($this->fp);
  90. }
  91. /**
  92. * read the underlying stream resource (automatically called by fread/fgets)
  93. * @todo modify this to convert an excel stream to an array
  94. * @param (int) $byte_count number of bytes to read (in 8192 byte blocks)
  95. */
  96. function stream_read($byte_count)
  97. {
  98. if (is_resource($this->fp) && !feof($this->fp))
  99. {
  100. $data .= fread($this->fp, $byte_count);
  101. $this->position = strlen($data);
  102. }
  103. return $data;
  104. }
  105. /**
  106. * called automatically by an fwrite() to the stream
  107. * @param (string) $data serialized array data string
  108. * representing a tabular worksheet
  109. */
  110. function stream_write($data)
  111. {
  112. // buffer the data
  113. $this->buffer .= $data;
  114. $bufsize = strlen($data);
  115. return $bufsize;
  116. }
  117. /**
  118. * pseudo write function to manipulate the data
  119. * stream before writing it
  120. * modify this to suit your data array
  121. * @access private
  122. * @param (array) $data associative array representing
  123. * a tabular worksheet
  124. */
  125. function _xls_stream_write($data)
  126. {
  127. if (is_array($data) && !empty($data))
  128. {
  129. $row = 0;
  130. foreach (array_values($data) as $_data)
  131. {
  132. if (is_array($_data) && !empty($_data))
  133. {
  134. if ($row == 0)
  135. {
  136. // write the column headers
  137. foreach (array_keys($_data) as $col => $val)
  138. {
  139. // next line intentionally commented out
  140. // since we don't want a warning about the
  141. // extra bytes written
  142. // $size += $this->write($row, $col, $val);
  143. $this->_xlsWriteCell($row, $col, $val);
  144. }
  145. $row++;
  146. }
  147. foreach (array_values($_data) as $col => $val)
  148. {
  149. $size += $this->_xlsWriteCell($row, $col, $val);
  150. }
  151. $row++;
  152. }
  153. }
  154. }
  155. return $size;
  156. }
  157. /**
  158. * Excel worksheet cell insertion
  159. * (single-worksheet supported only)
  160. * @access private
  161. * @param (int) $row worksheet row number (0...65536)
  162. * @param (int) $col worksheet column number (0..255)
  163. * @param (mixed) $val worksheet row number
  164. */
  165. function _xlsWriteCell($row, $col, $val)
  166. {
  167. if (is_float($val) || is_int($val))
  168. {
  169. // doubles, floats, integers
  170. $str = pack(str_repeat($this->bin[$this->endian], 5), 0x203, 14, $row, $col, 0x0);
  171. $str .= pack("d", $val);
  172. }
  173. else
  174. {
  175. // everything else is treated as a string
  176. $l = strlen($val);
  177. $str = pack(str_repeat($this->bin[$this->endian], 6), 0x204, 8 + $l, $row, $col, 0x0, $l);
  178. $str .= $val;
  179. }
  180. fwrite($this->fp, $str);
  181. $this->position += strlen($str);
  182. return strlen($str);
  183. }
  184. /**
  185. * called by an fclose() on the stream
  186. */
  187. function stream_close()
  188. {
  189. if (preg_match("/^w|x/", $this->mode))
  190. {
  191. // flush the buffer
  192. $bufsize = $this->_xls_stream_write(unserialize($this->buffer));
  193. // ...and empty it
  194. $this->buffer = null;
  195. // write the xls EOF
  196. $str = pack(str_repeat($this->bin[$this->endian], 2), 0x0A, 0x00);
  197. $this->position += strlen($str);
  198. fwrite($this->fp, $str);
  199. }
  200. // ...and close the internal stream
  201. return fclose($this->fp);
  202. }
  203. function stream_eof()
  204. {
  205. $eof = true;
  206. if (is_resource($this->fp))
  207. {
  208. $eof = feof($this->fp);
  209. }
  210. return $eof;
  211. }
  212. }
  213. stream_wrapper_register("xlsfile", "xlsStream")
  214. or die("Failed to register protocol: xlsfile");
  215. ?>