PageRenderTime 59ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/branches/v1.6.4/Classes/PHPExcel/Writer/Excel5/Worksheet.php

#
PHP | 3650 lines | 1802 code | 444 blank | 1404 comment | 263 complexity | a4e415e3687cea9552899ea3dbf07b64 MD5 | raw file
Possible License(s): AGPL-1.0, LGPL-2.0, LGPL-2.1, GPL-3.0, LGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /*
  3. * Module written/ported by Xavier Noguer <xnoguer@rezebra.com>
  4. *
  5. * The majority of this is _NOT_ my code. I simply ported it from the
  6. * PERL Spreadsheet::WriteExcel module.
  7. *
  8. * The author of the Spreadsheet::WriteExcel module is John McNamara
  9. * <jmcnamara@cpan.org>
  10. *
  11. * I _DO_ maintain this code, and John McNamara has nothing to do with the
  12. * porting of this code to PHP. Any questions directly related to this
  13. * class library should be directed to me.
  14. *
  15. * License Information:
  16. *
  17. * PHPExcel_Writer_Excel5_Writer: A library for generating Excel Spreadsheets
  18. * Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com
  19. *
  20. * This library is free software; you can redistribute it and/or
  21. * modify it under the terms of the GNU Lesser General Public
  22. * License as published by the Free Software Foundation; either
  23. * version 2.1 of the License, or (at your option) any later version.
  24. *
  25. * This library is distributed in the hope that it will be useful,
  26. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  27. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  28. * Lesser General Public License for more details.
  29. *
  30. * You should have received a copy of the GNU Lesser General Public
  31. * License along with this library; if not, write to the Free Software
  32. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  33. */
  34. require_once 'PHPExcel/Writer/Excel5/Parser.php';
  35. require_once 'PHPExcel/Writer/Excel5/BIFFwriter.php';
  36. /**
  37. * Class for generating Excel Spreadsheets
  38. *
  39. * @author Xavier Noguer <xnoguer@rezebra.com>
  40. * @category FileFormats
  41. * @package PHPExcel_Writer_Excel5_Writer
  42. */
  43. class PHPExcel_Writer_Excel5_Worksheet extends PHPExcel_Writer_Excel5_BIFFwriter
  44. {
  45. /**
  46. * Name of the Worksheet
  47. * @var string
  48. */
  49. var $name;
  50. /**
  51. * Index for the Worksheet
  52. * @var integer
  53. */
  54. var $index;
  55. /**
  56. * Reference to the (default) Format object for URLs
  57. * @var object Format
  58. */
  59. var $_url_format;
  60. /**
  61. * Reference to the parser used for parsing formulas
  62. * @var object Format
  63. */
  64. var $_parser;
  65. /**
  66. * Filehandle to the temporary file for storing data
  67. * @var resource
  68. */
  69. var $_filehandle;
  70. /**
  71. * Boolean indicating if we are using a temporary file for storing data
  72. * @var bool
  73. */
  74. var $_using_tmpfile;
  75. /**
  76. * Maximum number of rows for an Excel spreadsheet (BIFF5)
  77. * @var integer
  78. */
  79. var $_xls_rowmax;
  80. /**
  81. * Maximum number of columns for an Excel spreadsheet (BIFF5)
  82. * @var integer
  83. */
  84. var $_xls_colmax;
  85. /**
  86. * Maximum number of characters for a string (LABEL record in BIFF5)
  87. * @var integer
  88. */
  89. var $_xls_strmax;
  90. /**
  91. * First row for the DIMENSIONS record
  92. * @var integer
  93. * @see _storeDimensions()
  94. */
  95. var $_dim_rowmin;
  96. /**
  97. * Last row for the DIMENSIONS record
  98. * @var integer
  99. * @see _storeDimensions()
  100. */
  101. var $_dim_rowmax;
  102. /**
  103. * First column for the DIMENSIONS record
  104. * @var integer
  105. * @see _storeDimensions()
  106. */
  107. var $_dim_colmin;
  108. /**
  109. * Last column for the DIMENSIONS record
  110. * @var integer
  111. * @see _storeDimensions()
  112. */
  113. var $_dim_colmax;
  114. /**
  115. * Default column character width
  116. */
  117. private $_defColWidth = 8;
  118. /**
  119. * Default row height in twips = 1/20 point
  120. */
  121. private $_defaultRowHeight = null;
  122. /**
  123. * Array containing format information for columns
  124. * @var array
  125. */
  126. var $_colinfo;
  127. /**
  128. * Array containing the selected area for the worksheet
  129. * @var array
  130. */
  131. var $_selection;
  132. /**
  133. * Array containing the panes for the worksheet
  134. * @var array
  135. */
  136. var $_panes;
  137. /**
  138. * The active pane for the worksheet
  139. * @var integer
  140. */
  141. var $_active_pane;
  142. /**
  143. * Bit specifying if panes are frozen
  144. * @var integer
  145. */
  146. var $_frozen;
  147. /**
  148. * Bit specifying if the worksheet is selected
  149. * @var integer
  150. */
  151. var $selected;
  152. /**
  153. * The paper size (for printing) (DOCUMENT!!!)
  154. * @var integer
  155. */
  156. var $_paper_size;
  157. /**
  158. * Bit specifying paper orientation (for printing). 0 => landscape, 1 => portrait
  159. * @var integer
  160. */
  161. var $_orientation;
  162. /**
  163. * The page header caption
  164. * @var string
  165. */
  166. var $_header;
  167. /**
  168. * The page footer caption
  169. * @var string
  170. */
  171. var $_footer;
  172. /**
  173. * The horizontal centering value for the page
  174. * @var integer
  175. */
  176. var $_hcenter;
  177. /**
  178. * The vertical centering value for the page
  179. * @var integer
  180. */
  181. var $_vcenter;
  182. /**
  183. * The margin for the header
  184. * @var float
  185. */
  186. var $_margin_head;
  187. /**
  188. * The margin for the footer
  189. * @var float
  190. */
  191. var $_margin_foot;
  192. /**
  193. * The left margin for the worksheet in inches
  194. * @var float
  195. */
  196. var $_margin_left;
  197. /**
  198. * The right margin for the worksheet in inches
  199. * @var float
  200. */
  201. var $_margin_right;
  202. /**
  203. * The top margin for the worksheet in inches
  204. * @var float
  205. */
  206. var $_margin_top;
  207. /**
  208. * The bottom margin for the worksheet in inches
  209. * @var float
  210. */
  211. var $_margin_bottom;
  212. /**
  213. * First row to reapeat on each printed page
  214. * @var integer
  215. */
  216. var $title_rowmin;
  217. /**
  218. * Last row to reapeat on each printed page
  219. * @var integer
  220. */
  221. var $title_rowmax;
  222. /**
  223. * First column to reapeat on each printed page
  224. * @var integer
  225. */
  226. var $title_colmin;
  227. /**
  228. * First row of the area to print
  229. * @var integer
  230. */
  231. var $print_rowmin;
  232. /**
  233. * Last row to of the area to print
  234. * @var integer
  235. */
  236. var $print_rowmax;
  237. /**
  238. * First column of the area to print
  239. * @var integer
  240. */
  241. var $print_colmin;
  242. /**
  243. * Last column of the area to print
  244. * @var integer
  245. */
  246. var $print_colmax;
  247. /**
  248. * Whether to use outline.
  249. * @var integer
  250. */
  251. var $_outline_on;
  252. /**
  253. * Auto outline styles.
  254. * @var bool
  255. */
  256. var $_outline_style;
  257. /**
  258. * Whether to have outline summary below.
  259. * @var bool
  260. */
  261. var $_outline_below;
  262. /**
  263. * Whether to have outline summary at the right.
  264. * @var bool
  265. */
  266. var $_outline_right;
  267. /**
  268. * Outline row level.
  269. * @var integer
  270. */
  271. var $_outline_row_level;
  272. /**
  273. * Whether to fit to page when printing or not.
  274. * @var bool
  275. */
  276. var $_fit_page;
  277. /**
  278. * Number of pages to fit wide
  279. * @var integer
  280. */
  281. var $_fit_width;
  282. /**
  283. * Number of pages to fit high
  284. * @var integer
  285. */
  286. var $_fit_height;
  287. /**
  288. * Reference to the total number of strings in the workbook
  289. * @var integer
  290. */
  291. var $_str_total;
  292. /**
  293. * Reference to the number of unique strings in the workbook
  294. * @var integer
  295. */
  296. var $_str_unique;
  297. /**
  298. * Reference to the array containing all the unique strings in the workbook
  299. * @var array
  300. */
  301. var $_str_table;
  302. /**
  303. * Merged cell ranges
  304. * @var array
  305. */
  306. var $_merged_ranges;
  307. /**
  308. * Charset encoding currently used when calling writeString()
  309. * @var string
  310. */
  311. var $_input_encoding;
  312. /**
  313. * The temporary dir for storing files
  314. * @var string
  315. */
  316. var $_tmp_dir;
  317. /**
  318. * List of temporary files created
  319. * @var array
  320. */
  321. var $_tempFilesCreated = array();
  322. /**
  323. * Index of first used row (at least 0)
  324. * @var int
  325. */
  326. private $_firstRowIndex;
  327. /**
  328. * Index of last used row. (no used rows means -1)
  329. * @var int
  330. */
  331. private $_lastRowIndex;
  332. /**
  333. * Index of first used column (at least 0)
  334. * @var int
  335. */
  336. private $_firstColumnIndex;
  337. /**
  338. * Index of last used column (no used columns means -1)
  339. * @var int
  340. */
  341. private $_lastColumnIndex;
  342. /**
  343. * Constructor
  344. *
  345. * @param string $name The name of the new worksheet
  346. * @param integer $index The index of the new worksheet
  347. * @param mixed &$activesheet The current activesheet of the workbook we belong to
  348. * @param mixed &$firstsheet The first worksheet in the workbook we belong to
  349. * @param mixed &$url_format The default format for hyperlinks
  350. * @param mixed &$parser The formula parser created for the Workbook
  351. * @param string $tempDir The temporary directory to be used
  352. * @access private
  353. */
  354. function PHPExcel_Writer_Excel5_Worksheet($BIFF_version, $name,
  355. $index, &$activesheet,
  356. &$firstsheet, &$str_total,
  357. &$str_unique, &$str_table,
  358. &$url_format, &$parser, $tempDir = '')
  359. {
  360. // It needs to call its parent's constructor explicitly
  361. $this->PHPExcel_Writer_Excel5_BIFFwriter();
  362. $this->_BIFF_version = $BIFF_version;
  363. $rowmax = 65536; // 16384 in Excel 5
  364. $colmax = 256;
  365. $this->name = $name;
  366. $this->index = $index;
  367. $this->activesheet = &$activesheet;
  368. $this->firstsheet = &$firstsheet;
  369. $this->_str_total = &$str_total;
  370. $this->_str_unique = &$str_unique;
  371. $this->_str_table = &$str_table;
  372. $this->_url_format = &$url_format;
  373. $this->_parser = &$parser;
  374. //$this->ext_sheets = array();
  375. $this->_filehandle = '';
  376. $this->_using_tmpfile = true;
  377. //$this->fileclosed = 0;
  378. //$this->offset = 0;
  379. $this->_xls_rowmax = $rowmax;
  380. $this->_xls_colmax = $colmax;
  381. $this->_xls_strmax = 255;
  382. $this->_dim_rowmin = $rowmax + 1;
  383. $this->_dim_rowmax = 0;
  384. $this->_dim_colmin = $colmax + 1;
  385. $this->_dim_colmax = 0;
  386. $this->_colinfo = array();
  387. $this->_selection = array(0,0,0,0);
  388. $this->_panes = array();
  389. $this->_active_pane = 3;
  390. $this->_frozen = 0;
  391. $this->selected = 0;
  392. $this->_paper_size = 0x0;
  393. $this->_orientation = 0x1;
  394. $this->_header = '';
  395. $this->_footer = '';
  396. $this->_hcenter = 0;
  397. $this->_vcenter = 0;
  398. $this->_margin_head = 0.50;
  399. $this->_margin_foot = 0.50;
  400. $this->_margin_left = 0.75;
  401. $this->_margin_right = 0.75;
  402. $this->_margin_top = 1.00;
  403. $this->_margin_bottom = 1.00;
  404. $this->title_rowmin = null;
  405. $this->title_rowmax = null;
  406. $this->title_colmin = null;
  407. $this->title_colmax = null;
  408. $this->print_rowmin = null;
  409. $this->print_rowmax = null;
  410. $this->print_colmin = null;
  411. $this->print_colmax = null;
  412. $this->_print_gridlines = 1;
  413. $this->_screen_gridlines = 1;
  414. $this->_print_headers = 0;
  415. $this->_fit_page = 0;
  416. $this->_fit_width = 0;
  417. $this->_fit_height = 0;
  418. $this->_hbreaks = array();
  419. $this->_vbreaks = array();
  420. $this->_protect = 0;
  421. $this->_password = null;
  422. $this->col_sizes = array();
  423. $this->_row_sizes = array();
  424. $this->_zoom = 100;
  425. $this->_print_scale = 100;
  426. $this->_outline_row_level = 0;
  427. $this->_outline_style = 0;
  428. $this->_outline_below = 1;
  429. $this->_outline_right = 1;
  430. $this->_outline_on = 1;
  431. $this->_merged_ranges = array();
  432. $this->_input_encoding = '';
  433. $this->_dv = array();
  434. $this->_tmp_dir = $tempDir;
  435. $this->_initialize();
  436. }
  437. /**
  438. * Cleanup
  439. */
  440. public function cleanup() {
  441. @fclose($this->_filehandle);
  442. foreach ($this->_tempFilesCreated as $file) {
  443. @unlink($file);
  444. }
  445. }
  446. /**
  447. * Open a tmp file to store the majority of the Worksheet data. If this fails,
  448. * for example due to write permissions, store the data in memory. This can be
  449. * slow for large files.
  450. *
  451. * @access private
  452. */
  453. function _initialize()
  454. {
  455. // Open tmp file for storing Worksheet data
  456. $fileName = tempnam($this->_tmp_dir, 'XLSHEET');
  457. $fh = fopen($fileName, 'w+');
  458. if ($fh) {
  459. // Store filehandle
  460. $this->_filehandle = $fh;
  461. $this->_tempFilesCreated[] = $fileName;
  462. } else {
  463. // If tmpfile() fails store data in memory
  464. $this->_using_tmpfile = false;
  465. }
  466. }
  467. /**
  468. * Sets the temp dir used for storing files
  469. *
  470. * @access public
  471. * @param string $dir The dir to be used as temp dir
  472. * @return true if given dir is valid, false otherwise
  473. */
  474. function setTempDir($dir)
  475. {
  476. if (is_dir($dir)) {
  477. $this->_tmp_dir = $dir;
  478. return true;
  479. }
  480. return false;
  481. }
  482. /**
  483. * Add data to the beginning of the workbook (note the reverse order)
  484. * and to the end of the workbook.
  485. *
  486. * @access public
  487. * @see PHPExcel_Writer_Excel5_Workbook::storeWorkbook()
  488. * @param array $sheetnames The array of sheetnames from the Workbook this
  489. * worksheet belongs to
  490. */
  491. function close($sheetnames)
  492. {
  493. $num_sheets = count($sheetnames);
  494. /***********************************************
  495. * Prepend in reverse order!!
  496. */
  497. // Prepend the sheet dimensions
  498. $this->_storeDimensions();
  499. // Prepend the sheet password
  500. $this->_storePassword();
  501. // Prepend the sheet protection
  502. $this->_storeProtect();
  503. // Prepend the page setup
  504. $this->_storeSetup();
  505. /* FIXME: margins are actually appended */
  506. // Prepend the bottom margin
  507. $this->_storeMarginBottom();
  508. // Prepend the top margin
  509. $this->_storeMarginTop();
  510. // Prepend the right margin
  511. $this->_storeMarginRight();
  512. // Prepend the left margin
  513. $this->_storeMarginLeft();
  514. // Prepend the page vertical centering
  515. $this->_storeVcenter();
  516. // Prepend the page horizontal centering
  517. $this->_storeHcenter();
  518. // Prepend the page footer
  519. $this->_storeFooter();
  520. // Prepend the page header
  521. $this->_storeHeader();
  522. // Prepend the vertical page breaks
  523. $this->_storeVbreak();
  524. // Prepend the horizontal page breaks
  525. $this->_storeHbreak();
  526. // Prepend WSBOOL
  527. $this->_storeWsbool();
  528. // Prepend DEFAULTROWHEIGHT
  529. if ($this->_BIFF_version == 0x0600) {
  530. $this->_storeDefaultRowHeight();
  531. }
  532. // Prepend GRIDSET
  533. $this->_storeGridset();
  534. // Prepend GUTS
  535. $this->_storeGuts();
  536. // Prepend PRINTGRIDLINES
  537. $this->_storePrintGridlines();
  538. // Prepend PRINTHEADERS
  539. $this->_storePrintHeaders();
  540. // Prepend EXTERNSHEET references
  541. if ($this->_BIFF_version == 0x0500) {
  542. for ($i = $num_sheets; $i > 0; --$i) {
  543. $sheetname = $sheetnames[$i-1];
  544. $this->_storeExternsheet($sheetname);
  545. }
  546. }
  547. // Prepend the EXTERNCOUNT of external references.
  548. if ($this->_BIFF_version == 0x0500) {
  549. $this->_storeExterncount($num_sheets);
  550. }
  551. // Prepend the COLINFO records if they exist
  552. if (!empty($this->_colinfo)) {
  553. $colcount = count($this->_colinfo);
  554. for ($i = 0; $i < $colcount; ++$i) {
  555. $this->_storeColinfo($this->_colinfo[$i]);
  556. }
  557. }
  558. // Prepend the DEFCOLWIDTH record
  559. $this->_storeDefcol();
  560. // Prepend the BOF record
  561. $this->_storeBof(0x0010);
  562. /*
  563. * End of prepend. Read upwards from here.
  564. ***********************************************/
  565. // Append
  566. $this->_storeWindow2();
  567. $this->_storeZoom();
  568. if (!empty($this->_panes)) {
  569. $this->_storePanes($this->_panes);
  570. }
  571. $this->_storeSelection($this->_selection);
  572. $this->_storeMergedCells();
  573. /* TODO: add data validity */
  574. /*if ($this->_BIFF_version == 0x0600) {
  575. $this->_storeDataValidity();
  576. }*/
  577. $this->_storeEof();
  578. }
  579. /**
  580. * Retrieve the worksheet name.
  581. * This is usefull when creating worksheets without a name.
  582. *
  583. * @access public
  584. * @return string The worksheet's name
  585. */
  586. function getName()
  587. {
  588. return $this->name;
  589. }
  590. /**
  591. * Retrieves data from memory in one chunk, or from disk in $buffer
  592. * sized chunks.
  593. *
  594. * @return string The data
  595. */
  596. function getData()
  597. {
  598. $buffer = 4096;
  599. // Return data stored in memory
  600. if (isset($this->_data)) {
  601. $tmp = $this->_data;
  602. unset($this->_data);
  603. $fh = $this->_filehandle;
  604. if ($this->_using_tmpfile) {
  605. fseek($fh, 0);
  606. }
  607. return $tmp;
  608. }
  609. // Return data stored on disk
  610. if ($this->_using_tmpfile) {
  611. if ($tmp = fread($this->_filehandle, $buffer)) {
  612. return $tmp;
  613. }
  614. }
  615. // No data to return
  616. return '';
  617. }
  618. /**
  619. * Sets a merged cell range
  620. *
  621. * @access public
  622. * @param integer $first_row First row of the area to merge
  623. * @param integer $first_col First column of the area to merge
  624. * @param integer $last_row Last row of the area to merge
  625. * @param integer $last_col Last column of the area to merge
  626. */
  627. function setMerge($first_row, $first_col, $last_row, $last_col)
  628. {
  629. if (($last_row < $first_row) || ($last_col < $first_col)) {
  630. return;
  631. }
  632. // don't check rowmin, rowmax, etc... because we don't know when this
  633. // is going to be called
  634. $this->_merged_ranges[] = array($first_row, $first_col, $last_row, $last_col);
  635. }
  636. /**
  637. * Set this worksheet as a selected worksheet,
  638. * i.e. the worksheet has its tab highlighted.
  639. *
  640. * @access public
  641. */
  642. function select()
  643. {
  644. $this->selected = 1;
  645. }
  646. /**
  647. * Set this worksheet as the active worksheet,
  648. * i.e. the worksheet that is displayed when the workbook is opened.
  649. * Also set it as selected.
  650. *
  651. * @access public
  652. */
  653. function activate()
  654. {
  655. $this->selected = 1;
  656. $this->activesheet = $this->index;
  657. }
  658. /**
  659. * Set this worksheet as the first visible sheet.
  660. * This is necessary when there are a large number of worksheets and the
  661. * activated worksheet is not visible on the screen.
  662. *
  663. * @access public
  664. */
  665. function setFirstSheet()
  666. {
  667. $this->firstsheet = $this->index;
  668. }
  669. /**
  670. * Set the worksheet protection flag
  671. * to prevent accidental modification and to
  672. * hide formulas if the locked and hidden format properties have been set.
  673. *
  674. * @access public
  675. * @param string $password The password to use for protecting the sheet.
  676. */
  677. function protect($password, $encoded = false)
  678. {
  679. $this->_protect = 1;
  680. $this->_password = ($encoded ? $password : $this->_encodePassword($password));
  681. }
  682. /**
  683. * Set the width of a single column or a range of columns.
  684. *
  685. * @access public
  686. * @param integer $firstcol first column on the range
  687. * @param integer $lastcol last column on the range
  688. * @param integer $width width to set
  689. * @param mixed $format The optional XF format to apply to the columns
  690. * @param integer $hidden The optional hidden atribute
  691. * @param integer $level The optional outline level
  692. */
  693. function setColumn($firstcol, $lastcol, $width, $format = null, $hidden = 0, $level = 0)
  694. {
  695. $this->_colinfo[] = array($firstcol, $lastcol, $width, &$format, $hidden, $level);
  696. // Set width to zero if column is hidden
  697. $width = ($hidden) ? 0 : $width;
  698. for ($col = $firstcol; $col <= $lastcol; ++$col) {
  699. $this->col_sizes[$col] = $width;
  700. }
  701. }
  702. /**
  703. * Set which cell or cells are selected in a worksheet
  704. *
  705. * @access public
  706. * @param integer $first_row first row in the selected quadrant
  707. * @param integer $first_column first column in the selected quadrant
  708. * @param integer $last_row last row in the selected quadrant
  709. * @param integer $last_column last column in the selected quadrant
  710. */
  711. function setSelection($first_row,$first_column,$last_row,$last_column)
  712. {
  713. $this->_selection = array($first_row,$first_column,$last_row,$last_column);
  714. }
  715. /**
  716. * Set panes and mark them as frozen.
  717. *
  718. * @access public
  719. * @param array $panes This is the only parameter received and is composed of the following:
  720. * 0 => Vertical split position,
  721. * 1 => Horizontal split position
  722. * 2 => Top row visible
  723. * 3 => Leftmost column visible
  724. * 4 => Active pane
  725. */
  726. function freezePanes($panes)
  727. {
  728. $this->_frozen = 1;
  729. $this->_panes = $panes;
  730. }
  731. /**
  732. * Set panes and mark them as unfrozen.
  733. *
  734. * @access public
  735. * @param array $panes This is the only parameter received and is composed of the following:
  736. * 0 => Vertical split position,
  737. * 1 => Horizontal split position
  738. * 2 => Top row visible
  739. * 3 => Leftmost column visible
  740. * 4 => Active pane
  741. */
  742. function thawPanes($panes)
  743. {
  744. $this->_frozen = 0;
  745. $this->_panes = $panes;
  746. }
  747. /**
  748. * Set the page orientation as portrait.
  749. *
  750. * @access public
  751. */
  752. function setPortrait()
  753. {
  754. $this->_orientation = 1;
  755. }
  756. /**
  757. * Set the page orientation as landscape.
  758. *
  759. * @access public
  760. */
  761. function setLandscape()
  762. {
  763. $this->_orientation = 0;
  764. }
  765. /**
  766. * Set the paper type. Ex. 1 = US Letter, 9 = A4
  767. *
  768. * @access public
  769. * @param integer $size The type of paper size to use
  770. */
  771. function setPaper($size = 0)
  772. {
  773. $this->_paper_size = $size;
  774. }
  775. /**
  776. * Set the page header caption and optional margin.
  777. *
  778. * @access public
  779. * @param string $string The header text
  780. * @param float $margin optional head margin in inches.
  781. */
  782. function setHeader($string,$margin = 0.50)
  783. {
  784. if (strlen($string) >= 255) {
  785. //carp 'Header string must be less than 255 characters';
  786. return;
  787. }
  788. $this->_header = $string;
  789. $this->_margin_head = $margin;
  790. }
  791. /**
  792. * Set the page footer caption and optional margin.
  793. *
  794. * @access public
  795. * @param string $string The footer text
  796. * @param float $margin optional foot margin in inches.
  797. */
  798. function setFooter($string,$margin = 0.50)
  799. {
  800. if (strlen($string) >= 255) {
  801. //carp 'Footer string must be less than 255 characters';
  802. return;
  803. }
  804. $this->_footer = $string;
  805. $this->_margin_foot = $margin;
  806. }
  807. /**
  808. * Center the page horinzontally.
  809. *
  810. * @access public
  811. * @param integer $center the optional value for centering. Defaults to 1 (center).
  812. */
  813. function centerHorizontally($center = 1)
  814. {
  815. $this->_hcenter = $center;
  816. }
  817. /**
  818. * Center the page vertically.
  819. *
  820. * @access public
  821. * @param integer $center the optional value for centering. Defaults to 1 (center).
  822. */
  823. function centerVertically($center = 1)
  824. {
  825. $this->_vcenter = $center;
  826. }
  827. /**
  828. * Set all the page margins to the same value in inches.
  829. *
  830. * @access public
  831. * @param float $margin The margin to set in inches
  832. */
  833. function setMargins($margin)
  834. {
  835. $this->setMarginLeft($margin);
  836. $this->setMarginRight($margin);
  837. $this->setMarginTop($margin);
  838. $this->setMarginBottom($margin);
  839. }
  840. /**
  841. * Set the left and right margins to the same value in inches.
  842. *
  843. * @access public
  844. * @param float $margin The margin to set in inches
  845. */
  846. function setMargins_LR($margin)
  847. {
  848. $this->setMarginLeft($margin);
  849. $this->setMarginRight($margin);
  850. }
  851. /**
  852. * Set the top and bottom margins to the same value in inches.
  853. *
  854. * @access public
  855. * @param float $margin The margin to set in inches
  856. */
  857. function setMargins_TB($margin)
  858. {
  859. $this->setMarginTop($margin);
  860. $this->setMarginBottom($margin);
  861. }
  862. /**
  863. * Set the left margin in inches.
  864. *
  865. * @access public
  866. * @param float $margin The margin to set in inches
  867. */
  868. function setMarginLeft($margin = 0.75)
  869. {
  870. $this->_margin_left = $margin;
  871. }
  872. /**
  873. * Set the right margin in inches.
  874. *
  875. * @access public
  876. * @param float $margin The margin to set in inches
  877. */
  878. function setMarginRight($margin = 0.75)
  879. {
  880. $this->_margin_right = $margin;
  881. }
  882. /**
  883. * Set the top margin in inches.
  884. *
  885. * @access public
  886. * @param float $margin The margin to set in inches
  887. */
  888. function setMarginTop($margin = 1.00)
  889. {
  890. $this->_margin_top = $margin;
  891. }
  892. /**
  893. * Set the bottom margin in inches.
  894. *
  895. * @access public
  896. * @param float $margin The margin to set in inches
  897. */
  898. function setMarginBottom($margin = 1.00)
  899. {
  900. $this->_margin_bottom = $margin;
  901. }
  902. /**
  903. * Set the rows to repeat at the top of each printed page.
  904. *
  905. * @access public
  906. * @param integer $first_row First row to repeat
  907. * @param integer $last_row Last row to repeat. Optional.
  908. */
  909. function repeatRows($first_row, $last_row = null)
  910. {
  911. $this->title_rowmin = $first_row;
  912. if (isset($last_row)) { //Second row is optional
  913. $this->title_rowmax = $last_row;
  914. } else {
  915. $this->title_rowmax = $first_row;
  916. }
  917. }
  918. /**
  919. * Set the columns to repeat at the left hand side of each printed page.
  920. *
  921. * @access public
  922. * @param integer $first_col First column to repeat
  923. * @param integer $last_col Last column to repeat. Optional.
  924. */
  925. function repeatColumns($first_col, $last_col = null)
  926. {
  927. $this->title_colmin = $first_col;
  928. if (isset($last_col)) { // Second col is optional
  929. $this->title_colmax = $last_col;
  930. } else {
  931. $this->title_colmax = $first_col;
  932. }
  933. }
  934. /**
  935. * Set the area of each worksheet that will be printed.
  936. *
  937. * @access public
  938. * @param integer $first_row First row of the area to print
  939. * @param integer $first_col First column of the area to print
  940. * @param integer $last_row Last row of the area to print
  941. * @param integer $last_col Last column of the area to print
  942. */
  943. function printArea($first_row, $first_col, $last_row, $last_col)
  944. {
  945. $this->print_rowmin = $first_row;
  946. $this->print_colmin = $first_col;
  947. $this->print_rowmax = $last_row;
  948. $this->print_colmax = $last_col;
  949. }
  950. /**
  951. * Set the option to hide gridlines on the printed page.
  952. *
  953. * @access public
  954. */
  955. function hideGridlines()
  956. {
  957. $this->_print_gridlines = 0;
  958. }
  959. /**
  960. * Set the option to hide gridlines on the worksheet (as seen on the screen).
  961. *
  962. * @access public
  963. */
  964. function hideScreenGridlines()
  965. {
  966. $this->_screen_gridlines = 0;
  967. }
  968. /**
  969. * Set the option to print the row and column headers on the printed page.
  970. *
  971. * @access public
  972. * @param integer $print Whether to print the headers or not. Defaults to 1 (print).
  973. */
  974. function printRowColHeaders($print = 1)
  975. {
  976. $this->_print_headers = $print;
  977. }
  978. /**
  979. * Set the vertical and horizontal number of pages that will define the maximum area printed.
  980. * It doesn't seem to work with OpenOffice.
  981. *
  982. * @access public
  983. * @param integer $width Maximun width of printed area in pages
  984. * @param integer $height Maximun heigth of printed area in pages
  985. * @see setPrintScale()
  986. */
  987. function fitToPages($width, $height)
  988. {
  989. $this->_fit_page = 1;
  990. $this->_fit_width = $width;
  991. $this->_fit_height = $height;
  992. }
  993. /**
  994. * Store the horizontal page breaks on a worksheet (for printing).
  995. * The breaks represent the row after which the break is inserted.
  996. *
  997. * @access public
  998. * @param array $breaks Array containing the horizontal page breaks
  999. */
  1000. function setHPagebreaks($breaks)
  1001. {
  1002. foreach ($breaks as $break) {
  1003. array_push($this->_hbreaks, $break);
  1004. }
  1005. }
  1006. /**
  1007. * Store the vertical page breaks on a worksheet (for printing).
  1008. * The breaks represent the column after which the break is inserted.
  1009. *
  1010. * @access public
  1011. * @param array $breaks Array containing the vertical page breaks
  1012. */
  1013. function setVPagebreaks($breaks)
  1014. {
  1015. foreach ($breaks as $break) {
  1016. array_push($this->_vbreaks, $break);
  1017. }
  1018. }
  1019. /**
  1020. * Set the worksheet zoom factor.
  1021. *
  1022. * @access public
  1023. * @param integer $scale The zoom factor
  1024. */
  1025. function setZoom($scale = 100)
  1026. {
  1027. // Confine the scale to Excel's range
  1028. if ($scale < 10 || $scale > 400) {
  1029. throw new Exception("Zoom factor $scale outside range: 10 <= zoom <= 400");
  1030. $scale = 100;
  1031. }
  1032. $this->_zoom = floor($scale);
  1033. }
  1034. /**
  1035. * Set the scale factor for the printed page.
  1036. * It turns off the "fit to page" option
  1037. *
  1038. * @access public
  1039. * @param integer $scale The optional scale factor. Defaults to 100
  1040. */
  1041. function setPrintScale($scale = 100)
  1042. {
  1043. // Confine the scale to Excel's range
  1044. if ($scale < 10 || $scale > 400) {
  1045. throw new Exception("Print scale $scale outside range: 10 <= zoom <= 400");
  1046. $scale = 100;
  1047. }
  1048. // Turn off "fit to page" option
  1049. $this->_fit_page = 0;
  1050. $this->_print_scale = floor($scale);
  1051. }
  1052. /**
  1053. * Map to the appropriate write method acording to the token recieved.
  1054. *
  1055. * @access public
  1056. * @param integer $row The row of the cell we are writing to
  1057. * @param integer $col The column of the cell we are writing to
  1058. * @param mixed $token What we are writing
  1059. * @param mixed $format The optional format to apply to the cell
  1060. */
  1061. function write($row, $col, $token, $format = null, $numberFormat = null)
  1062. {
  1063. // Check for a cell reference in A1 notation and substitute row and column
  1064. /*if ($_[0] =~ /^\D/) {
  1065. @_ = $this->_substituteCellref(@_);
  1066. }*/
  1067. if (($numberFormat != 'General') && (PHPExcel_Shared_Date::isDateTimeFormatCode($numberFormat))) {
  1068. if (is_string($token)) {
  1069. // Error string
  1070. return $this->writeString($row, $col, $token, $format);
  1071. } elseif (!is_float($token)) {
  1072. // PHP serialized date/time or date/time object
  1073. return $this->writeNumber($row, $col, PHPExcel_Shared_Date::PHPToExcel($token), $format);
  1074. } else {
  1075. // Excel serialized date/time
  1076. return $this->writeNumber($row, $col, $token, $format);
  1077. }
  1078. } elseif (preg_match("/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/", $token)) {
  1079. // Match number
  1080. return $this->writeNumber($row, $col, $token, $format);
  1081. } elseif (preg_match("/^[fh]tt?p:\/\//", $token)) {
  1082. // Match http or ftp URL
  1083. return $this->writeUrl($row, $col, $token, '', $format);
  1084. } elseif (preg_match("/^mailto:/", $token)) {
  1085. // Match mailto:
  1086. return $this->writeUrl($row, $col, $token, '', $format);
  1087. } elseif (preg_match("/^(?:in|ex)ternal:/", $token)) {
  1088. // Match internal or external sheet link
  1089. return $this->writeUrl($row, $col, $token, '', $format);
  1090. } elseif (preg_match("/^=/", $token)) {
  1091. // Match formula
  1092. return $this->writeFormula($row, $col, $token, $format);
  1093. } elseif (preg_match("/^@/", $token)) {
  1094. // Match formula
  1095. return $this->writeFormula($row, $col, $token, $format);
  1096. } elseif ($token == '') {
  1097. // Match blank
  1098. return $this->writeBlank($row, $col, $format);
  1099. } else {
  1100. // Default: match string
  1101. return $this->writeString($row, $col, $token, $format);
  1102. }
  1103. }
  1104. /**
  1105. * Write an array of values as a row
  1106. *
  1107. * @access public
  1108. * @param integer $row The row we are writing to
  1109. * @param integer $col The first col (leftmost col) we are writing to
  1110. * @param array $val The array of values to write
  1111. * @param mixed $format The optional format to apply to the cell
  1112. */
  1113. function writeRow($row, $col, $val, $format = null, $numberFormat = null)
  1114. {
  1115. $retval = '';
  1116. if (is_array($val)) {
  1117. foreach ($val as $v) {
  1118. if (is_array($v)) {
  1119. $this->writeCol($row, $col, $v, $format, $numberFormat = null);
  1120. } else {
  1121. $this->write($row, $col, $v, $format, $numberFormat);
  1122. }
  1123. ++$col;
  1124. }
  1125. } else {
  1126. throw new Exception('$val needs to be an array');
  1127. }
  1128. return($retval);
  1129. }
  1130. /**
  1131. * Write an array of values as a column
  1132. *
  1133. * @access public
  1134. * @param integer $row The first row (uppermost row) we are writing to
  1135. * @param integer $col The col we are writing to
  1136. * @param array $val The array of values to write
  1137. * @param mixed $format The optional format to apply to the cell
  1138. */
  1139. function writeCol($row, $col, $val, $format = null, $numberFormat = null)
  1140. {
  1141. $retval = '';
  1142. if (is_array($val)) {
  1143. foreach ($val as $v) {
  1144. $this->write($row, $col, $v, $format, $numberFormat);
  1145. ++$row;
  1146. }
  1147. } else {
  1148. throw new Exception('$val needs to be an array');
  1149. }
  1150. return($retval);
  1151. }
  1152. /**
  1153. * Returns an index to the XF record in the workbook
  1154. *
  1155. * @access private
  1156. * @param mixed &$format The optional XF format
  1157. * @return integer The XF record index
  1158. */
  1159. function _XF(&$format)
  1160. {
  1161. if ($format) {
  1162. return($format->getXfIndex());
  1163. } else {
  1164. return(0x0F);
  1165. }
  1166. }
  1167. /******************************************************************************
  1168. *******************************************************************************
  1169. *
  1170. * Internal methods
  1171. */
  1172. /**
  1173. * Store Worksheet data in memory using the parent's class append() or to a
  1174. * temporary file, the default.
  1175. *
  1176. * @access private
  1177. * @param string $data The binary data to append
  1178. */
  1179. function _append($data)
  1180. {
  1181. if ($this->_using_tmpfile) {
  1182. // Add CONTINUE records if necessary
  1183. if (strlen($data) > $this->_limit) {
  1184. $data = $this->_addContinue($data);
  1185. }
  1186. fwrite($this->_filehandle, $data);
  1187. $this->_datasize += strlen($data);
  1188. } else {
  1189. parent::_append($data);
  1190. }
  1191. }
  1192. /**
  1193. * Substitute an Excel cell reference in A1 notation for zero based row and
  1194. * column values in an argument list.
  1195. *
  1196. * Ex: ("A4", "Hello") is converted to (3, 0, "Hello").
  1197. *
  1198. * @access private
  1199. * @param string $cell The cell reference. Or range of cells.
  1200. * @return array
  1201. */
  1202. function _substituteCellref($cell)
  1203. {
  1204. $cell = strtoupper($cell);
  1205. // Convert a column range: 'A:A' or 'B:G'
  1206. if (preg_match("/([A-I]?[A-Z]):([A-I]?[A-Z])/", $cell, $match)) {
  1207. list($no_use, $col1) = $this->_cellToRowcol($match[1] .'1'); // Add a dummy row
  1208. list($no_use, $col2) = $this->_cellToRowcol($match[2] .'1'); // Add a dummy row
  1209. return(array($col1, $col2));
  1210. }
  1211. // Convert a cell range: 'A1:B7'
  1212. if (preg_match("/\$?([A-I]?[A-Z]\$?\d+):\$?([A-I]?[A-Z]\$?\d+)/", $cell, $match)) {
  1213. list($row1, $col1) = $this->_cellToRowcol($match[1]);
  1214. list($row2, $col2) = $this->_cellToRowcol($match[2]);
  1215. return(array($row1, $col1, $row2, $col2));
  1216. }
  1217. // Convert a cell reference: 'A1' or 'AD2000'
  1218. if (preg_match("/\$?([A-I]?[A-Z]\$?\d+)/", $cell)) {
  1219. list($row1, $col1) = $this->_cellToRowcol($match[1]);
  1220. return(array($row1, $col1));
  1221. }
  1222. // TODO use real error codes
  1223. throw new Exception("Unknown cell reference $cell");
  1224. }
  1225. /**
  1226. * Convert an Excel cell reference in A1 notation to a zero based row and column
  1227. * reference; converts C1 to (0, 2).
  1228. *
  1229. * @access private
  1230. * @param string $cell The cell reference.
  1231. * @return array containing (row, column)
  1232. */
  1233. function _cellToRowcol($cell)
  1234. {
  1235. preg_match("/\$?([A-I]?[A-Z])\$?(\d+)/",$cell,$match);
  1236. $col = $match[1];
  1237. $row = $match[2];
  1238. // Convert base26 column string to number
  1239. $chars = split('', $col);
  1240. $expn = 0;
  1241. $col = 0;
  1242. while ($chars) {
  1243. $char = array_pop($chars); // LS char first
  1244. $col += (ord($char) -ord('A') +1) * pow(26,$expn);
  1245. ++$expn;
  1246. }
  1247. // Convert 1-index to zero-index
  1248. --$row;
  1249. --$col;
  1250. return(array($row, $col));
  1251. }
  1252. /**
  1253. * Based on the algorithm provided by Daniel Rentz of OpenOffice.
  1254. *
  1255. * @access private
  1256. * @param string $plaintext The password to be encoded in plaintext.
  1257. * @return string The encoded password
  1258. */
  1259. function _encodePassword($plaintext)
  1260. {
  1261. $password = 0x0000;
  1262. $i = 1; // char position
  1263. // split the plain text password in its component characters
  1264. $chars = preg_split('//', $plaintext, -1, PREG_SPLIT_NO_EMPTY);
  1265. foreach ($chars as $char) {
  1266. $value = ord($char) << $i; // shifted ASCII value
  1267. $rotated_bits = $value >> 15; // rotated bits beyond bit 15
  1268. $value &= 0x7fff; // first 15 bits
  1269. $password ^= ($value | $rotated_bits);
  1270. ++$i;
  1271. }
  1272. $password ^= strlen($plaintext);
  1273. $password ^= 0xCE4B;
  1274. return($password);
  1275. }
  1276. /**
  1277. * This method sets the properties for outlining and grouping. The defaults
  1278. * correspond to Excel's defaults.
  1279. *
  1280. * @param bool $visible
  1281. * @param bool $symbols_below
  1282. * @param bool $symbols_right
  1283. * @param bool $auto_style
  1284. */
  1285. function setOutline($visible = true, $symbols_below = true, $symbols_right = true, $auto_style = false)
  1286. {
  1287. $this->_outline_on = $visible;
  1288. $this->_outline_below = $symbols_below;
  1289. $this->_outline_right = $symbols_right;
  1290. $this->_outline_style = $auto_style;
  1291. // Ensure this is a boolean vale for Window2
  1292. if ($this->_outline_on) {
  1293. $this->_outline_on = 1;
  1294. }
  1295. }
  1296. /******************************************************************************
  1297. *******************************************************************************
  1298. *
  1299. * BIFF RECORDS
  1300. */
  1301. /**
  1302. * Write a double to the specified row and column (zero indexed).
  1303. * An integer can be written as a double. Excel will display an
  1304. * integer. $format is optional.
  1305. *
  1306. * Returns 0 : normal termination
  1307. * -2 : row or column out of range
  1308. *
  1309. * @access public
  1310. * @param integer $row Zero indexed row
  1311. * @param integer $col Zero indexed column
  1312. * @param float $num The number to write
  1313. * @param mixed $format The optional XF format
  1314. * @return integer
  1315. */
  1316. function writeNumber($row, $col, $num, $format = null)
  1317. {
  1318. $record = 0x0203; // Record identifier
  1319. $length = 0x000E; // Number of bytes to follow
  1320. $xf = $this->_XF($format); // The cell format
  1321. // Check that row and col are valid and store max and min values
  1322. if ($row >= $this->_xls_rowmax) {
  1323. return(-2);
  1324. }
  1325. if ($col >= $this->_xls_colmax) {
  1326. return(-2);
  1327. }
  1328. if ($row < $this->_dim_rowmin) {
  1329. $this->_dim_rowmin = $row;
  1330. }
  1331. if ($row > $this->_dim_rowmax) {
  1332. $this->_dim_rowmax = $row;
  1333. }
  1334. if ($col < $this->_dim_colmin) {
  1335. $this->_dim_colmin = $col;
  1336. }
  1337. if ($col > $this->_dim_colmax) {
  1338. $this->_dim_colmax = $col;
  1339. }
  1340. $header = pack("vv", $record, $length);
  1341. $data = pack("vvv", $row, $col, $xf);
  1342. $xl_double = pack("d", $num);
  1343. if ($this->_byte_order) { // if it's Big Endian
  1344. $xl_double = strrev($xl_double);
  1345. }
  1346. $this->_append($header.$data.$xl_double);
  1347. return(0);
  1348. }
  1349. /**
  1350. * Write a string to the specified row and column (zero indexed).
  1351. * NOTE: there is an Excel 5 defined limit of 255 characters.
  1352. * $format is optional.
  1353. * Returns 0 : normal termination
  1354. * -2 : row or column out of range
  1355. * -3 : long string truncated to 255 chars
  1356. *
  1357. * @access public
  1358. * @param integer $row Zero indexed row
  1359. * @param integer $col Zero indexed column
  1360. * @param string $str The string to write
  1361. * @param mixed $format The XF format for the cell
  1362. * @return integer
  1363. */
  1364. function writeString($row, $col, $str, $format = null)
  1365. {
  1366. if ($this->_BIFF_version == 0x0600) {
  1367. return $this->writeStringBIFF8($row, $col, $str, $format);
  1368. }
  1369. $strlen = strlen($str);
  1370. $record = 0x0204; // Record identifier
  1371. $length = 0x0008 + $strlen; // Bytes to follow
  1372. $xf = $this->_XF($format); // The cell format
  1373. $str_error = 0;
  1374. // Check that row and col are valid and store max and min values
  1375. if ($row >= $this->_xls_rowmax) {
  1376. return(-2);
  1377. }
  1378. if ($col >= $this->_xls_colmax) {
  1379. return(-2);
  1380. }
  1381. if ($row < $this->_dim_rowmin) {
  1382. $this->_dim_rowmin = $row;
  1383. }
  1384. if ($row > $this->_dim_rowmax) {
  1385. $this->_dim_rowmax = $row;
  1386. }
  1387. if ($col < $this->_dim_colmin) {
  1388. $this->_dim_colmin = $col;
  1389. }
  1390. if ($col > $this->_dim_colmax) {
  1391. $this->_dim_colmax = $col;
  1392. }
  1393. if ($strlen > $this->_xls_strmax) { // LABEL must be < 255 chars
  1394. $str = substr($str, 0, $this->_xls_strmax);
  1395. $length = 0x0008 + $this->_xls_strmax;
  1396. $strlen = $this->_xls_strmax;
  1397. $str_error = -3;
  1398. }
  1399. $header = pack("vv", $record, $length);
  1400. $data = pack("vvvv", $row, $col, $xf, $strlen);
  1401. $this->_append($header . $data . $str);
  1402. return($str_error);
  1403. }
  1404. var $_biff8_input_encoding = 'UTF-16LE';
  1405. function setBIFF8InputEncoding($encoding) {
  1406. if ($encoding != 'UTF-16LE' && !function_exists('iconv')) {
  1407. $this->raiseError("Using an input encoding other than UTF-16LE requires PHP support for iconv");
  1408. }
  1409. $this->_biff8_input_encoding = $encoding;
  1410. }
  1411. /**
  1412. * Sets Input Encoding for writing strings
  1413. *
  1414. * @access public
  1415. * @param string $encoding The encoding. Ex: 'UTF-16LE', 'utf-8', 'ISO-859-7'
  1416. */
  1417. function setInputEncoding($encoding)
  1418. {
  1419. if ($encoding != 'UTF-16LE' && !function_exists('iconv')) {
  1420. throw new Exception("Using an input encoding other than UTF-16LE requires PHP support for iconv");
  1421. }
  1422. $this->_input_encoding = $encoding;
  1423. }
  1424. /**
  1425. * Write a string to the specified row and column (zero indexed).
  1426. * This is the BIFF8 version (no 255 chars limit).
  1427. * $format is optional.
  1428. * Returns 0 : normal termination
  1429. * -2 : row or column out of range
  1430. * -3 : long string truncated to 255 chars
  1431. *
  1432. * @access public
  1433. * @param integer $row Zero indexed row
  1434. * @param integer $col Zero indexed column
  1435. * @param string $str The string to write
  1436. * @param mixed $format The XF format for the cell
  1437. * @return integer
  1438. */
  1439. function writeStringBIFF8($row, $col, $str, $format = null)
  1440. {
  1441. if ($this->_input_encoding == 'UTF-16LE')
  1442. {
  1443. $strlen = function_exists('mb_strlen') ? mb_strlen($str, 'UTF-16LE') : (strlen($str) / 2);
  1444. $encoding = 0x1;
  1445. }
  1446. elseif ($this->_input_encoding != '')
  1447. {
  1448. $str = iconv($this->_input_encoding, 'UTF-16LE', $str);
  1449. $strlen = function_exists('mb_strlen') ? mb_strlen($str, 'UTF-16LE') : (strlen($str) / 2);
  1450. $encoding = 0x1;
  1451. }
  1452. else
  1453. {
  1454. $strlen = strlen($str);
  1455. $encoding = 0x0;
  1456. }
  1457. $record = 0x00FD; // Record identifier
  1458. $length = 0x000A; // Bytes to follow
  1459. $xf = $this->_XF($format); // The cell format
  1460. $str_error = 0;
  1461. // Check that row and col are valid and store max and min values
  1462. if ($this->_checkRowCol($row, $col) == false) {
  1463. return -2;
  1464. }
  1465. $str = pack('vC', $strlen, $encoding).$str;
  1466. /* check if string is already present */
  1467. if (!isset($this->_str_table[$str])) {
  1468. $this->_str_table[$str] = $this->_str_unique++;
  1469. }
  1470. $this->_str_total++;
  1471. $header = pack('vv', $record, $length);
  1472. $data = pack('vvvV', $row, $col, $xf, $this->_str_table[$str]);
  1473. $this->_append($header.$data);
  1474. return $str_error;
  1475. }
  1476. /**
  1477. * Check row and col before writing to a cell, and update the sheet's
  1478. * dimensions accordingly
  1479. *
  1480. * @access private
  1481. * @param integer $row Zero indexed row
  1482. * @param integer $col Zero indexed column
  1483. * @return boolean true for success, false if row and/or col are grester
  1484. * then maximums allowed.
  1485. */
  1486. function _checkRowCol($row, $col)
  1487. {
  1488. if ($row >= $this->_xls_rowmax) {
  1489. return false;
  1490. }
  1491. if ($col >= $this->_xls_colmax) {
  1492. return false;
  1493. }
  1494. if ($row < $this->_dim_rowmin) {
  1495. $this->_dim_rowmin = $row;
  1496. }
  1497. if ($row > $this->_dim_rowmax) {
  1498. $this->_dim_rowmax = $row;
  1499. }
  1500. if ($col < $this->_dim_colmin) {
  1501. $this->_dim_colmin = $col;
  1502. }
  1503. if ($col > $this->_dim_colmax) {
  1504. $this->_dim_colmax = $col;
  1505. }
  1506. return true;
  1507. }
  1508. /**
  1509. * Writes a note associated with the cell given by the row and column.
  1510. * NOTE records don't have a length limit.
  1511. *
  1512. * @access public
  1513. * @param integer $row Zero indexed row
  1514. * @param integer $col Zero indexed column
  1515. * @param string $note The note to write
  1516. */
  1517. function writeNote($row, $col, $note)
  1518. {
  1519. $note_length = strlen($note);
  1520. $record = 0x001C; // Record identifier
  1521. $max_length = 2048; // Maximun length for a NOTE record
  1522. //$length = 0x0006 + $note_length; // Bytes to follow
  1523. // Check that row and col are valid and store max and min values
  1524. if ($row >= $this->_xls_rowmax) {
  1525. return(-2);
  1526. }
  1527. if ($col >= $this->_xls_colmax) {
  1528. return(-2);
  1529. }
  1530. if ($row < $this->_dim_rowmin) {
  1531. $this->_dim_rowmin = $row;
  1532. }
  1533. if ($row > $this->_dim_rowmax) {
  1534. $this->_dim_rowmax = $row;
  1535. }
  1536. if ($col < $this->_dim_colmin) {
  1537. $this->_dim_colmin = $col;
  1538. }
  1539. if ($col > $this->_dim_colmax) {
  1540. $this->_dim_colmax = $col;
  1541. }
  1542. // Length for this record is no more than 2048 + 6
  1543. $length = 0x0006 + min($note_length, 2048);
  1544. $header = pack("vv", $record, $length);
  1545. $data = pack("vvv", $row, $col, $note_length);
  1546. $this->_append($header . $data . substr($note, 0, 2048));
  1547. for ($i = $max_length; $i < $note_length; $i += $max_length) {
  1548. $chunk = substr($note, $i, $max_length);
  1549. $length = 0x0006 + strlen($chunk);
  1550. $header = pack("vv", $record, $length);
  1551. $data = pack("vvv", -1, 0, strlen($chunk));
  1552. $this->_append($header.$data.$chunk);
  1553. }
  1554. return(0);
  1555. }
  1556. /**
  1557. * Write a blank cell to the specified row and column (zero indexed).
  1558. * A blank cell is used to specify formatting without adding a string
  1559. * or a number.
  1560. *
  1561. * A blank cell without a format serves no purpose. Therefore, we don't write
  1562. * a BLANK record unless a format is specified.
  1563. *
  1564. * Returns 0 : normal termination (including no format)
  1565. * -1 : insufficient number of arguments
  1566. * -2 : row or column out of range
  1567. *
  1568. * @access public
  1569. * @param integer $row Zero indexed row
  1570. * @param integer $col Zero indexed column
  1571. * @param mixed $format The XF format
  1572. */
  1573. function writeBlank($row, $col, $format)
  1574. {
  1575. // Don't write a blank cell unless it has a format
  1576. if (!$format) {
  1577. return(0);
  1578. }
  1579. $record = 0x0201; // Record identifier
  1580. $length = 0x0006; // Number of bytes to follow
  1581. $xf = $this->_XF($format); // The cell format
  1582. // Check that row and col are valid and store max and min values
  1583. if ($row >= $this->_xls_rowmax) {
  1584. return(-2);
  1585. }
  1586. if ($col >= $this->_xls_colmax) {
  1587. return(-2);
  1588. }
  1589. if ($row < $this->_dim_rowmin) {
  1590. $this->_dim_rowmin = $row;
  1591. }
  1592. if ($row > $this->_dim_rowmax) {
  1593. $this->_dim_rowmax = $row;
  1594. }
  1595. if ($col < $this->_dim_colmin) {
  1596. $this->_dim_colmin = $col;
  1597. }
  1598. if ($col > $this->_dim_colmax) {
  1599. $this->_dim_colmax = $col;
  1600. }
  1601. $header = pack("vv", $record, $length);
  1602. $data = pack("vvv", $row, $col, $xf);
  1603. $this->_append($header . $data);
  1604. return 0;
  1605. }
  1606. /**
  1607. * Write a boolean or an error type to the specified row and column (zero indexed)
  1608. */
  1609. public function writeBoolErr($row, $col, $value, $isError, $format)
  1610. {
  1611. $record = 0x0205;
  1612. $length = 8;
  1613. $xf = $this->_XF($format);
  1614. // Check that row and col are valid and store max and min values
  1615. if ($row >= $this->_xls_rowmax) {
  1616. return(-2);
  1617. }
  1618. if ($col >= $this->_xls_colmax) {
  1619. return(-2);
  1620. }
  1621. if ($row < $this->_dim_rowmin) {
  1622. $this->_dim_rowmin = $row;
  1623. }
  1624. if ($row > $this->_dim_rowmax) {
  1625. $this->_dim_rowmax = $row;
  1626. }
  1627. if ($col < $this->_dim_colmin) {
  1628. $this->_dim_colmin = $col;
  1629. }
  1630. if ($col > $this->_dim_colmax) {
  1631. $this->_dim_colmax = $col;
  1632. }
  1633. $header = pack("vv", $record, $length);
  1634. $data = pack("vvvCC", $row, $col, $xf, $value, $isError);
  1635. $this->_append($header . $data);
  1636. return 0;
  1637. }
  1638. /**
  1639. * Write a formula to the specified row and column (zero indexed).
  1640. * The textual representation of the formula is passed to the parser in
  1641. * Parser.php which returns a packed binary string.
  1642. *
  1643. * Returns 0 : normal termination
  1644. * -1 : formula errors (bad formula)
  1645. * -2 : row or column out of range
  1646. *
  1647. * @access public
  1648. * @param integer $row Zero indexed row
  1649. * @param integer $col Zero indexed column
  1650. * @param string $formula The formula text string
  1651. * @param mixed $format The optional XF format
  1652. * @return integer
  1653. */
  1654. function writeFormula($row, $col, $formula, $format = null)
  1655. {
  1656. $record = 0x0006; // Record identifier
  1657. // Excel normally stores the last calculated value of the formula in $num.
  1658. // Clearly we are not in a position to calculate this a priori. Instead
  1659. // we set $num to zero and set the option flags in $grbit to ensure
  1660. // automatic calculation of the formula when the file is opened.
  1661. //
  1662. $xf = $this->_XF($format); // The cell format
  1663. $num = 0x00; // Current value of formula
  1664. $grbit = 0x03; // Option flags
  1665. $unknown = 0x0000; // Must be zero
  1666. // Check that row and col are valid and store max and min values
  1667. if ($this->_checkRowCol($row, $col) == false) {
  1668. return -2;
  1669. }
  1670. // Strip the '=' or '@' sign at the beginning of the formula string
  1671. if (preg_match("/^=/", $formula)) {
  1672. $formula = preg_replace("/(^=)/", "", $formula);
  1673. } elseif (preg_match("/^@/", $formula)) {
  1674. $formula = preg_replace("/(^@)/", "", $formula);
  1675. } else {
  1676. // Error handling
  1677. $this->writeString($row, $col, 'Unrecognised character for formula');
  1678. return -1;
  1679. }
  1680. // Parse the formula using the parser in Parser.php
  1681. $error = $this->_parser->parse($formula);
  1682. $formula = $this->_parser->toReversePolish();
  1683. $formlen = strlen($formula); // Length of the binary string
  1684. $length = 0x16 + $formlen; // Length of the record data
  1685. $header = pack("vv", $record, $length);
  1686. $data = pack("vvvdvVv", $row, $col, $xf, $num,
  1687. $grbit, $unknown, $formlen);
  1688. $this->_append($header . $data . $formula);
  1689. return 0;
  1690. }
  1691. /**
  1692. * Write a hyperlink.
  1693. * This is comprised of two elements: the visible label and
  1694. * the invisible link. The visible label is the same as the link unless an
  1695. * alternative string is specified. The label is written using the
  1696. * writeString() method. Therefore the 255 characters string limit applies.
  1697. * $string and $format are optional.
  1698. *
  1699. * The hyperlink can be to a http, ftp, mail, internal sheet (not yet), or external
  1700. * directory url.
  1701. *
  1702. * Returns 0 : normal termination
  1703. * -2 : row or column out of range
  1704. * -3 : long string truncated to 255 chars
  1705. *
  1706. * @access public
  1707. * @param integer $row Row
  1708. * @param integer $col Column
  1709. * @param string $url URL string
  1710. * @return integer
  1711. */
  1712. function writeUrl($row, $col, $url)
  1713. {
  1714. // Add start row and col to arg list
  1715. return($this->_writeUrlRange($row, $col, $row, $col, $url));
  1716. }
  1717. /**
  1718. * This is the more general form of writeUrl(). It allows a hyperlink to be
  1719. * written to a range of cells. This function also decides the type of hyperlink
  1720. * to be written. These are either, Web (http, ftp, mailto), Internal
  1721. * (Sheet1!A1) or external ('c:\temp\foo.xls#Sheet1!A1').
  1722. *
  1723. * @access private
  1724. * @see writeUrl()
  1725. * @param integer $row1 Start row
  1726. * @param integer $col1 Start column
  1727. * @param integer $row2 End row
  1728. * @param integer $col2 End column
  1729. * @param string $url URL string
  1730. * @return integer
  1731. */
  1732. function _writeUrlRange($row1, $col1, $row2, $col2, $url)
  1733. {
  1734. // Check for internal/external sheet links or default to web link
  1735. if (preg_match('[^internal:]', $url)) {
  1736. return($this->_writeUrlInternal($row1, $col1, $row2, $col2, $url));
  1737. }
  1738. if (preg_match('[^external:]', $url)) {
  1739. return($this->_writeUrlExternal($row1, $col1, $row2, $col2, $url));
  1740. }
  1741. return($this->_writeUrlWeb($row1, $col1, $row2, $col2, $url));
  1742. }
  1743. /**
  1744. * Used to write http, ftp and mailto hyperlinks.
  1745. * The link type ($options) is 0x03 is the same as absolute dir ref without
  1746. * sheet. However it is differentiated by the $unknown2 data stream.
  1747. *
  1748. * @access private
  1749. * @see writeUrl()
  1750. * @param integer $row1 Start row
  1751. * @param integer $col1 Start column
  1752. * @param integer $row2 End row
  1753. * @param integer $col2 End column
  1754. * @param string $url URL string
  1755. * @return integer
  1756. */
  1757. function _writeUrlWeb($row1, $col1, $row2, $col2, $url)
  1758. {
  1759. $record = 0x01B8; // Record identifier
  1760. $length = 0x00000; // Bytes to follow
  1761. // Pack the undocumented parts of the hyperlink stream
  1762. $unknown1 = pack("H*", "D0C9EA79F9BACE118C8200AA004BA90B02000000");
  1763. $unknown2 = pack("H*", "E0C9EA79F9BACE118C8200AA004BA90B");
  1764. // Pack the option flags
  1765. $options = pack("V", 0x03);
  1766. // Convert URL to a null terminated wchar string
  1767. $url = join("\0", preg_split("''", $url, -1, PREG_SPLIT_NO_EMPTY));
  1768. $url = $url . "\0\0\0";
  1769. // Pack the length of the URL
  1770. $url_len = pack("V", strlen($url));
  1771. // Calculate the data length
  1772. $length = 0x34 + strlen($url);
  1773. // Pack the header data
  1774. $header = pack("vv", $record, $length);
  1775. $data = pack("vvvv", $row1, $row2, $col1, $col2);
  1776. // Write the packed data
  1777. $this->_append($header . $data .
  1778. $unknown1 . $options .
  1779. $unknown2 . $url_len . $url);
  1780. return 0;
  1781. }
  1782. /**
  1783. * Used to write internal reference hyperlinks such as "Sheet1!A1".
  1784. *
  1785. * @access private
  1786. * @see writeUrl()
  1787. * @param integer $row1 Start row
  1788. * @param integer $col1 Start column
  1789. * @param integer $row2 End row
  1790. * @param integer $col2 End column
  1791. * @param string $url URL string
  1792. * @return integer
  1793. */
  1794. function _writeUrlInternal($row1, $col1, $row2, $col2, $url)
  1795. {
  1796. $record = 0x01B8; // Re…

Large files files are truncated, but you can click here to view the full file