This commit is contained in:
steven 2025-08-11 22:23:30 +02:00
commit 72a26edcff
22092 changed files with 2101903 additions and 0 deletions

31
setup/composer.json Normal file
View file

@ -0,0 +1,31 @@
{
"name": "faisalman/simple-excel-php",
"type": "library",
"description": "Easily parse / convert / write between Microsoft Excel XML / CSV / TSV / HTML / JSON / etc formats",
"keywords": ["excel", "spreadsheet", "document", "xml", "csv", "tsv", "html", "json", "parser", "converter", "writer"],
"homepage": "http://faisalman.github.com/simple-excel-php",
"repositories": [
{
"type": "vcs",
"url": "https://github.com/faisalman/simple-excel-php.git"
}
],
"license": "MIT",
"authors": [
{
"name": "Faisal Salman",
"email": "fyzlman@gmail.com",
"homepage": "http://faisalman.com",
"role": "Developer"
}
],
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "3.7.*"
},
"autoload": {
"psr-0": {"SimpleExcel\\": "src/"}
}
}

84
setup/readme.md Normal file
View file

@ -0,0 +1,84 @@
# Simple Excel
Easily parse / convert / write between Microsoft Excel XML / CSV / TSV / HTML / JSON / etc formats
### For further deatails see the GitHuib Pages site: http://faisalman.github.com/simple-excel-php ###
## PHP Versions Supported
PHP >= 5.3
## Installation
If you're using Composer to manage libraries, include this package in your composer.json
```json
"require" : {
"faisalman/simple-excel-php" : "0.3.*"
}
```
If you want to try version 0.4 (still in develop branch) you can use
```json
"require" : {
"faisalman/simple-excel-php" : "develop as 0.4.0-alpha"
}
```
Or just load this library in your PHP project by including SimpleExcel.php
```json
require_once('../your/project/directory/here/lib/SimpleExcel/SimpleExcel.php');
```
## Features
* Available parsers: Microsoft Excel 2003 XML, CSV, TSV, HTML, JSON
* Available writers: Microsoft Excel 2003 XML, CSV, TSV, HTML, JSON
## Usage
```php
use SimpleExcel\SimpleExcel
$excel = new SimpleExcel('CSV');
$excel->parser->loadFile('test.csv');
echo $excel->parser->getCell(1, 1);
$excel->convertTo('JSON');
$excel->writer->addRow(array('add', 'another', 'row'));
$excel->writer->saveFile('example');
```
## Development
[![Build Status](https://travis-ci.org/faisalman/simple-excel-php.png?branch=master)](https://travis-ci.org/faisalman/simple-excel-php)
Testing
```sh
$ phpunit --configuration test/phpunit.xml
```
Next version 0.4.0-alpha is now available under [develop](https://github.com/faisalman/simple-excel-php/tree/develop) branch
## License
Copyright (c) 2011-2012 Faisalman <<fyzlman@gmail.com>>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -0,0 +1,27 @@
<?php
namespace SimpleExcel\Exception;
/**
* Defines SimpleExcel exception enum
*
* @author Faisalman
* @package SimpleExcel
*/
/** define exception enum */
abstract class SimpleExcelException
{
const UNKNOWN = 0;
const FILE_NOT_FOUND = 1;
const FILE_EXTENSION_MISMATCH = 2;
const ERROR_READING_FILE = 3;
const INVALID_DOCUMENT_NAMESPACE = 4;
const FIELD_NOT_FOUND = 5;
const ROW_NOT_FOUND = 6;
const COLUMN_NOT_FOUND = 7;
const CELL_NOT_FOUND = 8;
const FILETYPE_NOT_SUPPORTED = 9;
const MALFORMED_JSON = 10;
}
?>

View file

@ -0,0 +1,193 @@
<?php
namespace SimpleExcel\Parser;
use SimpleExcel\Exception\SimpleExcelException;
/**
* SimpleExcel class for parsing HTML table
*
* @author Faisalman
* @package SimpleExcel
*/
abstract class BaseParser implements IParser
{
/**
* Holds the parsed result
*
* @access private
* @var array
*/
protected $table_arr;
/**
* Defines valid file extension
*
* @access protected
* @var string
*/
protected $file_extension = '';
/**
* @param string $file_url Path to file (optional)
*/
public function __construct($file_url = NULL) {
if(isset($file_url)) {
$this->loadFile($file_url);
}
}
/**
* Get value of the specified cell
*
* @param int $row_num Row number
* @param int $col_num Column number
* @param int $val_only
* @return array
* @throws Exception If the cell identified doesn't exist.
*/
public function getCell($row_num, $col_num, $val_only = true) {
// check whether the cell exists
if (!$this->isCellExists($row_num, $col_num)) {
throw new \Exception('Cell '.$row_num.','.$col_num.' doesn\'t exist', SimpleExcelException::CELL_NOT_FOUND);
}
return $this->table_arr[$row_num-1][$col_num-1];
}
/**
* Get data of the specified column as an array
*
* @param int $col_num Column number
* @param bool $val_only
* @return array
* @throws Exception If the column requested doesn't exist.
*/
public function getColumn($col_num, $val_only = TRUE) {
$col_arr = array();
if(!$this->isColumnExists($col_num)){
throw new \Exception('Column '.$col_num.' doesn\'t exist', SimpleExcelException::COLUMN_NOT_FOUND);
}
// get the specified column within every row
foreach($this->table_arr as $row){
array_push($col_arr, $row[$col_num-1]);
}
// return the array
return $col_arr;
}
/**
* Get data of all cells as an array
*
* @param bool $val_only
* @return array
* @throws Exception If the field is not set.
*/
public function getField($val_only = TRUE) {
if(!$this->isFieldExists()){
throw new \Exception('Field is not set', SimpleExcelException::FIELD_NOT_FOUND);
}
// return the array
return $this->table_arr;
}
/**
* Get data of the specified row as an array
*
* @param int $row_num Row number
* @param bool $val_only
* @return array
* @throws Exception When a row is requested that doesn't exist.
*/
public function getRow($row_num, $val_only = TRUE) {
if(!$this->isRowExists($row_num)){
throw new \Exception('Row '.$row_num.' doesn\'t exist', SimpleExcelException::ROW_NOT_FOUND);
}
// return the array
return $this->table_arr[$row_num-1];
}
/**
* Check whether cell with specified row & column exists
*
* @param int $row_num Row number
* @param int $col_num Column number
* @return bool
*/
public function isCellExists($row_num, $col_num){
return $this->isRowExists($row_num) && $this->isColumnExists($col_num);
}
/**
* Check whether a specified column exists
*
* @param int $col_num Column number
* @return bool
*/
public function isColumnExists($col_num){
$exist = false;
foreach($this->table_arr as $row){
if(array_key_exists($col_num-1, $row)){
$exist = true;
}
}
return $exist;
}
/**
* Check whether a specified row exists
*
* @param int $row_num Row number
* @return bool
*/
public function isRowExists($row_num){
return array_key_exists($row_num-1, $this->table_arr);
}
/**
* Check whether table exists
*
* @return bool
*/
public function isFieldExists(){
return isset($this->table_arr);
}
/**
* Check whether file exists, valid, and readable
*
* @param string $file_path Path to file
* @return bool
* @throws Exception If file being loaded doesn't exist
* @throws Exception If file extension doesn't match
* @throws Exception If error reading the file
*/
public function isFileReady($file_path) {
// file exists?
if (!file_exists($file_path)) {
throw new \Exception('File '.$file_path.' doesn\'t exist', SimpleExcelException::FILE_NOT_FOUND);
// extension valid?
} else if (strtoupper(pathinfo($file_path, PATHINFO_EXTENSION))!= strtoupper($this->file_extension)){
throw new \Exception('File extension '.strtoupper(pathinfo($file_path, PATHINFO_EXTENSION)).' doesn\'t match with '.$this->file_extension, SimpleExcelException::FILE_EXTENSION_MISMATCH);
// file readable?
} else if (($handle = fopen($file_path, 'r')) === FALSE) {
throw new \Exception('Error reading the file in'.$file_path, SimpleExcelException::ERROR_READING_FILE);
fclose($handle);
// okay then
} else {
return TRUE;
}
}
}

View file

@ -0,0 +1,124 @@
<?php
namespace SimpleExcel\Parser;
use SimpleExcel\Exception\SimpleExcelException;
/**
* SimpleExcel class for parsing Microsoft Excel CSV Spreadsheet
*
* @author Faisalman
* @package SimpleExcel
*/
class CSVParser extends BaseParser implements IParser
{
/**
* Defines delimiter character
*
* @access protected
* @var string
*/
protected $delimiter;
/**
* Defines valid file extension
*
* @access protected
* @var string
*/
protected $file_extension = 'csv';
/**
* Load the CSV file to be parsed
*
* @param string $file_path Path to CSV file
*/
public function loadFile($file_path){
if (!$this->isFileReady($file_path)) {
return;
}
$this->loadString(file_get_contents($file_path));
}
/**
* Load the string to be parsed
*
* @param string $str String with CSV format
*/
public function loadString($str){
$this->table_arr = array();
// 1. Split into lines by newline http://stackoverflow.com/questions/3997336/explode-php-string-by-new-line
$pattern = "/\r\n|\n|\r/";
$lines = preg_split($pattern, $str, -1, PREG_SPLIT_NO_EMPTY);
$total = count($lines);
// There are no lines to parse
if ($total == 0) {
return;
}
// 2. Guess delimiter if none set
$line = $lines[0];
if (!isset($this->delimiter)) {
// do guess work
$separators = array(';' => 0, ',' => 0);
foreach ($separators as $sep => $count) {
$args = str_getcsv($sep, $line);
$count = count($args);
$separators[$sep] = $count;
}
$sep = ',';
if (($separators[';'] > $separators[','])) {
$sep = ';';
}
$this->delimiter = $sep;
}
// 3. Parse the lines into rows,cols
$max = 0;
$min = PHP_INT_MAX;
$cols = 0;
$sep = $this->delimiter;
$rows = array();
foreach ($lines as $line) {
$args = str_getcsv($line, $sep);
$rows[] = $args;
$cols = count($args);
if ($cols > $max) {
$max = $cols;
}
if ($cols < $min) {
$min = $cols;
}
}
// 4. Expand those rows which have less cols than max cols found
if ($min != $max) {
foreach ($rows as $i => $row) {
$c = count($row);
while ($c < $max) {
$row[] = ""; // fill with empty strings
$c += 1;
}
$rows[$i] = $row;
}
}
$this->table_arr = $rows;
}
/**
* Set delimiter that should be used to parse CSV document
*
* @param string $delimiter Delimiter character
*/
public function setDelimiter($delimiter){
$this->delimiter = $delimiter;
}
}

View file

@ -0,0 +1,95 @@
<?php
namespace SimpleExcel\Parser;
use SimpleExcel\Exception\SimpleExcelException;
/**
* SimpleExcel class for parsing HTML table
*
* @author Faisalman
* @package SimpleExcel
*/
class HTMLParser extends BaseParser implements IParser
{
/**
* Defines valid file extension
*
* @access protected
* @var string
*/
protected $file_extension = 'html';
/**
* Process the loaded file/string
*
* @param DOMDocument $html DOMDocument object of HTML
*/
private function parseDOM($html){
$tables = $html->getElementsByTagName('table');
$field = array();
foreach ($tables as $table) {
$table_child = $table->childNodes;
foreach ($table_child as $twrap) {
if($twrap->nodeType === XML_ELEMENT_NODE) {
if ($twrap->nodeName === "thead" || $twrap->nodeName === "tbody") {
$twrap_child = $twrap->childNodes;
foreach ($twrap_child as $tr) {
if($tr->nodeType === XML_ELEMENT_NODE && $tr->nodeName === "tr") {
$row = array();
$tr_child = $tr->childNodes;
foreach ($tr_child as $td) {
if ($td->nodeType === XML_ELEMENT_NODE && ($td->nodeName === "th" || $td->nodeName === "td")) {
array_push($row, $td->nodeValue);
}
}
array_push($field, $row);
}
}
} else if ($twrap->nodeName === "tr") {
$row = array();
$twrap_child = $twrap->childNodes;
foreach ($twrap_child as $td) {
if ($td->nodeType === XML_ELEMENT_NODE && ($td->nodeName === "th" || $td->nodeName === "td")) {
array_push($row, $td->nodeValue);
}
}
array_push($field, $row);
}
}
}
}
$this->table_arr = $field;
}
/**
* Load the HTML file to be parsed
*
* @param string $file_path Path to HTML file
*/
public function loadFile($file_path) {
if (!$this->isFileReady($file_path)) {
return;
}
$html = new \DOMDocument('1.0', 'UTF-8');
$sp = mb_convert_encoding(file_get_contents($file_path), 'HTML-ENTITIES', "UTF-8");
$html->loadHTML($sp);
$html->encoding = 'UTF-8';
$this->parseDOM($html);
}
/**
* Load the string to be parsed
*
* @param string $str String with HTML format
*/
public function loadString($str){
$html = new \DOMDocument('1.0', 'UTF-8');
$sp = mb_convert_encoding($str, 'HTML-ENTITIES', "UTF-8");
$html->loadHTML($sp);
$html->encoding = 'UTF-8';
$this->parseDOM($html);
}
}

View file

@ -0,0 +1,28 @@
<?php
namespace SimpleExcel\Parser;
/**
* Defines SimpleExcel parser interface
*
* @author Faisalman
* @package SimpleExcel
*/
/** define parser interface */
interface IParser
{
public function getCell($row_num, $col_num, $val_only);
public function getColumn($col_num, $val_only);
public function getRow($row_num, $val_only);
public function getField($val_only);
public function isCellExists($row_num, $col_num);
public function isColumnExists($col_num);
public function isRowExists($row_num);
public function isFieldExists();
public function isFileReady($file_path);
public function loadFile($file_path);
public function loadString($str);
}
?>

View file

@ -0,0 +1,61 @@
<?php
namespace SimpleExcel\Parser;
use SimpleExcel\Exception\SimpleExcelException;
/**
* SimpleExcel class for parsing JSON table
*
* @author Faisalman
* @package SimpleExcel
*/
class JSONParser extends BaseParser implements IParser
{
/**
* Defines valid file extension
*
* @access protected
* @var string
*/
protected $file_extension = 'json';
/**
* Load the JSON file to be parsed
*
* @param string $file_path Path to JSON file
*/
public function loadFile($file_path) {
if (!$this->isFileReady($file_path)) {
return;
}
$handle = fopen($file_path, 'r');
$contents = fread($handle, filesize($file_path));
$this->loadString($contents);
fclose($handle);
}
/**
* Load the string to be parsed
*
* @param string $str String with JSON format
* @throws Exception If JSON format is invalid (or too deep)
*/
public function loadString($str){
$field = array();
if (($table = json_decode(utf8_encode($str), false, 4)) === NULL) {
throw new \Exception('Invalid JSON format: '.$str, SimpleExcelException::MALFORMED_JSON);
} else {
foreach ($table as $rows) {
$row = array();
foreach ($rows as $cell) {
array_push($row, $cell);
}
array_push($field, $row);
}
}
$this->table_arr = $field;
}
}

View file

@ -0,0 +1,35 @@
<?php
namespace SimpleExcel\Parser;
/**
* SimpleExcel class for parsing Microsoft Excel TSV Spreadsheet
*
* @author Faisalman
* @package SimpleExcel
*/
class TSVParser extends CSVParser
{
/**
* Defines delimiter character (TAB)
*
* @access protected
* @var string
*/
protected $delimiter = "\t";
/**
* Defines valid file extension
*
* @access protected
* @var string
*/
protected $file_extension = 'tsv';
/**
* Override parent class, this method is ignored in TSV
*/
public function setDelimiter($delimiter){
// do nothing
}
}

View file

@ -0,0 +1,34 @@
<?php
namespace SimpleExcel\Parser;
/**
* SimpleExcel class for parsing Microsoft Excel XLSX Spreadsheet
*
* @author Faisalman
* @package SimpleExcel
*/
class XLSXParser extends BaseParser implements IParser
{
/**
* Defines valid file extension
*
* @access protected
* @var string
*/
protected $file_extension = 'xlsx';
/**
* Load an XLSX file to be parsed
*
* @param string $file_path Path to XLSX file
*/
public function loadFile($file_path) { }
/**
* Load the string to be parsed
*
* @param string $str String with XLSX format
*/
public function loadString($str) { }
}

View file

@ -0,0 +1,324 @@
<?php
namespace SimpleExcel\Parser;
use SimpleExcel\Exception\SimpleExcelException;
/**
* SimpleExcel class for parsing Microsoft Excel 2003 XML Spreadsheet
*
* @author Faisalman
* @package SimpleExcel
*/
class XMLParser extends BaseParser implements IParser
{
/**
* Defines valid file extension
*
* @access protected
* @var string
*/
protected $file_extension = 'xml';
/**
* Extract attributes from SimpleXMLElement object
*
* @access private
* @param object $attrs_obj
* @return array
*/
private function getAttributes($attrs_obj) {
$attrs_arr = array();
if (!$attrs_obj) {
return $attrs_arr;
}
foreach ($attrs_obj as $attrs) {
$attrs = (array) $attrs;
foreach ($attrs as $attr) {
$attr_keys = array_keys($attr);
$attrs_arr[$attr_keys[0]] = $attr[$attr_keys[0]];
}
}
return $attrs_arr;
}
/**
* Get value of the specified cell
*
* @param int $row_num Row number
* @param int $col_num Column number
* @param int $val_only Whether returns only it's value or complete data
* @return array
* @throws Exception If the cell identified doesn't exist.
*/
public function getCell($row_num, $col_num, $val_only = true) {
// check whether the cell exists
if (!$this->isCellExists($row_num, $col_num)) {
throw new \Exception('Cell '.$row_num.','.$col_num.' doesn\'t exist', SimpleExcelException::CELL_NOT_FOUND);
}
if(is_array($this->table_arr['table_contents'][$row_num-1]['row_contents'])){
if(array_key_exists($col_num-1, $this->table_arr['table_contents'][$row_num-1]['row_contents'])){
$cell = $this->table_arr['table_contents'][$row_num-1]['row_contents'][$col_num-1];
if(!$val_only){
return $cell;
} else {
return $cell['value'];
}
}
}
return "";
}
/**
* Get data of the specified column as an array
*
* @param int $col_num Column number
* @param bool $val_only Returns (value only | complete data) for every cell, default to TRUE
* @return array
* @throws Exception If the column requested doesn't exist.
*/
public function getColumn($col_num, $val_only = TRUE) {
$col_arr = array();
if (!$this->isColumnExists($col_num)) {
throw new \Exception('Column '.$col_num.' doesn\'t exist', SimpleExcelException::COLUMN_NOT_FOUND);
}
// get the specified column within every row
foreach ($this->table_arr['table_contents'] as $row) {
if ($row['row_contents']) {
if(!$val_only) {
array_push($col_arr, $row['row_contents'][$col_num-1]);
} else {
array_push($col_arr, $row['row_contents'][$col_num-1]['value']);
}
} else {
array_push($col_arr, "");
}
}
// return the array
return $col_arr;
}
/**
* Get data of all cells as an array
*
* @param bool $val_only Returns (value only | complete data) for every cell, default to TRUE
* @return array
* @throws Exception If the field is not set.
*/
public function getField($val_only = TRUE) {
if (!$this->isFieldExists()) {
throw new \Exception('Field is not set', SimpleExcelException::FIELD_NOT_FOUND);
}
if($val_only){
$field = array();
foreach($this->table_arr['table_contents'] as $row){
$cells = array();
if($row['row_contents']){
foreach($row['row_contents'] as $cell){
array_push($cells, $cell['value']);
}
}
array_push($field, $cells);
}
return $field;
} else {
return $this->table_arr;
}
}
/**
* Get data of the specified row as an array
*
* @param int $row_num Row number
* @param bool $val_only Returns (value only | complete data) for every cell, default to TRUE
* @return array
* @throws Exception When a row is requested that doesn't exist.
*/
public function getRow($row_num, $val_only = TRUE) {
if (!$this->isRowExists($row_num)) {
throw new \Exception('Row '.$row_num.' doesn\'t exist', SimpleExcelException::ROW_NOT_FOUND);
}
$row = $this->table_arr['table_contents'][$row_num-1]['row_contents'];
$row_arr = array();
// get the specified column within every row
foreach ($row as $cell) {
if (!$val_only) {
array_push($row_arr, $cell);
} else {
array_push($row_arr, $cell['value']);
}
}
// return the array, if empty then return FALSE
return $row_arr;
}
/**
* Check whether a specified column exists
*
* @param int $col_num Column number
* @return bool
*/
public function isColumnExists($col_num){
$exist = false;
foreach($this->table_arr['table_contents'] as $row){
if(is_array($row['row_contents'])){
if(array_key_exists($col_num-1, $row['row_contents'])){
$exist = true;
}
}
}
return $exist;
}
/**
* Check whether a specified row exists
*
* @param int $row_num Row number
* @return bool
*/
public function isRowExists($row_num){
return array_key_exists($row_num-1, $this->table_arr['table_contents']);
}
/**
* Process the loaded file/string
*
* @param SimpleXMLElement $xml SimpleXMLElement object of XML
* @throws Exception If document namespace invalid
* @return bool
*/
private function parseDOM($xml){
// get XML namespace
$xmlns = $xml->getDocNamespaces();
// check file extension and XML namespace
if ($xmlns['ss'] != 'urn:schemas-microsoft-com:office:spreadsheet') {
throw new \Exception('Document namespace isn\'t a valid Excel XML 2003 Spreadsheet', SimpleExcelException::INVALID_DOCUMENT_NAMESPACE);
}
// extract document properties
$doc_props = (array)$xml->DocumentProperties;
$this->table_arr['doc_props'] = $doc_props;
$rows = $xml->Worksheet->Table->Row;
$row_num = 1;
$this->table_arr = array(
'doc_props' => array(),
'table_contents' => array()
);
// loop through all rows
foreach ($rows as $row) {
// check whether ss:Index attribute exist in this row
$row_index = $row->xpath('@ss:Index');
// if exist, push empty value until the specified index
if (count($row_index) > 0) {
$gap = $row_index[0]-count($this->table_arr['table_contents']);
for($i = 1; $i < $gap; $i++){
array_push($this->table_arr['table_contents'], array(
'row_num' => $row_num,
'row_contents' => '',
//'row_attrs' => $row_attrs_arr
));
$row_num += 1;
}
}
$cells = $row->Cell;
$row_attrs = $row->xpath('@ss:*');
$row_attrs_arr = $this->getAttributes($row_attrs);
$row_arr = array();
$col_num = 1;
// loop through all row's cells
foreach ($cells as $cell) {
// check whether ss:Index attribute exist
$cell_index = $cell->xpath('@ss:Index');
// if exist, push empty value until the specified index
if (count($cell_index) > 0) {
$gap = $cell_index[0]-count($row_arr);
for ($i = 1; $i < $gap; $i++) {
array_push ($row_arr, array(
'row_num' => $row_num,
'col_num' => $col_num,
'datatype' => '',
'value' => '',
//'cell_attrs' => '',
//'data_attrs' => ''
));
$col_num += 1;
}
}
// get all cell and data attributes
//$cell_attrs = $cell->xpath('@ss:*');
//$cell_attrs_arr = $this->getAttributes($cell_attrs);
$data_attrs = $cell->Data->xpath('@ss:*');
$data_attrs_arr = $this->getAttributes($data_attrs);
$cell_datatype = isset($data_attrs_arr['Type']) ? $data_attrs_arr['Type'] : 'String';
// extract data from cell
$cell_value = (string) $cell->Data;
// escape input from HTML tags
$cell_value = filter_var($cell_value, FILTER_SANITIZE_SPECIAL_CHARS);
// push column array
array_push($row_arr, array(
'row_num' => $row_num,
'col_num' => $col_num,
'datatype' => $cell_datatype,
'value' => $cell_value,
//'cell_attrs' => $cell_attrs_arr,
//'data_attrs' => $data_attrs_arr
));
$col_num += 1;
}
// push row array
array_push($this->table_arr['table_contents'], array(
'row_num' => $row_num,
'row_contents' => $row_arr,
//'row_attrs' => $row_attrs_arr
));
$row_num += 1;
}
return true;
}
/**
* Load the XML file to be parsed
*
* @param string $file_path Path to XML file
* @return bool
*/
public function loadFile($file_path) {
if (!$this->isFileReady($file_path)) {
return false;
}
return $this->parseDOM(simplexml_load_file($file_path));
}
/**
* Load the string to be parsed
*
* @param string $str String with XML format
* @return bool
*/
public function loadString($str){
return $this->parseDOM(simplexml_load_string($str));
}
}

View file

@ -0,0 +1,126 @@
<?php
/**
* Simple Excel
*
* A PHP library with simplistic approach
* Easily parse/convert/write between Microsoft Excel XML/CSV/TSV/HTML/JSON/etc formats
*
* Copyright (c) 2011-2013 Faisalman <fyzlman@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author Faisalman
* @copyright 2011-2013 (c) Faisalman
* @license http://www.opensource.org/licenses/mit-license
* @link http://github.com/faisalman/simple-excel-php
* @package SimpleExcel
* @version 0.3.15
*/
namespace SimpleExcel;
use SimpleExcel\Exception\SimpleExcelException;
if (!class_exists('Composer\\Autoload\\ClassLoader', false)){
// autoload all interfaces & classes
spl_autoload_register(function($class_name){
if($class_name != 'SimpleExcel') require_once(dirname(__FILE__).DIRECTORY_SEPARATOR.str_replace('\\', DIRECTORY_SEPARATOR, substr($class_name, strlen('SimpleExcel\\'))).'.php');
});
}
/**
* SimpleExcel main class
*
* @author Faisalman
* @package SimpleExcel
*/
class SimpleExcel
{
/**
*
* @var CSVParser | TSVParser | XMLParser | HTMLParser | JSONParser
*/
public $parser;
/**
*
* @var CSVWriter | TSVWriter | XMLWriter | HTMLWriter | JSONWriter
*/
public $writer;
/**
*
* @var array
*/
protected $validParserTypes = array('XML', 'CSV', 'TSV', 'HTML', 'JSON');
protected $validWriterTypes = array('XML', 'CSV', 'TSV', 'HTML', 'JSON');
/**
* SimpleExcel constructor method
*
* @param string $filetype Set the filetype of the file which will be parsed (XML/CSV/TSV/HTML/JSON)
* @return void
*/
public function __construct($filetype = 'XML'){
$this->constructParser($filetype);
$this->constructWriter($filetype);
}
/**
* Construct a SimpleExcel Parser
*
* @param string $filetype Set the filetype of the file which will be parsed (XML/CSV/TSV/HTML/JSON)
* @throws Exception If filetype is neither XML/CSV/TSV/HTML/JSON
*/
public function constructParser($filetype){
$filetype = strtoupper($filetype);
if(!in_array($filetype, $this->validParserTypes)){
throw new \Exception('Filetype '.$filetype.' is not supported', SimpleExcelException::FILETYPE_NOT_SUPPORTED);
}
$parser_class = 'SimpleExcel\\Parser\\'.$filetype.'Parser';
$this->parser = new $parser_class();
}
/**
* Construct a SimpleExcel Writer
*
* @param string $filetype Set the filetype of the file which will be written (XML/CSV/TSV/HTML/JSON)
* @return bool
* @throws Exception If filetype is neither XML/CSV/TSV/HTML/JSON
*/
public function constructWriter($filetype){
$filetype = strtoupper($filetype);
if(!in_array($filetype, $this->validWriterTypes)){
throw new \Exception('Filetype '.$filetype.' is not supported', SimpleExcelException::FILETYPE_NOT_SUPPORTED);
}
$writer_class = 'SimpleExcel\\Writer\\'.$filetype.'Writer';
$this->writer = new $writer_class();
}
/**
* Change writer type to convert to another format
*
* @param string $filetype Set the filetype of the file which will be written (XML/CSV/TSV/HTML/JSON)
*/
public function convertTo($filetype){
$this->constructWriter($filetype);
$this->writer->setData($this->parser->getField());
}
}

View file

@ -0,0 +1,124 @@
<?php
namespace SimpleExcel\Writer;
/**
* SimpleExcel base class for writing spreadsheet
*
* @author Faisalman
* @package SimpleExcel
*/
abstract class BaseWriter implements IWriter
{
/**
* Holds tabular data
*
* @access protected
* @var array
*/
protected $tabl_data;
/**
* Defines content-type for HTTP header
*
* @access protected
* @var string
*/
protected $content_type = 'text';
/**
* Defines file extension to be used when saving file
*
* @access protected
* @var string
*/
protected $file_extension = 'txt';
/**
* @return void
*/
public function __construct(){
$this->tabl_data = array();
}
/**
* Adding row data to table
*
* @param array $values An array contains ordered value for every cell
* @param bool Check if row goes at the beginning or end of array
* @return void
*/
public function addRow($values, $end = TRUE)
{
if (!is_array($values)) {
$values = array($values);
}
if ($end) {
array_push($this->tabl_data, $values);
return;
}
array_unshift($this->tabl_data, $values);
}
/**
* Get document content as string
*
* @return string Content of document
*/
public function saveString(){
$content = '';
foreach ($this->tabl_data as $row) {
foreach ($row as $cell) {
$content .= $cell.'\t';
}
$content .= '\n';
}
return $content;
}
/**
* Export the document
*
* @param string $filename Name for the saved file (extension will be set automatically)
* @param string $target Save location
* @return void
*/
public function saveFile($filename, $target = NULL){
if (!isset($filename)) {
$filename = date('YmdHis');
}
if (!isset($target)) {
// write output to browser
$target = 'php://output';
// set HTTP response header
header('Content-Type: '.$this->content_type);
header('Content-Disposition: attachment; filename='.$filename.'.'.$this->file_extension);
}
$fp = fopen($target, 'w');
fwrite($fp, $this->saveString());
fclose($fp);
if ($target == 'php://output') {
// since there must be no data below
exit();
}
}
/**
* Set tabular data
*
* @param array $values An array contains ordered value of arrays for all fields
* @return void
*/
public function setData($values){
if(!is_array($values)){
$values = array($values);
}
$this->tabl_data = $values;
}
}
?>

View file

@ -0,0 +1,63 @@
<?php
namespace SimpleExcel\Writer;
/**
* SimpleExcel class for writing CSV Spreadsheet
*
* @author Faisalman
* @package SimpleExcel
*/
class CSVWriter extends BaseWriter implements IWriter
{
/**
* Defines content-type for HTTP header
*
* @access protected
* @var string
*/
protected $content_type = 'text/csv';
/**
* Defines delimiter char
*
* @access protected
* @var string
*/
protected $delimiter = ',';
/**
* Defines file extension to be used when saving file
*
* @access protected
* @var string
*/
protected $file_extension = 'csv';
/**
* Get document content as string
*
* @return string Content of document
*/
public function saveString(){
$fp = fopen('php://temp', 'r+');
foreach ($this->tabl_data as $row) {
fputcsv($fp, $row, $this->delimiter);
}
rewind($fp);
$content = stream_get_contents($fp);
fclose($fp);
return $content;
}
/**
* Set character for delimiter
*
* @param string $delimiter Commonly used character can be a comma, semicolon, tab, or space
* @return void
*/
public function setDelimiter($delimiter){
$this->delimiter = $delimiter;
}
}
?>

View file

@ -0,0 +1,46 @@
<?php
namespace SimpleExcel\Writer;
/**
* SimpleExcel class for writing HTML table
*
* @author Faisalman
* @package SimpleExcel
*/
class HTMLWriter extends BaseWriter implements IWriter
{
/**
* Defines content-type for HTTP header
*
* @access protected
* @var string
*/
protected $content_type = 'text/html';
/**
* Defines file extension to be used when saving file
*
* @access protected
* @var string
*/
protected $file_extension = 'html';
/**
* Get document content as string
*
* @return string Content of document
*/
public function saveString(){
$content = '<table>';
foreach ($this->tabl_data as $row) {
$content .= '<tr>';
foreach ($row as $cell) {
$content .= '<td>'.$cell.'</td>';
}
$content .= '</tr>';
}
return $content.'</table>';
}
}
?>

View file

@ -0,0 +1,21 @@
<?php
namespace SimpleExcel\Writer;
/**
* Defines SimpleExcel writer interface
*
* @author Faisalman
* @package SimpleExcel
*/
/** define writer interface */
interface IWriter
{
public function addRow($values);
public function saveString();
public function saveFile($filename, $target);
public function setData($values);
}
?>

View file

@ -0,0 +1,46 @@
<?php
namespace SimpleExcel\Writer;
/**
* SimpleExcel class for writing table as JSON
*
* @author Faisalman
* @package SimpleExcel
*/
class JSONWriter extends BaseWriter implements IWriter
{
/**
* Defines content-type for HTTP header
*
* @access protected
* @var string
*/
protected $content_type = 'application/json';
/**
* Defines file extension to be used when saving file
*
* @access protected
* @var string
*/
protected $file_extension = 'json';
/**
* Get document content as string
*
* @return string Content of document
*/
public function saveString(){
$json = array();
foreach ($this->tabl_data as $row) {
$row_array = array();
for ($i = 0; $i < count($row); $i++) {
$row_array[$i] = $row[$i];
}
array_push($json, (object)$row);
}
return json_encode($json);
}
}
?>

View file

@ -0,0 +1,44 @@
<?php
namespace SimpleExcel\Writer;
/**
* SimpleExcel class for writing TSV Spreadsheet
*
* @author Faisalman
* @package SimpleExcel
*/
class TSVWriter extends CSVWriter implements IWriter
{
/**
* Defines content-type for HTTP header
*
* @access protected
* @var string
*/
protected $content_type = 'text/tab-separated-values';
/**
* Defines delimiter char
*
* @access protected
* @var string
*/
protected $delimiter = "\t";
/**
* Defines file extension to be used when saving file
*
* @access protected
* @var string
*/
protected $file_extension = 'tsv';
/**
* Override parent class, this method is ignored in TSV
*/
public function setDelimiter($delimiter){
// do nothing
}
}
?>

View file

@ -0,0 +1,76 @@
<?php
namespace SimpleExcel\Writer;
/**
* SimpleExcel class for writing Microsoft Excel XLSX Spreadsheet
*
* @author Faisalman
* @package SimpleExcel
*/
class XLSXWriter extends BaseWriter implements IWriter
{
/**
* Defines content-type for HTTP header
*
* @access protected
* @var string
*/
protected $content_type = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
/**
* Defines file extension to be used when saving file
*
* @access protected
* @var string
*/
protected $file_extension = 'xlsx';
/**
* Array containing document properties
*
* @access private
* @var array
*/
private $doc_prop;
/**
* @return void
*/
public function __construct() { }
/**
* Adding row data to XLSX
*
* @param array $values An array contains ordered value for every cell
* @return void
*/
public function addRow($values) { }
/**
* Get document content as string
*
* @return string Content of document
*/
public function saveString() { }
/**
* Set XLSX data
*
* @param array $values An array contains ordered value of arrays for all fields
* @return void
*/
public function setData($values) { }
/**
* Set a document property of the XLSX
*
* @param string $prop Document property to be set
* @param string $val Value of the document property
* @return void
*/
public function setDocProp($prop, $val) {
$this->doc_prop[$prop] = $val;
}
}
?>

View file

@ -0,0 +1,146 @@
<?php
namespace SimpleExcel\Writer;
/**
* SimpleExcel class for writing Microsoft Excel 2003 XML Spreadsheet
*
* @author Faisalman
* @package SimpleExcel
*/
class XMLWriter extends BaseWriter implements IWriter
{
/**
* Defines content-type for HTTP header
*
* @access protected
* @var string
*/
protected $content_type = 'application/xml';
/**
* Defines file extension to be used when saving file
*
* @access protected
* @var string
*/
protected $file_extension = 'xml';
/**
* Array containing document properties
*
* @access private
* @var array
*/
private $doc_prop;
/**
* @return void
*/
public function __construct(){
$this->doc_prop = array(
'Author' => 'SimpleExcel',
'Company' => 'SimpleExcel',
'Created' => gmdate("Y-m-d\TH:i:s\Z"),
'Keywords' => 'SimpleExcel',
'LastAuthor' => 'SimpleExcel',
'Version' => '12.00'
);
}
/**
* Adding row data to XML
*
* @param array $values An array contains ordered value for every cell
* @return void
*/
public function addRow($values){
$row = &$this->tabl_data;
$row .= '
<Row ss:AutoFitHeight="0">';
foreach($values as $val){
$value = '';
$datatype = 'String';
// check if given variable contains array
if(is_array($val)){
$value = $val[0];
$datatype = $val[1];
} else {
$value = $val;
$datatype = is_numeric($val) ? 'Number' : 'String';
}
// escape value from HTML tags
$value = filter_var($value, FILTER_SANITIZE_SPECIAL_CHARS);
$row .= '
<Cell><Data ss:Type="'.$datatype.'">'.$value.'</Data></Cell>';
}
$row .= '
</Row>';
}
/**
* Get document content as string
*
* @return string Content of document
*/
public function saveString(){
$content = '<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">';
foreach($this->doc_prop as $propname => $propval){
$content .= '
<'.$propname.'>'.$propval.'</'.$propname.'>';
}
$content .= '
</DocumentProperties>
<Worksheet ss:Name="Sheet1">
<Table>'.$this->tabl_data.'
</Table>
</Worksheet>
</Workbook>';
return $content;
}
/**
* Set XML data
*
* @param array $values An array contains ordered value of arrays for all fields
* @return void
*/
public function setData($values){
if(!is_array($values)){
$values = array($values);
}
$this->tabl_data = ""; // reset the xml data.
// append values as rows
foreach ($values as $value) {
$this->addRow($value);
}
}
/**
* Set a document property of the XML
*
* @param string $prop Document property to be set
* @param string $val Value of the document property
* @return void
*/
public function setDocProp($prop, $val){
$this->doc_prop[$prop] = $val;
}
}
?>

View file

@ -0,0 +1,47 @@
<?php
use SimpleExcel\SimpleExcel;
require_once('src/SimpleExcel/SimpleExcel.php');
class CSVTest extends PHPUnit_Framework_TestCase
{
public function testConstruct()
{
$excel = new SimpleExcel('CSV');
$excel2 = new SimpleExcel();
$excel2->constructParser('CSV');
$this->assertEquals($excel->parser, $excel2->parser);
return $excel;
}
/**
* @depends testConstruct
*/
public function testParser(SimpleExcel $excel)
{
$excel->parser->loadFile('test/CSV/test.csv');
$this->assertEquals('ID', $excel->parser->getCell(1, 1));
$this->assertEquals('Kab. Cianjur', $excel->parser->getCell(3, 2));
$this->assertEquals(array('5', 'Comma, inside, double-quotes', '3'), $excel->parser->getRow(6));
$this->assertEquals(array('Kode Wilayah', '1', '1', '1', '2', '3'), $excel->parser->getColumn(3));
}
/**
* @depends testConstruct
*/
public function testWriter(SimpleExcel $excel)
{
$excel->writer->setData(
array(
array('ID', 'Nama', 'Kode Wilayah'),
array('1', 'Kab. Bogor', '1')
)
);
$this->assertEquals("ID,Nama,\"Kode Wilayah\"\n1,\"Kab. Bogor\",1\n", $excel->writer->saveString());
$excel->writer->addRow(array('2', 'Kab. Cianjur', '1'));
$this->assertEquals("ID,Nama,\"Kode Wilayah\"\n1,\"Kab. Bogor\",1\n2,\"Kab. Cianjur\",1\n", $excel->writer->saveString());
}
}
?>

6
setup/test/CSV/test.csv Normal file
View file

@ -0,0 +1,6 @@
ID,Nama,Kode Wilayah
1,Kab. Bogor,1
2,"Kab. Cianjur",1
3,Kab. Sukabumi,1
4,Kab. Tasikmalaya,2
5,"Comma, inside, double-quotes",3
1 ID Nama Kode Wilayah
2 1 Kab. Bogor 1
3 2 Kab. Cianjur 1
4 3 Kab. Sukabumi 1
5 4 Kab. Tasikmalaya 2
6 5 Comma, inside, double-quotes 3

6
setup/test/CSV/test2.csv Normal file
View file

@ -0,0 +1,6 @@
ID;Nama;Kode Wilayah
1;Kab. Bogor;1
2;"Kab. Cianjur";1
3;Kab. Sukabumi;1
4;Kab. Tasikmalaya;2
5;"Semicolon; inside; double-quotes";3
1 ID Nama Kode Wilayah
2 1 Kab. Bogor 1
3 2 Kab. Cianjur 1
4 3 Kab. Sukabumi 1
5 4 Kab. Tasikmalaya 2
6 5 Semicolon; inside; double-quotes 3

View file

@ -0,0 +1,35 @@
<?php
use SimpleExcel\SimpleExcel;
require_once('src/SimpleExcel/SimpleExcel.php');
class HTMLTest extends PHPUnit_Framework_TestCase
{
public function testConstruct()
{
$excel = new SimpleExcel('HTML');
return $excel;
}
/**
* @depends testConstruct
*/
public function testParser(SimpleExcel $excel)
{
$excel->parser->loadFile('test/HTML/test.html');
$this->assertEquals(array('ID', 'Nama', 'Kode Wilayah'), $excel->parser->getRow(1));
$this->assertEquals(array('1', 'Kab. Bogor', '1'), $excel->parser->getRow(2));
}
/**
* @depends testConstruct
*/
public function testWriter(SimpleExcel $excel)
{
$excel->writer->addRow(array('ID', 'Nama', 'Kode Wilayah'));
$this->assertEquals('<table><tr><td>ID</td><td>Nama</td><td>Kode Wilayah</td></tr></table>', $excel->writer->saveString());
}
}
?>

37
setup/test/HTML/test.html Normal file
View file

@ -0,0 +1,37 @@
<!doctype html>
<html>
<head>
<style>
td { border: 1px solid #000 }
</style>
</head>
<body>
<table>
<tr>
<td>ID</td>
<td>Nama</td>
<td>Kode Wilayah</td>
</tr>
<tr>
<td>1</td>
<td>Kab. Bogor</td>
<td>1</td>
</tr>
<tr>
<td>2</td>
<td>Kab. Cianjur</td>
<td>1</td>
</tr>
<tr>
<td>3</td>
<td>Kab. Sukabumi</td>
<td>1</td>
</tr>
<tr>
<td>4</td>
<td>Kab. Tasikmalaya</td>
<td>2</td>
</tr>
</table>
</body>
</html>

View file

@ -0,0 +1,35 @@
<?php
use SimpleExcel\SimpleExcel;
require_once('src/SimpleExcel/SimpleExcel.php');
class JSONTest extends PHPUnit_Framework_TestCase
{
public function testConstruct()
{
$excel = new SimpleExcel('JSON');
return $excel;
}
/**
* @depends testConstruct
*/
public function testParser(SimpleExcel $excel)
{
$excel->parser->loadFile('test/JSON/test.json');
$this->assertEquals(array('ID', 'Nama', 'Kode Wilayah'), $excel->parser->getRow(1));
$this->assertEquals(array('1', 'Kab. Bogor', '1'), $excel->parser->getRow(2));
}
/**
* @depends testConstruct
*/
public function testWriter(SimpleExcel $excel)
{
$excel->writer->addRow(array('ID', 'Nama', 'Kode Wilayah'));
$this->assertEquals('[{"0":"ID","1":"Nama","2":"Kode Wilayah"}]', $excel->writer->saveString());
}
}
?>

12
setup/test/JSON/test.json Normal file
View file

@ -0,0 +1,12 @@
[
{
"1" : "ID",
"2" : "Nama",
"3" : "Kode Wilayah"
},
{
"3" : "1",
"1" : "Kab. Bogor",
"2" : "1"
}
]

View file

6
setup/test/TSV/test.tsv Normal file
View file

@ -0,0 +1,6 @@
ID Nama Kode Wilayah
1 Kab. Bogor 1
2 "Kab. Cianjur" 1
3 Kab. Sukabumi 1
4 Kab. Tasikmalaya 2
5 "Tab inside double-quotes" 3
1 ID Nama Kode Wilayah
2 1 Kab. Bogor 1
3 2 Kab. Cianjur 1
4 3 Kab. Sukabumi 1
5 4 Kab. Tasikmalaya 2
6 5 Tab inside double-quotes 3

View file

View file

View file

0
setup/test/XML/test.xml Normal file
View file

15
setup/test/phpunit.xml Normal file
View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit>
<testsuites>
<testsuite name="CSV">
<directory>./CSV/</directory>
</testsuite>
<testsuite name="JSON">
<directory>./JSON/</directory>
</testsuite>
<testsuite name="HTML">
<directory>./HTML/</directory>
</testsuite>
</testsuites>
</phpunit>