Merge branch 'master' into PHP8-Sane-Property-Names
# Conflicts: # CHANGELOG.md # src/PhpSpreadsheet/Shared/Drawing.php # src/PhpSpreadsheet/Spreadsheet.php # src/PhpSpreadsheet/Style/Conditional.php
This commit is contained in:
commit
11522afee0
|
|
@ -5,7 +5,6 @@
|
|||
/.php_cs.dist export-ignore
|
||||
/.sami.php export-ignore
|
||||
/.scrutinizer.yml export-ignore
|
||||
/.travis.yml export-ignore
|
||||
/CHANGELOG.PHPExcel.md export-ignore
|
||||
/bin export-ignore
|
||||
/composer.lock export-ignore
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
name: Build
|
||||
name: main
|
||||
on: [ push, pull_request ]
|
||||
jobs:
|
||||
test:
|
||||
|
|
@ -10,6 +10,7 @@ jobs:
|
|||
- '7.3'
|
||||
- '7.4'
|
||||
- '8.0'
|
||||
- '8.1'
|
||||
|
||||
name: PHP ${{ matrix.php-version }}
|
||||
|
||||
|
|
@ -37,7 +38,7 @@ jobs:
|
|||
|
||||
- name: Delete composer lock file
|
||||
id: composer-lock
|
||||
if: ${{ matrix.php-version == '8.0' }}
|
||||
if: ${{ matrix.php-version == '8.0' || matrix.php-version == '8.1' }}
|
||||
run: |
|
||||
rm composer.lock
|
||||
echo "::set-output name=flags::--ignore-platform-reqs"
|
||||
|
|
@ -148,3 +149,25 @@ jobs:
|
|||
./vendor/bin/phpunit --coverage-clover coverage-clover.xml
|
||||
curl -LO https://scrutinizer-ci.com/ocular.phar
|
||||
php ocular.phar code-coverage:upload --format=php-clover coverage-clover.xml
|
||||
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.ref }} # Otherwise our annotated tag is not fetched and we cannot get correct version
|
||||
|
||||
# Create release
|
||||
- name: Get release info
|
||||
id: release-info
|
||||
run: |
|
||||
echo "::set-output name=subject::$(git tag --format '%(contents:subject)' --points-at)"
|
||||
git tag --format '%(contents:body)' --points-at > release-body.txt
|
||||
- uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: ${{ steps.release-info.outputs.subject }}
|
||||
body_path: release-body.txt
|
||||
|
|
|
|||
34
.travis.yml
34
.travis.yml
|
|
@ -1,34 +0,0 @@
|
|||
language: php
|
||||
dist: bionic
|
||||
|
||||
php:
|
||||
- 7.2
|
||||
- 7.3
|
||||
- 7.4
|
||||
- nightly
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- vendor
|
||||
- $HOME/.composer/cache
|
||||
|
||||
before_script:
|
||||
# Deactivate xdebug
|
||||
- if [[ $TRAVIS_PHP_VERSION != nightly ]]; then phpenv config-rm xdebug.ini; fi
|
||||
- if [[ $TRAVIS_PHP_VERSION == nightly ]]; then rm composer.lock; fi
|
||||
- composer install --ignore-platform-reqs
|
||||
|
||||
script:
|
||||
- ./vendor/bin/phpunit --color=always --coverage-text
|
||||
|
||||
allow_failures:
|
||||
- php: nightly
|
||||
|
||||
jobs:
|
||||
include:
|
||||
|
||||
- stage: Code style
|
||||
php: 7.4
|
||||
script:
|
||||
- ./vendor/bin/php-cs-fixer fix --diff --verbose --dry-run
|
||||
- ./vendor/bin/phpcs
|
||||
12
CHANGELOG.md
12
CHANGELOG.md
|
|
@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
|
|||
|
||||
### Added
|
||||
|
||||
- CSV Reader - Best Guess for Encoding, and Handle Null-string Escape [#1647](https://github.com/PHPOffice/PhpSpreadsheet/issues/1647)
|
||||
- Provided a Size Helper class to validate size values (pt, px, em)
|
||||
|
||||
### Changed
|
||||
|
|
@ -25,8 +26,17 @@ and this project adheres to [Semantic Versioning](https://semver.org).
|
|||
|
||||
### Fixed
|
||||
|
||||
- Fix for Xls Reader when SST has a bad length [#1592](https://github.com/PHPOffice/PhpSpreadsheet/issues/1592)
|
||||
- Resolve Xlsx loader issue whe hyperlinks don't have a destination
|
||||
- Resolve issues when printer settings resources IDs clash with drawing IDs
|
||||
- Resolve issue with SLK long filenames [#1612](https://github.com/PHPOffice/PhpSpreadsheet/issues/1612)
|
||||
- ROUNDUP and ROUNDDOWN return incorrect results for values of 0 [#1627](https://github.com/phpoffice/phpspreadsheet/pull/1627)
|
||||
- Apply Column and Row Styles to Existing Cells [#1712](https://github.com/PHPOffice/PhpSpreadsheet/issues/1712) [PR #1721](https://github.com/PHPOffice/PhpSpreadsheet/pull/1721)
|
||||
- Resolve issues with defined names where worksheet doesn't exist (#1686)[https://github.com/PHPOffice/PhpSpreadsheet/issues/1686] and [#1723](https://github.com/PHPOffice/PhpSpreadsheet/issues/1723) - [PR #1742](https://github.com/PHPOffice/PhpSpreadsheet/pull/1742)
|
||||
- Fix for issue [#1735](https://github.com/PHPOffice/PhpSpreadsheet/issues/1735) Incorrect activeSheetIndex after RemoveSheetByIndex - [PR #1743](https://github.com/PHPOffice/PhpSpreadsheet/pull/1743)
|
||||
- Ensure that the list of shared formulae is maintained when an xlsx file is chunked with readFilter[Issue #169](https://github.com/PHPOffice/PhpSpreadsheet/issues/1669).
|
||||
- Fix for notice during accessing "cached magnification factor" offset [#1354](https://github.com/PHPOffice/PhpSpreadsheet/pull/1354)
|
||||
- Fix compatibility with ext-gd on php 8
|
||||
|
||||
### Security Fix (CVE-2020-7776)
|
||||
|
||||
|
|
@ -78,7 +88,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
|
|||
|
||||
### Fixed
|
||||
|
||||
- PrintArea causes exception [#1544](https://github.com/phpoffice/phpspreadsheet/pull/1544)
|
||||
- PrintArea causes exception [#1544](https://github.com/phpoffice/phpspreadsheet/pull/1544)
|
||||
- Calculation/DateTime Failure With PHP8 [#1661](https://github.com/phpoffice/phpspreadsheet/pull/1661)
|
||||
- Reader/Gnumeric Failure with PHP8 [#1662](https://github.com/phpoffice/phpspreadsheet/pull/1662)
|
||||
- ReverseSort bug, exposed but not caused by PHP8 [#1660](https://github.com/phpoffice/phpspreadsheet/pull/1660)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# PhpSpreadsheet
|
||||
|
||||
[](https://travis-ci.org/PHPOffice/PhpSpreadsheet)
|
||||
[](https://github.com/PHPOffice/PhpSpreadsheet/actions)
|
||||
[](https://scrutinizer-ci.com/g/PHPOffice/PhpSpreadsheet/?branch=master)
|
||||
[](https://scrutinizer-ci.com/g/PHPOffice/PhpSpreadsheet/?branch=master)
|
||||
[](https://packagist.org/packages/phpoffice/phpspreadsheet)
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@
|
|||
"psr/simple-cache": "^1.0",
|
||||
"psr/http-client": "^1.0",
|
||||
"psr/http-factory": "^1.0",
|
||||
"voku/anti-xss": "^4.1"
|
||||
"ezyang/htmlpurifier": "^4.13"
|
||||
},
|
||||
"require-dev": {
|
||||
"dompdf/dompdf": "^0.8.5",
|
||||
|
|
|
|||
|
|
@ -4,8 +4,62 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "209605c0b9329968170279f40db65d22",
|
||||
"content-hash": "458fe4e974b469230da589a8781d1e0e",
|
||||
"packages": [
|
||||
{
|
||||
"name": "ezyang/htmlpurifier",
|
||||
"version": "v4.13.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ezyang/htmlpurifier.git",
|
||||
"reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/08e27c97e4c6ed02f37c5b2b20488046c8d90d75",
|
||||
"reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"HTMLPurifier": "library/"
|
||||
},
|
||||
"files": [
|
||||
"library/HTMLPurifier.composer.php"
|
||||
],
|
||||
"exclude-from-classmap": [
|
||||
"/library/HTMLPurifier/Language/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL-2.1-or-later"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Edward Z. Yang",
|
||||
"email": "admin@htmlpurifier.org",
|
||||
"homepage": "http://ezyang.com"
|
||||
}
|
||||
],
|
||||
"description": "Standards compliant HTML filter written in PHP",
|
||||
"homepage": "http://htmlpurifier.org/",
|
||||
"keywords": [
|
||||
"html"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/ezyang/htmlpurifier/issues",
|
||||
"source": "https://github.com/ezyang/htmlpurifier/tree/master"
|
||||
},
|
||||
"time": "2020-06-29T00:56:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "maennchen/zipstream-php",
|
||||
"version": "2.1.0",
|
||||
|
|
@ -477,242 +531,6 @@
|
|||
],
|
||||
"time": "2017-10-23T01:57:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-iconv",
|
||||
"version": "v1.20.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-iconv.git",
|
||||
"reference": "c536646fdb4f29104dd26effc2fdcb9a5b085024"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/c536646fdb4f29104dd26effc2fdcb9a5b085024",
|
||||
"reference": "c536646fdb4f29104dd26effc2fdcb9a5b085024",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-iconv": "For best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.20-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Iconv\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for the Iconv extension",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"iconv",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-10-23T14:02:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-grapheme",
|
||||
"version": "v1.18.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
|
||||
"reference": "b740103edbdcc39602239ee8860f0f45a8eb9aa5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b740103edbdcc39602239ee8860f0f45a8eb9aa5",
|
||||
"reference": "b740103edbdcc39602239ee8860f0f45a8eb9aa5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "For best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.18-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Intl\\Grapheme\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for intl's grapheme_* functions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"grapheme",
|
||||
"intl",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-07-14T12:35:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-normalizer",
|
||||
"version": "v1.18.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
|
||||
"reference": "37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e",
|
||||
"reference": "37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "For best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.18-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Intl\\Normalizer\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"classmap": [
|
||||
"Resources/stubs"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for intl's Normalizer class and related functions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"intl",
|
||||
"normalizer",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-07-14T12:35:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.18.1",
|
||||
|
|
@ -789,323 +607,6 @@
|
|||
}
|
||||
],
|
||||
"time": "2020-07-14T12:35:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php72",
|
||||
"version": "v1.18.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php72.git",
|
||||
"reference": "639447d008615574653fb3bc60d1986d7172eaae"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/639447d008615574653fb3bc60d1986d7172eaae",
|
||||
"reference": "639447d008615574653fb3bc60d1986d7172eaae",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.18-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Php72\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-07-14T12:35:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "voku/anti-xss",
|
||||
"version": "4.1.30",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/voku/anti-xss.git",
|
||||
"reference": "ff6e54f4a98ad1cd28f8b4a0f3c3f92f3c421f0a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/voku/anti-xss/zipball/ff6e54f4a98ad1cd28f8b4a0f3c3f92f3c421f0a",
|
||||
"reference": "ff6e54f4a98ad1cd28f8b4a0f3c3f92f3c421f0a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.0.0",
|
||||
"voku/portable-utf8": "~5.4.50"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~6.0 || ~7.0 || ~9.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"voku\\helper\\": "src/voku/helper/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "EllisLab Dev Team",
|
||||
"homepage": "http://ellislab.com/"
|
||||
},
|
||||
{
|
||||
"name": "Lars Moelleken",
|
||||
"email": "lars@moelleken.org",
|
||||
"homepage": "http://www.moelleken.org/"
|
||||
}
|
||||
],
|
||||
"description": "anti xss-library",
|
||||
"homepage": "https://github.com/voku/anti-xss",
|
||||
"keywords": [
|
||||
"anti-xss",
|
||||
"clean",
|
||||
"security",
|
||||
"xss"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.paypal.me/moelleken",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/voku",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://opencollective.com/anti-xss",
|
||||
"type": "open_collective"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/voku",
|
||||
"type": "patreon"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/voku/anti-xss",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-11-12T00:30:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "voku/portable-ascii",
|
||||
"version": "1.5.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/voku/portable-ascii.git",
|
||||
"reference": "80953678b19901e5165c56752d087fc11526017c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/voku/portable-ascii/zipball/80953678b19901e5165c56752d087fc11526017c",
|
||||
"reference": "80953678b19901e5165c56752d087fc11526017c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~6.0 || ~7.0 || ~9.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "Use Intl for transliterator_transliterate() support"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"voku\\": "src/voku/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Lars Moelleken",
|
||||
"homepage": "http://www.moelleken.org/"
|
||||
}
|
||||
],
|
||||
"description": "Portable ASCII library - performance optimized (ascii) string functions for php.",
|
||||
"homepage": "https://github.com/voku/portable-ascii",
|
||||
"keywords": [
|
||||
"ascii",
|
||||
"clean",
|
||||
"php"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.paypal.me/moelleken",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/voku",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://opencollective.com/portable-ascii",
|
||||
"type": "open_collective"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/voku",
|
||||
"type": "patreon"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-11-12T00:07:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "voku/portable-utf8",
|
||||
"version": "5.4.50",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/voku/portable-utf8.git",
|
||||
"reference": "f14ed68ea9ced6639e71ca989c6d907892115ba0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/voku/portable-utf8/zipball/f14ed68ea9ced6639e71ca989c6d907892115ba0",
|
||||
"reference": "f14ed68ea9ced6639e71ca989c6d907892115ba0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.0.0",
|
||||
"symfony/polyfill-iconv": "~1.0",
|
||||
"symfony/polyfill-intl-grapheme": "~1.0",
|
||||
"symfony/polyfill-intl-normalizer": "~1.0",
|
||||
"symfony/polyfill-mbstring": "~1.0",
|
||||
"symfony/polyfill-php72": "~1.0",
|
||||
"voku/portable-ascii": "~1.5.6"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~6.0 || ~7.0 || ~9.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-ctype": "Use Ctype for e.g. hexadecimal digit detection",
|
||||
"ext-fileinfo": "Use Fileinfo for better binary file detection",
|
||||
"ext-iconv": "Use iconv for best performance",
|
||||
"ext-intl": "Use Intl for best performance",
|
||||
"ext-json": "Use JSON for string detection",
|
||||
"ext-mbstring": "Use Mbstring for best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"voku\\": "src/voku/"
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"(Apache-2.0 or GPL-2.0)"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Hamid Sarfraz",
|
||||
"homepage": "http://pageconfig.com/"
|
||||
},
|
||||
{
|
||||
"name": "Lars Moelleken",
|
||||
"homepage": "http://www.moelleken.org/"
|
||||
}
|
||||
],
|
||||
"description": "Portable UTF-8 library - performance optimized (unicode) string functions for php.",
|
||||
"homepage": "https://github.com/voku/portable-utf8",
|
||||
"keywords": [
|
||||
"UTF",
|
||||
"clean",
|
||||
"php",
|
||||
"unicode",
|
||||
"utf-8",
|
||||
"utf8"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.paypal.me/moelleken",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/voku",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://opencollective.com/portable-utf8",
|
||||
"type": "open_collective"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/voku",
|
||||
"type": "patreon"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/voku/portable-utf8",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-11-12T00:17:47+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
|
|
@ -4150,6 +3651,165 @@
|
|||
],
|
||||
"time": "2020-07-14T12:35:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-grapheme",
|
||||
"version": "v1.18.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
|
||||
"reference": "b740103edbdcc39602239ee8860f0f45a8eb9aa5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b740103edbdcc39602239ee8860f0f45a8eb9aa5",
|
||||
"reference": "b740103edbdcc39602239ee8860f0f45a8eb9aa5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "For best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.18-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Intl\\Grapheme\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for intl's grapheme_* functions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"grapheme",
|
||||
"intl",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-07-14T12:35:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-normalizer",
|
||||
"version": "v1.18.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
|
||||
"reference": "37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e",
|
||||
"reference": "37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "For best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.18-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Intl\\Normalizer\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"classmap": [
|
||||
"Resources/stubs"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for intl's Normalizer class and related functions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"intl",
|
||||
"normalizer",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-07-14T12:35:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php70",
|
||||
"version": "v1.18.1",
|
||||
|
|
@ -4227,6 +3887,79 @@
|
|||
],
|
||||
"time": "2020-07-14T12:35:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php72",
|
||||
"version": "v1.18.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php72.git",
|
||||
"reference": "639447d008615574653fb3bc60d1986d7172eaae"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/639447d008615574653fb3bc60d1986d7172eaae",
|
||||
"reference": "639447d008615574653fb3bc60d1986d7172eaae",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.18-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Php72\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-07-14T12:35:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php73",
|
||||
"version": "v1.18.1",
|
||||
|
|
@ -4836,7 +4569,7 @@
|
|||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": "^7.2|^8.0",
|
||||
"php": "^7.2||^8.0",
|
||||
"ext-ctype": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-gd": "*",
|
||||
|
|
@ -4852,5 +4585,5 @@
|
|||
"ext-zlib": "*"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "1.1.0"
|
||||
"plugin-api-version": "2.0.0"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -422,8 +422,10 @@ foreach ($worksheet->getRowIterator() as $row) {
|
|||
$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.
|
||||
// For 'TRUE', we loop through cells
|
||||
// only when their value is set.
|
||||
// If this method is not called,
|
||||
// the default value is 'false'.
|
||||
foreach ($cellIterator as $cell) {
|
||||
echo '<td>' .
|
||||
$cell->getValue() .
|
||||
|
|
|
|||
|
|
@ -458,6 +458,24 @@ $reader->setSheetIndex(0);
|
|||
|
||||
$spreadsheet = $reader->load("sample.csv");
|
||||
```
|
||||
You may also let PhpSpreadsheet attempt to guess the input encoding.
|
||||
It will do so based on a test for BOM (UTF-8, UTF-16BE, UTF-16LE, UTF-32BE,
|
||||
or UTF-32LE),
|
||||
or by doing heuristic tests for those encodings, falling back to a
|
||||
specifiable encoding (default is CP1252) if all of those tests fail.
|
||||
|
||||
```php
|
||||
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Csv();
|
||||
$encoding = \PhpOffice\PhpSpreadsheet\Reader\Csv::guessEncoding('sample.csv');
|
||||
// or, e.g. $encoding = \PhpOffice\PhpSpreadsheet\Reader\Csv::guessEncoding(
|
||||
// 'sample.csv', 'ISO-8859-2');
|
||||
$reader->setInputEncoding($encoding);
|
||||
$reader->setDelimiter(';');
|
||||
$reader->setEnclosure('');
|
||||
$reader->setSheetIndex(0);
|
||||
|
||||
$spreadsheet = $reader->load('sample.csv');
|
||||
```
|
||||
|
||||
#### Read a specific worksheet
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1108,6 +1108,10 @@ class MathTrig
|
|||
$digits = Functions::flattenSingleValue($digits);
|
||||
|
||||
if ((is_numeric($number)) && (is_numeric($digits))) {
|
||||
if ($number == 0.0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
if ($number < 0.0) {
|
||||
return round($number - 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_DOWN);
|
||||
}
|
||||
|
|
@ -1134,6 +1138,10 @@ class MathTrig
|
|||
$digits = Functions::flattenSingleValue($digits);
|
||||
|
||||
if ((is_numeric($number)) && (is_numeric($digits))) {
|
||||
if ($number == 0.0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
if ($number < 0.0) {
|
||||
return round($number + 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_UP);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,15 +27,15 @@ class TextData
|
|||
{
|
||||
$character = Functions::flattenSingleValue($character);
|
||||
|
||||
if ((!is_numeric($character)) || ($character < 0)) {
|
||||
if (!is_numeric($character)) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
$character = (int) $character;
|
||||
if ($character < 1 || $character > 255) {
|
||||
return Functions::VALUE();
|
||||
}
|
||||
|
||||
if (function_exists('iconv')) {
|
||||
return iconv('UCS-4LE', 'UTF-8', pack('V', $character));
|
||||
}
|
||||
|
||||
return mb_convert_encoding('&#' . (int) $character . ';', 'UTF-8', 'HTML-ENTITIES');
|
||||
return iconv('UCS-4LE', 'UTF-8', pack('V', $character));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -160,7 +160,7 @@ class TextData
|
|||
|
||||
// Validate parameters
|
||||
if (!is_numeric($value) || !is_numeric($decimals)) {
|
||||
return Functions::NAN();
|
||||
return Functions::VALUE();
|
||||
}
|
||||
$decimals = floor($decimals);
|
||||
|
||||
|
|
@ -174,6 +174,7 @@ class TextData
|
|||
}
|
||||
$value = MathTrig::MROUND($value, $round);
|
||||
}
|
||||
$mask = "$mask;($mask)";
|
||||
|
||||
return NumberFormat::toFormattedString($value, $mask);
|
||||
}
|
||||
|
|
@ -265,7 +266,7 @@ class TextData
|
|||
|
||||
// Validate parameters
|
||||
if (!is_numeric($value) || !is_numeric($decimals)) {
|
||||
return Functions::NAN();
|
||||
return Functions::VALUE();
|
||||
}
|
||||
$decimals = (int) floor($decimals);
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class NamedFormula extends DefinedName
|
|||
) {
|
||||
// Validate data
|
||||
if (empty($formula)) {
|
||||
throw new Exception('Tou must specify a Formula value for a Named Formula');
|
||||
throw new Exception('You must specify a Formula value for a Named Formula');
|
||||
}
|
||||
parent::__construct($name, $worksheet, $formula, $localOnly, $scope);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,21 @@ use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
|||
|
||||
class Csv extends BaseReader
|
||||
{
|
||||
const UTF8_BOM = "\xEF\xBB\xBF";
|
||||
const UTF8_BOM_LEN = 3;
|
||||
const UTF16BE_BOM = "\xfe\xff";
|
||||
const UTF16BE_BOM_LEN = 2;
|
||||
const UTF16BE_LF = "\x00\x0a";
|
||||
const UTF16LE_BOM = "\xff\xfe";
|
||||
const UTF16LE_BOM_LEN = 2;
|
||||
const UTF16LE_LF = "\x0a\x00";
|
||||
const UTF32BE_BOM = "\x00\x00\xfe\xff";
|
||||
const UTF32BE_BOM_LEN = 4;
|
||||
const UTF32BE_LF = "\x00\x00\x00\x0a";
|
||||
const UTF32LE_BOM = "\xff\xfe\x00\x00";
|
||||
const UTF32LE_BOM_LEN = 4;
|
||||
const UTF32LE_LF = "\x0a\x00\x00\x00";
|
||||
|
||||
/**
|
||||
* Input encoding.
|
||||
*
|
||||
|
|
@ -90,12 +105,8 @@ class Csv extends BaseReader
|
|||
{
|
||||
rewind($this->fileHandle);
|
||||
|
||||
switch ($this->inputEncoding) {
|
||||
case 'UTF-8':
|
||||
fgets($this->fileHandle, 4) == "\xEF\xBB\xBF" ?
|
||||
fseek($this->fileHandle, 3) : fseek($this->fileHandle, 0);
|
||||
|
||||
break;
|
||||
if (fgets($this->fileHandle, self::UTF8_BOM_LEN + 1) !== self::UTF8_BOM) {
|
||||
rewind($this->fileHandle);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -213,7 +224,9 @@ class Csv extends BaseReader
|
|||
private function getNextLine()
|
||||
{
|
||||
$line = '';
|
||||
$enclosure = '(?<!' . preg_quote($this->escapeCharacter, '/') . ')' . preg_quote($this->enclosure, '/');
|
||||
$enclosure = ($this->escapeCharacter === '' ? ''
|
||||
: ('(?<!' . preg_quote($this->escapeCharacter, '/') . ')'))
|
||||
. preg_quote($this->enclosure, '/');
|
||||
|
||||
do {
|
||||
// Get the next line in the file
|
||||
|
|
@ -307,7 +320,7 @@ class Csv extends BaseReader
|
|||
$this->fileHandle = fopen('php://memory', 'r+b');
|
||||
$data = StringHelper::convertEncoding($entireFile, 'UTF-8', $this->inputEncoding);
|
||||
fwrite($this->fileHandle, $data);
|
||||
rewind($this->fileHandle);
|
||||
$this->skipBOM();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -531,4 +544,63 @@ class Csv extends BaseReader
|
|||
|
||||
return in_array($type, $supportedTypes, true);
|
||||
}
|
||||
|
||||
private static function guessEncodingTestNoBom(string &$encoding, string &$contents, string $compare, string $setEncoding): void
|
||||
{
|
||||
if ($encoding === '') {
|
||||
$pos = strpos($contents, $compare);
|
||||
if ($pos !== false && $pos % strlen($compare) === 0) {
|
||||
$encoding = $setEncoding;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function guessEncodingNoBom(string $filename): string
|
||||
{
|
||||
$encoding = '';
|
||||
$contents = file_get_contents($filename);
|
||||
self::guessEncodingTestNoBom($encoding, $contents, self::UTF32BE_LF, 'UTF-32BE');
|
||||
self::guessEncodingTestNoBom($encoding, $contents, self::UTF32LE_LF, 'UTF-32LE');
|
||||
self::guessEncodingTestNoBom($encoding, $contents, self::UTF16BE_LF, 'UTF-16BE');
|
||||
self::guessEncodingTestNoBom($encoding, $contents, self::UTF16LE_LF, 'UTF-16LE');
|
||||
if ($encoding === '' && preg_match('//u', $contents) === 1) {
|
||||
$encoding = 'UTF-8';
|
||||
}
|
||||
|
||||
return $encoding;
|
||||
}
|
||||
|
||||
private static function guessEncodingTestBom(string &$encoding, string $first4, string $compare, string $setEncoding): void
|
||||
{
|
||||
if ($encoding === '') {
|
||||
if ($compare === substr($first4, 0, strlen($compare))) {
|
||||
$encoding = $setEncoding;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function guessEncodingBom(string $filename): string
|
||||
{
|
||||
$encoding = '';
|
||||
$first4 = file_get_contents($filename, false, null, 0, 4);
|
||||
if ($first4 !== false) {
|
||||
self::guessEncodingTestBom($encoding, $first4, self::UTF8_BOM, 'UTF-8');
|
||||
self::guessEncodingTestBom($encoding, $first4, self::UTF16BE_BOM, 'UTF-16BE');
|
||||
self::guessEncodingTestBom($encoding, $first4, self::UTF32BE_BOM, 'UTF-32BE');
|
||||
self::guessEncodingTestBom($encoding, $first4, self::UTF32LE_BOM, 'UTF-32LE');
|
||||
self::guessEncodingTestBom($encoding, $first4, self::UTF16LE_BOM, 'UTF-16LE');
|
||||
}
|
||||
|
||||
return $encoding;
|
||||
}
|
||||
|
||||
public static function guessEncoding(string $filename, string $dflt = 'CP1252'): string
|
||||
{
|
||||
$encoding = self::guessEncodingBom($filename);
|
||||
if ($encoding === '') {
|
||||
$encoding = self::guessEncodingNoBom($filename);
|
||||
}
|
||||
|
||||
return ($encoding === '') ? $dflt : $encoding;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException;
|
|||
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Border;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
|
||||
class Slk extends BaseReader
|
||||
{
|
||||
|
|
@ -516,7 +517,7 @@ class Slk extends BaseReader
|
|||
$spreadsheet->createSheet();
|
||||
}
|
||||
$spreadsheet->setActiveSheetIndex($this->sheetIndex);
|
||||
$spreadsheet->getActiveSheet()->setTitle(basename($pFilename, '.slk'));
|
||||
$spreadsheet->getActiveSheet()->setTitle(substr(basename($pFilename, '.slk'), 0, Worksheet::SHEET_TITLE_MAXIMUM_LENGTH));
|
||||
|
||||
// Loop through file
|
||||
$column = $row = '';
|
||||
|
|
|
|||
|
|
@ -2973,6 +2973,9 @@ class Xls extends BaseReader
|
|||
// offset within (spliced) record data
|
||||
$pos = 0;
|
||||
|
||||
// Limit global SST position, further control for bad SST Length in BIFF8 data
|
||||
$limitposSST = 0;
|
||||
|
||||
// get spliced record data
|
||||
$splicedRecordData = $this->getSplicedRecordData();
|
||||
|
||||
|
|
@ -2986,8 +2989,17 @@ class Xls extends BaseReader
|
|||
$nm = self::getInt4d($recordData, 4);
|
||||
$pos += 4;
|
||||
|
||||
// look up limit position
|
||||
foreach ($spliceOffsets as $spliceOffset) {
|
||||
// it can happen that the string is empty, therefore we need
|
||||
// <= and not just <
|
||||
if ($pos <= $spliceOffset) {
|
||||
$limitposSST = $spliceOffset;
|
||||
}
|
||||
}
|
||||
|
||||
// loop through the Unicode strings (16-bit length)
|
||||
for ($i = 0; $i < $nm; ++$i) {
|
||||
for ($i = 0; $i < $nm && $pos < $limitposSST; ++$i) {
|
||||
// number of characters in the Unicode string
|
||||
$numChars = self::getUInt2d($recordData, $pos);
|
||||
$pos += 2;
|
||||
|
|
@ -3020,7 +3032,7 @@ class Xls extends BaseReader
|
|||
// expected byte length of character array if not split
|
||||
$len = ($isCompressed) ? $numChars : $numChars * 2;
|
||||
|
||||
// look up limit position
|
||||
// look up limit position - Check it again to be sure that no error occurs when parsing SST structure
|
||||
foreach ($spliceOffsets as $spliceOffset) {
|
||||
// it can happen that the string is empty, therefore we need
|
||||
// <= and not just <
|
||||
|
|
|
|||
|
|
@ -1280,7 +1280,7 @@ class Xlsx extends BaseReader
|
|||
}
|
||||
|
||||
// Valid range?
|
||||
if (stripos((string) $definedName, '#REF!') !== false || $extractedRange == '') {
|
||||
if ($extractedRange == '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -1350,7 +1350,7 @@ class Xlsx extends BaseReader
|
|||
$extractedRange = (string) $definedName;
|
||||
|
||||
// Valid range?
|
||||
if (stripos((string) $definedName, '#REF!') !== false || $extractedRange == '') {
|
||||
if ($extractedRange == '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -1398,6 +1398,9 @@ class Xlsx extends BaseReader
|
|||
$locatedSheet = $excel->getSheetByName($extractedSheetName);
|
||||
}
|
||||
|
||||
if ($locatedSheet === null && !DefinedName::testIfFormula($definedRange)) {
|
||||
$definedRange = '#REF!';
|
||||
}
|
||||
$excel->addDefinedName(DefinedName::createInstance((string) $definedName['name'], $locatedSheet, $definedRange, false));
|
||||
}
|
||||
}
|
||||
|
|
@ -1968,7 +1971,7 @@ class Xlsx extends BaseReader
|
|||
|
||||
$unparsedPrinterSettings = &$unparsedLoadedData['sheets'][$docSheet->getCodeName()]['printerSettings'];
|
||||
foreach ($sheetPrinterSettings as $rId => $printerSettings) {
|
||||
$rId = substr($rId, 3); // rIdXXX
|
||||
$rId = substr($rId, 3) . 'ps'; // rIdXXX, add 'ps' suffix to avoid identical resource identifier collision with unparsed vmlDrawing
|
||||
$unparsedPrinterSettings[$rId] = [];
|
||||
$unparsedPrinterSettings[$rId]['filePath'] = self::dirAdd("$dir/$fileWorksheet", $printerSettings['Target']);
|
||||
$unparsedPrinterSettings[$rId]['relFilePath'] = (string) $printerSettings['Target'];
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class Hyperlinks
|
|||
foreach (Coordinate::extractAllCellReferencesInRange($hyperlink['ref']) as $cellReference) {
|
||||
$cell = $worksheet->getCell($cellReference);
|
||||
if (isset($linkRel['id'])) {
|
||||
$hyperlinkUrl = $this->hyperlinks[(string) $linkRel['id']];
|
||||
$hyperlinkUrl = $this->hyperlinks[(string) $linkRel['id']] ?? null;
|
||||
if (isset($hyperlink['location'])) {
|
||||
$hyperlinkUrl .= '#' . (string) $hyperlink['location'];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -617,9 +617,11 @@ class Xml extends BaseReader
|
|||
++$rowID;
|
||||
}
|
||||
|
||||
$xmlX = $worksheet->children($namespaces['x']);
|
||||
if (isset($xmlX->WorksheetOptions)) {
|
||||
(new PageSettings($xmlX, $namespaces))->loadPageSettings($spreadsheet);
|
||||
if (isset($namespaces['x'])) {
|
||||
$xmlX = $worksheet->children($namespaces['x']);
|
||||
if (isset($xmlX->WorksheetOptions)) {
|
||||
(new PageSettings($xmlX, $namespaces))->loadPageSettings($spreadsheet);
|
||||
}
|
||||
}
|
||||
}
|
||||
++$worksheetID;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace PhpOffice\PhpSpreadsheet\Shared;
|
||||
|
||||
use GdImage;
|
||||
|
||||
class Drawing
|
||||
{
|
||||
/**
|
||||
|
|
@ -98,7 +100,7 @@ class Drawing
|
|||
*/
|
||||
public static function pixelsToPoints($pxValue)
|
||||
{
|
||||
return $pxValue * 0.67777777;
|
||||
return $pxValue * 0.75;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -111,7 +113,7 @@ class Drawing
|
|||
public static function pointsToPixels($ptValue)
|
||||
{
|
||||
if ($ptValue != 0) {
|
||||
return (int) ceil($ptValue * 1.333333333);
|
||||
return (int) ceil($ptValue / 0.75);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -152,7 +154,7 @@ class Drawing
|
|||
*
|
||||
* @param string $bmpFilename Path to Windows DIB (BMP) image
|
||||
*
|
||||
* @return resource
|
||||
* @return GdImage|resource
|
||||
*/
|
||||
public static function imagecreatefrombmp($bmpFilename)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -666,7 +666,7 @@ class Spreadsheet
|
|||
// Adjust active sheet index if necessary
|
||||
if (
|
||||
($this->activeSheetIndex >= $sheetIndex) &&
|
||||
($sheetIndex > count($this->workSheetCollection) - 1)
|
||||
($this->activeSheetIndex > 0 || $numSheets <= 1)
|
||||
) {
|
||||
--$this->activeSheetIndex;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ class Conditional implements IComparable
|
|||
/**
|
||||
* Set Conditions.
|
||||
*
|
||||
* @param string[] $conditions Condition
|
||||
* @param bool|float|int|string|string[] $conditions Condition
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -42,13 +42,6 @@ class Style extends Supervisor
|
|||
*/
|
||||
protected $numberFormat;
|
||||
|
||||
/**
|
||||
* Conditional styles.
|
||||
*
|
||||
* @var Conditional[]
|
||||
*/
|
||||
protected $conditionalStyles;
|
||||
|
||||
/**
|
||||
* Protection.
|
||||
*
|
||||
|
|
@ -85,7 +78,6 @@ class Style extends Supervisor
|
|||
parent::__construct($isSupervisor);
|
||||
|
||||
// Initialise values
|
||||
$this->conditionalStyles = [];
|
||||
$this->font = new Font($isSupervisor, $isConditional);
|
||||
$this->fill = new Fill($isSupervisor, $isConditional);
|
||||
$this->borders = new Borders($isSupervisor, $isConditional);
|
||||
|
|
@ -210,6 +202,8 @@ class Style extends Supervisor
|
|||
$rangeEnd = Coordinate::coordinateFromString($rangeB);
|
||||
|
||||
// Translate column into index
|
||||
$rangeStart0 = $rangeStart[0];
|
||||
$rangeEnd0 = $rangeEnd[0];
|
||||
$rangeStart[0] = Coordinate::columnIndexFromString($rangeStart[0]);
|
||||
$rangeEnd[0] = Coordinate::columnIndexFromString($rangeEnd[0]);
|
||||
|
||||
|
|
@ -359,6 +353,13 @@ class Style extends Supervisor
|
|||
for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) {
|
||||
$oldXfIndexes[$this->getActiveSheet()->getColumnDimensionByColumn($col)->getXfIndex()] = true;
|
||||
}
|
||||
foreach ($this->getActiveSheet()->getColumnIterator($rangeStart0, $rangeEnd0) as $columnIterator) {
|
||||
$cellIterator = $columnIterator->getCellIterator();
|
||||
$cellIterator->setIterateOnlyExistingCells(true);
|
||||
foreach ($cellIterator as $columnCell) {
|
||||
$columnCell->getStyle()->applyFromArray($pStyles);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 'ROW':
|
||||
|
|
@ -370,6 +371,13 @@ class Style extends Supervisor
|
|||
$oldXfIndexes[$this->getActiveSheet()->getRowDimension($row)->getXfIndex()] = true;
|
||||
}
|
||||
}
|
||||
foreach ($this->getActiveSheet()->getRowIterator((int) $rangeStart[1], (int) $rangeEnd[1]) as $rowIterator) {
|
||||
$cellIterator = $rowIterator->getCellIterator();
|
||||
$cellIterator->setIterateOnlyExistingCells(true);
|
||||
foreach ($cellIterator as $rowCell) {
|
||||
$rowCell->getStyle()->applyFromArray($pStyles);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 'CELL':
|
||||
|
|
@ -597,18 +605,12 @@ class Style extends Supervisor
|
|||
*/
|
||||
public function getHashCode()
|
||||
{
|
||||
$hashConditionals = '';
|
||||
foreach ($this->conditionalStyles as $conditional) {
|
||||
$hashConditionals .= $conditional->getHashCode();
|
||||
}
|
||||
|
||||
return md5(
|
||||
$this->fill->getHashCode() .
|
||||
$this->font->getHashCode() .
|
||||
$this->borders->getHashCode() .
|
||||
$this->alignment->getHashCode() .
|
||||
$this->numberFormat->getHashCode() .
|
||||
$hashConditionals .
|
||||
$this->protection->getHashCode() .
|
||||
($this->quotePrefix ? 't' : 'f') .
|
||||
__CLASS__
|
||||
|
|
|
|||
|
|
@ -92,10 +92,11 @@ class ColumnCellIterator extends CellIterator
|
|||
*/
|
||||
public function seek($row = 1)
|
||||
{
|
||||
if ($this->onlyExistingCells && !($this->worksheet->cellExistsByColumnAndRow($this->columnIndex, $row))) {
|
||||
throw new PhpSpreadsheetException('In "IterateOnlyExistingCells" mode and Cell does not exist');
|
||||
}
|
||||
if (($row < $this->startRow) || ($row > $this->endRow)) {
|
||||
throw new PhpSpreadsheetException("Row $row is out of range ({$this->startRow} - {$this->endRow})");
|
||||
} elseif ($this->onlyExistingCells && !($this->worksheet->cellExistsByColumnAndRow($this->columnIndex, $row))) {
|
||||
throw new PhpSpreadsheetException('In "IterateOnlyExistingCells" mode and Cell does not exist');
|
||||
}
|
||||
$this->currentRow = $row;
|
||||
|
||||
|
|
@ -113,7 +114,7 @@ class ColumnCellIterator extends CellIterator
|
|||
/**
|
||||
* Return the current cell in this worksheet column.
|
||||
*
|
||||
* @return null|\PhpOffice\PhpSpreadsheet\Cell\Cell
|
||||
* @return \PhpOffice\PhpSpreadsheet\Cell\Cell
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
|
|
@ -180,18 +181,12 @@ class ColumnCellIterator extends CellIterator
|
|||
) {
|
||||
++$this->startRow;
|
||||
}
|
||||
if ($this->startRow > $this->endRow) {
|
||||
throw new PhpSpreadsheetException('No cells exist within the specified range');
|
||||
}
|
||||
while (
|
||||
(!$this->worksheet->cellExistsByColumnAndRow($this->columnIndex, $this->endRow)) &&
|
||||
($this->endRow >= $this->startRow)
|
||||
) {
|
||||
--$this->endRow;
|
||||
}
|
||||
if ($this->endRow < $this->startRow) {
|
||||
throw new PhpSpreadsheetException('No cells exist within the specified range');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace PhpOffice\PhpSpreadsheet\Worksheet;
|
||||
|
||||
use GdImage;
|
||||
|
||||
class MemoryDrawing extends BaseDrawing
|
||||
{
|
||||
// Rendering functions
|
||||
|
|
@ -19,7 +21,7 @@ class MemoryDrawing extends BaseDrawing
|
|||
/**
|
||||
* Image resource.
|
||||
*
|
||||
* @var resource
|
||||
* @var GdImage|resource
|
||||
*/
|
||||
private $imageResource;
|
||||
|
||||
|
|
@ -62,7 +64,7 @@ class MemoryDrawing extends BaseDrawing
|
|||
/**
|
||||
* Get image resource.
|
||||
*
|
||||
* @return resource
|
||||
* @return GdImage|resource
|
||||
*/
|
||||
public function getImageResource()
|
||||
{
|
||||
|
|
@ -72,7 +74,7 @@ class MemoryDrawing extends BaseDrawing
|
|||
/**
|
||||
* Set image resource.
|
||||
*
|
||||
* @param resource $value
|
||||
* @param GdImage|resource $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -93,12 +93,14 @@ class RowCellIterator extends CellIterator
|
|||
*/
|
||||
public function seek($column = 'A')
|
||||
{
|
||||
$columnx = $column;
|
||||
$column = Coordinate::columnIndexFromString($column);
|
||||
if (($column < $this->startColumnIndex) || ($column > $this->endColumnIndex)) {
|
||||
throw new PhpSpreadsheetException("Column $column is out of range ({$this->startColumnIndex} - {$this->endColumnIndex})");
|
||||
} elseif ($this->onlyExistingCells && !($this->worksheet->cellExistsByColumnAndRow($column, $this->rowIndex))) {
|
||||
if ($this->onlyExistingCells && !($this->worksheet->cellExistsByColumnAndRow($column, $this->rowIndex))) {
|
||||
throw new PhpSpreadsheetException('In "IterateOnlyExistingCells" mode and Cell does not exist');
|
||||
}
|
||||
if (($column < $this->startColumnIndex) || ($column > $this->endColumnIndex)) {
|
||||
throw new PhpSpreadsheetException("Column $columnx is out of range ({$this->startColumnIndex} - {$this->endColumnIndex})");
|
||||
}
|
||||
$this->currentColumnIndex = $column;
|
||||
|
||||
return $this;
|
||||
|
|
@ -181,15 +183,9 @@ class RowCellIterator extends CellIterator
|
|||
while ((!$this->worksheet->cellExistsByColumnAndRow($this->startColumnIndex, $this->rowIndex)) && ($this->startColumnIndex <= $this->endColumnIndex)) {
|
||||
++$this->startColumnIndex;
|
||||
}
|
||||
if ($this->startColumnIndex > $this->endColumnIndex) {
|
||||
throw new PhpSpreadsheetException('No cells exist within the specified range');
|
||||
}
|
||||
while ((!$this->worksheet->cellExistsByColumnAndRow($this->endColumnIndex, $this->rowIndex)) && ($this->endColumnIndex >= $this->startColumnIndex)) {
|
||||
--$this->endColumnIndex;
|
||||
}
|
||||
if ($this->endColumnIndex < $this->startColumnIndex) {
|
||||
throw new PhpSpreadsheetException('No cells exist within the specified range');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace PhpOffice\PhpSpreadsheet\Writer;
|
||||
|
||||
use HTMLPurifier;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Cell;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
|
||||
|
|
@ -23,7 +24,6 @@ use PhpOffice\PhpSpreadsheet\Style\Style;
|
|||
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
use voku\helper\AntiXSS;
|
||||
|
||||
class Html extends BaseWriter
|
||||
{
|
||||
|
|
@ -1789,9 +1789,9 @@ class Html extends BaseWriter
|
|||
{
|
||||
$result = '';
|
||||
if (!$this->isPdf && isset($pSheet->getComments()[$coordinate])) {
|
||||
$sanitizer = new AntiXSS();
|
||||
$sanitizedString = $sanitizer->xss_clean($pSheet->getComment($coordinate)->getText()->getPlainText());
|
||||
if (!$sanitizer->isXssFound()) {
|
||||
$sanitizer = new HTMLPurifier();
|
||||
$sanitizedString = $sanitizer->purify($pSheet->getComment($coordinate)->getText()->getPlainText());
|
||||
if ($sanitizedString !== '') {
|
||||
$result .= '<a class="comment-indicator"></a>';
|
||||
$result .= '<div class="comment">' . nl2br($sanitizedString) . '</div>';
|
||||
$result .= PHP_EOL;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace PhpOffice\PhpSpreadsheet\Writer\Xls;
|
||||
|
||||
use GdImage;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\DataType;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\DataValidation;
|
||||
|
|
@ -2254,7 +2255,7 @@ class Worksheet extends BIFFwriter
|
|||
*/
|
||||
public function insertBitmap($row, $col, $bitmap, $x = 0, $y = 0, $scale_x = 1, $scale_y = 1): void
|
||||
{
|
||||
$bitmap_array = (is_resource($bitmap) ? $this->processBitmapGd($bitmap) : $this->processBitmap($bitmap));
|
||||
$bitmap_array = (is_resource($bitmap) || $bitmap instanceof GdImage ? $this->processBitmapGd($bitmap) : $this->processBitmap($bitmap));
|
||||
[$width, $height, $size, $data] = $bitmap_array;
|
||||
|
||||
// Scale the frame of the image.
|
||||
|
|
@ -2460,7 +2461,7 @@ class Worksheet extends BIFFwriter
|
|||
/**
|
||||
* Convert a GD-image into the internal format.
|
||||
*
|
||||
* @param resource $image The image to process
|
||||
* @param GdImage|resource $image The image to process
|
||||
*
|
||||
* @return array Array with data and properties of the bitmap
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1079,7 +1079,7 @@ class Worksheet extends WriterPart
|
|||
{
|
||||
$objWriter->writeAttribute('t', $mappedType);
|
||||
if (!$cellValue instanceof RichText) {
|
||||
self::writeElementIf($objWriter, isset($pFlippedStringTable[$cellValue]), 'v', $pFlippedStringTable[$cellValue]);
|
||||
self::writeElementIf($objWriter, isset($pFlippedStringTable[$cellValue]), 'v', $pFlippedStringTable[$cellValue] ?? '');
|
||||
} else {
|
||||
$objWriter->writeElement('v', $pFlippedStringTable[$cellValue->getHashCode()]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace PhpOffice\PhpSpreadsheetTests;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\DefinedName;
|
||||
use PhpOffice\PhpSpreadsheet\NamedFormula;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
|
|
@ -164,4 +165,24 @@ class DefinedNameFormulaTest extends TestCase
|
|||
'utf-8 named ranges in a formula' => ['Здравствуй+мир', true],
|
||||
];
|
||||
}
|
||||
|
||||
public function testEmptyNamedFormula(): void
|
||||
{
|
||||
$this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class);
|
||||
$spreadSheet = new Spreadsheet();
|
||||
$workSheet1 = $spreadSheet->getActiveSheet();
|
||||
new NamedFormula('namedformula', $workSheet1);
|
||||
}
|
||||
|
||||
public function testChangeFormula(): void
|
||||
{
|
||||
$spreadSheet = new Spreadsheet();
|
||||
$workSheet1 = $spreadSheet->getActiveSheet();
|
||||
$namedFormula = new NamedFormula('namedformula', $workSheet1, '=1');
|
||||
self::assertEquals('=1', $namedFormula->getFormula());
|
||||
$namedFormula->setFormula('=2');
|
||||
self::assertEquals('=2', $namedFormula->getFormula());
|
||||
$namedFormula->setFormula('');
|
||||
self::assertEquals('=2', $namedFormula->getFormula());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace PhpOffice\PhpSpreadsheetTests;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\DefinedName;
|
||||
use PhpOffice\PhpSpreadsheet\NamedRange;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
|
@ -121,4 +122,83 @@ class DefinedNameTest extends TestCase
|
|||
$this->spreadsheet->getDefinedName('foo')->getValue()
|
||||
);
|
||||
}
|
||||
|
||||
public function testDefinedNameNoWorksheetNoScope(): void
|
||||
{
|
||||
$this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class);
|
||||
new NamedRange('xyz');
|
||||
}
|
||||
|
||||
public function testSetAndGetRange(): void
|
||||
{
|
||||
$this->spreadsheet->addDefinedName(
|
||||
DefinedName::createInstance('xyz', $this->spreadsheet->getActiveSheet(), 'A1')
|
||||
);
|
||||
|
||||
$namedRange = $this->spreadsheet->getDefinedName('XYZ');
|
||||
self::assertInstanceOf(NamedRange::class, $namedRange);
|
||||
self::assertEquals('A1', $namedRange->getRange());
|
||||
self::assertEquals('A1', $namedRange->getValue());
|
||||
$namedRange->setRange('A2');
|
||||
self::assertEquals('A2', $namedRange->getValue());
|
||||
}
|
||||
|
||||
public function testChangeWorksheet(): void
|
||||
{
|
||||
$sheet1 = $this->spreadsheet->getSheetByName('Sheet #1');
|
||||
$sheet2 = $this->spreadsheet->getSheetByName('Sheet #2');
|
||||
$sheet1->getCell('A1')->setValue(1);
|
||||
$sheet2->getCell('A1')->setValue(2);
|
||||
$namedRange = new NamedRange('xyz', $sheet2, '$A$1');
|
||||
$namedRange->setWorksheet($sheet1);
|
||||
$this->spreadsheet->addNamedRange($namedRange);
|
||||
$sheet1->getCell('B2')->setValue('=XYZ');
|
||||
self::assertEquals(1, $sheet1->getCell('B2')->getCalculatedValue());
|
||||
$sheet2->getCell('B2')->setValue('=XYZ');
|
||||
self::assertEquals(1, $sheet2->getCell('B2')->getCalculatedValue());
|
||||
}
|
||||
|
||||
public function testLocalOnly(): void
|
||||
{
|
||||
$sheet1 = $this->spreadsheet->getSheetByName('Sheet #1');
|
||||
$sheet2 = $this->spreadsheet->getSheetByName('Sheet #2');
|
||||
$sheet1->getCell('A1')->setValue(1);
|
||||
$sheet2->getCell('A1')->setValue(2);
|
||||
$namedRange = new NamedRange('abc', $sheet2, '$A$1');
|
||||
$namedRange->setWorksheet($sheet1)->setLocalOnly(true);
|
||||
$this->spreadsheet->addNamedRange($namedRange);
|
||||
$sheet1->getCell('C2')->setValue('=ABC');
|
||||
self::assertEquals(1, $sheet1->getCell('C2')->getCalculatedValue());
|
||||
$sheet2->getCell('C2')->setValue('=ABC');
|
||||
self::assertEquals('#NAME?', $sheet2->getCell('C2')->getCalculatedValue());
|
||||
}
|
||||
|
||||
public function testScope(): void
|
||||
{
|
||||
$sheet1 = $this->spreadsheet->getSheetByName('Sheet #1');
|
||||
$sheet2 = $this->spreadsheet->getSheetByName('Sheet #2');
|
||||
$sheet1->getCell('A1')->setValue(1);
|
||||
$sheet2->getCell('A1')->setValue(2);
|
||||
$namedRange = new NamedRange('abc', $sheet2, '$A$1');
|
||||
$namedRange->setScope($sheet1);
|
||||
$this->spreadsheet->addNamedRange($namedRange);
|
||||
$sheet1->getCell('C2')->setValue('=ABC');
|
||||
self::assertEquals(2, $sheet1->getCell('C2')->getCalculatedValue());
|
||||
$sheet2->getCell('C2')->setValue('=ABC');
|
||||
self::assertEquals('#NAME?', $sheet2->getCell('C2')->getCalculatedValue());
|
||||
}
|
||||
|
||||
public function testClone(): void
|
||||
{
|
||||
$sheet1 = $this->spreadsheet->getSheetByName('Sheet #1');
|
||||
$sheet2 = $this->spreadsheet->getSheetByName('Sheet #2');
|
||||
$sheet1->getCell('A1')->setValue(1);
|
||||
$sheet2->getCell('A1')->setValue(2);
|
||||
$namedRange = new NamedRange('abc', $sheet2, '$A$1');
|
||||
$namedRangeClone = clone $namedRange;
|
||||
$ss1 = $namedRange->getWorksheet();
|
||||
$ss2 = $namedRangeClone->getWorksheet();
|
||||
self::assertNotSame($ss1, $ss2);
|
||||
self::assertEquals($ss1->getTitle(), $ss2->getTitle());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
|||
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
|
||||
use PhpOffice\PhpSpreadsheet\DocumentGenerator;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use UnexpectedValueException;
|
||||
|
||||
class DocumentGeneratorTest extends TestCase
|
||||
{
|
||||
|
|
@ -137,4 +138,13 @@ EXPECTED
|
|||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function testGenerateFunctionBadArray(): void
|
||||
{
|
||||
$this->expectException(UnexpectedValueException::class);
|
||||
$phpSpreadsheetFunctions = [
|
||||
'ABS' => ['category' => Cat::CATEGORY_MATH_AND_TRIG, 'functionCall' => 1],
|
||||
];
|
||||
DocumentGenerator::generateFunctionListByName($phpSpreadsheetFunctions);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace PhpOffice\PhpSpreadsheetTests\Functional;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Alignment;
|
||||
|
||||
class CommentsTest extends AbstractFunctional
|
||||
{
|
||||
|
|
@ -35,10 +36,22 @@ class CommentsTest extends AbstractFunctional
|
|||
|
||||
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, $format);
|
||||
|
||||
$commentsLoaded = $reloadedSpreadsheet->getSheet(0)->getComments();
|
||||
$sheet = $reloadedSpreadsheet->getSheet(0);
|
||||
$commentsLoaded = $sheet->getComments();
|
||||
self::assertCount(1, $commentsLoaded);
|
||||
|
||||
$commentCoordinate = key($commentsLoaded);
|
||||
self::assertSame('E10', $commentCoordinate);
|
||||
$comment = $commentsLoaded[$commentCoordinate];
|
||||
self::assertEquals('Comment to test', (string) $comment);
|
||||
$commentClone = clone $comment;
|
||||
self::assertEquals($comment, $commentClone);
|
||||
self::assertNotSame($comment, $commentClone);
|
||||
if ($format === 'Xlsx') {
|
||||
self::assertEquals('feb0c24b880a8130262dadf801f85e94', $comment->getHashCode());
|
||||
self::assertEquals(Alignment::HORIZONTAL_GENERAL, $comment->getAlignment());
|
||||
$comment->setAlignment(Alignment::HORIZONTAL_RIGHT);
|
||||
self::assertEquals(Alignment::HORIZONTAL_RIGHT, $comment->getAlignment());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class SampleTest extends TestCase
|
|||
}
|
||||
|
||||
// Unfortunately some tests are too long be ran with code-coverage
|
||||
// analysis on Travis, so we need to exclude them
|
||||
// analysis on GitHub Actions, so we need to exclude them
|
||||
global $argv;
|
||||
if (in_array('--coverage-clover', $argv)) {
|
||||
$tooLongToBeCovered = [
|
||||
|
|
|
|||
|
|
@ -161,4 +161,45 @@ class IOFactoryTest extends TestCase
|
|||
|
||||
IOFactory::registerReader('foo', 'bar');
|
||||
}
|
||||
|
||||
public function testCreateInvalidWriter(): void
|
||||
{
|
||||
$this->expectException(\PhpOffice\PhpSpreadsheet\Writer\Exception::class);
|
||||
$spreadsheet = new Spreadsheet();
|
||||
IOFactory::createWriter($spreadsheet, 'bad');
|
||||
}
|
||||
|
||||
public function testCreateInvalidReader(): void
|
||||
{
|
||||
$this->expectException(\PhpOffice\PhpSpreadsheet\Reader\Exception::class);
|
||||
IOFactory::createReader('bad');
|
||||
}
|
||||
|
||||
public function testCreateReaderUnknownExtension(): void
|
||||
{
|
||||
$filename = 'samples/Reader/sampleData/example1.tsv';
|
||||
$reader = IOFactory::createReaderForFile($filename);
|
||||
self::assertEquals('PhpOffice\\PhpSpreadsheet\\Reader\\Csv', get_class($reader));
|
||||
}
|
||||
|
||||
public function testCreateReaderCsvExtension(): void
|
||||
{
|
||||
$filename = 'samples/Reader/sampleData/example1.csv';
|
||||
$reader = IOFactory::createReaderForFile($filename);
|
||||
self::assertEquals('PhpOffice\\PhpSpreadsheet\\Reader\\Csv', get_class($reader));
|
||||
}
|
||||
|
||||
public function testCreateReaderNoExtension(): void
|
||||
{
|
||||
$filename = 'samples/Reader/sampleData/example1xls';
|
||||
$reader = IOFactory::createReaderForFile($filename);
|
||||
self::assertEquals('PhpOffice\\PhpSpreadsheet\\Reader\\Xls', get_class($reader));
|
||||
}
|
||||
|
||||
public function testCreateReaderNotSpreadsheet(): void
|
||||
{
|
||||
$this->expectException(\PhpOffice\PhpSpreadsheet\Reader\Exception::class);
|
||||
$filename = __FILE__;
|
||||
IOFactory::createReaderForFile($filename);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -275,4 +275,66 @@ EOF;
|
|||
$reader = new Csv();
|
||||
$reader->load('tests/data/Reader/CSV/encoding.utf8.csvxxx');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerEscapes
|
||||
*/
|
||||
public function testInferSeparator(string $escape, string $delimiter): void
|
||||
{
|
||||
$reader = new Csv();
|
||||
$reader->setEscapeCharacter($escape);
|
||||
$filename = 'tests/data/Reader/CSV/escape.csv';
|
||||
$reader->listWorksheetInfo($filename);
|
||||
self::assertEquals($delimiter, $reader->getDelimiter());
|
||||
}
|
||||
|
||||
public function providerEscapes()
|
||||
{
|
||||
return [
|
||||
['\\', ';'],
|
||||
["\x0", ','],
|
||||
[(version_compare(PHP_VERSION, '7.4') < 0) ? "\x0" : '', ','],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerGuessEncoding
|
||||
*/
|
||||
public function testGuessEncoding(string $filename): void
|
||||
{
|
||||
$reader = new Csv();
|
||||
$reader->setInputEncoding(Csv::guessEncoding($filename));
|
||||
$spreadsheet = $reader->load($filename);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
self::assertEquals('première', $sheet->getCell('A1')->getValue());
|
||||
self::assertEquals('sixième', $sheet->getCell('C2')->getValue());
|
||||
}
|
||||
|
||||
public function providerGuessEncoding()
|
||||
{
|
||||
return [
|
||||
['tests/data/Reader/CSV/premiere.utf8.csv'],
|
||||
['tests/data/Reader/CSV/premiere.utf8bom.csv'],
|
||||
['tests/data/Reader/CSV/premiere.utf16be.csv'],
|
||||
['tests/data/Reader/CSV/premiere.utf16bebom.csv'],
|
||||
['tests/data/Reader/CSV/premiere.utf16le.csv'],
|
||||
['tests/data/Reader/CSV/premiere.utf16lebom.csv'],
|
||||
['tests/data/Reader/CSV/premiere.utf32be.csv'],
|
||||
['tests/data/Reader/CSV/premiere.utf32bebom.csv'],
|
||||
['tests/data/Reader/CSV/premiere.utf32le.csv'],
|
||||
['tests/data/Reader/CSV/premiere.utf32lebom.csv'],
|
||||
['tests/data/Reader/CSV/premiere.win1252.csv'],
|
||||
];
|
||||
}
|
||||
|
||||
public function testGuessEncodingDefltIso2(): void
|
||||
{
|
||||
$filename = 'tests/data/Reader/CSV/premiere.win1252.csv';
|
||||
$reader = new Csv();
|
||||
$reader->setInputEncoding(Csv::guessEncoding($filename, 'ISO-8859-2'));
|
||||
$spreadsheet = $reader->load($filename);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
self::assertEquals('premičre', $sheet->getCell('A1')->getValue());
|
||||
self::assertEquals('sixičme', $sheet->getCell('C2')->getValue());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Reader;
|
|||
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException;
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Slk;
|
||||
use PhpOffice\PhpSpreadsheet\Shared\File;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Border;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Fill;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Font;
|
||||
|
|
@ -12,6 +13,16 @@ class SlkTest extends \PHPUnit\Framework\TestCase
|
|||
{
|
||||
private static $testbook = __DIR__ . '/../../../samples/templates/SylkTest.slk';
|
||||
|
||||
private $filename = '';
|
||||
|
||||
protected function teardown(): void
|
||||
{
|
||||
if ($this->filename) {
|
||||
unlink($this->filename);
|
||||
$this->filename = '';
|
||||
}
|
||||
}
|
||||
|
||||
public function testInfo(): void
|
||||
{
|
||||
$reader = new Slk();
|
||||
|
|
@ -131,4 +142,17 @@ class SlkTest extends \PHPUnit\Framework\TestCase
|
|||
|
||||
self::assertEquals('FFFF0000', $sheet->getCell('A1')->getStyle()->getFont()->getColor()->getARGB());
|
||||
}
|
||||
|
||||
public function testLongName(): void
|
||||
{
|
||||
$contents = file_get_contents(self::$testbook);
|
||||
$this->filename = File::sysGetTempDir()
|
||||
. '/123456789a123456789b123456789c12345.slk';
|
||||
file_put_contents($this->filename, $contents);
|
||||
$reader = new Slk();
|
||||
$spreadsheet = $reader->load($this->filename);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
self::assertEquals('123456789a123456789b123456789c1', $sheet->getTitle());
|
||||
self::assertEquals('FFFF0000', $sheet->getCell('A1')->getStyle()->getFont()->getColor()->getARGB());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,4 +43,39 @@ class XlsTest extends AbstractFunctional
|
|||
self::assertEquals($sheet->getCell('A1')->getFormattedValue(), $newsheet->getCell('A1')->getFormattedValue());
|
||||
self::assertEquals($sheet->getCell("$col$row")->getFormattedValue(), $newsheet->getCell("$col$row")->getFormattedValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test load Xls file with invalid length in SST map.
|
||||
*/
|
||||
public function testLoadXlsBug1592(): void
|
||||
{
|
||||
$filename = 'tests/data/Reader/XLS/bug1592.xls';
|
||||
$reader = new Xls();
|
||||
// When no fix applied, spreadsheet is not loaded
|
||||
$spreadsheet = $reader->load($filename);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$col = $sheet->getHighestColumn();
|
||||
$row = $sheet->getHighestRow();
|
||||
|
||||
$newspreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx');
|
||||
$newsheet = $newspreadsheet->getActiveSheet();
|
||||
$newcol = $newsheet->getHighestColumn();
|
||||
$newrow = $newsheet->getHighestRow();
|
||||
|
||||
self::assertEquals($spreadsheet->getSheetCount(), $newspreadsheet->getSheetCount());
|
||||
self::assertEquals($sheet->getTitle(), $newsheet->getTitle());
|
||||
self::assertEquals($sheet->getColumnDimensions(), $newsheet->getColumnDimensions());
|
||||
self::assertEquals($col, $newcol);
|
||||
self::assertEquals($row, $newrow);
|
||||
|
||||
$rowIterator = $sheet->getRowIterator();
|
||||
|
||||
foreach ($rowIterator as $row) {
|
||||
foreach ($row->getCellIterator() as $cell) {
|
||||
$valOld = $cell->getFormattedValue();
|
||||
$valNew = $newsheet->getCell($cell->getCoordinate())->getFormattedValue();
|
||||
self::assertEquals($valOld, $valNew);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class NamedRangeTest extends TestCase
|
||||
{
|
||||
public static function testBug1686b(): void
|
||||
{
|
||||
$xlsxFile = 'tests/data/Reader/XLSX/bug1686b.xlsx';
|
||||
$reader = new Xlsx();
|
||||
$spreadsheet = $reader->load($xlsxFile);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
self::assertEquals(2.1, $sheet->getCell('A1')->getCalculatedValue());
|
||||
self::assertEquals('#REF!', $sheet->getCell('A2')->getCalculatedValue());
|
||||
self::assertEquals('#REF!', $sheet->getCell('A3')->getCalculatedValue());
|
||||
self::assertEquals('#NAME?', $sheet->getCell('A4')->getCalculatedValue());
|
||||
self::assertEquals('#REF!', $sheet->getCell('A5')->getCalculatedValue());
|
||||
}
|
||||
}
|
||||
|
|
@ -82,14 +82,9 @@ class XmlLoadTest extends TestCase
|
|||
public function testLoadUnusableSample(): void
|
||||
{
|
||||
// Sample spreadsheet is not readable by Excel.
|
||||
// But PhpSpreadsheet can load it except for coverage test.
|
||||
//global $argv;
|
||||
//if (in_array('--coverage-clover', $argv)) {
|
||||
// self::markTestSkipped('Mysterious Travis coverage failure IOFactoryTest');
|
||||
//}
|
||||
// But PhpSpreadsheet can load it.
|
||||
$filename = __DIR__
|
||||
. '/../../../..'
|
||||
//. '/samples/templates/Excel2003XMLTest.xml';
|
||||
. '/samples/templates/excel2003.short.bad.xml';
|
||||
$reader = new Xml();
|
||||
$spreadsheet = $reader->load($filename);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xml;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Xml;
|
||||
use PhpOffice\PhpSpreadsheet\Shared\File;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class XmlOddTest extends TestCase
|
||||
{
|
||||
private $filename = '';
|
||||
|
||||
protected function teardown(): void
|
||||
{
|
||||
if ($this->filename) {
|
||||
unlink($this->filename);
|
||||
$this->filename = '';
|
||||
}
|
||||
}
|
||||
|
||||
public function testWriteThenRead(): void
|
||||
{
|
||||
$xmldata = <<< 'EOT'
|
||||
<?xml version="1.0" encoding="UTF-8"?><?mso-application progid="Excel.Sheet"?>
|
||||
<Workbook xmlns:c="urn:schemas-microsoft-com:office:component:spreadsheet"
|
||||
xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
|
||||
xmlns="urn:schemas-microsoft-com:office:spreadsheet"
|
||||
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
|
||||
>
|
||||
<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
|
||||
<Title>Xml2003 Short Workbook</Title>
|
||||
</DocumentProperties>
|
||||
<CustomDocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
|
||||
<my_x05d0_Int dt:dt="integer">2</my_x05d0_Int>
|
||||
</CustomDocumentProperties>
|
||||
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
|
||||
<WindowHeight>9000</WindowHeight>
|
||||
<WindowWidth>13860</WindowWidth>
|
||||
<WindowTopX>240</WindowTopX>
|
||||
<WindowTopY>75</WindowTopY>
|
||||
<ProtectStructure>False</ProtectStructure>
|
||||
<ProtectWindows>False</ProtectWindows>
|
||||
</ExcelWorkbook>
|
||||
<ss:Worksheet ss:Name="Sample Data">
|
||||
<Table>
|
||||
<Column ss:Width="96.4913"/>
|
||||
<Row ss:Index="8" ss:AutoFitHeight="0" ss:Height="14.9953">
|
||||
<Cell>
|
||||
<ss:Data ss:Type="String">Test String 1</ss:Data>
|
||||
</Cell>
|
||||
</Row>
|
||||
</Table>
|
||||
</ss:Worksheet>
|
||||
</Workbook>
|
||||
EOT;
|
||||
$this->filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test');
|
||||
file_put_contents($this->filename, $xmldata);
|
||||
$reader = new Xml();
|
||||
$spreadsheet = $reader->load($this->filename);
|
||||
self::assertEquals(1, $spreadsheet->getSheetCount());
|
||||
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
self::assertEquals('Sample Data', $sheet->getTitle());
|
||||
self::assertEquals('Test String 1', $sheet->getCell('A8')->getValue());
|
||||
|
||||
$props = $spreadsheet->getProperties();
|
||||
self::assertEquals('Xml2003 Short Workbook', $props->getTitle());
|
||||
self::assertEquals('2', $props->getCustomPropertyValue('myאInt'));
|
||||
}
|
||||
}
|
||||
|
|
@ -51,6 +51,147 @@ class SpreadsheetTest extends TestCase
|
|||
*/
|
||||
public function testGetSheetByName($index, $sheetName): void
|
||||
{
|
||||
self::assertEquals($this->object->getSheet($index), $this->object->getSheetByName($sheetName));
|
||||
self::assertSame($this->object->getSheet($index), $this->object->getSheetByName($sheetName));
|
||||
}
|
||||
|
||||
public function testAddSheetDuplicateTitle(): void
|
||||
{
|
||||
$this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class);
|
||||
$sheet = new Worksheet();
|
||||
$sheet->setTitle('someSheet2');
|
||||
$this->object->addSheet($sheet);
|
||||
}
|
||||
|
||||
public function testAddSheetNoAdjustActive(): void
|
||||
{
|
||||
$this->object->setActiveSheetIndex(2);
|
||||
self::assertEquals(2, $this->object->getActiveSheetIndex());
|
||||
$sheet = new Worksheet();
|
||||
$sheet->setTitle('someSheet4');
|
||||
$this->object->addSheet($sheet);
|
||||
self::assertEquals(2, $this->object->getActiveSheetIndex());
|
||||
}
|
||||
|
||||
public function testAddSheetAdjustActive(): void
|
||||
{
|
||||
$this->object->setActiveSheetIndex(2);
|
||||
self::assertEquals(2, $this->object->getActiveSheetIndex());
|
||||
$sheet = new Worksheet();
|
||||
$sheet->setTitle('someSheet0');
|
||||
$this->object->addSheet($sheet, 0);
|
||||
self::assertEquals(3, $this->object->getActiveSheetIndex());
|
||||
}
|
||||
|
||||
public function testRemoveSheetIndexTooHigh(): void
|
||||
{
|
||||
$this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class);
|
||||
$this->object->removeSheetByIndex(4);
|
||||
}
|
||||
|
||||
public function testRemoveSheetNoAdjustActive(): void
|
||||
{
|
||||
$this->object->setActiveSheetIndex(1);
|
||||
self::assertEquals(1, $this->object->getActiveSheetIndex());
|
||||
$this->object->removeSheetByIndex(2);
|
||||
self::assertEquals(1, $this->object->getActiveSheetIndex());
|
||||
}
|
||||
|
||||
public function testRemoveSheetAdjustActive(): void
|
||||
{
|
||||
$this->object->setActiveSheetIndex(2);
|
||||
self::assertEquals(2, $this->object->getActiveSheetIndex());
|
||||
$this->object->removeSheetByIndex(1);
|
||||
self::assertEquals(1, $this->object->getActiveSheetIndex());
|
||||
}
|
||||
|
||||
public function testGetSheetIndexTooHigh(): void
|
||||
{
|
||||
$this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class);
|
||||
$this->object->getSheet(4);
|
||||
}
|
||||
|
||||
public function testGetIndexNonExistent(): void
|
||||
{
|
||||
$this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class);
|
||||
$sheet = new Worksheet();
|
||||
$sheet->setTitle('someSheet4');
|
||||
$this->object->getIndex($sheet);
|
||||
}
|
||||
|
||||
public function testSetIndexByName(): void
|
||||
{
|
||||
$this->object->setIndexByName('someSheet1', 1);
|
||||
self::assertEquals('someSheet2', $this->object->getSheet(0)->getTitle());
|
||||
self::assertEquals('someSheet1', $this->object->getSheet(1)->getTitle());
|
||||
self::assertEquals('someSheet 3', $this->object->getSheet(2)->getTitle());
|
||||
}
|
||||
|
||||
public function testRemoveAllSheets(): void
|
||||
{
|
||||
$this->object->setActiveSheetIndex(2);
|
||||
self::assertEquals(2, $this->object->getActiveSheetIndex());
|
||||
$this->object->removeSheetByIndex(0);
|
||||
self::assertEquals(1, $this->object->getActiveSheetIndex());
|
||||
$this->object->removeSheetByIndex(0);
|
||||
self::assertEquals(0, $this->object->getActiveSheetIndex());
|
||||
$this->object->removeSheetByIndex(0);
|
||||
self::assertEquals(-1, $this->object->getActiveSheetIndex());
|
||||
$sheet = new Worksheet();
|
||||
$sheet->setTitle('someSheet4');
|
||||
$this->object->addSheet($sheet);
|
||||
self::assertEquals(0, $this->object->getActiveSheetIndex());
|
||||
}
|
||||
|
||||
public function testBug1735(): void
|
||||
{
|
||||
$spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
|
||||
$spreadsheet->createSheet()->setTitle('addedsheet');
|
||||
$spreadsheet->setActiveSheetIndex(1);
|
||||
$spreadsheet->removeSheetByIndex(0);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
self::assertEquals('addedsheet', $sheet->getTitle());
|
||||
}
|
||||
|
||||
public function testSetActiveSheetIndexTooHigh(): void
|
||||
{
|
||||
$this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class);
|
||||
$this->object->setActiveSheetIndex(4);
|
||||
}
|
||||
|
||||
public function testSetActiveSheetNoSuchName(): void
|
||||
{
|
||||
$this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class);
|
||||
$this->object->setActiveSheetIndexByName('unknown');
|
||||
}
|
||||
|
||||
public function testAddExternal(): void
|
||||
{
|
||||
$spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
|
||||
$sheet = $spreadsheet->createSheet()->setTitle('someSheet19');
|
||||
$sheet->getCell('A1')->setValue(1);
|
||||
$sheet->getCell('A1')->getStyle()->getFont()->setBold(true);
|
||||
$sheet->getCell('B1')->getStyle()->getFont()->setSuperscript(true);
|
||||
$sheet->getCell('C1')->getStyle()->getFont()->setSubscript(true);
|
||||
self::assertCount(4, $spreadsheet->getCellXfCollection());
|
||||
self::assertEquals(1, $sheet->getCell('A1')->getXfIndex());
|
||||
$this->object->getActiveSheet()->getCell('A1')->getStyle()->getFont()->setBold(true);
|
||||
self::assertCount(2, $this->object->getCellXfCollection());
|
||||
$sheet3 = $this->object->addExternalSheet($sheet);
|
||||
self::assertCount(6, $this->object->getCellXfCollection());
|
||||
self::assertEquals('someSheet19', $sheet3->getTitle());
|
||||
self::assertEquals(1, $sheet3->getCell('A1')->getValue());
|
||||
self::assertTrue($sheet3->getCell('A1')->getStyle()->getFont()->getBold());
|
||||
// Prove Xf index changed although style is same.
|
||||
self::assertEquals(3, $sheet3->getCell('A1')->getXfIndex());
|
||||
}
|
||||
|
||||
public function testAddExternalDuplicateName(): void
|
||||
{
|
||||
$this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class);
|
||||
$spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
|
||||
$sheet = $spreadsheet->createSheet()->setTitle('someSheet1');
|
||||
$sheet->getCell('A1')->setValue(1);
|
||||
$sheet->getCell('A1')->getStyle()->getFont()->setBold(true);
|
||||
$this->object->addExternalSheet($sheet);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace PhpOffice\PhpSpreadsheetTests\Style;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Fill;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class StyleTest extends TestCase
|
||||
|
|
@ -19,4 +20,141 @@ class StyleTest extends TestCase
|
|||
$outArray = $cell1style->getStyleArray($styleArray);
|
||||
self::assertEquals($styleArray, $outArray['quotePrefix']);
|
||||
}
|
||||
|
||||
public function testStyleColumn(): void
|
||||
{
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$cellCoordinates = 'A:B';
|
||||
$styleArray = [
|
||||
'font' => [
|
||||
'bold' => true,
|
||||
],
|
||||
];
|
||||
$sheet->getStyle($cellCoordinates)->applyFromArray($styleArray);
|
||||
$sheet->setCellValue('A1', 'xxxa1');
|
||||
$sheet->setCellValue('A2', 'xxxa2');
|
||||
$sheet->setCellValue('A3', 'xxxa3');
|
||||
$sheet->setCellValue('B1', 'xxxa1');
|
||||
$sheet->setCellValue('B2', 'xxxa2');
|
||||
$sheet->setCellValue('B3', 'xxxa3');
|
||||
$sheet->setCellValue('C1', 'xxxc1');
|
||||
$sheet->setCellValue('C2', 'xxxc2');
|
||||
$sheet->setCellValue('C3', 'xxxc3');
|
||||
$styleArray = [
|
||||
'font' => [
|
||||
'italic' => true,
|
||||
],
|
||||
];
|
||||
$sheet->getStyle($cellCoordinates)->applyFromArray($styleArray);
|
||||
self::assertTrue($sheet->getStyle('A1')->getFont()->getBold());
|
||||
self::assertTrue($sheet->getStyle('B2')->getFont()->getBold());
|
||||
self::assertFalse($sheet->getStyle('C3')->getFont()->getBold());
|
||||
self::assertTrue($sheet->getStyle('A1')->getFont()->getItalic());
|
||||
self::assertTrue($sheet->getStyle('B2')->getFont()->getItalic());
|
||||
self::assertFalse($sheet->getStyle('C3')->getFont()->getItalic());
|
||||
}
|
||||
|
||||
public function testStyleRow(): void
|
||||
{
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$cellCoordinates = '2:3';
|
||||
$styleArray = [
|
||||
'font' => [
|
||||
'bold' => true,
|
||||
],
|
||||
];
|
||||
$sheet->getStyle($cellCoordinates)->applyFromArray($styleArray);
|
||||
$sheet->setCellValue('A1', 'xxxa1');
|
||||
$sheet->setCellValue('A2', 'xxxa2');
|
||||
$sheet->setCellValue('A3', 'xxxa3');
|
||||
$sheet->setCellValue('B1', 'xxxa1');
|
||||
$sheet->setCellValue('B2', 'xxxa2');
|
||||
$sheet->setCellValue('B3', 'xxxa3');
|
||||
$sheet->setCellValue('C1', 'xxxc1');
|
||||
$sheet->setCellValue('C2', 'xxxc2');
|
||||
$sheet->setCellValue('C3', 'xxxc3');
|
||||
$styleArray = [
|
||||
'font' => [
|
||||
'italic' => true,
|
||||
],
|
||||
];
|
||||
$sheet->getStyle($cellCoordinates)->applyFromArray($styleArray);
|
||||
self::assertFalse($sheet->getStyle('A1')->getFont()->getBold());
|
||||
self::assertTrue($sheet->getStyle('B2')->getFont()->getBold());
|
||||
self::assertTrue($sheet->getStyle('C3')->getFont()->getBold());
|
||||
self::assertFalse($sheet->getStyle('A1')->getFont()->getItalic());
|
||||
self::assertTrue($sheet->getStyle('B2')->getFont()->getItalic());
|
||||
self::assertTrue($sheet->getStyle('C3')->getFont()->getItalic());
|
||||
}
|
||||
|
||||
public function testIssue1712A(): void
|
||||
{
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$rgb = '4467b8';
|
||||
$sheet->fromArray(['OK', 'KO']);
|
||||
$spreadsheet->getActiveSheet()
|
||||
->getStyle('A1')
|
||||
->getFill()
|
||||
->setFillType(Fill::FILL_SOLID)
|
||||
->getStartColor()
|
||||
->setRGB($rgb);
|
||||
$spreadsheet->getActiveSheet()
|
||||
->getStyle('B')
|
||||
->getFill()
|
||||
->setFillType(Fill::FILL_SOLID)
|
||||
->getStartColor()
|
||||
->setRGB($rgb);
|
||||
self::assertEquals($rgb, $sheet->getCell('A1')->getStyle()->getFill()->getStartColor()->getRGB());
|
||||
self::assertEquals($rgb, $sheet->getCell('B1')->getStyle()->getFill()->getStartColor()->getRGB());
|
||||
}
|
||||
|
||||
public function testIssue1712B(): void
|
||||
{
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$rgb = '4467b8';
|
||||
$spreadsheet->getActiveSheet()
|
||||
->getStyle('A1')
|
||||
->getFill()
|
||||
->setFillType(Fill::FILL_SOLID)
|
||||
->getStartColor()
|
||||
->setRGB($rgb);
|
||||
$spreadsheet->getActiveSheet()
|
||||
->getStyle('B')
|
||||
->getFill()
|
||||
->setFillType(Fill::FILL_SOLID)
|
||||
->getStartColor()
|
||||
->setRGB($rgb);
|
||||
$sheet->fromArray(['OK', 'KO']);
|
||||
self::assertEquals($rgb, $sheet->getCell('A1')->getStyle()->getFill()->getStartColor()->getRGB());
|
||||
self::assertEquals($rgb, $sheet->getCell('B1')->getStyle()->getFill()->getStartColor()->getRGB());
|
||||
}
|
||||
|
||||
public function testStyleLoopUpwards(): void
|
||||
{
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$cellCoordinates = 'C5:A3';
|
||||
$styleArray = [
|
||||
'font' => [
|
||||
'bold' => true,
|
||||
],
|
||||
];
|
||||
$sheet->getStyle($cellCoordinates)->applyFromArray($styleArray);
|
||||
$sheet->setCellValue('A1', 'xxxa1');
|
||||
$sheet->setCellValue('A2', 'xxxa2');
|
||||
$sheet->setCellValue('A3', 'xxxa3');
|
||||
$sheet->setCellValue('B1', 'xxxa1');
|
||||
$sheet->setCellValue('B2', 'xxxa2');
|
||||
$sheet->setCellValue('B3', 'xxxa3');
|
||||
$sheet->setCellValue('C1', 'xxxc1');
|
||||
$sheet->setCellValue('C2', 'xxxc2');
|
||||
$sheet->setCellValue('C3', 'xxxc3');
|
||||
self::assertFalse($sheet->getStyle('A1')->getFont()->getBold());
|
||||
self::assertFalse($sheet->getStyle('B2')->getFont()->getBold());
|
||||
self::assertTrue($sheet->getStyle('C3')->getFont()->getBold());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Worksheet;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\ColumnCellIterator;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ColumnCellIterator2Test extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerExistingCell
|
||||
*/
|
||||
public function testEndRange(?bool $existing, string $expectedResultFirst, string $expectedResultLast): void
|
||||
{
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('B2')->setValue('cellb2');
|
||||
$sheet->getCell('B6')->setValue('cellb6');
|
||||
|
||||
$iterator = new ColumnCellIterator($sheet, 'B', 1, 8);
|
||||
if (isset($existing)) {
|
||||
$iterator->setIterateOnlyExistingCells($existing);
|
||||
}
|
||||
$lastCoordinate = '';
|
||||
$firstCoordinate = '';
|
||||
foreach ($iterator as $cell) {
|
||||
$lastCoordinate = $cell->getCoordinate();
|
||||
if (!$firstCoordinate) {
|
||||
$firstCoordinate = $lastCoordinate;
|
||||
}
|
||||
}
|
||||
self::assertEquals($expectedResultFirst, $firstCoordinate);
|
||||
self::assertEquals($expectedResultLast, $lastCoordinate);
|
||||
}
|
||||
|
||||
public function providerExistingCell(): array
|
||||
{
|
||||
return [
|
||||
[null, 'B1', 'B8'],
|
||||
[false, 'B1', 'B8'],
|
||||
[true, 'B2', 'B6'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerEmptyColumn
|
||||
*/
|
||||
public function testEmptyColumn(?bool $existing, int $expectedResult): void
|
||||
{
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('B2')->setValue('cellb2');
|
||||
$sheet->getCell('B6')->setValue('cellb6');
|
||||
|
||||
$iterator = new ColumnCellIterator($sheet, 'C');
|
||||
if (isset($existing)) {
|
||||
$iterator->setIterateOnlyExistingCells($existing);
|
||||
}
|
||||
$numCells = 0;
|
||||
foreach ($iterator as $cell) {
|
||||
++$numCells;
|
||||
}
|
||||
self::assertEquals($expectedResult, $numCells);
|
||||
}
|
||||
|
||||
public function providerEmptyColumn(): array
|
||||
{
|
||||
return [
|
||||
[null, 6],
|
||||
[false, 6],
|
||||
[true, 0],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -71,11 +71,21 @@ class ColumnCellIteratorTest extends TestCase
|
|||
public function testSeekOutOfRange(): void
|
||||
{
|
||||
$this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class);
|
||||
|
||||
$this->expectExceptionMessage('Row 1 is out of range');
|
||||
$iterator = new ColumnCellIterator($this->mockWorksheet, 'A', 2, 4);
|
||||
$iterator->seek(1);
|
||||
}
|
||||
|
||||
public function testSeekNotExisting(): void
|
||||
{
|
||||
$this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class);
|
||||
$this->expectExceptionMessage('Cell does not exist');
|
||||
|
||||
$iterator = new ColumnCellIterator($this->mockWorksheet, 'A', 2, 4);
|
||||
$iterator->setIterateOnlyExistingCells(true);
|
||||
$iterator->seek(2);
|
||||
}
|
||||
|
||||
public function testPrevOutOfRange(): void
|
||||
{
|
||||
$iterator = new ColumnCellIterator($this->mockWorksheet, 'A', 2, 4);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Worksheet;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\RowCellIterator;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class RowCellIterator2Test extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider providerExistingCell
|
||||
*/
|
||||
public function testEndRangeTrue(?bool $existing, string $expectedResultFirst, string $expectedResultLast): void
|
||||
{
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('C2')->setValue('cellb2');
|
||||
$sheet->getCell('F2')->setValue('cellf2');
|
||||
|
||||
$iterator = new RowCellIterator($sheet, 2, 'B', 'H');
|
||||
if (isset($existing)) {
|
||||
$iterator->setIterateOnlyExistingCells($existing);
|
||||
}
|
||||
$lastCoordinate = '';
|
||||
$firstCoordinate = '';
|
||||
foreach ($iterator as $cell) {
|
||||
$lastCoordinate = $cell->getCoordinate();
|
||||
if (!$firstCoordinate) {
|
||||
$firstCoordinate = $lastCoordinate;
|
||||
}
|
||||
}
|
||||
self::assertEquals($expectedResultFirst, $firstCoordinate);
|
||||
self::assertEquals($expectedResultLast, $lastCoordinate);
|
||||
}
|
||||
|
||||
public function providerExistingCell(): array
|
||||
{
|
||||
return [
|
||||
[null, 'B2', 'H2'],
|
||||
[false, 'B2', 'H2'],
|
||||
[true, 'C2', 'F2'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerEmptyRow
|
||||
*/
|
||||
public function testEmptyRow(?bool $existing, int $expectedResult): void
|
||||
{
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->getCell('B2')->setValue('cellb2');
|
||||
$sheet->getCell('F2')->setValue('cellf2');
|
||||
|
||||
$iterator = new RowCellIterator($sheet, '3');
|
||||
if (isset($existing)) {
|
||||
$iterator->setIterateOnlyExistingCells($existing);
|
||||
}
|
||||
$numCells = 0;
|
||||
foreach ($iterator as $cell) {
|
||||
++$numCells;
|
||||
}
|
||||
self::assertEquals($expectedResult, $numCells);
|
||||
}
|
||||
|
||||
public function providerEmptyRow(): array
|
||||
{
|
||||
return [
|
||||
[null, 6],
|
||||
[false, 6],
|
||||
[true, 0],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -73,9 +73,22 @@ class RowCellIteratorTest extends TestCase
|
|||
public function testSeekOutOfRange(): void
|
||||
{
|
||||
$this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class);
|
||||
$this->expectExceptionMessage('Column A is out of range');
|
||||
|
||||
$iterator = new RowCellIterator($this->mockWorksheet, 2, 'B', 'D');
|
||||
$iterator->seek(1);
|
||||
self::assertFalse($iterator->getIterateOnlyExistingCells());
|
||||
self::assertEquals(2, $iterator->getCurrentColumnIndex());
|
||||
$iterator->seek('A');
|
||||
}
|
||||
|
||||
public function testSeekNotExisting(): void
|
||||
{
|
||||
$this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class);
|
||||
$this->expectExceptionMessage('Cell does not exist');
|
||||
|
||||
$iterator = new RowCellIterator($this->mockWorksheet, 2, 'B', 'D');
|
||||
$iterator->setIterateOnlyExistingCells(true);
|
||||
$iterator->seek('B');
|
||||
}
|
||||
|
||||
public function testPrevOutOfRange(): void
|
||||
|
|
|
|||
|
|
@ -10,15 +10,56 @@ use PhpOffice\PhpSpreadsheetTests\Functional;
|
|||
|
||||
class XssVulnerabilityTest extends Functional\AbstractFunctional
|
||||
{
|
||||
public function providerAcceptableMarkupRichText()
|
||||
{
|
||||
return [
|
||||
'basic text' => ['Hello, I am safely viewing your site', 'Hello, I am safely viewing your site'],
|
||||
'link' => ["<a href='Visit Google'>Google is here</a>", '<a href="Visit%20Google">Google is here</a>'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerAcceptableMarkupRichText
|
||||
*
|
||||
* @param string $safeTextString
|
||||
* @param string $adjustedTextString
|
||||
*/
|
||||
public function testMarkupInComment($safeTextString, $adjustedTextString): void
|
||||
{
|
||||
$spreadsheet = new Spreadsheet();
|
||||
|
||||
$richText = new RichText();
|
||||
$richText->createText($safeTextString);
|
||||
|
||||
$spreadsheet->getActiveSheet()->getCell('A1')->setValue('XSS Test');
|
||||
|
||||
$spreadsheet->getActiveSheet()
|
||||
->getComment('A1')
|
||||
->setText($richText);
|
||||
|
||||
$filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test');
|
||||
|
||||
$writer = IOFactory::createWriter($spreadsheet, 'Html');
|
||||
$writer->save($filename);
|
||||
|
||||
$verify = file_get_contents($filename);
|
||||
// Ensure that executable js has been stripped from the comments
|
||||
self::assertStringContainsString($adjustedTextString, $verify);
|
||||
}
|
||||
|
||||
public function providerXssRichText()
|
||||
{
|
||||
return [
|
||||
'script tag' => ['<script>alert(1)</script>'],
|
||||
'javascript tag' => ['javascript:alert(1)'],
|
||||
'with unicode' => ['java\u0003script:alert(1)'],
|
||||
'script tag' => ["Hello, I am trying to <script>alert('Hack');</script> your site"],
|
||||
'javascript tag' => ["<a href=' javascript:alert(1)'>CLICK</a>"],
|
||||
'with unicode' => ['<a href="\\u0001java\\u0003script:alert(1)">CLICK<a>'],
|
||||
'inline css' => ['<li style="list-style-image: url(javascript:alert(0))">'],
|
||||
'char value chevron' => ["\x3cscript src=http://www.example.com/malicious-code.js\x3e\x3c/script\x3e"],
|
||||
];
|
||||
}
|
||||
|
||||
private static $counter = 0;
|
||||
|
||||
/**
|
||||
* @dataProvider providerXssRichText
|
||||
*
|
||||
|
|
@ -43,6 +84,8 @@ class XssVulnerabilityTest extends Functional\AbstractFunctional
|
|||
$writer->save($filename);
|
||||
|
||||
$verify = file_get_contents($filename);
|
||||
$counter = self::$counter++;
|
||||
file_put_contents("verify{$counter}.html", $verify);
|
||||
// Ensure that executable js has been stripped from the comments
|
||||
self::assertStringNotContainsString($xssTextString, $verify);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
[
|
||||
0,
|
||||
0,
|
||||
2,
|
||||
],
|
||||
[
|
||||
662,
|
||||
662.78999999999996,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
[
|
||||
0,
|
||||
0,
|
||||
2,
|
||||
],
|
||||
[
|
||||
663,
|
||||
662.78999999999996,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@ return [
|
|||
'#VALUE!',
|
||||
-5,
|
||||
],
|
||||
[
|
||||
'#VALUE!',
|
||||
0,
|
||||
],
|
||||
[
|
||||
'A',
|
||||
65,
|
||||
|
|
@ -22,27 +26,39 @@ return [
|
|||
126,
|
||||
],
|
||||
[
|
||||
'⽇',
|
||||
'Á',
|
||||
193,
|
||||
],
|
||||
[
|
||||
'ÿ',
|
||||
255,
|
||||
],
|
||||
[
|
||||
'#VALUE!',
|
||||
256,
|
||||
],
|
||||
[
|
||||
'#VALUE!', // '⽇',
|
||||
12103,
|
||||
],
|
||||
[
|
||||
'œ',
|
||||
'#VALUE!', // 'œ',
|
||||
0x153,
|
||||
],
|
||||
[
|
||||
'ƒ',
|
||||
'#VALUE!', // 'ƒ',
|
||||
0x192,
|
||||
],
|
||||
[
|
||||
'℅',
|
||||
'#VALUE!', // '℅',
|
||||
0x2105,
|
||||
],
|
||||
[
|
||||
'∑',
|
||||
'#VALUE!', // '∑',
|
||||
0x2211,
|
||||
],
|
||||
[
|
||||
'†',
|
||||
'#VALUE!', // '†',
|
||||
0x2020,
|
||||
],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -6,11 +6,20 @@ return [
|
|||
123.456,
|
||||
2,
|
||||
],
|
||||
[
|
||||
'$123.46',
|
||||
123.456,
|
||||
],
|
||||
[
|
||||
'$123.32',
|
||||
123.321,
|
||||
2,
|
||||
],
|
||||
[
|
||||
'($123.32)',
|
||||
-123.321,
|
||||
2,
|
||||
],
|
||||
[
|
||||
'$1,235,000',
|
||||
1234567,
|
||||
|
|
@ -22,12 +31,17 @@ return [
|
|||
-5,
|
||||
],
|
||||
[
|
||||
'#NUM!',
|
||||
'($1,200,000)',
|
||||
-1234567,
|
||||
-5,
|
||||
],
|
||||
[
|
||||
'#VALUE!',
|
||||
'ABC',
|
||||
2,
|
||||
],
|
||||
[
|
||||
'#NUM!',
|
||||
'#VALUE!',
|
||||
123.456,
|
||||
'ABC',
|
||||
],
|
||||
|
|
|
|||
|
|
@ -20,13 +20,41 @@ return [
|
|||
true,
|
||||
],
|
||||
[
|
||||
'#NUM!',
|
||||
'-123456.79',
|
||||
-123456.789,
|
||||
2,
|
||||
true,
|
||||
],
|
||||
[
|
||||
'123500',
|
||||
123456.789,
|
||||
-2,
|
||||
true,
|
||||
],
|
||||
[
|
||||
'123,500',
|
||||
123456.789,
|
||||
-2,
|
||||
],
|
||||
[
|
||||
'-123500',
|
||||
-123456.789,
|
||||
-2,
|
||||
true,
|
||||
],
|
||||
[
|
||||
'-123,500',
|
||||
-123456.789,
|
||||
-2,
|
||||
],
|
||||
[
|
||||
'#VALUE!',
|
||||
'ABC',
|
||||
2,
|
||||
null,
|
||||
],
|
||||
[
|
||||
'#NUM!',
|
||||
'#VALUE!',
|
||||
123.456,
|
||||
'ABC',
|
||||
null,
|
||||
|
|
|
|||
|
|
@ -54,6 +54,11 @@ return [
|
|||
'Mark Baker',
|
||||
2,
|
||||
],
|
||||
[
|
||||
1,
|
||||
'',
|
||||
'Mark Baker',
|
||||
],
|
||||
[
|
||||
'#VALUE!',
|
||||
'BITE',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
a\"hello;hello;hello;\",b\"hello;hello;hello;\",c\"\hello;hello;hello;\"
|
||||
a\"hello;hello;hello;\",b\"hello;hello;hello;\",c\"\hello;hello;hello;\",d
|
||||
a\"hello;hello;hello;\",b\"hello;hello;hello;\",c\"\hello;hello;hello;\"
|
||||
a\"hello;hello;hello;\",b\"hello;hello;hello;\",c\"\hello;hello;hello;\"
|
||||
|
Can't render this file because it contains an unexpected character in line 1 and column 3.
|
Binary file not shown.
|
Binary file not shown.
|
Binary file not shown.
|
Binary file not shown.
|
Binary file not shown.
|
Binary file not shown.
|
Binary file not shown.
|
Binary file not shown.
|
|
|
@ -0,0 +1,2 @@
|
|||
première,second,troisième
|
||||
Quatrième,cinquième,sixième
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
première,second,troisième
|
||||
Quatrième,cinquième,sixième
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
première,second,troisième
|
||||
Quatrième,cinquième,sixième
|
||||
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue