PHPOffice/PhpSpreadsheet 10002
A pure PHP library for reading and writing spreadsheet files
Shared components between all PHPOffice projects
ARCHIVED
A pure PHP library for reading and writing spreadsheet files
A pure PHP library for reading and writing word processing documents
issue openedPHPOffice/PhpSpreadsheet
PPMT() function should not asserts that rate is a positive number
This is:
- [x] a bug report
What is the expected behavior?
In an native excel, the =PPMT (rate, per, nper, pv, [fv], [type]) function allows rate parameter to be a negative value.

What is the current behavior?
The changes added in this commit/line now trigger error when calculating value of the PPMT function when negative rate value is given to it.
I have to admit that I'm not an expert on what the PPMT function does and how it is meant to be used but we have a lot of excel files from experts in the financial industry and they seem to use a negative rate value in this function which now causes our app to crash.
My proposed solution is to simply remove that one line of validation which will make PHPOffice/PhpSpreadsheet behave consistently with native excel.
Which versions of PhpSpreadsheet and PHP are affected?
Effected PhpSpreadsheet version: 1.18.0 and higher
created time in 2 hours
issue commentPHPOffice/PhpSpreadsheet
restore explicit list of changes to PHPExcel migration document
Thanks you so much @nschulzke for highlighting this issue. I ran into a similar problem as I was trying to migrate my code using rector. I had to manually review each line of code which was calling the function setCellValueByColumnAndRow() and increment all my indices +1 in order to make it work.
It would be great to specify in the API doc that indices in now start from 1 and not from 0.
comment created time in 3 hours
pull request commentPHPOffice/PhpSpreadsheet
Xlsx Reader Better Namespace Handling Phase 1
Don't go ahead! Those merge conflicts need resolution first; I've tried manually resolving them once already, and ended up with a slew of errors. I'll have another go later, and try to identify what the actual problems are with the merge
comment created time in 5 hours
issue commentPHPOffice/PhpSpreadsheet
Looking at the chart1.xml (after unzipping the sheet) the main items missing completely are the DataSeriesLables. For example
<c:f>Worksheet!$B$3</c:f><c:strCache><c:ptCount val="1"/><c:pt idx="0"><c:v>Course Minutes</c:v></c:pt></c:strCache></c:strRef></c:tx><c:invertIfNegative val="0"/><c:cat><c:strRef>
The $xAxisTickValues are there but missing their values
The rest of the .xml looks ok although series data xml ends with <c:tx><c:strRef> on the good chart but <c:invertIfNegative val="0"/><c:val><c:numRef> when the spreadsheet has multiple worksheets which may or may not be relevant.
comment created time in 7 hours
pull request commentPHPOffice/PhpSpreadsheet
Fix for #2149 / Read data validations for drop down list in another sheet.
Thank you for this contribution: it may be reworked a bit as we work with the handling of namespaces in Xlsx files
comment created time in 7 hours
push eventPHPOffice/PhpSpreadsheet
commit sha 803737a893ef6e8b2b46050577e83453e774e223
Fix for #2149 / Read data validations for drop down list in another sheet. (#2150) * Read data validations for drop down list in another sheet. * Add function testLoadXlsxDataValidationOfAnotherSheet() in class tests/PhpSpreadsheetTests/Reader/XlsxTest.php for unit test. * Add sample xlsx for unit tests. * Modifiy call function isset() for warnings. * Additional assertions to ensure that the worksheet has been read correctly for DataValidation that references a list on a different worksheet * This should resolve the phpstan issues Co-authored-by: Mark Baker <[email protected]>
push time in 7 hours
PR merged PHPOffice/PhpSpreadsheet
This is:
- [x] a bugfix
- [ ] a new feature
Checklist:
- [x] Changes are covered by unit tests
- [x] Code style is respected
- [x] Commit message explains why the change is made (see https://github.com/erlang/otp/wiki/Writing-good-commit-messages)
- [ ] CHANGELOG.md contains a short summary of the change
- [ ] Documentation is updated as necessary
Why this change is needed?
This modification makes it possible to read the drop-down lists linked to other sheets. See issue #2149
pr closed time in 7 hours
pull request commentPHPOffice/PhpSpreadsheet
Fix for #2149 / Read data validations for drop down list in another sheet.
I've added some more assertions to verify that the list address is correctly loaded with the worksheet name, and resolved the phpstan issue
comment created time in 8 hours
issue openedPHPOffice/PhpSpreadsheet
This is:
- [x] a bug report
- [ ] a feature request
- [ ] **not** a usage question (ask them on https://stackoverflow.com/questions/tagged/phpspreadsheet or https://gitter.im/PHPOffice/PhpSpreadsheet)
What is the expected behavior?
Creating charts with multiple worksheets should not be different from creating charts with just one worksheet
What is the current behavior?
I can create one or 2 charts happily so long as I stick to the first worksheet, but as soon as I add multiple worksheets the charts written are corrupted or just blank.
What are the steps to reproduce?
Please provide a Minimal, Complete, and Verifiable example of code that exhibits the issue without relying on an external Excel file or a web server:
If you run the code below with $stickToOneSheet set to true, the code runs fine.
There are several options for adding a worksheet and 2 (different?) $writers and none of them produce working charts if there is more than one worksheet.
<?php
require __DIR__ . '/vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Chart\Legend;
use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
use PhpOffice\PhpSpreadsheet\Chart\Title;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
$stickToOneSheet = true;
$useNewWriterFactory = false;
$cloneNewWorksheet = true; // Only relevant if multiple sheets
$multipleCharts = true;
$title = 'newworksheet';
$spreadsheet = new Spreadsheet();
if ($stickToOneSheet) {
$worksheet = $spreadsheet->getActiveSheet();
} elseif ($cloneNewWorksheet) {
$worksheet1 = $spreadsheet->getActiveSheet();
$worksheet = clone $worksheet1;
$worksheet->setTitle($title);
$spreadsheet->addSheet($worksheet,1);
} elseif ($useNewWriterFactory) {
$worksheet = new Worksheet($spreadsheet, $title);
$spreadsheet->addSheet($worksheet,1);
} else {
echo "Sorry, no idea what you want to test";
die;
}
// Todo generate data in this format
$data = [ // Note this data need to be transposed
['Tutor Dashboard Report for [email protected]'],
[''],
['','Course Minutes','Quiz Minutes','Book Minutes','Other Minutes','Panopto Minutes','Total Minutes', 'Graded Activities', '# Vidoes Watched', '# Watched Completely', 'Quartile Rank'],
['Sep20',22,23,65,60,37,256,2,3,2,1],
['Oct20',18,39,47,68,38,256,2,3,2,1],
['Nov20',12,15,43,67,38,256,4,3,2,3],
['Dec20',4,1,154,0,21,256,2,3,2,1],
['Jan21',22,15,38,18,10,256,4,4,2,4],
['Feb21',18,39,47,68,38,256,2,3,2,1],
['Mar21',12,15,43,67,38,256,2,5,2,1],
['Apr21',4,1,154,14,21,256,2,1,1,1],
['May21',18,39,47,68,38,256,2,3,2,2],
];
$worksheet->fromArray($data);
$num_columns = count($data[2]);
$num_rows = count($data)-3;
echo "\n\nColumns: $num_columns, Rows: $num_rows\n\n";
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
//Todo set start values to calculations
$dataSeriesLabels = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$3', null, 1), // Course
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$3', null, 1), // Quiz
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$3', null, 1), // Books
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$E$3', null, 1), // Other
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$F$3', null, 1), // Panopto
];
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$xAxisTickValues = [
//Todo set values to calculations
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$4:$A$12', null, 4), // Q1 to Q4
];
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
//Todo set start and end values to calculations
$dataSeriesValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$4:$B$12', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$4:$C$12', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$4:$D$12', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$E$4:$E$12', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$F$4:$F$12', null, 4),
];
// Build the dataseries
$series = new DataSeries(
DataSeries::TYPE_BARCHART, // plotType
DataSeries::GROUPING_STACKED, // plotGrouping
range(0, count($dataSeriesValues) - 1), // plotOrder
$dataSeriesLabels, // plotLabel
$xAxisTickValues, // plotCategory
$dataSeriesValues // plotValues
);
// Set additional dataseries parameters
// Make it a vertical column rather than a horizontal bar graph
$series->setPlotDirection(DataSeries::DIRECTION_COL);
// Set the series in the plot area
$plotArea = new PlotArea(null, [$series]);
// Set the chart legend
$legend = new Legend(Legend::POSITION_RIGHT, null, false);
$title = new Title('Tutor Dashboard - [email protected]'); // Todo add student email
$yAxisLabel = new Title('Learning Minutes');
// Create the chart
$chart = new Chart(
'chart1', // name
$title, // title
$legend, // legend
$plotArea, // plotArea
true, // plotVisibleOnly
DataSeries::EMPTY_AS_GAP, // displayBlanksAs
null, // xAxisLabel
$yAxisLabel // yAxisLabel
);
// Set the position where the chart should appear in the worksheet
$chart->setTopLeftPosition('A'.($num_rows + 7));
$chart->setBottomRightPosition('M'.($num_rows + 22));
// Add the chart to the worksheet
$worksheet->addChart($chart);
if ($multipleCharts) {
// OK, try adding another chart!
$dataSeriesLabels2 = [
//new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$G$3', null, 1), // Total Minutes - ignore!
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$H$3', null, 1), // Graded Activities
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$I$3', null, 1), // Videos Watched
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$J$3', null, 1), // Watched Completely
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$K$3', null, 1), // Quartile Ranking
];
$xAxisTickValues2 = [
//Todo set values to calculations
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$4:$A$12', null, 4), // Q1 to Q4
];
//Todo set start and end values to calculations
$dataSeriesValues2 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$H$4:$H$12', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$I$4:$I$12', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$J$4:$J$12', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$K$4:$K$12', null, 4),
//new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$F$4:$F$12', null, 4),
];
// Build the dataseries
$series2 = new DataSeries(
DataSeries::TYPE_BARCHART, // plotType
DataSeries::GROUPING_CLUSTERED, // plotGrouping
range(0, count($dataSeriesValues2) - 1), // plotOrder
$dataSeriesLabels2, // plotLabel
$xAxisTickValues2, // plotCategory
$dataSeriesValues2 // plotValues
);
// Set additional dataseries parameters
// Make it a vertical column rather than a horizontal bar graph
$series2->setPlotDirection(DataSeries::DIRECTION_COL);
// Set the series in the plot area
$plotArea2 = new PlotArea(null, [$series2]);
// Set the chart legend
$legend2 = new Legend(Legend::POSITION_RIGHT, null, false);
$title2 = new Title('Graded Activities, Videos Watched, and Quartile Ranking'); // Todo add student email
$yAxisLabel2 = new Title('Number of Each');
$chart2 = new Chart(
'chart2', // name
$title2, // title
$legend2, // legend
$plotArea2, // plotArea
true, // plotVisibleOnly
DataSeries::EMPTY_AS_GAP, // displayBlanksAs
null, // xAxisLabel
$yAxisLabel2 // yAxisLabel
);
// Set the position where the chart should appear in the worksheet
$chart2->setTopLeftPosition('A' . ($num_rows + 29));
$chart2->setBottomRightPosition('M' . ($num_rows + 44));
// Add the chart to the worksheet
$worksheet->addChart($chart2);
}
// Save Excel file
$filename = "test_col1_stacked_7.xlsx";
if ($useNewWriterFactory) {
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
} else {
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
}
$writer->setIncludeCharts(true);
$callStartTime = microtime(true);
$writer->save($filename);
return 0;
// add code that show the issue here...
$stickToOneSheet = false; // Change the code above and the charts will not have visible data or be corrupted.
Which versions of PhpSpreadsheet and PHP are affected?
PHP 7.4.12 Phpspreadsheet versions 1.16 and 1.18 Excel version 2105 build 14026...
created time in 8 hours
push eventPHPOffice/PhpSpreadsheet
commit sha 1e74282259c325d575cf1afb453d490419b84ccc
Fix for Issue 2158 (AverageIf Calculation Problem) (#2160) * Improve Identification of Samples in Coverage Report The Phpunit coverage report currently contains bullet items like `PhpOffice\PhpSpreadsheetTests\Helper\SampleTest\testSample with data set "49"`. This extremely simple change takes advantage of Phpunit's ability to accept an array with keys which are either strings or integers, by using the sample filenames as the array keys rather than sequential but otherwise meaningless integers (e.g. `49` in the earlier cited item). The bullet item will now read `PhpOffice\PhpSpreadsheetTests\Helper\SampleTest\testSample with data set "Basic/38_Clone_worksheet.php"`. * Fix for Issue 2158 (AverageIf Calculation Problem) Issue #2158 reports an error calculating AverageIf because a function returns null rather than a string. There turn out to be several components to this problem: - The nominal fix to the problem is to add some null-to-nullstring coercion in DatabaseAbstract. - This fixes the error, but does not necessarily lead to the correct result because buildQuery treats values of null and null-string identically, whereas Excel does not. So change that to treat null-string as any other string. - But that doesn't lead to the correct result either. That's because Functions/ifCondition recognizes a null string, but then continues to (over-)process it until it returns the wrong result. Fix this problem in conjunction with the other two, and we finally get the correct result. A new unit test is added for AVERAGEIF, and new test cases are added for SUMIF. In each case, there are complementary tests for conditions of null and null-string, and the results agree with Excel. There may or may not be value in adding new tests to other functions, and I will be glad to do so for any functions which you care to identify, but no existing tests broke as a result of these changes.
push time in 11 hours
PR merged PHPOffice/PhpSpreadsheet
This is:
- [x] a bugfix
- [ ] a new feature
Checklist:
- [x] Changes are covered by unit tests
- [x] Code style is respected
- [x] Commit message explains why the change is made (see https://github.com/erlang/otp/wiki/Writing-good-commit-messages)
- [ ] CHANGELOG.md contains a short summary of the change
- [ ] Documentation is updated as necessary
Why this change is needed?
Issue #2158 reports an error calculating AverageIf because a function returns null rather than a string. There turn out to be several components to this problem:
- The nominal fix to the problem is to add some null-to-nullstring coercion in DatabaseAbstract.
- This fixes the error, but does not necessarily lead to the correct result because buildQuery treats values of null and null-string identically, whereas Excel does not. So change that to treat null-string as any other string.
- But that doesn't lead to the correct result either. That's because Functions/ifCondition recognizes a null string, but then continues to (over-)process it until it returns the wrong result. Fix this problem in conjunction with the other two, and we finally get the correct result.
A new unit test is added for AVERAGEIF, and new test cases are added for SUMIF. In each case, there are complementary tests for conditions of null and null-string, and the results agree with Excel. There may or may not be value in adding new tests to other functions, and I will be glad to do so for any functions which you care to identify, but no existing tests broke as a result of these changes.
pr closed time in 11 hours
issue commentPHPOffice/PhpSpreadsheet
The filename is not recognised as an OLE file
Hello Mark, thank you for the detailed explanation. I was wondering about the CDATA tags but makes sense they should be used in this case.
It might be possible to add a stream filter to the Xml Reader that would convert the HTML Entities to valid XML Entities before it's passed to simplexml_load_string(), but I'd have to investigate that further
Let me know if there is anything I can do to help.
comment created time in 12 hours
push eventPHPOffice/PhpSpreadsheet
commit sha 4f06d8424805e1ef00985128c522f3b2c1f017ca
TextData - Minor Changes, Test Coverage (#2151) * PHP8.1 Deprecation Passing Null to String Function For each of the files in this PR, one or more statements can pass a null to string functions like strlower. This is deprecated in PHP8.1, and, when deprecated messages are enabled, causes many tests to error out. In every case, use coercion to pass null string rather than null. * TextData - Minor Changes, Test Coverage Per agreement on a previous push, I looked into standardizing the initialization of the TextData functions (like Engineering and MathTrig), with particular regard for avoiding multiple later null coercions. This simplifies the code quite a bit. This PR also increases coverage to 100% for all TextData modules. All entries in Phpstan baseline for non-deprecated TEXTDATA functions are removed. There were some minor bugfixes. Whereas Excel (and Gnumeric) treat booleans when supplied as strings as 'TRUE' or 'FALSE', ODS treats them as '1' or '0'. Unlike Excel, ODS generally does not allow bool for int arguments; it does, however, allow them for FIND and SEARCH. ODS allows boolean for into for SUBSTITUTE even though Excel doesn't. ODS allows bool for string for NUMBERVALUE and VALUE even though Excel doesn't. ODS accepts 0 as an argument for CHAR; Excel doesn't. Most of this seems like random decisions on the part of the developers; I've done my best to follow the products in each case. There is a new test member devoted to ODS tests. Gnumeric has an anomaly vis-a-vis the others - if length is supplied to LEFT/MID/RIGHT as null, Gnumeric treats it as 0 rather than 1. All tests now take place in the context of a spreadsheet ... Except for RETURNSTRING, which is not the implementation of an Excel function, and is referred to in the rest of PhpSpreadsheet only in the unit tests for itself. It should probably be deprecated, but that is not part of this PR, just in case there is some reason for it that I couldn't discern. I have tried to make the first line of each doc block identify the Excel function name rather than its name in PhpSpreadsheet. I think it makes things more comprehensible. Some tests call Settings::setLocale, but there was no Settings::getLocale. At the end of the tests which do it, they invoke setLocale('EN-US'), which, in a practical sense, is sufficient. However, in theory it would be better for them to get the current locale before changing it, then changing it back to the original when the time came. I have added getLocale and made the appropriate testing change. The CHAR function took an interesting turn. One can set the value of a cell to, say, CHAR(2), the ASCII/UTF-8 representation of a control character, which is not legal in certain contexts. The only Reader/Writer that could handle this without problems is Xls, which deals with binary data all the time. However, if you tried to write it to Xlsx, Excel would not be able to open the resulting file because of what it considers an illegal character. I changed the Xlsx writer to escape such characters when writing the value of a string function. I did not make any other changes to the Xlsx writer - it seems to me that setting a cell to CHAR(2) is legitimate, but setting it to say `"\x02"` seems less likely to be legitimate, so the latter will still fail (although `="\x02"` should work). The Xlsx reader already supports the escape mechanism that I added to the writer. CHAR control character and Ods - not supported by either Reader or Writer. I did not attempt to add this now. There is lots still missing from ODS, and this item just can't be a high priority amongst all of those. CHAR control character and Csv - it is supported by reader and writer if the file has a csv extension. However, trying to guess the mime type without an extension - the control character makes mime_get_type guess application/octet-stream, and PhpSpreadsheet therefore thinks that Csv can't read it. CHAR control character and Html. Actual use of the control character in the file is subject to the same problems as Xml (i.e. Xlsx and Ods). It wasn't terribly difficult to get the Html Writer to change `"\x02"` to "``". I believe that this is technically legal; however, DOMDocument.loadHTML rejects it as an illegal entity, and I am not convinced that it is wrong to do so, so I haven't changed the Html writer. * Scrutinizer Correct 3 minor errors.
push time in 12 hours
PR merged PHPOffice/PhpSpreadsheet
This is:
- [x] a bugfix (minor)
- [ ] a new feature
- [x] code cleanup
Checklist:
- [x] Changes are covered by unit tests
- [x] Code style is respected
- [x] Commit message explains why the change is made (see https://github.com/erlang/otp/wiki/Writing-good-commit-messages)
- [ ] CHANGELOG.md contains a short summary of the change
- [ ] Documentation is updated as necessary
Why this change is needed?
Per agreement on a previous push, I looked into standardizing the initialization of the TextData functions (like Engineering and MathTrig), with particular regard for avoiding multiple later null coercions. This simplifies the code quite a bit. This PR also increases coverage to 100% for all TextData modules. All entries in Phpstan baseline for non-deprecated TEXTDATA functions are removed. There were some minor bugfixes.
Whereas Excel (and Gnumeric) treat booleans when supplied as strings as 'TRUE' or 'FALSE', ODS treats them as '1' or '0'. Unlike Excel, ODS generally does not allow bool for int arguments; it does, however, allow them for FIND and SEARCH. ODS allows boolean for into for SUBSTITUTE even though Excel doesn't. ODS allows bool for string for NUMBERVALUE and VALUE even though Excel doesn't. ODS accepts 0 as an argument for CHAR; Excel doesn't. Most of this seems like random decisions on the part of the developers; I've done my best to follow the products in each case. There is a new test member devoted to ODS tests.
Gnumeric has an anomaly vis-a-vis the others - if length is supplied to LEFT/MID/RIGHT as null, Gnumeric treats it as 0 rather than 1.
All tests now take place in the context of a spreadsheet ...
Except for RETURNSTRING, which is not the implementation of an Excel function, and is referred to in the rest of PhpSpreadsheet only in the unit tests for itself. It should probably be deprecated, but that is not part of this PR, just in case there is some reason for it that I couldn't discern.
I have tried to make the first line of each doc block identify the Excel function name rather than its name in PhpSpreadsheet. I think it makes things more comprehensible.
Some tests call Settings::setLocale, but there was no Settings::getLocale. At the end of the tests which do it, they invoke setLocale('EN-US'), which, in a practical sense, is sufficient. However, in theory it would be better for them to get the current locale before changing it, then changing it back to the original when the time came. I have added getLocale and made the appropriate testing change.
The CHAR function took an interesting turn. One can set the value of a cell to, say, CHAR(2), the ASCII/UTF-8 representation of a control character, which is not legal in certain contexts. The only Reader/Writer that could handle this without problems is Xls, which deals with binary data all the time. However, if you tried to write it to Xlsx, Excel would not be able to open the resulting file because of what it considers an illegal character. I changed the Xlsx writer to escape such characters when writing the value of a string function. I did not make any other changes to the Xlsx writer - it seems to me that setting a cell to CHAR(2) is legitimate, but setting it to say "\x02" seems less likely to be legitimate, so the latter will still fail (although ="\x02" should work). The Xlsx reader already supports the escape mechanism that I added to the writer.
CHAR control character and Ods - not supported by either Reader or Writer. I did not attempt to add this now. There is lots still missing from ODS, and this item just can't be a high priority amongst all of those.
CHAR control character and Csv - it is supported by reader and writer if the file has a csv extension. However, trying to guess the mime type without an extension - the control character makes mime_get_type guess application/octet-stream, and PhpSpreadsheet therefore thinks that Csv can't read it.
CHAR control character and Html. Actual use of the control character in the file is subject to the same problems as Xml (i.e. Xlsx and Ods). It wasn't terribly difficult to get the Html Writer to change "\x02" to "". I believe that this is technically legal; however, DOMDocument.loadHTML rejects it as an illegal entity, and I am not convinced that it is wrong to do so, so I haven't changed the Html writer.
pr closed time in 12 hours
issue commentPHPOffice/PhpSpreadsheet
I just started work on the absolute basics of Pivot Tables for the Xlsx Reader/Writer two weeks ago... at the moment, I have some very simplistic code that just allows the pivot table to be read and written, without any form of editing or access to the data, just so that it won't get lost in a read/write; but that doesn't handle pivot tables that have any form of customisation (even something as basic as a custom style will trigger errors on the save) It's likely to take several months of work to get something robust enough to merge, and that depends how much time I get to work on it over the Summer.
comment created time in a day
issue commentPHPOffice/PhpSpreadsheet
Correct... none of the Readers support dynamic tables like pivot tables. That is something we are currently investigating
Thanks in advance. I think it's a very important function because I need to integrate with some softwares, for example, Microsoft Dynamics NAV (from Rapid Start).
I need to use https://products.aspose.app/cells/editor to keep Dynamic Tables.
Are you working on that? It will take long time?
Thanks in advance.
comment created time in a day
issue commentPHPOffice/PhpSpreadsheet
Correct... none of the Readers support dynamic tables like pivot tables. That is something we are currently investigating
comment created time in a day
issue commentPHPOffice/PhpSpreadsheet
The filename is not recognised as an OLE file
The Xls Reader will not read the file, because it isn't an xls file (Just giving a file an extension of .xls doesn't make it an ls file), it isn't BIFF-format, but Xml as you note. This is why we provide the IOFactory's identify() method, to determine the correct Reader to use because files are commonly misnamed with the wrong extension for their actual file type. The identify() method looks at the basic content and structure of the file to determine what it really is, not simply what the extension claims it is. The load() method uses identify() to determine which Reader should be used,
The Xml Reader will not load it however, because it isn't valid Xml. Entities like ι as HTML Entities, but aren't Xml Entities. It would only be valid if those entities were actually defined in the file itself, or were used within CDATA blocks. And the file itself is UTF-8, so there is no need to use HTML Entities in the file at all. In practise, we disallow the definition of entities within the Xml that we load, because allowing Entity definition also allows XXE/XEE attacks.
Spreadsheet programs like Excel are clearly more forgiving, and will read this and convert the invalid HTML Entities. It might be possible to add a stream filter to the Xml Reader that would convert the HTML Entities to valid XML Entities before it's passed to simplexml_load_string(), but I'd have to investigate that further
comment created time in a day
issue openedPHPOffice/PhpSpreadsheet
This is:
- [ ] a bug report
- [ ] a feature request
- [ ] **not** a usage question (ask them on https://stackoverflow.com/questions/tagged/phpspreadsheet or https://gitter.im/PHPOffice/PhpSpreadsheet)
What is the expected behavior?
Open the excel file (.xlsx) with dynamic tables and save the same file with dynamic tables
What is the current behavior?
The spreadsheet opens the excel file and saves the file without dynamic tables. Only plain text.
What are the steps to reproduce?
Use reader fuction to open the file Force to readonly Define a worksheet Use writer function to save the file
Please provide a Minimal, Complete, and Verifiable example of code that exhibits the issue without relying on an external Excel file or a web server:
<?php
require __DIR__ . '/vendor/autoload.php';
// Create new Spreadsheet object
$spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
// add code that show the issue here...
$inputFileName = 'template-sample.xlsx';
$inputFileType = IOFactory::identify($inputFileName); $reader = IOFactory::createReader($inputFileType); $reader->setReadDataOnly(true); $spreadsheet = $reader->load($inputFileName);
$spreadsheet->setActiveSheetIndex(1);
$writer = IOFactory::createWriter($spreadsheet, "Xlsx"); $writer->save("template-test.xlsx");
Which versions of PhpSpreadsheet and PHP are affected?
1.18.0
created time in a day
issue commentPHPOffice/PhpSpreadsheet
HLookup::hLookupSearch(..) sends wrong arguments to LookupBase::checkMatch(..).
This is still and issue for us so I created a test excel sheet to demonstrate the problem.
Running this code:
$spreadsheet = IOFactory::load('./hlookup-test.xlsx');
$sheet = $spreadsheet->getSheet(0);
$cellVal = $sheet->getCell('H8')->getCalculatedValue();
On this excel spreadsheet: hlookup-test.xlsx

Results in:
TypeError {#3754
#message: "Argument 4 passed to PhpOffice\PhpSpreadsheet\Calculation\LookupRef\LookupBase::checkMatch() must be of the type int, string given, called in xxx/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/HLookup.php on line 74"
#code: 0
#file: "./vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/LookupBase.php"
#line: 25
trace: {
./vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/LookupBase.php:25 { …}
./vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/HLookup.php:74 { …}
./vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/LookupRef/HLookup.php:45 { …}
PhpOffice\PhpSpreadsheet\Calculation\LookupRef\HLookup::lookup() {}
./vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Calculation.php:4846 { …}
./vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Calculation.php:3539 { …}
./vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Calculation.php:3332 { …}
./vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Cell/Cell.php:259 { …}
./src/MyNamespace/Command/TestExcel.php:30 {
MyNamespace\Command\TestExcel->execute(InputInterface $input, OutputInterface $output): void
› $sheet = $spreadsheet->getSheet(0);
› $cellVal = $sheet->getCell('H8')->getCalculatedValue();
›
}
ping @MarkBaker let me know if I should provide any more information ;-)
comment created time in a day
issue openedPHPOffice/PhpSpreadsheet
Return Value Error - DatabaseAbstruct::buildQuery() return null but must be string
This is:
- [x] a bug report
What is the expected behavior?
DatabaseAbstruct::buildQuery() return string
What is the current behavior?
DatabaseAbstruct::buildQuery() return null but it must be string, throwed Return Value Error
What are the steps to reproduce?
An error occurs when I try to export a spreadsheet with the following formula,
=AVERAGEIF(A:A, "", B:B)
when a blank cell is specified in the search condition.
<?php
require __DIR__ . '/vendor/autoload.php';
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();
// Create new Spreadsheet object
$spreadSheet = $reader->load('example.xlsx');
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadSheet);
$writer->save('php://output'); // anywhere
// add code that show the issue here...
Which versions of PhpSpreadsheet and PHP are affected?
created time in a day
issue openedPHPOffice/PhpSpreadsheet
The filename is not recognised as an OLE file
This is:
- [x] a bug report
Not even sure if this is a bug report or a feature request as I could not find if this type of XLS file is supported.
What is the expected behavior?
PhpSpreadsheet to read the file as I can open it just fine in OpenOffice.
What is the current behavior?
Trying to read the file I get the error The filename products.xls is not recognised as an OLE file trying to read it as Xls. Trying to read it as Xml because the content is just XML, generates a lot of PHP warnings:
HP Warning: simplexml_load_string(): Entity: line 1261: parser error : Entity 'iota' not defined in /vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml.php on line 120
PHP Warning: simplexml_load_string(): Οι Κάνφιλντ και & in /vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml.php on line 120
PHP Warning: simplexml_load_string(): ^ in /vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml.php on line 120
PHP Warning: simplexml_load_string(): Entity: line 1261: parser error : Detected an entity reference loop in /vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml.php on line 120
PHP Warning: simplexml_load_string(): Οι Κάνφιλντ και & in /vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml.php on line 120
PHP Warning: simplexml_load_string(): ^ in /vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xml.php on line 120
What are the steps to reproduce?
The file used in this example: ProductsAPI-14-06-2021.xls
Please provide a Minimal, Complete, and Verifiable example of code that exhibits the issue without relying on an external Excel file or a web server:
This is trying to read it as XLS:
<?php
use PhpOffice\PhpSpreadsheet\IOFactory;
require __DIR__ . '/vendor/autoload.php';
$reader = IOFactory::createReader('Xls');
$reader->setLoadAllSheets();
$spreadsheet = $reader->load('products.xls');
This is trying to read it as XML:
<?php
use PhpOffice\PhpSpreadsheet\IOFactory;
require __DIR__ . '/vendor/autoload.php';
$reader = IOFactory::createReader('Xml');
$reader->setLoadAllSheets();
$spreadsheet = $reader->load('products.xls');
I have also tried it with this code:
<?php
use PhpOffice\PhpSpreadsheet\IOFactory;
require __DIR__ . '/vendor/autoload.php';
$excel = IOFactory::load('products.xls');
That results in the same output as trying to read it as an XML file above.
Which versions of PhpSpreadsheet and PHP are affected?
1.18.0
created time in a day
pull request commentPHPOffice/PhpSpreadsheet
Xlsx Reader Better Namespace Handling Phase 1
I'll take a look at lunchtime (CEST) but most of the merge conflicts seem to resolve around reading the date properties from the document, and a big conflict in XlsxTest.php
comment created time in a day
push eventPHPOffice/PhpSpreadsheet
commit sha 66cd68daeab53e921c65d77db4629a76cc233133
Update Change log
push time in 2 days
push eventPHPOffice/PhpSpreadsheet
commit sha 74b02fb31c9b3b72f7e1785ccfa19937bc1bea9f
Fix for the BIFF-8 Xls colour mappings in the Reader (#2156) * Fix for the BIFF-8 Xls colour mappings in the Reader * Unit test for reading colours, writing hen rereading and ensuring that the RGB values have not changed
push time in 2 days
PR merged PHPOffice/PhpSpreadsheet
This is:
- [X] a bugfix
- [ ] a new feature
Checklist:
- [ ] Changes are covered by unit tests
- [X] Code style is respected
- [X] Commit message explains why the change is made (see https://github.com/erlang/otp/wiki/Writing-good-commit-messages)
- [ ] CHANGELOG.md contains a short summary of the change
- [ ] Documentation is updated as necessary
Why this change is needed?
Resolve BIFF-8 colour map for the Xls reader. This should fix Issue #2147
pr closed time in 2 days
issue closedPHPOffice/PhpSpreadsheet
Changing grey background to black in Excel template
This is:
- [x] a bug report
- [ ] a feature request
- [ ] **not** a usage question (ask them on https://stackoverflow.com/questions/tagged/phpspreadsheet or https://gitter.im/PHPOffice/PhpSpreadsheet)
What is the expected behavior?
Not change the cell background color
What is the current behavior?
Grey background cells are changing to black
What are the steps to reproduce?
Create spreadsheet with grey background cells Use IOFactory::load to load the spreadsheet Use the Xls writer to write a new spreadsheet
Please provide a Minimal, Complete, and Verifiable example of code that exhibits the issue without relying on an external Excel file or a web server:
<?php
require __DIR__ . '/vendor/autoload.php';
$spreadsheet = IOFactory::load('input.xls');
$writer = new Xls($spreadsheet);
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename="output.xls"');
$writer->save('php://output');
Which versions of PhpSpreadsheet and PHP are affected?
Works fine in 1.16.0. I noticed it broke in 1.18.0. Didn't test 1.17.0. I did look closer and 1.16.0 has a different shade of grey than what is originally there, but it's not doing what the latest version is doing which turns it to black.
closed time in 2 days
keithslaterpush eventPHPOffice/PhpSpreadsheet
commit sha 716124ca6012e0642f6d768c0a5009c3fc4e3c07
Unit test for reading colours, writing hen rereading and ensuring that the RGB values have not changed
push time in 2 days
PR opened PHPOffice/PhpSpreadsheet
This is:
- [X] a bugfix
- [ ] a new feature
Checklist:
- [ ] Changes are covered by unit tests
- [X] Code style is respected
- [X] Commit message explains why the change is made (see https://github.com/erlang/otp/wiki/Writing-good-commit-messages)
- [ ] CHANGELOG.md contains a short summary of the change
- [ ] Documentation is updated as necessary
Why this change is needed?
Resolve BIFF-8 colour map for the Xls reader
pr created time in 3 days