Reader XML Properties - Eliminate strtotime (#2134)

* Document Properties - Coverage and 32-bit-safe Timestamps

While researching an issue, I noticed that coverage of Document/Properties was poor. Further, the use of int timestamps will eventually lead to problems for 32-bit PHP (see issue #1826).

Coverage Changes:
- Many property types with no special handling are enumerated but not tested. These are removed, but will continue to function as before.
- Existing code theoretically allows property to be set to an object, but there is no means to read or write such a property, and, even if there were, I don't believe Excel supports it. Setting a property to an object will now be changed to a no-op (can throw an exception if preferred).
- Since the Properties object now has no members which are themselves objects, there is no need for a deep clone. The untested __clone method is removed.
- Large switch statements are replaced with associative arrays. Scrutinizer will like that.
- Coverage is now 100%.

<!-- end of coverage changes list -->

Timestamp Changes:
- Timestamps will be stored as int if possible, or float if not. This is, or will soon be, needed for 32-bit systems. Tests have been added for beyond-epoch dates, and run successfully with 32-bit.
- LibreOffice doesn't quite get the Created/Modified properties correct. These are written to the file as a string which includes offset from UTC, but LibreOffice ignores the offset portion when displaying them. Code had been generating these in UTC, but now generates them in default timezone, which should meet user's expectations.

<!-- end of timestamp changes list -->

Other Changes:
- Custom properties added to ODS Writer.
- Samples had not been generating any ODS files. One is now generated.
- Ods uses a single 'keywords' property rather than multiple 'keyword' properties.
- Breaking change - default company is changed to null string from Microsoft Corporation.
- Breaking change of sorts - PropertiesTest incorrectly tested a custom date property against a string, Reader/XlsxTest correctly tested against a timestamp converted to a string. PropertiesTest was defective, and will no longer work as coded; anyone using it as a model will likewise have a problem.
- PHP8.1 has been complaining for weeks about a time zone conversion test. I have now downloaded a version, and changed the code so that it will work in 8.1 as well as prior releases. (It is still likely that the existing code should work in 8.1, but I haven't yet figured out how to file a bug report.) In the course of testing, 3 additional 8.1 problems were reported (all along the lines of "can't pass null to strpos"), and are fixed with null coercion.
- Two Calculation tests failed because of large results on 32-bit system. These are corrected by allowing the functions involved to return float|int rather than int. I suspect that there are other functions with this problem, and will investigate as a follow-up activity.
- See issue #2090. I believe that changes between 17.1 and master will merely cause the problematic spreadsheet to fail in a different way. I believe that enclosing in quotes some variables passed to Document/Properties by Reader/Xlsx will eliminate the problem, but, in the absence of an example file, cannot say for sure.
- Properties tests are now separated out from Reader/XlsxTest and Reader/OdsTest, and now test both Read and Write (via reload).

<!-- end of other changes list -->

Miscellaneous Notes:
- There remains no support for Custom Properties in Xls Reader or Writer.
- We now have default timezones for all of PHP itself, Shared/Date, and Shared/Timezone. That is least one too many. I was unable to disentangle the latter two for this change, but will look into deprecating one or the other in future.

* Phpstan

6 baseline deletions, 2 docblock changes

* Scrutinizer's Turn

3 minor errors that hadn't blocked the request.

* Reader XML Properties - Eliminate strtotime

Piggyback on top of prior changes to eliminate 32-bit-unsafe call.

Add explicit tests for created, modified, and custom date properties.
This commit is contained in:
oleibman 2021-05-31 02:04:07 -07:00 committed by GitHub
parent e1cb997ee6
commit eccfecd529
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 15 additions and 11 deletions

View File

@ -14,7 +14,7 @@
<Description>Some comments about the PHPExcel Gnumeric Reader</Description> <Description>Some comments about the PHPExcel Gnumeric Reader</Description>
<LastAuthor>Owen Leibman</LastAuthor> <LastAuthor>Owen Leibman</LastAuthor>
<Created>2010-09-02T20:48:39Z</Created> <Created>2010-09-02T20:48:39Z</Created>
<LastSaved>2010-09-02T20:48:39Z</LastSaved> <LastSaved>2010-09-03T21:48:39Z</LastSaved>
<Category>PHPExcel Xml Reader Test Category</Category> <Category>PHPExcel Xml Reader Test Category</Category>
<Manager>Maarten Balliauw</Manager> <Manager>Maarten Balliauw</Manager>
<Company>PHPExcel</Company> <Company>PHPExcel</Company>

View File

@ -70,7 +70,7 @@ class Properties
break; break;
case 'Created': case 'Created':
$docProps->setCreated($this->processTimestampValue($stringValue)); $docProps->setCreated($stringValue);
break; break;
case 'LastAuthor': case 'LastAuthor':
@ -78,7 +78,7 @@ class Properties
break; break;
case 'LastSaved': case 'LastSaved':
$docProps->setModified($this->processTimestampValue($stringValue)); $docProps->setModified($stringValue);
break; break;
case 'Company': case 'Company':
@ -135,7 +135,7 @@ class Properties
break; break;
case 'dateTime.tz': case 'dateTime.tz':
$propertyType = DocumentProperties::PROPERTY_TYPE_DATE; $propertyType = DocumentProperties::PROPERTY_TYPE_DATE;
$propertyValue = $this->processTimestampValue(trim((string) $propertyValue)); $propertyValue = trim((string) $propertyValue);
break; break;
} }
@ -154,11 +154,4 @@ class Properties
? new SimpleXMLElement('<xml></xml>') ? new SimpleXMLElement('<xml></xml>')
: ($simple->attributes($node) ?? new SimpleXMLElement('<xml></xml>')); : ($simple->attributes($node) ?? new SimpleXMLElement('<xml></xml>'));
} }
protected function processTimestampValue(string $dateTimeValue): int
{
$dateTime = strtotime($dateTimeValue);
return $dateTime === false ? time() : $dateTime;
}
} }

View File

@ -2,7 +2,9 @@
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xml; namespace PhpOffice\PhpSpreadsheetTests\Reader\Xml;
use DateTimeZone;
use PhpOffice\PhpSpreadsheet\Reader\Xml; use PhpOffice\PhpSpreadsheet\Reader\Xml;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
class XmlLoadTest extends TestCase class XmlLoadTest extends TestCase
@ -21,8 +23,17 @@ class XmlLoadTest extends TestCase
self::assertEquals('BCD', $sheet->getCell('A4')->getValue()); self::assertEquals('BCD', $sheet->getCell('A4')->getValue());
$props = $spreadsheet->getProperties(); $props = $spreadsheet->getProperties();
self::assertEquals('Mark Baker', $props->getCreator()); self::assertEquals('Mark Baker', $props->getCreator());
$creationDate = $props->getCreated();
$result = Date::formattedDateTimeFromTimestamp("$creationDate", 'Y-m-d\\TH:i:s\\Z', new DateTimeZone('UTC'));
self::assertEquals('2010-09-02T20:48:39Z', $result);
$creationDate = $props->getModified();
$result = Date::formattedDateTimeFromTimestamp("$creationDate", 'Y-m-d\\TH:i:s\\Z', new DateTimeZone('UTC'));
self::assertEquals('2010-09-03T21:48:39Z', $result);
self::assertEquals('AbCd1234', $props->getCustomPropertyValue('my_API_Token')); self::assertEquals('AbCd1234', $props->getCustomPropertyValue('my_API_Token'));
self::assertEquals('2', $props->getCustomPropertyValue('myאInt')); self::assertEquals('2', $props->getCustomPropertyValue('myאInt'));
$creationDate = $props->getCustomPropertyValue('my_API_Token_Expiry');
$result = Date::formattedDateTimeFromTimestamp("$creationDate", 'Y-m-d\\TH:i:s\\Z', new DateTimeZone('UTC'));
self::assertEquals('2019-01-31T07:00:00Z', $result);
$sheet = $spreadsheet->getSheet(0); $sheet = $spreadsheet->getSheet(0);
self::assertEquals('Sample Data', $sheet->getTitle()); self::assertEquals('Sample Data', $sheet->getTitle());