initial commit of SVN release repo

This commit is contained in:
Ryan Prather
2018-05-07 10:51:08 -04:00
committed by Ryan Prather
parent 2c25d5e577
commit 8c38a6cdb9
4369 changed files with 728576 additions and 0 deletions

View File

@ -0,0 +1,474 @@
# Accessing cells
Accessing cells in a Spreadsheet should be pretty straightforward. This
topic lists some of the options to access a cell.
## Setting a cell value by coordinate
Setting a cell value by coordinate can be done using the worksheet's
`setCellValue()` method.
``` php
// Set cell A1 with a string value
$spreadsheet->getActiveSheet()->setCellValue('A1', 'PhpSpreadsheet');
// Set cell A2 with a numeric value
$spreadsheet->getActiveSheet()->setCellValue('A2', 12345.6789);
// Set cell A3 with a boolean value
$spreadsheet->getActiveSheet()->setCellValue('A3', TRUE);
// Set cell A4 with a formula
$spreadsheet->getActiveSheet()->setCellValue(
'A4',
'=IF(A3, CONCATENATE(A1, " ", A2), CONCATENATE(A2, " ", A1))'
);
```
Alternatively, you can retrieve the cell object, and then call the
cells `setValue()` method:
``` php
$spreadsheet->getActiveSheet()
->getCell('B8')
->setValue('Some value');
```
## Excel DataTypes
MS Excel supports 7 basic datatypes:
- string
- number
- boolean
- null
- formula
- error
- Inline (or rich text) string
By default, when you call the worksheet's `setCellValue()` method or the
cell's `setValue()` method, PhpSpreadsheet will use the appropriate
datatype for PHP nulls, booleans, floats or integers; or cast any string
data value that you pass to the method into the most appropriate
datatype, so numeric strings will be cast to numbers, while string
values beginning with `=` will be converted to a formula. Strings that
aren't numeric, or that don't begin with a leading `=` will be treated
as genuine string values.
This "conversion" is handled by a cell "value binder", and you can write
custom "value binders" to change the behaviour of these "conversions".
The standard PhpSpreadsheet package also provides an "advanced value
binder" that handles a number of more complex conversions, such as
converting strings with a fractional format like "3/4" to a number value
(0.75 in this case) and setting an appropriate "fraction" number format
mask. Similarly, strings like "5%" will be converted to a value of 0.05,
and a percentage number format mask applied, and strings containing
values that look like dates will be converted to Excel serialized
datetimestamp values, and a corresponding mask applied. This is
particularly useful when loading data from csv files, or setting cell
values from a database.
Formats handled by the advanced value binder include:
- TRUE or FALSE (dependent on locale settings) are converted to booleans.
- Numeric strings identified as scientific (exponential) format are
converted to numbers.
- Fractions and vulgar fractions are converted to numbers, and
an appropriate number format mask applied.
- Percentages are converted
to numbers, divided by 100, and an appropriate number format mask
applied.
- Dates and times are converted to Excel timestamp values
(numbers), and an appropriate number format mask applied.
- When strings contain a newline character (`\n`), then the cell styling is
set to wrap.
You can read more about value binders later in this section of the
documentation.
### Setting a date and/or time value in a cell
Date or time values are held as timestamp in Excel (a simple floating
point value), and a number format mask is used to show how that value
should be formatted; so if we want to store a date in a cell, we need to
calculate the correct Excel timestamp, and set a number format mask.
``` php
// Get the current date/time and convert to an Excel date/time
$dateTimeNow = time();
$excelDateValue = \PhpOffice\PhpSpreadsheet\Shared\Date::PHPToExcel( $dateTimeNow );
// Set cell A6 with the Excel date/time value
$spreadsheet->getActiveSheet()->setCellValue(
'A6',
$excelDateValue
);
// Set the number format mask so that the excel timestamp will be displayed as a human-readable date/time
$spreadsheet->getActiveSheet()->getStyle('A6')
->getNumberFormat()
->setFormatCode(
\PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_DATE_DATETIME
);
```
### Setting a number with leading zeroes
By default, PhpSpreadsheet will automatically detect the value type and
set it to the appropriate Excel numeric datatype. This type conversion
is handled by a value binder, as described in the section of this
document entitled "Using value binders to facilitate data entry".
Numbers don't have leading zeroes, so if you try to set a numeric value
that does have leading zeroes (such as a telephone number) then these
will be normally be lost as the value is cast to a number, so
"01513789642" will be displayed as 1513789642.
There are two ways you can force PhpSpreadsheet to override this
behaviour.
Firstly, you can set the datatype explicitly as a string so that it is
not converted to a number.
``` php
// Set cell A8 with a numeric value, but tell PhpSpreadsheet it should be treated as a string
$spreadsheet->getActiveSheet()->setCellValueExplicit(
'A8',
"01513789642",
\PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING
);
```
Alternatively, you can use a number format mask to display the value
with leading zeroes.
``` php
// Set cell A9 with a numeric value
$spreadsheet->getActiveSheet()->setCellValue('A9', 1513789642);
// Set a number format mask to display the value as 11 digits with leading zeroes
$spreadsheet->getActiveSheet()->getStyle('A9')
->getNumberFormat()
->setFormatCode(
'00000000000'
);
```
With number format masking, you can even break up the digits into groups
to make the value more easily readable.
``` php
// Set cell A10 with a numeric value
$spreadsheet->getActiveSheet()->setCellValue('A10', 1513789642);
// Set a number format mask to display the value as 11 digits with leading zeroes
$spreadsheet->getActiveSheet()->getStyle('A10')
->getNumberFormat()
->setFormatCode(
'0000-000-0000'
);
```
![07-simple-example-1.png](./images/07-simple-example-1.png)
**Note:** that not all complex format masks such as this one will work
when retrieving a formatted value to display "on screen", or for certain
writers such as HTML or PDF, but it will work with the true spreadsheet
writers (Xlsx and Xls).
## Setting a range of cells from an array
It is also possible to set a range of cell values in a single call by
passing an array of values to the `fromArray()` method.
``` php
$arrayData = array(
array(NULL, 2010, 2011, 2012),
array('Q1', 12, 15, 21),
array('Q2', 56, 73, 86),
array('Q3', 52, 61, 69),
array('Q4', 30, 32, 0),
);
$spreadsheet->getActiveSheet()
->fromArray(
$arrayData, // The data to set
NULL, // Array values with this value will not be set
'C3' // Top left coordinate of the worksheet range where
// we want to set these values (default is A1)
);
```
![07-simple-example-2.png](./images/07-simple-example-2.png)
If you pass a 2-d array, then this will be treated as a series of rows
and columns. A 1-d array will be treated as a single row, which is
particularly useful if you're fetching an array of data from a database.
``` php
$rowArray = array('Value1', 'Value2', 'Value3', 'Value4');
$spreadsheet->getActiveSheet()
->fromArray(
$rowArray, // The data to set
NULL, // Array values with this value will not be set
'C3' // Top left coordinate of the worksheet range where
// we want to set these values (default is A1)
);
```
![07-simple-example-3.png](./images/07-simple-example-3.png)
If you have a simple 1-d array, and want to write it as a column, then
the following will convert it into an appropriately structured 2-d array
that can be fed to the `fromArray()` method:
``` php
$rowArray = array('Value1', 'Value2', 'Value3', 'Value4');
$columnArray = array_chunk($rowArray, 1);
$spreadsheet->getActiveSheet()
->fromArray(
$columnArray, // The data to set
NULL, // Array values with this value will not be set
'C3' // Top left coordinate of the worksheet range where
// we want to set these values (default is A1)
);
```
![07-simple-example-4.png](./images/07-simple-example-4.png)
## Retrieving a cell value by coordinate
To retrieve the value of a cell, the cell should first be retrieved from
the worksheet using the `getCell()` method. A cell's value can be read
using the `getValue()` method.
``` php
// Get the value from cell A1
$cellValue = $spreadsheet->getActiveSheet()->getCell('A1')->getValue();
```
This will retrieve the raw, unformatted value contained in the cell.
If a cell contains a formula, and you need to retrieve the calculated
value rather than the formula itself, then use the cell's
`getCalculatedValue()` method. This is further explained in
[the calculation engine](./calculation-engine.md).
``` php
// Get the value from cell A4
$cellValue = $spreadsheet->getActiveSheet()->getCell('A4')->getCalculatedValue();
```
Alternatively, if you want to see the value with any cell formatting
applied (e.g. for a human-readable date or time value), then you can use
the cell's `getFormattedValue()` method.
``` php
// Get the value from cell A6
$cellValue = $spreadsheet->getActiveSheet()->getCell('A6')->getFormattedValue();
```
## Setting a cell value by column and row
Setting a cell value by coordinate can be done using the worksheet's
`setCellValueByColumnAndRow()` method.
``` php
// Set cell A5 with a string value
$spreadsheet->getActiveSheet()->setCellValueByColumnAndRow(1, 5, 'PhpSpreadsheet');
```
**Note:** that column references start with `1` for column `A`.
## Retrieving a cell value by column and row
To retrieve the value of a cell, the cell should first be retrieved from
the worksheet using the `getCellByColumnAndRow()` method. A cells value can
be read again using the following line of code:
``` php
// Get the value from cell B5
$cellValue = $spreadsheet->getActiveSheet()->getCellByColumnAndRow(2, 5)->getValue();
```
If you need the calculated value of a cell, use the following code. This
is further explained in [the calculation engine](./calculation-engine.md).
``` php
// Get the value from cell A4
$cellValue = $spreadsheet->getActiveSheet()->getCellByColumnAndRow(1, 4)->getCalculatedValue();
```
## Retrieving a range of cell values to an array
It is also possible to retrieve a range of cell values to an array in a
single call using the `toArray()`, `rangeToArray()` or
`namedRangeToArray()` methods.
``` php
$dataArray = $spreadsheet->getActiveSheet()
->rangeToArray(
'C3:E5', // The worksheet range that we want to retrieve
NULL, // Value that should be returned for empty cells
TRUE, // Should formulas be calculated (the equivalent of getCalculatedValue() for each cell)
TRUE, // Should values be formatted (the equivalent of getFormattedValue() for each cell)
TRUE // Should the array be indexed by cell row and cell column
);
```
These methods will all return a 2-d array of rows and columns. The
`toArray()` method will return the whole worksheet; `rangeToArray()`
will return a specified range or cells; while `namedRangeToArray()` will
return the cells within a defined `named range`.
## Looping through cells
### Looping through cells using iterators
The easiest way to loop cells is by using iterators. Using iterators,
one can use foreach to loop worksheets, rows within a worksheet, and
cells within a row.
Below is an example where we read all the values in a worksheet and
display them in a table.
``` php
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader('Xlsx');
$reader->setReadDataOnly(TRUE);
$spreadsheet = $reader->load("test.xlsx");
$worksheet = $spreadsheet->getActiveSheet();
echo '<table>' . PHP_EOL;
foreach ($worksheet->getRowIterator() as $row) {
echo '<tr>' . PHP_EOL;
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(FALSE); // This loops through all cells,
// even if a cell value is not set.
// By default, only cells that have a value
// set will be iterated.
foreach ($cellIterator as $cell) {
echo '<td>' .
$cell->getValue() .
'</td>' . PHP_EOL;
}
echo '</tr>' . PHP_EOL;
}
echo '</table>' . PHP_EOL;
```
Note that we have set the cell iterator's
`setIterateOnlyExistingCells()` to FALSE. This makes the iterator loop
all cells within the worksheet range, even if they have not been set.
The cell iterator will return a `null` as the cell value if it is not
set in the worksheet. Setting the cell iterator's
`setIterateOnlyExistingCells()` to `false` will loop all cells in the
worksheet that can be available at that moment. This will create new
cells if required and increase memory usage! Only use it if it is
intended to loop all cells that are possibly available.
### Looping through cells using indexes
One can use the possibility to access cell values by column and row
index like `[1, 1]` instead of `'A1'` for reading and writing cell values in
loops.
**Note:** In PhpSpreadsheet column index and row index are 1-based. That means `'A1'` ~ `[1, 1]`
Below is an example where we read all the values in a worksheet and
display them in a table.
``` php
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader('Xlsx');
$reader->setReadDataOnly(TRUE);
$spreadsheet = $reader->load("test.xlsx");
$worksheet = $spreadsheet->getActiveSheet();
// Get the highest row and column numbers referenced in the worksheet
$highestRow = $worksheet->getHighestRow(); // e.g. 10
$highestColumn = $worksheet->getHighestColumn(); // e.g 'F'
$highestColumnIndex = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::columnIndexFromString($highestColumn); // e.g. 5
echo '<table>' . "\n";
for ($row = 1; $row <= $highestRow; ++$row) {
echo '<tr>' . PHP_EOL;
for ($col = 1; $col <= $highestColumnIndex; ++$col) {
$value = $worksheet->getCellByColumnAndRow($col, $row)->getValue();
echo '<td>' . $value . '</td>' . PHP_EOL;
}
echo '</tr>' . PHP_EOL;
}
echo '</table>' . PHP_EOL;
```
Alternatively, you can take advantage of PHP's "Perl-style" character
incrementors to loop through the cells by coordinate:
``` php
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader('Xlsx');
$reader->setReadDataOnly(TRUE);
$spreadsheet = $reader->load("test.xlsx");
$worksheet = $spreadsheet->getActiveSheet();
// Get the highest row number and column letter referenced in the worksheet
$highestRow = $worksheet->getHighestRow(); // e.g. 10
$highestColumn = $worksheet->getHighestColumn(); // e.g 'F'
// Increment the highest column letter
$highestColumn++;
echo '<table>' . "\n";
for ($row = 1; $row <= $highestRow; ++$row) {
echo '<tr>' . PHP_EOL;
for ($col = 'A'; $col != $highestColumn; ++$col) {
echo '<td>' .
$worksheet->getCell($col . $row)
->getValue() .
'</td>' . PHP_EOL;
}
echo '</tr>' . PHP_EOL;
}
echo '</table>' . PHP_EOL;
```
Note that we can't use a &lt;= comparison here, because 'AA' would match
as &lt;= 'B', so we increment the highest column letter and then loop
while \$col != the incremented highest column.
## Using value binders to facilitate data entry
Internally, PhpSpreadsheet uses a default
`\PhpOffice\PhpSpreadsheet\Cell\IValueBinder` implementation
(\PhpOffice\PhpSpreadsheet\Cell\DefaultValueBinder) to determine data
types of entered data using a cell's `setValue()` method (the
`setValueExplicit()` method bypasses this check).
Optionally, the default behaviour of PhpSpreadsheet can be modified,
allowing easier data entry. For example, a
`\PhpOffice\PhpSpreadsheet\Cell\AdvancedValueBinder` class is available.
It automatically converts percentages, number in scientific format, and
dates entered as strings to the correct format, also setting the cell's
style information. The following example demonstrates how to set the
value binder in PhpSpreadsheet:
``` php
/** PhpSpreadsheet */
require_once 'src/Boostrap.php';
// Set value binder
\PhpOffice\PhpSpreadsheet\Cell\Cell::setValueBinder( new \PhpOffice\PhpSpreadsheet\Cell\AdvancedValueBinder() );
// Create new Spreadsheet object
$spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
// ...
// Add some data, resembling some different data types
$spreadsheet->getActiveSheet()->setCellValue('A4', 'Percentage value:');
// Converts the string value to 0.1 and sets percentage cell style
$spreadsheet->getActiveSheet()->setCellValue('B4', '10%');
$spreadsheet->getActiveSheet()->setCellValue('A5', 'Date/time value:');
// Converts the string value to an Excel datestamp and sets the date format cell style
$spreadsheet->getActiveSheet()->setCellValue('B5', '21 December 1983');
```
**Creating your own value binder is easy.** When advanced value binding
is required, you can implement the
`\PhpOffice\PhpSpreadsheet\Cell\IValueBinder` interface or extend the
`\PhpOffice\PhpSpreadsheet\Cell\DefaultValueBinder` or
`\PhpOffice\PhpSpreadsheet\Cell\AdvancedValueBinder` classes.

View File

@ -0,0 +1,75 @@
# Architecture
## Schematical
![01-schematic.png](./images/01-schematic.png "Basic Architecture Schematic")
## AutoLoader
PhpSpreadsheet relies on Composer autoloader. So before working with
PhpSpreadsheet in standalone, be sure to run `composer install`. Or add it to a
pre-existing project with `composer require phpoffice/phpspreadsheet`.
## Spreadsheet in memory
PhpSpreadsheet's architecture is built in a way that it can serve as an
in-memory spreadsheet. This means that, if one would want to create a
web based view of a spreadsheet which communicates with PhpSpreadsheet's
object model, he would only have to write the front-end code.
Just like desktop spreadsheet software, PhpSpreadsheet represents a
spreadsheet containing one or more worksheets, which contain cells with
data, formulas, images, ...
## Readers and writers
On its own, the `Spreadsheet` class does not provide the functionality
to read from or write to a persisted spreadsheet (on disk or in a
database). To provide that functionality, readers and writers can be
used.
By default, the PhpSpreadsheet package provides some readers and
writers, including one for the Open XML spreadsheet format (a.k.a. Excel
2007 file format). You are not limited to the default readers and
writers, as you are free to implement the
`\PhpOffice\PhpSpreadsheet\Reader\IReader` and
`\PhpOffice\PhpSpreadsheet\Writer\IWriter` interface in a custom class.
![02-readers-writers.png](./images/02-readers-writers.png "Readers/Writers")
## Fluent interfaces
PhpSpreadsheet supports fluent interfaces in most locations. This means
that you can easily "chain" calls to specific methods without requiring
a new PHP statement. For example, take the following code:
``` php
$spreadsheet->getProperties()->setCreator("Maarten Balliauw");
$spreadsheet->getProperties()->setLastModifiedBy("Maarten Balliauw");
$spreadsheet->getProperties()->setTitle("Office 2007 XLSX Test Document");
$spreadsheet->getProperties()->setSubject("Office 2007 XLSX Test Document");
$spreadsheet->getProperties()->setDescription("Test document for Office 2007 XLSX, generated using PHP classes.");
$spreadsheet->getProperties()->setKeywords("office 2007 openxml php");
$spreadsheet->getProperties()->setCategory("Test result file");
```
This can be rewritten as:
``` php
$spreadsheet->getProperties()
->setCreator("Maarten Balliauw")
->setLastModifiedBy("Maarten Balliauw")
->setTitle("Office 2007 XLSX Test Document")
->setSubject("Office 2007 XLSX Test Document")
->setDescription("Test document for Office 2007 XLSX, generated using PHP classes.")
->setKeywords("office 2007 openxml php")
->setCategory("Test result file");
```
> **Using fluent interfaces is not required** Fluent interfaces have
> been implemented to provide a convenient programming API. Use of them
> is not required, but can make your code easier to read and maintain.
> It can also improve performance, as you are reducing the overall
> number of calls to PhpSpreadsheet methods: in the above example, the
> `getProperties()` method is being called only once rather than 7 times
> in the non-fluent version.

View File

@ -0,0 +1,530 @@
# AutoFilter Reference
## Introduction
Each worksheet in an Excel Workbook can contain a single autoFilter
range. Filtered data displays only the rows that meet criteria that you
specify and hides rows that you do not want displayed. You can filter by
more than one column: filters are additive, which means that each
additional filter is based on the current filter and further reduces the
subset of data.
![01-01-autofilter.png](./images/01-01-autofilter.png)
When an AutoFilter is applied to a range of cells, the first row in an
autofilter range will be the heading row, which displays the autoFilter
dropdown icons. It is not part of the actual autoFiltered data. All
subsequent rows are the autoFiltered data. So an AutoFilter range should
always contain the heading row and one or more data rows (one data row
is pretty meaningless), but PhpSpreadsheet won't actually stop you
specifying a meaningless range: it's up to you as a developer to avoid
such errors.
To determine if a filter is applied, note the icon in the column
heading. A drop-down arrow
(![01-03-filter-icon-1.png](./images/01-03-filter-icon-1.png)) means
that filtering is enabled but not applied. In MS Excel, when you hover
over the heading of a column with filtering enabled but not applied, a
screen tip displays the cell text for the first row in that column, and
the message "(Showing All)".
![01-02-autofilter.png](./images/01-02-autofilter.png)
A Filter button
(![01-03-filter-icon-2.png](./images/01-03-filter-icon-2.png)) means
that a filter is applied. When you hover over the heading of a filtered
column, a screen tip displays the filter that has been applied to that
column, such as "Equals a red cell color" or "Larger than 150".
![01-04-autofilter.png](./images/01-04-autofilter.png)
## Setting an AutoFilter area on a worksheet
To set an autoFilter on a range of cells.
``` php
$spreadsheet->getActiveSheet()->setAutoFilter('A1:E20');
```
The first row in an autofilter range will be the heading row, which
displays the autoFilter dropdown icons. It is not part of the actual
autoFiltered data. All subsequent rows are the autoFiltered data. So an
AutoFilter range should always contain the heading row and one or more
data rows (one data row is pretty meaningless, but PhpSpreadsheet won't
actually stop you specifying a meaningless range: it's up to you as a
developer to avoid such errors.
If you want to set the whole worksheet as an autofilter region
``` php
$spreadsheet->getActiveSheet()->setAutoFilter(
$spreadsheet->getActiveSheet()
->calculateWorksheetDimension()
);
```
This enables filtering, but does not actually apply any filters.
## Autofilter Expressions
PHPEXcel 1.7.8 introduced the ability to actually create, read and write
filter expressions; initially only for Xlsx files, but later releases
will extend this to other formats.
To apply a filter expression to an autoFilter range, you first need to
identify which column you're going to be applying this filter to.
``` php
$autoFilter = $spreadsheet->getActiveSheet()->getAutoFilter();
$columnFilter = $autoFilter->getColumn('C');
```
This returns an autoFilter column object, and you can then apply filter
expressions to that column.
There are a number of different types of autofilter expressions. The
most commonly used are:
- Simple Filters
- DateGroup Filters
- Custom filters
- Dynamic Filters
- Top Ten Filters
These different types are mutually exclusive within any single column.
You should not mix the different types of filter in the same column.
PhpSpreadsheet will not actively prevent you from doing this, but the
results are unpredictable.
Other filter expression types (such as cell colour filters) are not yet
supported.
### Simple filters
In MS Excel, Simple Filters are a dropdown list of all values used in
that column, and the user can select which ones they want to display and
which ones they want to hide by ticking and unticking the checkboxes
alongside each option. When the filter is applied, rows containing the
checked entries will be displayed, rows that don't contain those values
will be hidden.
![04-01-simple-autofilter.png](./images/04-01-simple-autofilter.png)
To create a filter expression, we need to start by identifying the
filter type. In this case, we're just going to specify that this filter
is a standard filter.
``` php
$columnFilter->setFilterType(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column::AUTOFILTER_FILTERTYPE_FILTER
);
```
Now we've identified the filter type, we can create a filter rule and
set the filter values:
When creating a simple filter in PhpSpreadsheet, you only need to
specify the values for "checked" columns: you do this by creating a
filter rule for each value.
``` php
$columnFilter->createRule()
->setRule(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_EQUAL,
'France'
);
$columnFilter->createRule()
->setRule(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_EQUAL,
'Germany'
);
```
This creates two filter rules: the column will be filtered by values
that match "France" OR "Germany". For Simple Filters, you can create as
many rules as you want
Simple filters are always a comparison match of EQUALS, and multiple
standard filters are always treated as being joined by an OR condition.
#### Matching Blanks
If you want to create a filter to select blank cells, you would use:
``` php
$columnFilter->createRule()
->setRule(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_EQUAL,
''
);
```
### DateGroup Filters
In MS Excel, DateGroup filters provide a series of dropdown filter
selectors for date values, so you can specify entire years, or months
within a year, or individual days within each month.
![04-02-dategroup-autofilter.png](./images/04-02-dategroup-autofilter.png)
DateGroup filters are still applied as a Standard Filter type.
``` php
$columnFilter->setFilterType(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column::AUTOFILTER_FILTERTYPE_FILTER
);
```
Creating a dateGroup filter in PhpSpreadsheet, you specify the values
for "checked" columns as an associative array of year. month, day, hour
minute and second. To select a year and month, you need to create a
DateGroup rule identifying the selected year and month:
``` php
$columnFilter->createRule()
->setRule(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_EQUAL,
array(
'year' => 2012,
'month' => 1
)
)
->setRuleType(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP
);
```
The key values for the associative array are:
- year
- month
- day
- hour
- minute
- second
Like Standard filters, DateGroup filters are always a match of EQUALS,
and multiple standard filters are always treated as being joined by an
OR condition.
Note that we alse specify a ruleType: to differentiate this from a
standard filter, we explicitly set the Rule's Type to
AUTOFILTER\_RULETYPE\_DATEGROUP. As with standard filters, we can create
any number of DateGroup Filters.
### Custom filters
In MS Excel, Custom filters allow us to select more complex conditions
using an operator as well as a value. Typical examples might be values
that fall within a range (e.g. between -20 and +20), or text values with
wildcards (e.g. beginning with the letter U). To handle this, they
![04-03-custom-autofilter-1.png](./images/04-03-custom-autofilter-1.png)
![04-03-custom-autofilter-2.png](./images/04-03-custom-autofilter-2.png)
Custom filters are limited to 2 rules, and these can be joined using
either an AND or an OR.
We start by specifying a Filter type, this time a CUSTOMFILTER.
``` php
$columnFilter->setFilterType(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column::AUTOFILTER_FILTERTYPE_CUSTOMFILTER
);
```
And then define our rules.
The following shows a simple wildcard filter to show all column entries
beginning with the letter `U`.
``` php
$columnFilter->createRule()
->setRule(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_EQUAL,
'U*'
)
->setRuleType(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER
);
```
MS Excel uses \* as a wildcard to match any number of characters, and ?
as a wildcard to match a single character. 'U\*' equates to "begins with
a 'U'"; '\*U' equates to "ends with a 'U'"; and '\*U\*' equates to
"contains a 'U'"
If you want to match explicitly against a \* or a ? character, you can
escape it with a tilde (\~), so ?\~\*\* would explicitly match for a \*
character as the second character in the cell value, followed by any
number of other characters. The only other character that needs escaping
is the \~ itself.
To create a "between" condition, we need to define two rules:
``` php
$columnFilter->createRule()
->setRule(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_GREATERTHANOREQUAL,
-20
)
->setRuleType(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER
);
$columnFilter->createRule()
->setRule(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_LESSTHANOREQUAL,
20
)
->setRuleType(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER
);
```
We also set the rule type to CUSTOMFILTER.
This defined two rules, filtering numbers that are &gt;= -20 OR &lt;=
20, so we also need to modify the join condition to reflect AND rather
than OR.
``` php
$columnFilter->setAndOr(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column::AUTOFILTER_COLUMN_ANDOR_AND
);
```
The valid set of operators for Custom Filters are defined in the
`\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule` class, and
comprise:
Operator Constant | Value
------------------------------------------|----------------------
AUTOFILTER_COLUMN_RULE_EQUAL | 'equal'
AUTOFILTER_COLUMN_RULE_NOTEQUAL | 'notEqual'
AUTOFILTER_COLUMN_RULE_GREATERTHAN | 'greaterThan'
AUTOFILTER_COLUMN_RULE_GREATERTHANOREQUAL | 'greaterThanOrEqual'
AUTOFILTER_COLUMN_RULE_LESSTHAN | 'lessThan'
AUTOFILTER_COLUMN_RULE_LESSTHANOREQUAL | 'lessThanOrEqual'
### Dynamic Filters
Dynamic Filters are based on a dynamic comparison condition, where the
value we're comparing against the cell values is variable, such as
'today'; or when we're testing against an aggregate of the cell data
(e.g. 'aboveAverage'). Only a single dynamic filter can be applied to a
column at a time.
![04-04-dynamic-autofilter.png](./images/04-04-dynamic-autofilter.png)
Again, we start by specifying a Filter type, this time a DYNAMICFILTER.
``` php
$columnFilter->setFilterType(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER
);
```
When defining the rule for a dynamic filter, we don't define a value (we
can simply set that to NULL) but we do specify the dynamic filter
category.
``` php
$columnFilter->createRule()
->setRule(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_EQUAL,
NULL,
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_YEARTODATE
)
->setRuleType(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER
);
```
We also set the rule type to DYNAMICFILTER.
The valid set of dynamic filter categories is defined in the
`\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule` class, and
comprises:
Operator Constant | Value
-----------------------------------------|----------------
AUTOFILTER_RULETYPE_DYNAMIC_YESTERDAY | 'yesterday'
AUTOFILTER_RULETYPE_DYNAMIC_TODAY | 'today'
AUTOFILTER_RULETYPE_DYNAMIC_TOMORROW | 'tomorrow'
AUTOFILTER_RULETYPE_DYNAMIC_YEARTODATE | 'yearToDate'
AUTOFILTER_RULETYPE_DYNAMIC_THISYEAR | 'thisYear'
AUTOFILTER_RULETYPE_DYNAMIC_THISQUARTER | 'thisQuarter'
AUTOFILTER_RULETYPE_DYNAMIC_THISMONTH | 'thisMonth'
AUTOFILTER_RULETYPE_DYNAMIC_THISWEEK | 'thisWeek'
AUTOFILTER_RULETYPE_DYNAMIC_LASTYEAR | 'lastYear'
AUTOFILTER_RULETYPE_DYNAMIC_LASTQUARTER | 'lastQuarter'
AUTOFILTER_RULETYPE_DYNAMIC_LASTMONTH | 'lastMonth'
AUTOFILTER_RULETYPE_DYNAMIC_LASTWEEK | 'lastWeek'
AUTOFILTER_RULETYPE_DYNAMIC_NEXTYEAR | 'nextYear'
AUTOFILTER_RULETYPE_DYNAMIC_NEXTQUARTER | 'nextQuarter'
AUTOFILTER_RULETYPE_DYNAMIC_NEXTMONTH | 'nextMonth'
AUTOFILTER_RULETYPE_DYNAMIC_NEXTWEEK | 'nextWeek'
AUTOFILTER_RULETYPE_DYNAMIC_MONTH_1 | 'M1'
AUTOFILTER_RULETYPE_DYNAMIC_JANUARY | 'M1'
AUTOFILTER_RULETYPE_DYNAMIC_MONTH_2 | 'M2'
AUTOFILTER_RULETYPE_DYNAMIC_FEBRUARY | 'M2'
AUTOFILTER_RULETYPE_DYNAMIC_MONTH_3 | 'M3'
AUTOFILTER_RULETYPE_DYNAMIC_MARCH | 'M3'
AUTOFILTER_RULETYPE_DYNAMIC_MONTH_4 | 'M4'
AUTOFILTER_RULETYPE_DYNAMIC_APRIL | 'M4'
AUTOFILTER_RULETYPE_DYNAMIC_MONTH_5 | 'M5'
AUTOFILTER_RULETYPE_DYNAMIC_MAY | 'M5'
AUTOFILTER_RULETYPE_DYNAMIC_MONTH_6 | 'M6'
AUTOFILTER_RULETYPE_DYNAMIC_JUNE | 'M6'
AUTOFILTER_RULETYPE_DYNAMIC_MONTH_7 | 'M7'
AUTOFILTER_RULETYPE_DYNAMIC_JULY | 'M7'
AUTOFILTER_RULETYPE_DYNAMIC_MONTH_8 | 'M8'
AUTOFILTER_RULETYPE_DYNAMIC_AUGUST | 'M8'
AUTOFILTER_RULETYPE_DYNAMIC_MONTH_9 | 'M9'
AUTOFILTER_RULETYPE_DYNAMIC_SEPTEMBER | 'M9'
AUTOFILTER_RULETYPE_DYNAMIC_MONTH_10 | 'M10'
AUTOFILTER_RULETYPE_DYNAMIC_OCTOBER | 'M10'
AUTOFILTER_RULETYPE_DYNAMIC_MONTH_11 | 'M11'
AUTOFILTER_RULETYPE_DYNAMIC_NOVEMBER | 'M11'
AUTOFILTER_RULETYPE_DYNAMIC_MONTH_12 | 'M12'
AUTOFILTER_RULETYPE_DYNAMIC_DECEMBER | 'M12'
AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_1 | 'Q1'
AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_2 | 'Q2'
AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_3 | 'Q3'
AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_4 | 'Q4'
AUTOFILTER_RULETYPE_DYNAMIC_ABOVEAVERAGE | 'aboveAverage'
AUTOFILTER_RULETYPE_DYNAMIC_BELOWAVERAGE | 'belowAverage'
We can only apply a single Dynamic Filter rule to a column at a time.
### Top Ten Filters
Top Ten Filters are similar to Dynamic Filters in that they are based on
a summarisation of the actual data values in the cells. However, unlike
Dynamic Filters where you can only select a single option, Top Ten
Filters allow you to select based on a number of criteria:
![04-05-custom-topten-1.png](./images/04-05-topten-autofilter-1.png)
![04-05-custom-topten-2.png](./images/04-05-topten-autofilter-2.png)
You can identify whether you want the top (highest) or bottom (lowest)
values.You can identify how many values you wish to select in the
filterYou can identify whether this should be a percentage or a number
of items.
Like Dynamic Filters, only a single Top Ten filter can be applied to a
column at a time.
We start by specifying a Filter type, this time a DYNAMICFILTER.
``` php
$columnFilter->setFilterType(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column::AUTOFILTER_FILTERTYPE_TOPTENFILTER
);
```
Then we create the rule:
``` php
$columnFilter->createRule()
->setRule(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT,
5,
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP
)
->setRuleType(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_TOPTENFILTER
);
```
This will filter the Top 5 percent of values in the column.
To specify the lowest (bottom 2 values), we would specify a rule of:
``` php
$columnFilter->createRule()
->setRule(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE,
5,
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM
)
->setRuleType(
\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_TOPTENFILTER
);
```
The option values for TopTen Filters top/bottom value/percent are all
defined in the
`\PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule` class, and
comprise:
Operator Constant | Value
---------------------------------------|-------------
AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE | 'byValue'
AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT | 'byPercent'
and
Operator Constant | Value
-------------------------------------|----------
AUTOFILTER_COLUMN_RULE_TOPTEN_TOP | 'top'
AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM | 'bottom'
## Executing an AutoFilter
When an autofilter is applied in MS Excel, it sets the row
hidden/visible flags for each row of the autofilter area based on the
selected criteria, so that only those rows that match the filter
criteria are displayed.
PhpSpreadsheet will not execute the equivalent function automatically
when you set or change a filter expression, but only when the file is
saved.
### Applying the Filter
If you wish to execute your filter from within a script, you need to do
this manually. You can do this using the autofilters `showHideRows()`
method.
``` php
$autoFilter = $spreadsheet->getActiveSheet()->getAutoFilter();
$autoFilter->showHideRows();
```
This will set all rows that match the filter criteria to visible, while
hiding all other rows within the autofilter area.
### Displaying Filtered Rows
Simply looping through the rows in an autofilter area will still access
ever row, whether it matches the filter criteria or not. To selectively
access only the filtered rows, you need to test each rows visibility
settings.
``` php
foreach ($spreadsheet->getActiveSheet()->getRowIterator() as $row) {
if ($spreadsheet->getActiveSheet()
->getRowDimension($row->getRowIndex())->getVisible()) {
echo ' Row number - ' , $row->getRowIndex() , ' ';
echo $spreadsheet->getActiveSheet()
->getCell(
'C'.$row->getRowIndex()
)
->getValue(), ' ';
echo $spreadsheet->getActiveSheet()
->getCell(
'D'.$row->getRowIndex()
)->getFormattedValue(), ' ';
echo PHP_EOL;
}
}
```
## AutoFilter Sorting
In MS Excel, Autofiltering also allows the rows to be sorted. This
feature is ***not*** supported by PhpSpreadsheet.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,59 @@
# Creating a spreadsheet
## The `Spreadsheet` class
The `Spreadsheet` class is the core of PhpSpreadsheet. It contains
references to the contained worksheets, document security settings and
document meta data.
To simplify the PhpSpreadsheet concept: the `Spreadsheet` class
represents your workbook.
Typically, you will create a workbook in one of two ways, either by
loading it from a spreadsheet file, or creating it manually. A third
option, though less commonly used, is cloning an existing workbook that
has been created using one of the previous two methods.
### Loading a Workbook from a file
Details of the different spreadsheet formats supported, and the options
available to read them into a Spreadsheet object are described fully in
the [Reading Files](./reading-files.md) document.
``` php
$inputFileName = './sampleData/example1.xls';
/** Load $inputFileName to a Spreadsheet object **/
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($inputFileName);
```
### Creating a new workbook
If you want to create a new workbook, rather than load one from file,
then you simply need to instantiate it as a new Spreadsheet object.
``` php
/** Create a new Spreadsheet Object **/
$spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
```
A new workbook will always be created with a single worksheet.
## Clearing a Workbook from memory
The PhpSpreadsheet object contains cyclic references (e.g. the workbook
is linked to the worksheets, and the worksheets are linked to their
parent workbook) which cause problems when PHP tries to clear the
objects from memory when they are `unset()`, or at the end of a function
when they are in local scope. The result of this is "memory leaks",
which can easily use a large amount of PHP's limited memory.
This can only be resolved manually: if you need to unset a workbook,
then you also need to "break" these cyclic references before doing so.
PhpSpreadsheet provides the `disconnectWorksheets()` method for this
purpose.
``` php
$spreadsheet->disconnectWorksheets();
unset($spreadsheet);
```

View File

@ -0,0 +1,121 @@
# File Formats
PhpSpreadsheet can read a number of different spreadsheet and file
formats, although not all features are supported by all of the readers.
Check the [features cross
reference](../references/features-cross-reference.md) for a list that
identifies which features are supported by which readers.
Currently, PhpSpreadsheet supports the following File Types for Reading:
### Xls
The Microsoft Excel™ Binary file format (BIFF5 and BIFF8) is a binary
file format that was used by Microsoft Excel™ between versions 95 and 2003.
The format is supported (to various extents) by most spreadsheet
programs. BIFF files normally have an extension of .xls. Documentation
describing the format can be [read online](https://msdn.microsoft.com/en-us/library/cc313154(v=office.12).aspx)
or [downloaded as PDF](http://download.microsoft.com/download/2/4/8/24862317-78F0-4C4B-B355-C7B2C1D997DB/%5BMS-XLS%5D.pdf).
### Xml
Microsoft Excel™ 2003 included options for a file format called
SpreadsheetML. This file is a zipped XML document. It is not very
common, but its core features are supported. Documentation for the
format can be [read online](https://msdn.microsoft.com/en-us/library/aa140066(office.10).aspx)
though its sadly rather sparse in its detail.
### Xlsx
Microsoft Excel™ 2007 shipped with a new file format, namely Microsoft
Office Open XML SpreadsheetML, and Excel 2010 extended this still
further with its new features such as sparklines. These files typically
have an extension of .xlsx. This format is based around a zipped
collection of eXtensible Markup Language (XML) files. Microsoft Office
Open XML SpreadsheetML is mostly standardized in [ECMA 376](http://www.ecma-international.org/news/TC45_current_work/TC45_available_docs.htm)
and ISO 29500.
### Ods
aka Open Document Format (ODF) or OASIS, this is the OpenOffice.org XML
file format for spreadsheets. It comprises a zip archive including
several components all of which are text files, most of these with
markup in the eXtensible Markup Language (XML). It is the standard file
format for OpenOffice.org Calc and StarCalc, and files typically have an
extension of .ods. The published specification for the file format is
available from [the OASIS Open Office XML Format Technical Committee web
page](https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=office).
Other information is available from [the OpenOffice.org XML File Format
web page](http://www.openoffice.org/xml/), part of the
OpenOffice.org project.
### Slk
This is the Microsoft Multiplan Symbolic Link Interchange (SYLK) file
format. Multiplan was a predecessor to Microsoft Excel™. Files normally
have an extension of .slk. While not common, there are still a few
applications that generate SYLK files as a cross-platform option,
because (despite being limited to a single worksheet) it is a simple
format to implement, and supports some basic data and cell formatting
options (unlike CSV files).
### Gnumeric
The [Gnumeric file format](https://help.gnome.org/users/gnumeric/stable/sect-file-formats.html.en#file-format-gnumeric)
is used by the Gnome Gnumeric spreadsheet
application, and typically files have an extension of `.gnumeric`. The
file contents are stored using eXtensible Markup Language (XML) markup,
and the file is then compressed using the GNU project's gzip compression
library.
### Csv
Comma Separated Value (CSV) file format is a common structuring strategy
for text format files. In CSV flies, each line in the file represents a
row of data and (within each line of the file) the different data fields
(or columns) are separated from one another using a comma (`,`). If a
data field contains a comma, then it should be enclosed (typically in
quotation marks (`"`). Sometimes tabs `\t`, or the pipe symbol (`|`), or a
semi-colon (`;`) are used as separators instead of a comma, although
other symbols can be used. Because CSV is a text-only format, it doesn't
support any data formatting options.
"CSV" is not a single, well-defined format (although see RFC 4180 for
one definition that is commonly used). Rather, in practice the term
"CSV" refers to any file that:
- is plain text using a character set such as ASCII, Unicode, EBCDIC,
or Shift JIS,
- consists of records (typically one record per line),
- with the records divided into fields separated by delimiters
(typically a single reserved character such as comma, semicolon, or
tab,
- where every record has the same sequence of fields.
Within these general constraints, many variations are in use. Therefore
"CSV" files are not entirely portable. Nevertheless, the variations are
fairly small, and many implementations allow users to glance at the file
(which is feasible because it is plain text), and then specify the
delimiter character(s), quoting rules, etc.
**Warning:** Microsoft Excel™ will open .csv files, but depending on the
system's regional settings, it may expect a semicolon as a separator
instead of a comma, since in some languages the comma is used as the
decimal separator. Also, many regional versions of Excel will not be
able to deal with Unicode characters in a CSV file.
### Html
HyperText Markup Language (HTML) is the main markup language for
creating web pages and other information that can be displayed in a web
browser. Files typically have an extension of .html or .htm. HTML markup
provides a means to create structured documents by denoting structural
semantics for text such as headings, paragraphs, lists, links, quotes
and other items. Since 1996, the HTML specifications have been
maintained, with input from commercial software vendors, by the World
Wide Web Consortium (W3C). However, in 2000, HTML also became an
international standard (ISO/IEC 15445:2000). HTML 4.01 was published in
late 1999, with further errata published through 2001. In 2004
development began on HTML5 in the Web Hypertext Application Technology
Working Group (WHATWG), which became a joint deliverable with the W3C in
2008.

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 640 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@ -0,0 +1,107 @@
# Memory saving
PhpSpreadsheet uses an average of about 1k per cell in your worksheets, so
large workbooks can quickly use up available memory. Cell caching
provides a mechanism that allows PhpSpreadsheet to maintain the cell
objects in a smaller size of memory, or off-memory (eg: on disk, in APCu,
memcache or redis). This allows you to reduce the memory usage for large
workbooks, although at a cost of speed to access cell data.
By default, PhpSpreadsheet holds all cell objects in memory, but
you can specify alternatives by providing your own
[PSR-16](http://www.php-fig.org/psr/psr-16/) implementation. PhpSpreadsheet keys
are automatically namespaced, and cleaned up after use, so a single cache
instance may be shared across several usage of PhpSpreadsheet or even with other
cache usages.
To enable cell caching, you must provide your own implementation of cache like so:
``` php
$cache = new MyCustomPsr16Implementation();
\PhpOffice\PhpSpreadsheet\Settings::setCache($cache);
```
A separate cache is maintained for each individual worksheet, and is
automatically created when the worksheet is instantiated based on the
settings that you have configured. You cannot change
the configuration settings once you have started to read a workbook, or
have created your first worksheet.
## Beware of TTL
As opposed to common cache concept, PhpSpreadsheet data cannot be re-generated
from scratch. If some data is stored and later is not retrievable,
PhpSpreadsheet will throw an exception.
That means that the data stored in cache **must not be deleted** by a
third-party or via TTL mechanism.
So be sure that TTL is either de-activated or long enough to cover the entire
usage of PhpSpreadsheet.
## Common use cases
PhpSpreadsheet does not ship with alternative cache implementation. It is up to
you to select the most appropriate implementation for your environnement. You
can either implement [PSR-16](http://www.php-fig.org/psr/psr-16/) from scratch,
or use [pre-existing libraries](https://packagist.org/search/?q=psr-16).
One such library is [PHP Cache](https://www.php-cache.com/) which
provides a wide range of alternatives. Refers to their documentation for
details, but here are a few suggestions that should get you started.
### APCu
Require the packages into your project:
```sh
composer require cache/simple-cache-bridge cache/apcu-adapter
```
Configure PhpSpreadsheet with something like:
```php
$pool = new \Cache\Adapter\Apcu\ApcuCachePool();
$simpleCache = new \Cache\Bridge\SimpleCache\SimpleCacheBridge($pool);
\PhpOffice\PhpSpreadsheet\Settings::setCache($simpleCache);
```
### Redis
Require the packages into your project:
```sh
composer require cache/simple-cache-bridge cache/redis-adapter
```
Configure PhpSpreadsheet with something like:
```php
$client = new \Redis();
$client->connect('127.0.0.1', 6379);
$pool = new \Cache\Adapter\Redis\RedisCachePool($client);
$simpleCache = new \Cache\Bridge\SimpleCache\SimpleCacheBridge($pool);
\PhpOffice\PhpSpreadsheet\Settings::setCache($simpleCache);
```
### Memcache
Require the packages into your project:
```sh
composer require cache/simple-cache-bridge cache/memcache-adapter
```
Configure PhpSpreadsheet with something like:
```php
$client = new \Memcache();
$client->connect('localhost', 11211);
$pool = new \Cache\Adapter\Memcache\MemcacheCachePool($client);
$simpleCache = new \Cache\Bridge\SimpleCache\SimpleCacheBridge($pool);
\PhpOffice\PhpSpreadsheet\Settings::setCache($simpleCache);
```

View File

@ -0,0 +1,427 @@
# Migration from PHPExcel
PhpSpreadsheet introduced many breaking changes by introducing
namespaces and renaming some classes. To help you migrate existing
project, a tool was written to replace all references to PHPExcel
classes to their new names. But they are also manual changes that
need to be done.
## Automated tool
The tool is included in PhpSpreadsheet. It scans recursively all files
and directories, starting from the current directory. Assuming it was
installed with composer, it can be run like so:
``` sh
cd /project/to/migrate/src
/project/to/migrate/vendor/phpoffice/phpspreadsheet/bin/migrate-from-phpexcel
```
**Important** The tool will irreversibly modify your sources, be sure to
backup everything, and double check the result before committing.
## Manual changes
In addition to automated changes, a few things need to be migrated manually.
### Renamed readers and writers
When using `IOFactory::createReader()`, `IOFactory::createWriter()` and
`IOFactory::identify()`, the reader/writer short names are used. Those were
changed, along as their corresponding class, to remove ambiguity:
Before | After
-----------------|---------
`'CSV'` | `'Csv'`
`'Excel2003XML'` | `'Xml'`
`'Excel2007'` | `'Xlsx'`
`'Excel5'` | `'Xls'`
`'Gnumeric'` | `'Gnumeric'`
`'HTML'` | `'Html'`
`'OOCalc'` | `'Ods'`
`'OpenDocument'` | `'Ods'`
`'PDF'` | `'Pdf'`
`'SYLK'` | `'Slk'`
### Simplified IOFactory
The following methods :
- `PHPExcel_IOFactory::getSearchLocations()`
- `PHPExcel_IOFactory::setSearchLocations()`
- `PHPExcel_IOFactory::addSearchLocation()`
were replaced by `IOFactory::registerReader()` and `IOFactory::registerWriter()`. That means
IOFactory now relies on classes autoloading.
Before:
```php
\PHPExcel_IOFactory::addSearchLocation($type, $location, $classname);
```
After:
```php
\PhpOffice\PhpSpreadsheet\IOFactory::registerReader($type, $classname);
```
### Removed deprecated things
#### Worksheet::duplicateStyleArray()
``` php
// Before
$worksheet->duplicateStyleArray($styles, $range, $advanced);
// After
$worksheet->getStyle($range)->applyFromArray($styles, $advanced);
```
#### DataType::dataTypeForValue()
``` php
// Before
DataType::dataTypeForValue($value);
// After
DefaultValueBinder::dataTypeForValue($value);
```
#### Conditional::getCondition()
``` php
// Before
$conditional->getCondition();
// After
$conditional->getConditions()[0];
```
#### Conditional::setCondition()
``` php
// Before
$conditional->setCondition($value);
// After
$conditional->setConditions($value);
```
#### Worksheet::getDefaultStyle()
``` php
// Before
$worksheet->getDefaultStyle();
// After
$worksheet->getParent()->getDefaultStyle();
```
#### Worksheet::setDefaultStyle()
``` php
// Before
$worksheet->setDefaultStyle($value);
// After
$worksheet->getParent()->getDefaultStyle()->applyFromArray([
'font' => [
'name' => $pValue->getFont()->getName(),
'size' => $pValue->getFont()->getSize(),
],
]);
```
#### Worksheet::setSharedStyle()
``` php
// Before
$worksheet->setSharedStyle($sharedStyle, $range);
// After
$worksheet->duplicateStyle($sharedStyle, $range);
```
#### Worksheet::getSelectedCell()
``` php
// Before
$worksheet->getSelectedCell();
// After
$worksheet->getSelectedCells();
```
#### Writer\Xls::setTempDir()
``` php
// Before
$writer->setTempDir();
// After, there is no way to set temporary storage directory anymore
```
### Autoloader
The class `PHPExcel_Autoloader` was removed entirely and is replaced by composer
autoloading mechanism.
### Writing PDF
PDF libraries must be installed via composer. And the following methods were removed
and are replaced by `IOFactory::registerWriter()` instead:
- `PHPExcel_Settings::getPdfRenderer()`
- `PHPExcel_Settings::setPdfRenderer()`
- `PHPExcel_Settings::getPdfRendererName()`
- `PHPExcel_Settings::setPdfRendererName()`
Before:
```php
\PHPExcel_Settings::setPdfRendererName(PHPExcel_Settings::PDF_RENDERER_MPDF);
\PHPExcel_Settings::setPdfRenderer($somePath);
$writer = \PHPExcel_IOFactory::createWriter($spreadsheet, 'PDF');
```
After:
```php
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Mpdf');
// Or alternatively
\PhpOffice\PhpSpreadsheet\IOFactory::registerWriter('Pdf', \PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf::class);
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Pdf');
// Or alternatively
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf($spreadsheet);
```
### Rendering charts
When rendering charts for HTML or PDF outputs, the process was also simplified. And while
JpGraph support is still available, it is unfortunately not up to date for latest PHP versions
and it will generate various warnings.
If you rely on this feature, please consider
contributing either patches to JpGraph or another `IRenderer` implementation (a good
candidate might be [CpChart](https://github.com/szymach/c-pchart)).
Before:
```php
$rendererName = \PHPExcel_Settings::CHART_RENDERER_JPGRAPH;
$rendererLibrary = 'jpgraph3.5.0b1/src/';
$rendererLibraryPath = '/php/libraries/Charts/' . $rendererLibrary;
\PHPExcel_Settings::setChartRenderer($rendererName, $rendererLibraryPath);
```
After:
Require the dependency via composer:
```sh
composer require jpgraph/jpgraph
```
And then:
```php
Settings::setChartRenderer(\PhpOffice\PhpSpreadsheet\Chart\Renderer\JpGraph::class);
```
### PclZip and ZipArchive
Support for PclZip were dropped in favor of the more complete and modern
[PHP extension ZipArchive](http://php.net/manual/en/book.zip.php).
So the following were removed:
- `PclZip`
- `PHPExcel_Settings::setZipClass()`
- `PHPExcel_Settings::getZipClass()`
- `PHPExcel_Shared_ZipArchive`
- `PHPExcel_Shared_ZipStreamWrapper`
### Cell caching
Cell caching was heavily refactored to leverage
[PSR-16](http://www.php-fig.org/psr/psr-16/). That means most classes
related to that feature were removed:
- `PHPExcel_CachedObjectStorage_APC`
- `PHPExcel_CachedObjectStorage_DiscISAM`
- `PHPExcel_CachedObjectStorage_ICache`
- `PHPExcel_CachedObjectStorage_Igbinary`
- `PHPExcel_CachedObjectStorage_Memcache`
- `PHPExcel_CachedObjectStorage_Memory`
- `PHPExcel_CachedObjectStorage_MemoryGZip`
- `PHPExcel_CachedObjectStorage_MemorySerialized`
- `PHPExcel_CachedObjectStorage_PHPTemp`
- `PHPExcel_CachedObjectStorage_SQLite`
- `PHPExcel_CachedObjectStorage_SQLite3`
- `PHPExcel_CachedObjectStorage_Wincache`
In addition to that, `\PhpOffice\PhpSpreadsheet::getCellCollection()` was renamed
to `\PhpOffice\PhpSpreadsheet::getCoordinates()` and
`\PhpOffice\PhpSpreadsheet::getCellCacheController()` to
`\PhpOffice\PhpSpreadsheet::getCellCollection()` for clarity.
Refer to [the new documentation](./memory_saving.md) to see how to migrate.
### Dropped conditionally returned cell
For all the following methods, it is no more possible to change the type of
returned value. It always return the Worksheet and never the Cell or Rule:
- Worksheet::setCellValue()
- Worksheet::setCellValueByColumnAndRow()
- Worksheet::setCellValueExplicit()
- Worksheet::setCellValueExplicitByColumnAndRow()
- Worksheet::addRule()
Migration would be similar to:
``` php
// Before
$cell = $worksheet->setCellValue('A1', 'value', true);
// After
$cell = $worksheet->getCell('A1')->setValue('value');
```
### Standardized keys for styling
Array keys used for styling have been standardized for a more coherent experience.
It now uses the same wording and casing as the getter and setter:
```php
// Before
$style = [
'numberformat' => [
'code' => NumberFormat::FORMAT_CURRENCY_EUR_SIMPLE,
],
'font' => [
'strike' => true,
'superScript' => true,
'subScript' => true,
],
'alignment' => [
'rotation' => 90,
'readorder' => Alignment::READORDER_RTL,
'wrap' => true,
],
'borders' => [
'diagonaldirection' => Borders::DIAGONAL_BOTH,
'allborders' => [
'style' => Border::BORDER_THIN,
],
],
'fill' => [
'type' => Fill::FILL_GRADIENT_LINEAR,
'startcolor' => [
'argb' => 'FFA0A0A0',
],
'endcolor' => [
'argb' => 'FFFFFFFF',
],
],
];
// After
$style = [
'numberFormat' => [
'formatCode' => NumberFormat::FORMAT_CURRENCY_EUR_SIMPLE,
],
'font' => [
'strikethrough' => true,
'superscript' => true,
'subscript' => true,
],
'alignment' => [
'textRotation' => 90,
'readOrder' => Alignment::READORDER_RTL,
'wrapText' => true,
],
'borders' => [
'diagonalDirection' => Borders::DIAGONAL_BOTH,
'allBorders' => [
'borderStyle' => Border::BORDER_THIN,
],
],
'fill' => [
'fillType' => Fill::FILL_GRADIENT_LINEAR,
'startColor' => [
'argb' => 'FFA0A0A0',
],
'endColor' => [
'argb' => 'FFFFFFFF',
],
],
];
```
### Dedicated class to manipulate coordinates
Methods to manipulate coordinates that used to exists in `PHPExcel_Cell` were extracted
to a dedicated new class `\PhpOffice\PhpSpreadsheet\Cell\Coordinate`. The methods are:
- `absoluteCoordinate()`
- `absoluteReference()`
- `buildRange()`
- `columnIndexFromString()`
- `coordinateFromString()`
- `extractAllCellReferencesInRange()`
- `getRangeBoundaries()`
- `mergeRangesInCollection()`
- `rangeBoundaries()`
- `rangeDimension()`
- `splitRange()`
- `stringFromColumnIndex()`
### Column index based on 1
Column indexes are now based on 1. So column `A` is the index `1`. This is consistent
with rows starting at 1 and Excel function `COLUMN()` that returns `1` for column `A`.
So the code must be adapted with something like:
```php
// Before
$cell = $worksheet->getCellByColumnAndRow($column, $row);
for ($column = 0; $column < $max; $column++) {
$worksheet->setCellValueByColumnAndRow($column, $row, 'value ' . $column);
}
// After
$cell = $worksheet->getCellByColumnAndRow($column + 1, $row);
for ($column = 1; $column <= $max; $column++) {
$worksheet->setCellValueByColumnAndRow($column, $row, 'value ' . $column);
}
```
All the following methods are affected:
- `PHPExcel_Worksheet::cellExistsByColumnAndRow()`
- `PHPExcel_Worksheet::freezePaneByColumnAndRow()`
- `PHPExcel_Worksheet::getCellByColumnAndRow()`
- `PHPExcel_Worksheet::getColumnDimensionByColumn()`
- `PHPExcel_Worksheet::getCommentByColumnAndRow()`
- `PHPExcel_Worksheet::getStyleByColumnAndRow()`
- `PHPExcel_Worksheet::insertNewColumnBeforeByIndex()`
- `PHPExcel_Worksheet::mergeCellsByColumnAndRow()`
- `PHPExcel_Worksheet::protectCellsByColumnAndRow()`
- `PHPExcel_Worksheet::removeColumnByIndex()`
- `PHPExcel_Worksheet::setAutoFilterByColumnAndRow()`
- `PHPExcel_Worksheet::setBreakByColumnAndRow()`
- `PHPExcel_Worksheet::setCellValueByColumnAndRow()`
- `PHPExcel_Worksheet::setCellValueExplicitByColumnAndRow()`
- `PHPExcel_Worksheet::setSelectedCellByColumnAndRow()`
- `PHPExcel_Worksheet::stringFromColumnIndex()`
- `PHPExcel_Worksheet::unmergeCellsByColumnAndRow()`
- `PHPExcel_Worksheet::unprotectCellsByColumnAndRow()`
- `PHPExcel_Worksheet_PageSetup::addPrintAreaByColumnAndRow()`
- `PHPExcel_Worksheet_PageSetup::setPrintAreaByColumnAndRow()`

View File

@ -0,0 +1,877 @@
# Reading and writing to file
As you already know from the [architecture](./architecture.md#readers-and-writers),
reading and writing to a
persisted storage is not possible using the base PhpSpreadsheet classes.
For this purpose, PhpSpreadsheet provides readers and writers, which are
implementations of `\PhpOffice\PhpSpreadsheet\Reader\IReader` and
`\PhpOffice\PhpSpreadsheet\Writer\IWriter`.
## \PhpOffice\PhpSpreadsheet\IOFactory
The PhpSpreadsheet API offers multiple methods to create a
`\PhpOffice\PhpSpreadsheet\Reader\IReader` or
`\PhpOffice\PhpSpreadsheet\Writer\IWriter` instance:
Direct creation via `\PhpOffice\PhpSpreadsheet\IOFactory`. All examples
underneath demonstrate the direct creation method. Note that you can
also use the `\PhpOffice\PhpSpreadsheet\IOFactory` class to do this.
### Creating `\PhpOffice\PhpSpreadsheet\Reader\IReader` using `\PhpOffice\PhpSpreadsheet\IOFactory`
There are 2 methods for reading in a file into PhpSpreadsheet: using
automatic file type resolving or explicitly.
Automatic file type resolving checks the different
`\PhpOffice\PhpSpreadsheet\Reader\IReader` distributed with
PhpSpreadsheet. If one of them can load the specified file name, the
file is loaded using that `\PhpOffice\PhpSpreadsheet\Reader\IReader`.
Explicit mode requires you to specify which
`\PhpOffice\PhpSpreadsheet\Reader\IReader` should be used.
You can create a `\PhpOffice\PhpSpreadsheet\Reader\IReader` instance using
`\PhpOffice\PhpSpreadsheet\IOFactory` in automatic file type resolving
mode using the following code sample:
``` php
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load("05featuredemo.xlsx");
```
A typical use of this feature is when you need to read files uploaded by
your users, and you dont know whether they are uploading xls or xlsx
files.
If you need to set some properties on the reader, (e.g. to only read
data, see more about this later), then you may instead want to use this
variant:
``` php
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReaderForFile("05featuredemo.xlsx");
$reader->setReadDataOnly(true);
$reader->load("05featuredemo.xlsx");
```
You can create a `\PhpOffice\PhpSpreadsheet\Reader\IReader` instance using
`\PhpOffice\PhpSpreadsheet\IOFactory` in explicit mode using the following
code sample:
``` php
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader("Xlsx");
$spreadsheet = $reader->load("05featuredemo.xlsx");
```
Note that automatic type resolving mode is slightly slower than explicit
mode.
### Creating `\PhpOffice\PhpSpreadsheet\Writer\IWriter` using `\PhpOffice\PhpSpreadsheet\IOFactory`
You can create a `\PhpOffice\PhpSpreadsheet\Writer\IWriter` instance using
`\PhpOffice\PhpSpreadsheet\IOFactory`:
``` php
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, "Xlsx");
$writer->save("05featuredemo.xlsx");
```
## Excel 2007 (SpreadsheetML) file format
Xlsx file format is the main file format of PhpSpreadsheet. It allows
outputting the in-memory spreadsheet to a .xlsx file.
### \PhpOffice\PhpSpreadsheet\Reader\Xlsx
#### Reading a spreadsheet
You can read an .xlsx file using the following code:
``` php
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();
$spreadsheet = $reader->load("05featuredemo.xlsx");
```
#### Read data only
You can set the option setReadDataOnly on the reader, to instruct the
reader to ignore styling, data validation, … and just read cell data:
``` php
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();
$reader->setReadDataOnly(true);
$spreadsheet = $reader->load("05featuredemo.xlsx");
```
#### Read specific sheets only
You can set the option setLoadSheetsOnly on the reader, to instruct the
reader to only load the sheets with a given name:
``` php
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();
$reader->setLoadSheetsOnly( array("Sheet 1", "My special sheet") );
$spreadsheet = $reader->load("05featuredemo.xlsx");
```
#### Read specific cells only
You can set the option setReadFilter on the reader, to instruct the
reader to only load the cells which match a given rule. A read filter
can be any class which implements
`\PhpOffice\PhpSpreadsheet\Reader\IReadFilter`. By default, all cells are
read using the `\PhpOffice\PhpSpreadsheet\Reader\DefaultReadFilter`.
The following code will only read row 1 and rows 20 30 of any sheet in
the Excel file:
``` php
class MyReadFilter implements \PhpOffice\PhpSpreadsheet\Reader\IReadFilter {
public function readCell($column, $row, $worksheetName = '') {
// Read title row and rows 20 - 30
if ($row == 1 || ($row >= 20 && $row <= 30)) {
return true;
}
return false;
}
}
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();
$reader->setReadFilter( new MyReadFilter() );
$spreadsheet = $reader->load("06largescale.xlsx");
```
### \PhpOffice\PhpSpreadsheet\Writer\Xlsx
#### Writing a spreadsheet
You can write an .xlsx file using the following code:
``` php
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
$writer->save("05featuredemo.xlsx");
```
#### Formula pre-calculation
By default, this writer pre-calculates all formulas in the spreadsheet.
This can be slow on large spreadsheets, and maybe even unwanted. You can
however disable formula pre-calculation:
``` php
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
$writer->setPreCalculateFormulas(false);
$writer->save("05featuredemo.xlsx");
```
#### Office 2003 compatibility pack
Because of a bug in the Office2003 compatibility pack, there can be some
small issues when opening Xlsx spreadsheets (mostly related to formula
calculation). You can enable Office2003 compatibility with the following
code:
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
$writer->setOffice2003Compatibility(true);
$writer->save("05featuredemo.xlsx");
**Office2003 compatibility should only be used when needed** Office2003
compatibility option should only be used when needed. This option
disables several Office2007 file format options, resulting in a
lower-featured Office2007 spreadsheet when this option is used.
## Excel 5 (BIFF) file format
Xls file format is the old Excel file format, implemented in
PhpSpreadsheet to provide a uniform manner to create both .xlsx and .xls
files. It is basically a modified version of [PEAR
Spreadsheet\_Excel\_Writer](http://pear.php.net/package/Spreadsheet_Excel_Writer),
although it has been extended and has fewer limitations and more
features than the old PEAR library. This can read all BIFF versions that
use OLE2: BIFF5 (introduced with office 95) through BIFF8, but cannot
read earlier versions.
Xls file format will not be developed any further, it just provides an
additional file format for PhpSpreadsheet.
**Excel5 (BIFF) limitations** Please note that BIFF file format has some
limits regarding to styling cells and handling large spreadsheets via
PHP.
### \PhpOffice\PhpSpreadsheet\Reader\Xls
#### Reading a spreadsheet
You can read an .xls file using the following code:
``` php
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xls();
$spreadsheet = $reader->load("05featuredemo.xls");
```
#### Read data only
You can set the option setReadDataOnly on the reader, to instruct the
reader to ignore styling, data validation, … and just read cell data:
``` php
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xls();
$reader->setReadDataOnly(true);
$spreadsheet = $reader->load("05featuredemo.xls");
```
#### Read specific sheets only
You can set the option setLoadSheetsOnly on the reader, to instruct the
reader to only load the sheets with a given name:
``` php
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xls();
$reader->setLoadSheetsOnly( array("Sheet 1", "My special sheet") );
$spreadsheet = $reader->load("05featuredemo.xls");
```
#### Read specific cells only
You can set the option setReadFilter on the reader, to instruct the
reader to only load the cells which match a given rule. A read filter
can be any class which implements
`\PhpOffice\PhpSpreadsheet\Reader\IReadFilter`. By default, all cells are
read using the `\PhpOffice\PhpSpreadsheet\Reader\DefaultReadFilter`.
The following code will only read row 1 and rows 20 to 30 of any sheet
in the Excel file:
``` php
class MyReadFilter implements \PhpOffice\PhpSpreadsheet\Reader\IReadFilter {
public function readCell($column, $row, $worksheetName = '') {
// Read title row and rows 20 - 30
if ($row == 1 || ($row >= 20 && $row <= 30)) {
return true;
}
return false;
}
}
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xls();
$reader->setReadFilter( new MyReadFilter() );
$spreadsheet = $reader->load("06largescale.xls");
```
### \PhpOffice\PhpSpreadsheet\Writer\Xls
#### Writing a spreadsheet
You can write an .xls file using the following code:
``` php
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xls($spreadsheet);
$writer->save("05featuredemo.xls");
```
## Excel 2003 XML file format
Excel 2003 XML file format is a file format which can be used in older
versions of Microsoft Excel.
**Excel 2003 XML limitations** Please note that Excel 2003 XML format
has some limits regarding to styling cells and handling large
spreadsheets via PHP.
### \PhpOffice\PhpSpreadsheet\Reader\Xml
#### Reading a spreadsheet
You can read an Excel 2003 .xml file using the following code:
``` php
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xml();
$spreadsheet = $reader->load("05featuredemo.xml");
```
#### Read specific cells only
You can set the option setReadFilter on the reader, to instruct the
reader to only load the cells which match a given rule. A read filter
can be any class which implements
`\PhpOffice\PhpSpreadsheet\Reader\IReadFilter`. By default, all cells are
read using the `\PhpOffice\PhpSpreadsheet\Reader\DefaultReadFilter`.
The following code will only read row 1 and rows 20 to 30 of any sheet
in the Excel file:
``` php
class MyReadFilter implements \PhpOffice\PhpSpreadsheet\Reader\IReadFilter {
public function readCell($column, $row, $worksheetName = '') {
// Read title row and rows 20 - 30
if ($row == 1 || ($row >= 20 && $row <= 30)) {
return true;
}
return false;
}
}
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xml();
$reader->setReadFilter( new MyReadFilter() );
$spreadsheet = $reader->load("06largescale.xml");
```
## Symbolic LinK (SYLK)
Symbolic Link (SYLK) is a Microsoft file format typically used to
exchange data between applications, specifically spreadsheets. SYLK
files conventionally have a .slk suffix. Composed of only displayable
ANSI characters, it can be easily created and processed by other
applications, such as databases.
**SYLK limitations** Please note that SYLK file format has some limits
regarding to styling cells and handling large spreadsheets via PHP.
### \PhpOffice\PhpSpreadsheet\Reader\Slk
#### Reading a spreadsheet
You can read an .slk file using the following code:
``` php
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Slk();
$spreadsheet = $reader->load("05featuredemo.slk");
```
#### Read specific cells only
You can set the option setReadFilter on the reader, to instruct the
reader to only load the cells which match a given rule. A read filter
can be any class which implements
`\PhpOffice\PhpSpreadsheet\Reader\IReadFilter`. By default, all cells are
read using the `\PhpOffice\PhpSpreadsheet\Reader\DefaultReadFilter`.
The following code will only read row 1 and rows 20 to 30 of any sheet
in the SYLK file:
``` php
class MyReadFilter implements \PhpOffice\PhpSpreadsheet\Reader\IReadFilter {
public function readCell($column, $row, $worksheetName = '') {
// Read title row and rows 20 - 30
if ($row == 1 || ($row >= 20 && $row <= 30)) {
return true;
}
return false;
}
}
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Slk();
$reader->setReadFilter( new MyReadFilter() );
$spreadsheet = $reader->load("06largescale.slk");
```
## Open/Libre Office (.ods)
Open Office or Libre Office .ods files are the standard file format for
Open Office or Libre Office Calc files.
### \PhpOffice\PhpSpreadsheet\Reader\Ods
#### Reading a spreadsheet
You can read an .ods file using the following code:
``` php
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Ods();
$spreadsheet = $reader->load("05featuredemo.ods");
```
#### Read specific cells only
You can set the option setReadFilter on the reader, to instruct the
reader to only load the cells which match a given rule. A read filter
can be any class which implements
`\PhpOffice\PhpSpreadsheet\Reader\IReadFilter`. By default, all cells are
read using the `\PhpOffice\PhpSpreadsheet\Reader\DefaultReadFilter`.
The following code will only read row 1 and rows 20 to 30 of any sheet
in the Calc file:
``` php
class MyReadFilter implements \PhpOffice\PhpSpreadsheet\Reader\IReadFilter {
public function readCell($column, $row, $worksheetName = '') {
// Read title row and rows 20 - 30
if ($row == 1 || ($row >= 20 && $row <= 30)) {
return true;
}
return false;
}
}
$reader = new PhpOffice\PhpSpreadsheet\Reader\Ods();
$reader->setReadFilter( new MyReadFilter() );
$spreadsheet = $reader->load("06largescale.ods");
```
## CSV (Comma Separated Values)
CSV (Comma Separated Values) are often used as an import/export file
format with other systems. PhpSpreadsheet allows reading and writing to
CSV files.
**CSV limitations** Please note that CSV file format has some limits
regarding to styling cells, number formatting, ...
### \PhpOffice\PhpSpreadsheet\Reader\Csv
#### Reading a CSV file
You can read a .csv file using the following code:
``` php
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Csv();
$spreadsheet = $reader->load("sample.csv");
```
#### Setting CSV options
Often, CSV files are not really "comma separated", or use semicolon (`;`)
as a separator. You can instruct
`\PhpOffice\PhpSpreadsheet\Reader\Csv` some options before reading a CSV
file.
The separator will be auto-detected, so in most cases it should not be necessary
to specify it. But in cases where auto-detection does not fit the use-case, then
it can be set manually.
Note that `\PhpOffice\PhpSpreadsheet\Reader\Csv` by default assumes that
the loaded CSV file is UTF-8 encoded. If you are reading CSV files that
were created in Microsoft Office Excel the correct input encoding may
rather be Windows-1252 (CP1252). Always make sure that the input
encoding is set appropriately.
``` php
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Csv();
$reader->setInputEncoding('CP1252');
$reader->setDelimiter(';');
$reader->setEnclosure('');
$reader->setSheetIndex(0);
$spreadsheet = $reader->load("sample.csv");
```
#### Read a specific worksheet
CSV files can only contain one worksheet. Therefore, you can specify
which sheet to read from CSV:
``` php
$reader->setSheetIndex(0);
```
#### Read into existing spreadsheet
When working with CSV files, it might occur that you want to import CSV
data into an existing `Spreadsheet` object. The following code loads a
CSV file into an existing `$spreadsheet` containing some sheets, and
imports onto the 6th sheet:
``` php
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Csv();
$reader->setDelimiter(';');
$reader->setEnclosure('');
$reader->setSheetIndex(5);
$reader->loadIntoExisting("05featuredemo.csv", $spreadsheet);
```
### \PhpOffice\PhpSpreadsheet\Writer\Csv
#### Writing a CSV file
You can write a .csv file using the following code:
``` php
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Csv($spreadsheet);
$writer->save("05featuredemo.csv");
```
#### Setting CSV options
Often, CSV files are not really "comma separated", or use semicolon (`;`)
as a separator. You can instruct
`\PhpOffice\PhpSpreadsheet\Writer\Csv` some options before writing a CSV
file:
``` php
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Csv($spreadsheet);
$writer->setDelimiter(';');
$writer->setEnclosure('');
$writer->setLineEnding("\r\n");
$writer->setSheetIndex(0);
$writer->save("05featuredemo.csv");
```
#### Write a specific worksheet
CSV files can only contain one worksheet. Therefore, you can specify
which sheet to write to CSV:
``` php
$writer->setSheetIndex(0);
```
#### Formula pre-calculation
By default, this writer pre-calculates all formulas in the spreadsheet.
This can be slow on large spreadsheets, and maybe even unwanted. You can
however disable formula pre-calculation:
``` php
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Csv($spreadsheet);
$writer->setPreCalculateFormulas(false);
$writer->save("05featuredemo.csv");
```
#### Writing UTF-8 CSV files
A CSV file can be marked as UTF-8 by writing a BOM file header. This can
be enabled by using the following code:
``` php
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Csv($spreadsheet);
$writer->setUseBOM(true);
$writer->save("05featuredemo.csv");
```
#### Decimal and thousands separators
If the worksheet you are exporting contains numbers with decimal or
thousands separators then you should think about what characters you
want to use for those before doing the export.
By default PhpSpreadsheet looks up in the server's locale settings to
decide what characters to use. But to avoid problems it is recommended
to set the characters explicitly as shown below.
English users will want to use this before doing the export:
``` php
\PhpOffice\PhpSpreadsheet\Shared\StringHelper::setDecimalSeparator('.');
\PhpOffice\PhpSpreadsheet\Shared\StringHelper::setThousandsSeparator(',');
```
German users will want to use the opposite values.
``` php
\PhpOffice\PhpSpreadsheet\Shared\StringHelper::setDecimalSeparator(',');
\PhpOffice\PhpSpreadsheet\Shared\StringHelper::setThousandsSeparator('.');
```
Note that the above code sets decimal and thousand separators as global
options. This also affects how HTML and PDF is exported.
## HTML
PhpSpreadsheet allows you to read or write a spreadsheet as HTML format,
for quick representation of the data in it to anyone who does not have a
spreadsheet application on their PC, or loading files saved by other
scripts that simply create HTML markup and give it a .xls file
extension.
**HTML limitations** Please note that HTML file format has some limits
regarding to styling cells, number formatting, ...
### \PhpOffice\PhpSpreadsheet\Reader\Html
#### Reading a spreadsheet
You can read an .html or .htm file using the following code:
``` php
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Html();
$spreadsheet = $reader->load("05featuredemo.html");
```
**HTML limitations** Please note that HTML reader is still experimental
and does not yet support merged cells or nested tables cleanly
### \PhpOffice\PhpSpreadsheet\Writer\Html
Please note that `\PhpOffice\PhpSpreadsheet\Writer\Html` only outputs the
first worksheet by default.
#### Writing a spreadsheet
You can write a .htm file using the following code:
``` php
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Html($spreadsheet);
$writer->save("05featuredemo.htm");
```
#### Write all worksheets
HTML files can contain one or more worksheets. If you want to write all
sheets into a single HTML file, use the following code:
``` php
$writer->writeAllSheets();
```
#### Write a specific worksheet
HTML files can contain one or more worksheets. Therefore, you can
specify which sheet to write to HTML:
``` php
$writer->setSheetIndex(0);
```
#### Setting the images root of the HTML file
There might be situations where you want to explicitly set the included
images root. For example, one might want to see
``` html
<img style="position: relative; left: 0px; top: 0px; width: 140px; height: 78px;" src="http://www.domain.com/*images/logo.jpg" border="0">
```
instead of
``` html
<img style="position: relative; left: 0px; top: 0px; width: 140px; height: 78px;" src="./images/logo.jpg" border="0">.
```
You can use the following code to achieve this result:
``` php
$writer->setImagesRoot('http://www.example.com');
```
#### Formula pre-calculation
By default, this writer pre-calculates all formulas in the spreadsheet.
This can be slow on large spreadsheets, and maybe even unwanted. You can
however disable formula pre-calculation:
``` php
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Html($spreadsheet);
$writer->setPreCalculateFormulas(false);
$writer->save("05featuredemo.htm");
```
#### Embedding generated HTML in a web page
There might be a situation where you want to embed the generated HTML in
an existing website. \PhpOffice\PhpSpreadsheet\Writer\Html provides
support to generate only specific parts of the HTML code, which allows
you to use these parts in your website.
Supported methods:
- `generateHTMLHeader()`
- `generateStyles()`
- `generateSheetData()`
- `generateHTMLFooter()`
Here's an example which retrieves all parts independently and merges
them into a resulting HTML page:
``` php
<?php
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Html($spreadsheet);
echo $writer->generateHTMLHeader();
?>
<style>
<!--
html {
font-family: Times New Roman;
font-size: 9pt;
background-color: white;
}
<?php
echo $writer->generateStyles(false); // do not write <style> and </style>
?>
-->
</style>
<?php
echo $writer->generateSheetData();
echo $writer->generateHTMLFooter();
?>
```
#### Writing UTF-8 HTML files
A HTML file can be marked as UTF-8 by writing a BOM file header. This
can be enabled by using the following code:
``` php
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Html($spreadsheet);
$writer->setUseBOM(true);
$writer->save("05featuredemo.htm");
```
#### Decimal and thousands separators
See section `\PhpOffice\PhpSpreadsheet\Writer\Csv` how to control the
appearance of these.
## PDF
PhpSpreadsheet allows you to write a spreadsheet into PDF format, for
fast distribution of represented data.
**PDF limitations** Please note that PDF file format has some limits
regarding to styling cells, number formatting, ...
### \PhpOffice\PhpSpreadsheet\Writer\Pdf
PhpSpreadsheets PDF Writer is a wrapper for a 3rd-Party PDF Rendering
library such as TCPDF, mPDF or Dompdf. You must now install a PDF
rendering library yourself; but PhpSpreadsheet will work with a number
of different libraries.
Currently, the following libraries are supported:
Library | Downloadable from | PhpSpreadsheet writer
--------|-------------------------------------|----------------------
TCPDF | https://github.com/tecnickcom/tcpdf | Tcpdf
mPDF | https://github.com/mpdf/mpdf | Mpdf
Dompdf | https://github.com/dompdf/dompdf | Dompdf
The different libraries have different strengths and weaknesses. Some
generate better formatted output than others, some are faster or use
less memory than others, while some generate smaller .pdf files. It is
the developers choice which one they wish to use, appropriate to their
own circumstances.
You can instantiate a writer with its specific name, like so:
``` php
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Mpdf');
```
Or you can register which writer you are using with a more generic name,
so you don't need to remember which library you chose, only that you want
to write PDF files:
``` php
$class = \PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf::class;
\PhpOffice\PhpSpreadsheet\IOFactory::registerWriter('Pdf', $class);
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Pdf');
```
Or you can instantiate directly the writer of your choice like so:
``` php
$writer = \PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf($spreadsheet);
```
#### Custom implementation or configuration
If you need a custom implementation, or custom configuration, of a supported
PDF library. You can extends the PDF library, and the PDF writer like so:
``` php
class My_Custom_TCPDF extends TCPDF
{
// ...
}
class My_Custom_TCPDF_Writer extends \PhpOffice\PhpSpreadsheet\Writer\Pdf\Tcpdf
{
protected function createExternalWriterInstance($orientation, $unit, $paperSize)
{
$instance = new My_Custom_TCPDF($orientation, $unit, $paperSize);
// more configuration of $instance
return $instance;
}
}
\PhpOffice\PhpSpreadsheet\IOFactory::registerWriter('Pdf', MY_TCPDF_WRITER::class);
```
#### Writing a spreadsheet
Once you have identified the Renderer that you wish to use for PDF
generation, you can write a .pdf file using the following code:
``` php
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf($spreadsheet);
$writer->save("05featuredemo.pdf");
```
Please note that `\PhpOffice\PhpSpreadsheet\Writer\Pdf` only outputs the
first worksheet by default.
#### Write all worksheets
PDF files can contain one or more worksheets. If you want to write all
sheets into a single PDF file, use the following code:
``` php
$writer->writeAllSheets();
```
#### Write a specific worksheet
PDF files can contain one or more worksheets. Therefore, you can specify
which sheet to write to PDF:
``` php
$writer->setSheetIndex(0);
```
#### Formula pre-calculation
By default, this writer pre-calculates all formulas in the spreadsheet.
This can be slow on large spreadsheets, and maybe even unwanted. You can
however disable formula pre-calculation:
``` php
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf($spreadsheet);
$writer->setPreCalculateFormulas(false);
$writer->save("05featuredemo.pdf");
```
#### Decimal and thousands separators
See section `\PhpOffice\PhpSpreadsheet\Writer\Csv` how to control the
appearance of these.
## Generating Excel files from templates (read, modify, write)
Readers and writers are the tools that allow you to generate Excel files
from templates. This requires less coding effort than generating the
Excel file from scratch, especially if your template has many styles,
page setup properties, headers etc.
Here is an example how to open a template file, fill in a couple of
fields and save it again:
``` php
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load('template.xlsx');
$worksheet = $spreadsheet->getActiveSheet();
$worksheet->getCell('A1')->setValue('John');
$worksheet->getCell('A2')->setValue('Smith');
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xls');
$writer->save('write.xls');
```
Notice that it is ok to load an xlsx file and generate an xls file.

View File

@ -0,0 +1,688 @@
# Reading Files
## Security
XML-based formats such as OfficeOpen XML, Excel2003 XML, OASIS and
Gnumeric are susceptible to XML External Entity Processing (XXE)
injection attacks when reading spreadsheet files. This can lead to:
- Disclosure whether a file is existent
- Server Side Request Forgery
- Command Execution (depending on the installed PHP wrappers)
To prevent this, by default every XML-based Reader looks for XML
entities declared inside the DOCTYPE and if any is found an exception
is raised.
Read more [about of XXE injection](https://websec.io/2012/08/27/Preventing-XXE-in-PHP.html).
## Loading a Spreadsheet File
The simplest way to load a workbook file is to let PhpSpreadsheet's IO
Factory identify the file type and load it, calling the static `load()`
method of the `\PhpOffice\PhpSpreadsheet\IOFactory` class.
``` php
$inputFileName = './sampleData/example1.xls';
/** Load $inputFileName to a Spreadsheet Object **/
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($inputFileName);
```
See `samples/Reader/01_Simple_file_reader_using_IOFactory.php` for a working
example of this code.
The `load()` method will attempt to identify the file type, and
instantiate a loader for that file type; using it to load the file and
store the data and any formatting in a `Spreadsheet` object.
The method makes an initial guess at the loader to instantiate based on
the file extension; but will test the file before actually executing the
load: so if (for example) the file is actually a CSV file or contains
HTML markup, but that has been given a .xls extension (quite a common
practise), it will reject the Xls loader that it would normally use for
a .xls file; and test the file using the other loaders until it finds
the appropriate loader, and then use that to read the file.
While easy to implement in your code, and you don't need to worry about
the file type; this isn't the most efficient method to load a file; and
it lacks the flexibility to configure the loader in any way before
actually reading the file into a `Spreadsheet` object.
## Creating a Reader and Loading a Spreadsheet File
If you know the file type of the spreadsheet file that you need to load,
you can instantiate a new reader object for that file type, then use the
reader's `load()` method to read the file to a `Spreadsheet` object. It is
possible to instantiate the reader objects for each of the different
supported filetype by name. However, you may get unpredictable results
if the file isn't of the right type (e.g. it is a CSV with an extension
of .xls), although this type of exception should normally be trapped.
``` php
$inputFileName = './sampleData/example1.xls';
/** Create a new Xls Reader **/
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xls();
// $reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();
// $reader = new \PhpOffice\PhpSpreadsheet\Reader\Xml();
// $reader = new \PhpOffice\PhpSpreadsheet\Reader\Ods();
// $reader = new \PhpOffice\PhpSpreadsheet\Reader\Slk();
// $reader = new \PhpOffice\PhpSpreadsheet\Reader\Gnumeric();
// $reader = new \PhpOffice\PhpSpreadsheet\Reader\Csv();
/** Load $inputFileName to a Spreadsheet Object **/
$spreadsheet = $reader->load($inputFileName);
```
See `samples/Reader/02_Simple_file_reader_using_a_specified_reader.php`
for a working example of this code.
Alternatively, you can use the IO Factory's `createReader()` method to
instantiate the reader object for you, simply telling it the file type
of the reader that you want instantiating.
``` php
$inputFileType = 'Xls';
// $inputFileType = 'Xlsx';
// $inputFileType = 'Xml';
// $inputFileType = 'Ods';
// $inputFileType = 'Slk';
// $inputFileType = 'Gnumeric';
// $inputFileType = 'Csv';
$inputFileName = './sampleData/example1.xls';
/** Create a new Reader of the type defined in $inputFileType **/
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
/** Load $inputFileName to a Spreadsheet Object **/
$spreadsheet = $reader->load($inputFileName);
```
See `samples/Reader/03_Simple_file_reader_using_the_IOFactory_to_return_a_reader.php`
for a working example of this code.
If you're uncertain of the filetype, you can use the `IOFactory::identify()`
method to identify the reader that you need, before using the
`createReader()` method to instantiate the reader object.
``` php
$inputFileName = './sampleData/example1.xls';
/** Identify the type of $inputFileName **/
$inputFileType = \PhpOffice\PhpSpreadsheet\IOFactory::identify($inputFileName);
/** Create a new Reader of the type that has been identified **/
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
/** Load $inputFileName to a Spreadsheet Object **/
$spreadsheet = $reader->load($inputFileName);
```
See `samples/Reader/04_Simple_file_reader_using_the_IOFactory_to_identify_a_reader_to_use.php`
for a working example of this code.
## Spreadsheet Reader Options
Once you have created a reader object for the workbook that you want to
load, you have the opportunity to set additional options before
executing the `load()` method.
### Reading Only Data from a Spreadsheet File
If you're only interested in the cell values in a workbook, but don't
need any of the cell formatting information, then you can set the reader
to read only the data values and any formulae from each cell using the
`setReadDataOnly()` method.
``` php
$inputFileType = 'Xls';
$inputFileName = './sampleData/example1.xls';
/** Create a new Reader of the type defined in $inputFileType **/
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
/** Advise the Reader that we only want to load cell data **/
$reader->setReadDataOnly(true);
/** Load $inputFileName to a Spreadsheet Object **/
$spreadsheet = $reader->load($inputFileName);
```
See `samples/Reader/05_Simple_file_reader_using_the_read_data_only_option.php`
for a working example of this code.
It is important to note that Workbooks (and PhpSpreadsheet) store dates
and times as simple numeric values: they can only be distinguished from
other numeric values by the format mask that is applied to that cell.
When setting read data only to true, PhpSpreadsheet doesn't read the
cell format masks, so it is not possible to differentiate between
dates/times and numbers.
The Gnumeric loader has been written to read the format masks for date
values even when read data only has been set to true, so it can
differentiate between dates/times and numbers; but this change hasn't
yet been implemented for the other readers.
Reading Only Data from a Spreadsheet File applies to Readers:
Reader | Y/N |Reader | Y/N |Reader | Y/N |
----------|:---:|--------|:---:|--------------|:---:|
Xlsx | YES | Xls | YES | Xml | YES |
Ods | YES | SYLK | NO | Gnumeric | YES |
CSV | NO | HTML | NO
### Reading Only Named WorkSheets from a File
If your workbook contains a number of worksheets, but you are only
interested in reading some of those, then you can use the
`setLoadSheetsOnly()` method to identify those sheets you are interested
in reading.
To read a single sheet, you can pass that sheet name as a parameter to
the `setLoadSheetsOnly()` method.
``` php
$inputFileType = 'Xls';
$inputFileName = './sampleData/example1.xls';
$sheetname = 'Data Sheet #2';
/** Create a new Reader of the type defined in $inputFileType **/
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
/** Advise the Reader of which WorkSheets we want to load **/
$reader->setLoadSheetsOnly($sheetname);
/** Load $inputFileName to a Spreadsheet Object **/
$spreadsheet = $reader->load($inputFileName);
```
See `samples/Reader/07_Simple_file_reader_loading_a_single_named_worksheet.php`
for a working example of this code.
If you want to read more than just a single sheet, you can pass a list
of sheet names as an array parameter to the `setLoadSheetsOnly()` method.
``` php
$inputFileType = 'Xls';
$inputFileName = './sampleData/example1.xls';
$sheetnames = array('Data Sheet #1','Data Sheet #3');
/** Create a new Reader of the type defined in $inputFileType **/
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
/** Advise the Reader of which WorkSheets we want to load **/
$reader->setLoadSheetsOnly($sheetnames);
/** Load $inputFileName to a Spreadsheet Object **/
$spreadsheet = $reader->load($inputFileName);
```
See `samples/Reader/08_Simple_file_reader_loading_several_named_worksheets.php`
for a working example of this code.
To reset this option to the default, you can call the `setLoadAllSheets()`
method.
``` php
$inputFileType = 'Xls';
$inputFileName = './sampleData/example1.xls';
/** Create a new Reader of the type defined in $inputFileType **/
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
/** Advise the Reader to load all Worksheets **/
$reader->setLoadAllSheets();
/** Load $inputFileName to a Spreadsheet Object **/
$spreadsheet = $reader->load($inputFileName);
```
See `samples/Reader/06_Simple_file_reader_loading_all_worksheets.php` for a
working example of this code.
Reading Only Named WorkSheets from a File applies to Readers:
Reader | Y/N |Reader | Y/N |Reader | Y/N |
----------|:---:|--------|:---:|--------------|:---:|
Xlsx | YES | Xls | YES | Xml | YES |
Ods | YES | SYLK | NO | Gnumeric | YES |
CSV | NO | HTML | NO
### Reading Only Specific Columns and Rows from a File (Read Filters)
If you are only interested in reading part of a worksheet, then you can
write a filter class that identifies whether or not individual cells
should be read by the loader. A read filter must implement the
`\PhpOffice\PhpSpreadsheet\Reader\IReadFilter` interface, and contain a
`readCell()` method that accepts arguments of `$column`, `$row` and
`$worksheetName`, and return a boolean true or false that indicates
whether a workbook cell identified by those arguments should be read or
not.
``` php
$inputFileType = 'Xls';
$inputFileName = './sampleData/example1.xls';
$sheetname = 'Data Sheet #3';
/** Define a Read Filter class implementing \PhpOffice\PhpSpreadsheet\Reader\IReadFilter */
class MyReadFilter implements \PhpOffice\PhpSpreadsheet\Reader\IReadFilter
{
public function readCell($column, $row, $worksheetName = '') {
// Read rows 1 to 7 and columns A to E only
if ($row >= 1 && $row <= 7) {
if (in_array($column,range('A','E'))) {
return true;
}
}
return false;
}
}
/** Create an Instance of our Read Filter **/
$filterSubset = new MyReadFilter();
/** Create a new Reader of the type defined in $inputFileType **/
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
/** Tell the Reader that we want to use the Read Filter **/
$reader->setReadFilter($filterSubset);
/** Load only the rows and columns that match our filter to Spreadsheet **/
$spreadsheet = $reader->load($inputFileName);
```
See `samples/Reader/09_Simple_file_reader_using_a_read_filter.php` for a
working example of this code.
This example is not particularly useful, because it can only be used in
a very specific circumstance (when you only want cells in the range
A1:E7 from your worksheet. A generic Read Filter would probably be more
useful:
``` php
/** Define a Read Filter class implementing \PhpOffice\PhpSpreadsheet\Reader\IReadFilter */
class MyReadFilter implements \PhpOffice\PhpSpreadsheet\Reader\IReadFilter
{
private $startRow = 0;
private $endRow = 0;
private $columns = array();
/** Get the list of rows and columns to read */
public function __construct($startRow, $endRow, $columns) {
$this->startRow = $startRow;
$this->endRow = $endRow;
$this->columns = $columns;
}
public function readCell($column, $row, $worksheetName = '') {
// Only read the rows and columns that were configured
if ($row >= $this->startRow && $row <= $this->endRow) {
if (in_array($column,$this->columns)) {
return true;
}
}
return false;
}
}
/** Create an Instance of our Read Filter, passing in the cell range **/
$filterSubset = new MyReadFilter(9,15,range('G','K'));
```
See `samples/Reader/10_Simple_file_reader_using_a_configurable_read_filter.php`
for a working example of this code.
This can be particularly useful for conserving memory, by allowing you
to read and process a large workbook in "chunks": an example of this
usage might be when transferring data from an Excel worksheet to a
database.
``` php
$inputFileType = 'Xls';
$inputFileName = './sampleData/example2.xls';
/** Define a Read Filter class implementing \PhpOffice\PhpSpreadsheet\Reader\IReadFilter */
class ChunkReadFilter implements \PhpOffice\PhpSpreadsheet\Reader\IReadFilter
{
private $startRow = 0;
private $endRow = 0;
/** Set the list of rows that we want to read */
public function setRows($startRow, $chunkSize) {
$this->startRow = $startRow;
$this->endRow = $startRow + $chunkSize;
}
public function readCell($column, $row, $worksheetName = '') {
// Only read the heading row, and the configured rows
if (($row == 1) || ($row >= $this->startRow && $row < $this->endRow)) {
return true;
}
return false;
}
}
/** Create a new Reader of the type defined in $inputFileType **/
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
/** Define how many rows we want to read for each "chunk" **/
$chunkSize = 2048;
/** Create a new Instance of our Read Filter **/
$chunkFilter = new ChunkReadFilter();
/** Tell the Reader that we want to use the Read Filter **/
$reader->setReadFilter($chunkFilter);
/** Loop to read our worksheet in "chunk size" blocks **/
for ($startRow = 2; $startRow <= 65536; $startRow += $chunkSize) {
/** Tell the Read Filter which rows we want this iteration **/
$chunkFilter->setRows($startRow,$chunkSize);
/** Load only the rows that match our filter **/
$spreadsheet = $reader->load($inputFileName);
// Do some processing here
}
```
See `samples/Reader/12_Reading_a_workbook_in_chunks_using_a_configurable_read_filter_`
for a working example of this code.
Using Read Filters applies to:
Reader | Y/N |Reader | Y/N |Reader | Y/N |
----------|:---:|--------|:---:|--------------|:---:|
Xlsx | YES | Xls | YES | Xml | YES |
Ods | YES | SYLK | NO | Gnumeric | YES |
CSV | YES | HTML | NO | | |
### Combining Multiple Files into a Single Spreadsheet Object
While you can limit the number of worksheets that are read from a
workbook file using the `setLoadSheetsOnly()` method, certain readers also
allow you to combine several individual "sheets" from different files
into a single `Spreadsheet` object, where each individual file is a
single worksheet within that workbook. For each file that you read, you
need to indicate which worksheet index it should be loaded into using
the `setSheetIndex()` method of the `$reader`, then use the
`loadIntoExisting()` method rather than the `load()` method to actually read
the file into that worksheet.
``` php
$inputFileType = 'Csv';
$inputFileNames = array('./sampleData/example1.csv',
'./sampleData/example2.csv'
'./sampleData/example3.csv'
);
/** Create a new Reader of the type defined in $inputFileType **/
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
/** Extract the first named file from the array list **/
$inputFileName = array_shift($inputFileNames);
/** Load the initial file to the first worksheet in a `Spreadsheet` Object **/
$spreadsheet = $reader->load($inputFileName);
/** Set the worksheet title (to the filename that we've loaded) **/
$spreadsheet->getActiveSheet()
->setTitle(pathinfo($inputFileName,PATHINFO_BASENAME));
/** Loop through all the remaining files in the list **/
foreach($inputFileNames as $sheet => $inputFileName) {
/** Increment the worksheet index pointer for the Reader **/
$reader->setSheetIndex($sheet+1);
/** Load the current file into a new worksheet in Spreadsheet **/
$reader->loadIntoExisting($inputFileName,$spreadsheet);
/** Set the worksheet title (to the filename that we've loaded) **/
$spreadsheet->getActiveSheet()
->setTitle(pathinfo($inputFileName,PATHINFO_BASENAME));
}
```
See `samples/Reader/13_Simple_file_reader_for_multiple_CSV_files.php` for a
working example of this code.
Note that using the same sheet index for multiple sheets won't append
files into the same sheet, but overwrite the results of the previous
load. You cannot load multiple CSV files into the same worksheet.
Combining Multiple Files into a Single Spreadsheet Object applies to:
Reader | Y/N |Reader | Y/N |Reader | Y/N |
----------|:---:|--------|:---:|--------------|:---:|
Xlsx | NO | Xls | NO | Xml | NO |
Ods | NO | SYLK | YES | Gnumeric | NO |
CSV | YES | HTML | NO
### Combining Read Filters with the `setSheetIndex()` method to split a large CSV file across multiple Worksheets
An Xls BIFF .xls file is limited to 65536 rows in a worksheet, while the
Xlsx Microsoft Office Open XML SpreadsheetML .xlsx file is limited to
1,048,576 rows in a worksheet; but a CSV file is not limited other than
by available disk space. This means that we wouldnt ordinarily be able
to read all the rows from a very large CSV file that exceeded those
limits, and save it as an Xls or Xlsx file. However, by using Read
Filters to read the CSV file in "chunks" (using the ChunkReadFilter
Class that we defined in [the above section](#reading-only-specific-columns-and-rows-from-a-file-read-filters),
and the `setSheetIndex()` method of the `$reader`, we can split the CSV
file across several individual worksheets.
``` php
$inputFileType = 'Csv';
$inputFileName = './sampleData/example2.csv';
echo 'Loading file ',pathinfo($inputFileName,PATHINFO_BASENAME),' using IOFactory with a defined reader type of ',$inputFileType,'<br />';
/** Create a new Reader of the type defined in $inputFileType **/
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
/** Define how many rows we want to read for each "chunk" **/
$chunkSize = 65530;
/** Create a new Instance of our Read Filter **/
$chunkFilter = new ChunkReadFilter();
/** Tell the Reader that we want to use the Read Filter **/
/** and that we want to store it in contiguous rows/columns **/
$reader->setReadFilter($chunkFilter)
->setContiguous(true);
/** Instantiate a new Spreadsheet object manually **/
$spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
/** Set a sheet index **/
$sheet = 0;
/** Loop to read our worksheet in "chunk size" blocks **/
/** $startRow is set to 2 initially because we always read the headings in row #1 **/
for ($startRow = 2; $startRow <= 1000000; $startRow += $chunkSize) {
/** Tell the Read Filter which rows we want to read this loop **/
$chunkFilter->setRows($startRow,$chunkSize);
/** Increment the worksheet index pointer for the Reader **/
$reader->setSheetIndex($sheet);
/** Load only the rows that match our filter into a new worksheet **/
$reader->loadIntoExisting($inputFileName,$spreadsheet);
/** Set the worksheet title for the sheet that we've justloaded) **/
/** and increment the sheet index as well **/
$spreadsheet->getActiveSheet()->setTitle('Country Data #'.(++$sheet));
}
```
See `samples/Reader/14_Reading_a_large_CSV_file_in_chunks_to_split_across_multiple_worksheets.php`
for a working example of this code.
This code will read 65,530 rows at a time from the CSV file that were
loading, and store each "chunk" in a new worksheet.
The `setContiguous()` method for the Reader is important here. It is
applicable only when working with a Read Filter, and identifies whether
or not the cells should be stored by their position within the CSV file,
or their position relative to the filter.
For example, if the filter returned true for cells in the range B2:C3,
then with setContiguous set to false (the default) these would be loaded
as B2:C3 in the `Spreadsheet` object; but with setContiguous set to
true, they would be loaded as A1:B2.
Splitting a single loaded file across multiple worksheets applies to:
Reader | Y/N |Reader | Y/N |Reader | Y/N |
----------|:---:|--------|:---:|--------------|:---:|
Xlsx | NO | Xls | NO | Xml | NO |
Ods | NO | SYLK | NO | Gnumeric | NO |
CSV | YES | HTML | NO
### Pipe or Tab Separated Value Files
The CSV loader will attempt to auto-detect the separator used in the file. If it
cannot auto-detect, it will default to the comma. If this does not fit your
use-case, you can manually specify a separator by using the `setDelimiter()`
method.
``` php
$inputFileType = 'Csv';
$inputFileName = './sampleData/example1.tsv';
/** Create a new Reader of the type defined in $inputFileType **/
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
/** Set the delimiter to a TAB character **/
$reader->setDelimiter("\t");
// $reader->setDelimiter('|');
/** Load the file to a Spreadsheet Object **/
$spreadsheet = $reader->load($inputFileName);
```
See `samples/Reader/15_Simple_file_reader_for_tab_separated_value_file_using_the_Advanced_Value_Binder.php`
for a working example of this code.
In addition to the delimiter, you can also use the following methods to
set other attributes for the data load:
Method | Default
-------------------|----------
setEnclosure() | `"`
setInputEncoding() | `UTF-8`
Setting CSV delimiter applies to:
Reader | Y/N |Reader | Y/N |Reader | Y/N |
----------|:---:|--------|:---:|--------------|:---:|
Xlsx | NO | Xls | NO | Xml | NO |
Ods | NO | SYLK | NO | Gnumeric | NO |
CSV | YES | HTML | NO
### A Brief Word about the Advanced Value Binder
When loading data from a file that contains no formatting information,
such as a CSV file, then data is read either as strings or numbers
(float or integer). This means that PhpSpreadsheet does not
automatically recognise dates/times (such as `16-Apr-2009` or `13:30`),
booleans (`true` or `false`), percentages (`75%`), hyperlinks
(`https://www.example.com`), etc as anything other than simple strings.
However, you can apply additional processing that is executed against
these values during the load process within a Value Binder.
A Value Binder is a class that implement the
`\PhpOffice\PhpSpreadsheet\Cell\IValueBinder` interface. It must contain a
`bindValue()` method that accepts a `\PhpOffice\PhpSpreadsheet\Cell\Cell` and a
value as arguments, and return a boolean `true` or `false` that indicates
whether the workbook cell has been populated with the value or not. The
Advanced Value Binder implements such a class: amongst other tests, it
identifies a string comprising "TRUE" or "FALSE" (based on locale
settings) and sets it to a boolean; or a number in scientific format
(e.g. "1.234e-5") and converts it to a float; or dates and times,
converting them to their Excel timestamp value before storing the
value in the cell object. It also sets formatting for strings that are
identified as dates, times or percentages. It could easily be extended
to provide additional handling (including text or cell formatting) when
it encountered a hyperlink, or HTML markup within a CSV file.
So using a Value Binder allows a great deal more flexibility in the
loader logic when reading unformatted text files.
``` php
/** Tell PhpSpreadsheet that we want to use the Advanced Value Binder **/
\PhpOffice\PhpSpreadsheet\Cell\Cell::setValueBinder( new \PhpOffice\PhpSpreadsheet\Cell\AdvancedValueBinder() );
$inputFileType = 'Csv';
$inputFileName = './sampleData/example1.tsv';
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
$reader->setDelimiter("\t");
$spreadsheet = $reader->load($inputFileName);
```
See `samples/Reader/15_Simple_file_reader_for_tab_separated_value_file_using_the_Advanced_Value_Binder.php`
for a working example of this code.
Loading using a Value Binder applies to:
Reader | Y/N |Reader | Y/N |Reader | Y/N
----------|:---:|--------|:---:|--------------|:---:
Xlsx | NO | Xls | NO | Xml | NO
Ods | NO | SYLK | NO | Gnumeric | NO
CSV | YES | HTML | YES
## Error Handling
Of course, you should always apply some error handling to your scripts
as well. PhpSpreadsheet throws exceptions, so you can wrap all your code
that accesses the library methods within Try/Catch blocks to trap for
any problems that are encountered, and deal with them in an appropriate
manner.
The PhpSpreadsheet Readers throw a
`\PhpOffice\PhpSpreadsheet\Reader\Exception`.
``` php
$inputFileName = './sampleData/example-1.xls';
try {
/** Load $inputFileName to a Spreadsheet Object **/
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($inputFileName);
} catch(\PhpOffice\PhpSpreadsheet\Reader\Exception $e) {
die('Error loading file: '.$e->getMessage());
}
```
See `samples/Reader/16_Handling_loader_exceptions_using_TryCatch.php` for a
working example of this code.
## Helper Methods
You can retrieve a list of worksheet names contained in a file without
loading the whole file by using the Readers `listWorksheetNames()`
method; similarly, a `listWorksheetInfo()` method will retrieve the
dimensions of worksheet in a file without needing to load and parse the
whole file.
### listWorksheetNames
The `listWorksheetNames()` method returns a simple array listing each
worksheet name within the workbook:
``` php
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
$worksheetNames = $reader->listWorksheetNames($inputFileName);
echo '<h3>Worksheet Names</h3>';
echo '<ol>';
foreach ($worksheetNames as $worksheetName) {
echo '<li>', $worksheetName, '</li>';
}
echo '</ol>';
```
See `samples/Reader/18_Reading_list_of_worksheets_without_loading_entire_file.php`
for a working example of this code.
### listWorksheetInfo
The `listWorksheetInfo()` method returns a nested array, with each entry
listing the name and dimensions for a worksheet:
``` php
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
$worksheetData = $reader->listWorksheetInfo($inputFileName);
echo '<h3>Worksheet Information</h3>';
echo '<ol>';
foreach ($worksheetData as $worksheet) {
echo '<li>', $worksheet['worksheetName'], '<br />';
echo 'Rows: ', $worksheet['totalRows'],
' Columns: ', $worksheet['totalColumns'], '<br />';
echo 'Cell Range: A1:',
$worksheet['lastColumnLetter'], $worksheet['totalRows'];
echo '</li>';
}
echo '</ol>';
```
See `samples/Reader/19_Reading_worksheet_information_without_loading_entire_file.php`
for a working example of this code.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,45 @@
# Configuration Settings
Once you have included the PhpSpreadsheet files in your script, but
before instantiating a `Spreadsheet` object or loading a workbook file,
there are a number of configuration options that can be set which will
affect the subsequent behaviour of the script.
## Cell collection caching
By default, PhpSpreadsheet holds all cell objects in memory, but
you can specify alternatives to reduce memory consumption at the cost of speed.
Read more about [memory saving](./memory_saving.md).
To enable cell caching, you must provide your own implementation of cache like so:
``` php
$cache = new MyCustomPsr16Implementation();
\PhpOffice\PhpSpreadsheet\Settings::setCache($cache);
```
## Language/Locale
Some localisation elements have been included in PhpSpreadsheet. You can
set a locale by changing the settings. To set the locale to Brazilian
Portuguese you would use:
``` php
$locale = 'pt_br';
$validLocale = \PhpOffice\PhpSpreadsheet\Settings::setLocale($locale);
if (!$validLocale) {
echo 'Unable to set locale to ' . $locale . " - reverting to en_us" . PHP_EOL;
}
```
- If Brazilian Portuguese language files aren't available, then Portuguese
will be enabled instead
- If Portuguese language files aren't available,
then the `setLocale()` method will return an error, and American English
(en\_us) settings will be used throughout.
More details of the features available once a locale has been set,
including a list of the languages and locales currently supported, can
be found in [Locale Settings for
Formulae](./recipes.md#locale-settings-for-formulae).

View File

@ -0,0 +1,130 @@
# Worksheets
A worksheet is a collection of cells, formulae, images, graphs, etc. It
holds all data necessary to represent a spreadsheet worksheet.
When you load a workbook from a spreadsheet file, it will be loaded with
all its existing worksheets (unless you specified that only certain
sheets should be loaded). When you load from non-spreadsheet files (such
as a CSV or HTML file) or from spreadsheet formats that don't identify
worksheets by name (such as SYLK), then a single worksheet called
"WorkSheet1" will be created containing the data from that file.
When you instantiate a new workbook, PhpSpreadsheet will create it with
a single worksheet called "WorkSheet1".
The `getSheetCount()` method will tell you the number of worksheets in
the workbook; while the `getSheetNames()` method will return a list of
all worksheets in the workbook, indexed by the order in which their
"tabs" would appear when opened in MS Excel (or other appropriate
Spreadsheet program).
Individual worksheets can be accessed by name, or by their index
position in the workbook. The index position represents the order that
each worksheet "tab" is shown when the workbook is opened in MS Excel
(or other appropriate Spreadsheet program). To access a sheet by its
index, use the `getSheet()` method.
``` php
// Get the second sheet in the workbook
// Note that sheets are indexed from 0
$spreadsheet->getSheet(1);
```
If you don't specify a sheet index, then the first worksheet will be
returned.
Methods also exist allowing you to reorder the worksheets in the
workbook.
To access a sheet by name, use the `getSheetByName()` method, specifying
the name of the worksheet that you want to access.
``` php
// Retrieve the worksheet called 'Worksheet 1'
$spreadsheet->getSheetByName('Worksheet 1');
```
Alternatively, one worksheet is always the currently active worksheet,
and you can access that directly. The currently active worksheet is the
one that will be active when the workbook is opened in MS Excel (or
other appropriate Spreadsheet program).
``` php
// Retrieve the current active worksheet
$spreadsheet->getActiveSheet();
```
You can change the currently active sheet by index or by name using the
`setActiveSheetIndex()` and `setActiveSheetIndexByName()` methods.
## Adding a new Worksheet
You can add a new worksheet to the workbook using the `createSheet()`
method of the `Spreadsheet` object. By default, this will be created as
a new "last" sheet; but you can also specify an index position as an
argument, and the worksheet will be inserted at that position, shuffling
all subsequent worksheets in the collection down a place.
``` php
$spreadsheet->createSheet();
```
A new worksheet created using this method will be called
"Worksheet&lt;n&gt;" where "&lt;n&gt;" is the lowest number possible to
guarantee that the title is unique.
Alternatively, you can instantiate a new worksheet (setting the title to
whatever you choose) and then insert it into your workbook using the
`addSheet()` method.
``` php
// Create a new worksheet called "My Data"
$myWorkSheet = new \PhpOffice\PhpSpreadsheet\Worksheet($spreadsheet, 'My Data');
// Attach the "My Data" worksheet as the first worksheet in the Spreadsheet object
$spreadsheet->addSheet($myWorkSheet, 0);
```
If you don't specify an index position as the second argument, then the
new worksheet will be added after the last existing worksheet.
## Copying Worksheets
Sheets within the same workbook can be copied by creating a clone of the
worksheet you wish to copy, and then using the `addSheet()` method to
insert the clone into the workbook.
``` php
$clonedWorksheet = clone $spreadsheet->getSheetByName('Worksheet 1');
$clonedWorksheet->setTitle('Copy of Worksheet 1');
$spreadsheet->addSheet($clonedWorksheet);
```
You can also copy worksheets from one workbook to another, though this
is more complex as PhpSpreadsheet also has to replicate the styling
between the two workbooks. The `addExternalSheet()` method is provided for
this purpose.
$clonedWorksheet = clone $spreadsheet1->getSheetByName('Worksheet 1');
$spreadsheet->addExternalSheet($clonedWorksheet);
In both cases, it is the developer's responsibility to ensure that
worksheet names are not duplicated. PhpSpreadsheet will throw an
exception if you attempt to copy worksheets that will result in a
duplicate name.
## Removing a Worksheet
You can delete a worksheet from a workbook, identified by its index
position, using the `removeSheetByIndex()` method
``` php
$sheetIndex = $spreadsheet->getIndex(
$spreadsheet->getSheetByName('Worksheet 1')
);
$spreadsheet->removeSheetByIndex($sheetIndex);
```
If the currently active worksheet is deleted, then the sheet at the
previous index position will become the currently active sheet.