Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory exhausted while load blank excel which the first column setDataValidation with a column range #797

Closed
yhdban opened this issue Dec 3, 2018 · 5 comments · Fixed by #4240

Comments

@yhdban
Copy link

yhdban commented Dec 3, 2018

I has a blank excel file which the first column setDataValidation with a column range.
then when use phpoffice/phpspreadsheet 1.5.2 to load the file, code as follows.

$phpReader = IOFactory::createReader('Xlsx');
$excel = $phpReader->load('D:\\develop\\test.xlsx');

What is the current behavior?

Apache record error log as follows 
Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to allocate 64 bytes) in phpoffice\phpspreadsheet\src\PhpSpreadsheet\Cell\Coordinate.php on line 336
@yhdban
Copy link
Author

yhdban commented Dec 3, 2018

test.xlsx

@yhdban
Copy link
Author

yhdban commented Dec 11, 2018

I chage the data validation code in \PhpOffice\PhpSpreadsheet\Reader\Xlsx.php as follow:

if ($xmlSheet && $xmlSheet->dataValidations && !$this->readDataOnly) {
	foreach ($xmlSheet->dataValidations->dataValidation as $dataValidation) {
		$docValidation = new DataValidation();
		$docValidation->setType((string) $dataValidation['type']);
		$docValidation->setErrorStyle((string) $dataValidation['errorStyle']);
		$docValidation->setOperator((string) $dataValidation['operator']);
		$docValidation->setAllowBlank($dataValidation['allowBlank'] != 0);
		$docValidation->setShowDropDown($dataValidation['showDropDown'] == 0);
		$docValidation->setShowInputMessage($dataValidation['showInputMessage'] != 0);
		$docValidation->setShowErrorMessage($dataValidation['showErrorMessage'] != 0);
		$docValidation->setErrorTitle((string) $dataValidation['errorTitle']);
		$docValidation->setError((string) $dataValidation['error']);
		$docValidation->setPromptTitle((string) $dataValidation['promptTitle']);
		$docValidation->setPrompt((string) $dataValidation['prompt']);
		$docValidation->setFormula1((string) $dataValidation->formula1);
		$docValidation->setFormula2((string) $dataValidation->formula2);
		$docSheet->setDataValidation(str_replace('$', '', $dataValidation['sqref']), $docValidation);
	}
}

@stale
Copy link

stale bot commented Feb 9, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
If this is still an issue for you, please try to help by debugging it further and sharing your results.
Thank you for your contributions.

@stale stale bot added the stale label Feb 9, 2019
@stale stale bot closed this as completed Feb 16, 2019
@huelsgp27
Copy link

same issue

<dataValidation type="list" allowBlank="1" showInputMessage="1" showErrorMessage="1" sqref="N\$1:N\$1048576"> <formula1>&quot;A, B, C&quot;</formula1> </dataValidation>

@oleibman
Copy link
Collaborator

I have some ideas here. It may require a breaking change.

@oleibman oleibman reopened this Nov 16, 2024
@stale stale bot removed the stale label Nov 16, 2024
oleibman added a commit to oleibman/PhpSpreadsheet that referenced this issue Nov 24, 2024
Fix PHPOffice#797 (marked stale in 2018, but now reopened). Fix PHPOffice#4091. DataValidation is specified in the Xml at the sheet level rather than the cell level. PhpSpreadsheet, however, currently requires a cell and a data validation object for each cell in a range. As a consequence, it may exhaust memory allocating objects that are never really needed. If it reads a spreadsheet which applies DataValidation to an entire column, the reader creates a million cells and a million DataValidation objects. An additional problem is that, when it saves the spreadsheet, it creates a row entry for each of the million rows even if they contain no data.

The code is changed to locate DataValidation for a cell by running the DataValidation list to see if the Sqref for any entry matches the cell in question. This eliminates the need to require a DataValidation entry for each cell; indeed, it eliminates the need to create a cell just because it is subject to DataValidation. Initial tests are very encouraging. The memory-exhausting spreadsheet from 797 required over 1GB of memory. With this change in place, that is reduced to 6MB, and DataValidation works as expected for all cells in the range.

This change is a work in progress. It needs formal tests. I need to see how it works with inserting or removing rows and columns. I need to see how Excel handles conflicting entries. My early tests indicate that it at least doesn't do anything irrational (like claiming corruption) when dealing with conflicts. It appears that, if I have a DataValidation applied to column A, and another applied to cell A5, whichever appears first in the Xml is the ultimate arbiter of what rule applies to A5.

If this change is merged, it will be a breaking range. It will require a new major release (probably PhpSpreadsheet 4.0), and will not happen for at least a couple of months, and probably later.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.

3 participants