Last active
December 15, 2015 03:29
-
-
Save DaveRandom/5195058 to your computer and use it in GitHub Desktop.
Small library for manipulating Excel spreadsheets using COM on a Windows machine with Microsoft Office is installed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
spl_autoload_register(function($className) use($classMap) { | |
static $classMap; | |
if (!isset($classMap)) { | |
$classMap = array( | |
'excelcom\workbook' => __DIR__ . '/Workbook.php';, | |
'excelcom\worksheet' => __DIR__ . '/Worksheet.php';, | |
'excelcom\cell' => __DIR__ . '/Cell.php';, | |
); | |
} | |
$className = strtolower($className); | |
if (isset($classMap[$className])) { | |
require $classMap[$className]; | |
} | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Class for objects representing a single cell in an Excel worksheet | |
* | |
* PHP version 5.3/Windows, requires Microsoft Office Excel to be installed on the host system | |
* | |
* @package ExcelCOM | |
* @author Chris Wright <[email protected]> | |
* @license http://www.opensource.org/licenses/mit-license.html MIT License | |
* @version 1.0.0 | |
*/ | |
namespace ExcelCOM; | |
/** | |
* Class for objects representing a single cell in an Excel worksheet | |
* | |
* @package ExcelCOM | |
* @author Chris Wright <[email protected]> | |
*/ | |
class Cell | |
{ | |
/** | |
* @var \VARIANT Object from COM representing the internal cell | |
*/ | |
private $cell; | |
/** | |
* @var \DaveRandom\ExcelCOM\Worksheet Reference to the parent Worksheet object | |
*/ | |
private $worksheet; | |
/** | |
* Constructor | |
* | |
* @param \VARIANT $cell Object from COM representing the internal cell | |
* @param \DaveRandom\ExcelCOM\Worksheet $workbook Reference to the parent Worksheet object | |
*/ | |
public function __construct($cell, Worksheet $worksheet) | |
{ | |
$this->cell = $cell; | |
$this->worksheet = $worksheet; | |
} | |
/** | |
* Called when the object is used in a string context | |
* | |
* @return string A string representation of the cell value | |
*/ | |
public function __toString() | |
{ | |
return (string) $this->getValue(); | |
} | |
/** | |
* Get the parent Worksheet object | |
* | |
* @return \DaveRandom\ExcelCOM\Worksheet The parent Worksheet object | |
*/ | |
public function getWorksheet() | |
{ | |
return $this->worksheet; | |
} | |
/** | |
* Set the cell value | |
* | |
* @param mixed $value The new cell value | |
* | |
* @return \DaveRandom\ExcelCOM\Cell The current Cell object for method chaining | |
* | |
* @throws \RuntimeException When the set operation fails | |
*/ | |
public function setValue($value) | |
{ | |
try { | |
$this->cell->Value = $value; | |
} catch (\Exception $e) { | |
throw new \RuntimeException('Unable to set cell value', 0, $e); | |
} | |
return $this; | |
} | |
/** | |
* Get the cell value | |
* | |
* @return mixed The cell value | |
*/ | |
public function getValue() | |
{ | |
return $this->cell->Value; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Simple example for setting the value of cell B4 | |
use \DaveRandom\ExcelCOM\Workbook, | |
\DaveRandom\ExcelCOM\Worksheet, | |
\DaveRandom\ExcelCOM\Cell; | |
require 'ExcelCOM/bootstrap.php'; | |
$workbook = new Workbook('path/to/file.xls'); | |
// Get a worksheet by numeric index (1-indexed) | |
// Also accepts the string name of a sheet | |
$worksheet = $workbook->getWorksheet(1); | |
// Get Cell B4 and set the value | |
$cell = $worksheet->getCell('B4'); | |
$cell->setValue('Hello world!'); | |
// Save and close the workbook | |
$workbook->save(); | |
$workbook->close(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Class for objects representing an Excel workbook | |
* | |
* PHP version 5.3/Windows, requires Microsoft Office Excel to be installed on the host system | |
* | |
* @package ExcelCOM | |
* @author Chris Wright <[email protected]> | |
* @license http://www.opensource.org/licenses/mit-license.html MIT License | |
* @version 1.0.0 | |
*/ | |
namespace ExcelCOM; | |
/** | |
* Class for objects representing an Excel workbook | |
* | |
* @package ExcelCOM | |
* @author Chris Wright <[email protected]> | |
*/ | |
class Workbook | |
{ | |
/** | |
* @var bool Whether the file is currently open | |
* | |
* This is a work-around for the fact that you end up with an orphaned Excel.exe when | |
* the script dies before performing a graceful close | |
*/ | |
private $open = false; | |
/** | |
* @var \COM Master COM object | |
*/ | |
private $com; | |
/** | |
* @var \VARIANT Object from COM representing the internal workbook | |
*/ | |
private $workbook; | |
/** | |
* @var \DaveRandom\ExcelCOM\Cell[] Cache of Cell objects, used to avoid creating the same Cell more than once | |
*/ | |
private $worksheetCache = array(); | |
/** | |
* Constructor | |
* | |
* @param string $path Path to the file on disk | |
* | |
* @throws \RuntimeException When the file does not exist or cannot be opened | |
*/ | |
public function __construct($path) | |
{ | |
$realPath = realpath($path); | |
if (!$realPath || !is_file($realPath)) { | |
throw new \RuntimeException("The specified file '$path' does not exist"); | |
} | |
try { | |
$this->com = new \COM('Excel.Application'); | |
$this->workbook = $this->com->Workbooks->Open($realPath); | |
} catch (\Exception $e) { | |
throw new \RuntimeException("Unable to open workbook '$realPath'", 0, $e); | |
} | |
// To avoid orphaned Excel.exe if a fatal error occurs. I know it looks odd to | |
// register a proper destructor as a shutdown function, but it really is required | |
// in order to circumvent the problem, I promise. | |
$this->open = true; | |
register_shutdown_function(array($this, '__destruct')); | |
} | |
/** | |
* Destructor | |
* | |
* Force a clean shutdown of Excel without saving changes | |
*/ | |
public function __destruct() | |
{ | |
$this->close(false); | |
} | |
/** | |
* Get an object representing a worksheet in the file | |
* | |
* @param string|int $sheetId The worksheet name or number. Numbers are 1-indexed. Returns the current active sheet if omitted. | |
* | |
* @return \DaveRandom\ExcelCOM\Worksheet The worksheet object | |
* | |
* @throws \RuntimeException When a reference to the worksheet could not be obtained | |
*/ | |
public function getWorksheet($sheetId = null) | |
{ | |
try { | |
if (isset($sheetId)) { | |
$sheet = $this->workbook->Sheets($sheetId); | |
} else { | |
$sheet = $this->workbook->ActiveSheet; | |
} | |
} catch (\Exception $e) { | |
throw new \RuntimeException('Unable to obtain a reference to the specified sheet', 0, $e); | |
} | |
if (!$sheet) { | |
throw new \RuntimeException('The workbook has no active worksheet'); | |
} | |
return new Worksheet($sheet, $this); | |
} | |
/** | |
* Save any changes to the file | |
* | |
* @param string $as Path to save the file. Overwrites the source file if omitted. | |
* | |
* @return \DaveRandom\ExcelCOM\Workbook The current Workbook object for method chaining | |
* | |
* @throws \RuntimeException When the file could not be saved | |
*/ | |
public function save($as = null) | |
{ | |
try { | |
$this->com->Calculate(); | |
if ($as !== null) { | |
$as = str_replace('/', '\\', $as); | |
$this->workbook->SaveAs($as); | |
} else { | |
$this->workbook->Save(); | |
} | |
} catch (\Exception $e) { | |
throw new \RuntimeException('Unable to save workbook', 0, $e); | |
} | |
return $this; | |
} | |
/** | |
* Close the current workbook | |
* | |
* @param bool $save Save changes to source file if true. | |
* | |
* @throws \RuntimeException When the file could not be closed, this most likely indicates a problem saving. | |
*/ | |
public function close($save = false) | |
{ | |
if ($this->open) { | |
try { | |
$this->open = false; | |
$this->workbook->Close((bool) $save); | |
$this->workbook = $this->com = null; | |
} catch (\Exception $e) { | |
throw new \RuntimeException('Unable to close workbook', 0, $e); | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Class for objects representing a single worksheet in an Excel workbook | |
* | |
* PHP version 5.3/Windows, requires Microsoft Office Excel to be installed on the host system | |
* | |
* @package ExcelCOM | |
* @author Chris Wright <[email protected]> | |
* @license http://www.opensource.org/licenses/mit-license.html MIT License | |
* @version 1.0.0 | |
*/ | |
namespace ExcelCOM; | |
/** | |
* Class for objects representing a single worksheet in an Excel workbook | |
* | |
* @package ExcelCOM | |
* @author Chris Wright <[email protected]> | |
*/ | |
class Worksheet | |
{ | |
/** | |
* @var \VARIANT Object from COM representing the internal worksheet | |
*/ | |
private $worksheet; | |
/** | |
* @var \DaveRandom\ExcelCOM\Workbook Reference to the parent Workbook object | |
*/ | |
private $workbook; | |
/** | |
* @var \DaveRandom\ExcelCOM\Cell[] Cache of Cell objects, used to avoid creating the same Cell more than once | |
*/ | |
private $cellCache = array(); | |
/** | |
* Constructor | |
* | |
* @param \VARIANT $worksheet Object from COM representing the internal worksheet | |
* @param \DaveRandom\ExcelCOM\Workbook $workbook Reference to the parent Workbook object | |
*/ | |
public function __construct($worksheet, Workbook $workbook) | |
{ | |
$this->worksheet = $worksheet; | |
$this->workbook = $workbook; | |
} | |
/** | |
* Convert an alpha column reference to an integer | |
* | |
* @param string $x Alpha-string representing an X-coordinate in the worksheet | |
* | |
* @return int Numeric representation of input | |
* | |
* @throws \OutOfRangeException When the input does not represent a valid X-coordinate | |
*/ | |
private function xAlphaToInt($x) | |
{ | |
switch (strlen($x)) { | |
case 1: | |
return ord($x) - 64; | |
case 2: | |
return ((ord($x[0]) - 64) * 26) + ord($x[1]) - 64; | |
default: | |
throw new \OutOfRangeException('Invalid cell coordinate'); | |
} | |
} | |
/** | |
* Get a Cell object from the internal cache, creating it if it doesn't yet exist | |
* | |
* @param int $x The X-coordinate of the cell | |
* @param int $y The Y-coordinate of the cell | |
* | |
* @return \DaveRandom\ExcelCOM\Cell The Cell object | |
* | |
* @throws \RuntimeException When a reference to the cell cannot be obtained | |
*/ | |
private function getCellCached($x, $y) | |
{ | |
if (!isset($this->cellCache[$x][$y])) { | |
try { | |
$cell = $this->worksheet->Cells($y, $x); | |
} catch (\Exception $e) { | |
throw new \RuntimeException('Unable to get reference to the specified cell', 0, $e); | |
} | |
$this->cellCache[$x][$y] = new Cell($cell, $this); | |
} | |
return $this->cellCache[$x][$y]; | |
} | |
/** | |
* Get the parent Workbook object | |
* | |
* @return \DaveRandom\ExcelCOM\Workbook The parent Workbook object | |
*/ | |
public function getWorkbook() | |
{ | |
return $this->workbook; | |
} | |
/** | |
* Get a Cell object representing the cell at the specified coordinate | |
* | |
* @param string|int $x The X-coordinate of the cell or a full cell identifier string | |
* @param int $y The Y-coordinate of the cell, ignored if $x received a full cell indentifier | |
* | |
* @return \DaveRandom\ExcelCOM\Cell The Cell object | |
* | |
* @throws \OutOfRangeException When an invalid cell coordinate is requested | |
* @throws \RuntimeException When a reference to the cell cannot be obtained | |
*/ | |
public function getCell($x, $y = null) | |
{ | |
if (preg_match('/^(?P<x>[A-Z]+)(?P<y>\d+)?$/', strtoupper(trim($x)), $coords)) { | |
if (!empty($coords['y'])) { | |
$y = $coords['y']; | |
} | |
$x = $this->xAlphaToInt($coords['x']); | |
} | |
if (!isset($y)) { | |
throw new \OutOfRangeException('Invalid cell coordinate'); | |
} | |
$x = (int) $x; | |
$y = (int) $y; | |
if (!$x || !$y || $x > 256 || $y > 65536) { | |
throw new \OutOfRangeException('Invalid cell coordinate'); | |
} | |
return $this->getCellCached($x, $y); | |
} | |
/** | |
* Unprotect the worksheet | |
* | |
* @param string $password The password used to protect the sheet, no password if omitted | |
* | |
* @return \DaveRandom\ExcelCOM\Worksheet The current Worksheet object for method chaining | |
* | |
* @throws \RuntimeException When the unprotect operation fails | |
*/ | |
public function unprotect($password = null) | |
{ | |
try { | |
if (isset($password)) { | |
$this->worksheet->Unprotect($password); | |
} else { | |
$this->worksheet->Unprotect(); | |
} | |
} catch (\Exception $e) { | |
throw new \RuntimeException('Unable to unprotect sheet', 0, $e); | |
} | |
return $this; | |
} | |
/** | |
* Protect the worksheet | |
* | |
* @param string $password The password used to protect the sheet, no password if omitted | |
* | |
* @return \DaveRandom\ExcelCOM\Worksheet The current Worksheet object for method chaining | |
* | |
* @throws \RuntimeException When the protect operation fails | |
*/ | |
public function protect($password = null) | |
{ | |
try { | |
if ($password !== null) { | |
$this->worksheet->Protect($password); | |
} else { | |
$this->worksheet->Protect(); | |
} | |
} catch (\Exception $e) { | |
throw new \RuntimeException('Unable to protect sheet', 0, $e); | |
} | |
return $this; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment