Merge branch 'master' into docprops

This commit is contained in:
Mark Baker 2021-05-30 13:37:07 +02:00 committed by GitHub
commit bff2317a03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 1626 additions and 1397 deletions

View File

@ -27,9 +27,11 @@ and this project adheres to [Semantic Versioning](https://semver.org).
### Removed
- Nothing.
- Use of `nb` rather than `no` as the locale language code for Norsk Bokmål.
### Fixed
- Fixed error in COUPNCD() calculation for end of month [Issue #2116](https://github.com/PHPOffice/PhpSpreadsheet/issues/2116) - [PR #2119](https://github.com/PHPOffice/PhpSpreadsheet/pull/2119)
- Resolve default values when a null argument is passed for HLOOKUP(), VLOOKUP() and ADDRESS() functions [Issue #2120](https://github.com/PHPOffice/PhpSpreadsheet/issues/2120) - [PR #2121](https://github.com/PHPOffice/PhpSpreadsheet/pull/2121)
- Fixed incorrect R1C1 to A1 subtraction formula conversion (`R[-2]C-R[2]C`) [Issue #2076](https://github.com/PHPOffice/PhpSpreadsheet/pull/2076) [PR #2086](https://github.com/PHPOffice/PhpSpreadsheet/pull/2086)
- Correctly handle absolute A1 references when converting to R1C1 format [PR #2060](https://github.com/PHPOffice/PhpSpreadsheet/pull/2060)
- Correct default fill style for conditional without a pattern defined [Issue #2035](https://github.com/PHPOffice/PhpSpreadsheet/issues/2035) [PR #2050](https://github.com/PHPOffice/PhpSpreadsheet/pull/2050)
@ -41,6 +43,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
- Fixed issue with Xlsx@listWorksheetInfo not returning any data
- Fixed invalid arguments triggering mb_substr() error in LEFT(), MID() and RIGHT() text functions. [Issue #640](https://github.com/PHPOffice/PhpSpreadsheet/issues/640)
- Fix for [Issue #1916](https://github.com/PHPOffice/PhpSpreadsheet/issues/1916) - Invalid signature check for XML files
- Fix change in `Font::setSize()` behavior for PHP8. [PR #2100](https://github.com/PHPOffice/PhpSpreadsheet/pull/2100)
## 1.17.1 - 2021-03-01
@ -109,7 +112,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
### Deprecated
- Nothing.
- All Excel Function implementations in `Calculation\Database`, `Calculation\DateTime`, `Calculation\Engineering`, `Calculation\Financial`, `Calculation\Logical`, `Calculation\LookupRef`, `Calculation\MathTrig`, `Calculation\Statistical`, `Calculation\TextData` and `Calculation\Web` have been moved to dedicated classes for individual functions or groups of related functions. See the docblocks against all the deprecated methods for details of the new methods to call instead. At some point, these old classes will be deleted.
### Removed

View File

@ -2,12 +2,13 @@
<?php
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\DocumentGenerator;
use PhpOffice\PhpSpreadsheetInfra\DocumentGenerator;
require_once 'vendor/autoload.php';
try {
$phpSpreadsheetFunctionsProperty = (new ReflectionClass(Calculation::class))->getProperty('phpSpreadsheetFunctions');
$phpSpreadsheetFunctionsProperty = (new ReflectionClass(Calculation::class))
->getProperty('phpSpreadsheetFunctions');
$phpSpreadsheetFunctionsProperty->setAccessible(true);
$phpSpreadsheetFunctions = $phpSpreadsheetFunctionsProperty->getValue();
ksort($phpSpreadsheetFunctions);

View File

@ -7,14 +7,16 @@ use PhpOffice\PhpSpreadsheetInfra\LocaleGenerator;
require_once 'vendor/autoload.php';
try {
$phpSpreadsheetFunctionsProperty = (new ReflectionClass(Calculation::class))->getProperty('phpSpreadsheetFunctions');
$phpSpreadsheetFunctionsProperty = (new ReflectionClass(Calculation::class))
->getProperty('phpSpreadsheetFunctions');
$phpSpreadsheetFunctionsProperty->setAccessible(true);
$phpSpreadsheetFunctions = $phpSpreadsheetFunctionsProperty->getValue();
$localeGenerator = new LocaleGenerator(
__DIR__ . '/../src/PhpSpreadsheet/Calculation/locale/',
realpath(__DIR__ . '/../src/PhpSpreadsheet/Calculation/locale/'),
'Translations.xlsx',
$phpSpreadsheetFunctions
$phpSpreadsheetFunctions,
true
);
$localeGenerator->generateLocales();
} catch (\Exception $e) {

View File

@ -1,195 +0,0 @@
<?php
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
error_reporting(E_ALL);
set_time_limit(0);
date_default_timezone_set('UTC');
// Adjust the path as required to reference the PHPSpreadsheet Bootstrap file
require_once __DIR__ . '/../samples/Bootstrap.php';
class ExcelFunction
{
public $category;
public $functionName;
public $excelVersion;
public $implementation;
public function __construct(string $category, string $functionName, string $excelVersion, string $implementation)
{
$this->category = $category;
$this->functionName = $functionName;
$this->excelVersion = $excelVersion;
$this->implementation = $implementation;
}
}
class ColumnSettings
{
public $length;
public $title;
public $underline;
public function __construct(string $title, int $length)
{
$this->length = $length;
$this->title = str_pad($title, $length, ' ');
$this->underline = str_repeat('-', $length);
}
}
class ListBuilder
{
private $inputFileName;
public $list = [];
public function __construct(string $inputFileName)
{
$this->inputFileName = $inputFileName;
$this->buildList();
uasort(
$this->list,
function ($a, $b) {
$aSortName = str_replace('.', '', $a->functionName, $aCount) . str_repeat('.', $aCount);
$bSortName = str_replace('.', '', $b->functionName, $bCount) . str_repeat('.', $bCount);
return $aSortName <=> $bSortName;
}
);
}
private function buildList(): void
{
$inputFile = new \SplFileObject($this->inputFileName);
$category = null;
while (!$inputFile->eof()) {
$line = $inputFile->fgets();
if (strpos($line, '#') === 0) {
if (strpos($line, '##') === 0) {
$category = trim(substr($line, 3));
}
continue;
}
$lineData = explode('|', $line);
if (count($lineData) <= 1 || strpos($line, '--') === 0) {
continue;
}
$functionData = array_map('trim', $lineData);
if ($functionData[0] === 'Excel Function') {
continue;
}
$function = new ExcelFunction($category, ...$functionData);
if (array_key_exists($function->functionName, $this->list)) {
echo " ERROR: Duplicate entry for function {$function->functionName} in master file", PHP_EOL;
continue;
}
$this->list[$function->functionName] = $function;
}
}
}
class AlphabeticFileWriter
{
private $outputFileName;
private $outputFile;
public function __construct(string $outputFileName)
{
$this->outputFileName = $outputFileName;
}
public function generate(ExcelFunction ...$functionList): void
{
$this->outputFile = new \SplFileObject($this->outputFileName, 'w');
$this->excelFunctionColumnSettings = new ColumnSettings('Excel Function', max(array_map('strlen', array_column($functionList, 'functionName'))));
$this->categoryColumnSettings = new ColumnSettings('Category', max(array_map('strlen', array_column($functionList, 'category'))));
$this->excelVersionColumnSettings = new ColumnSettings('Excel Version', 13);
$this->phpSpreadsheetFunctionColumnSettings = new ColumnSettings('PhpSpreadsheet Function', 24);
$this->header();
$this->body(...$functionList);
}
private function header(): void
{
$this->outputFile->fwrite('# Function list by name' . PHP_EOL);
}
private function body(ExcelFunction ...$functionList): void
{
$initialCharacter = null;
foreach ($functionList as $excelFunction) {
if (substr($excelFunction->functionName, 0, 1) !== $initialCharacter) {
$initialCharacter = $this->subHeader($excelFunction);
}
$functionName = str_pad($excelFunction->functionName, $this->excelFunctionColumnSettings->length, ' ');
$category = str_pad($excelFunction->category, $this->categoryColumnSettings->length, ' ');
$excelVersion = str_pad($excelFunction->excelVersion, $this->excelVersionColumnSettings->length, ' ');
$this->outputFile->fwrite("{$functionName} | {$category} | {$excelVersion} | {$excelFunction->implementation}" . PHP_EOL);
}
}
private function subHeader(ExcelFunction $excelFunction)
{
$initialCharacter = substr($excelFunction->functionName, 0, 1);
$this->outputFile->fwrite(PHP_EOL . "## {$initialCharacter}" . PHP_EOL . PHP_EOL);
$this->outputFile->fwrite("{$this->excelFunctionColumnSettings->title} | {$this->categoryColumnSettings->title} | {$this->excelVersionColumnSettings->title} | {$this->phpSpreadsheetFunctionColumnSettings->title}" . PHP_EOL);
$this->outputFile->fwrite("{$this->excelFunctionColumnSettings->underline}-|-{$this->categoryColumnSettings->underline}-|-{$this->excelVersionColumnSettings->underline}-|-{$this->phpSpreadsheetFunctionColumnSettings->underline}" . PHP_EOL);
return $initialCharacter;
}
}
$folder = __DIR__ . '/../docs/references/';
$inputFileName = 'function-list-by-category.md';
$outputFileName = 'function-list-by-name.md';
echo "Building list of functions from master file {$inputFileName}", PHP_EOL;
$listBuilder = new ListBuilder($folder . $inputFileName);
echo "Building new documentation list of alphabetic functions in {$outputFileName}", PHP_EOL;
$alphabeticFileWriter = new AlphabeticFileWriter($folder . $outputFileName);
$alphabeticFileWriter->generate(...array_values($listBuilder->list));
echo 'Identifying discrepancies between the master file and the Calculation Engine codebase', PHP_EOL;
$definedFunctions = (new Calculation())->getFunctions();
foreach ($listBuilder->list as $excelFunction) {
if (!array_key_exists($excelFunction->functionName, $definedFunctions)) {
echo " ERROR: Function {$excelFunction->functionName}() of category {$excelFunction->category} is not defined in the Calculation Engine", PHP_EOL;
} elseif (array_key_exists($excelFunction->functionName, $definedFunctions) && $excelFunction->implementation === '**Not yet Implemented**') {
if ($definedFunctions[$excelFunction->functionName]['functionCall'] !== [Functions::class, 'DUMMY']) {
echo " ERROR: Function {$excelFunction->functionName}() of category {$excelFunction->category} is flagged as not yet implemented in the documentation", PHP_EOL;
echo ' but does have an implementation in the code', PHP_EOL;
}
}
}
foreach ($definedFunctions as $definedFunction => $definedFunctionDetail) {
if (!array_key_exists($definedFunction, $listBuilder->list)) {
echo " ERROR: Function {$definedFunction}() of category {$definedFunctionDetail['category']} is defined in the Calculation Engine, but not in the master file", PHP_EOL;
}
}

352
composer.lock generated
View File

@ -133,16 +133,16 @@
},
{
"name": "markbaker/complex",
"version": "2.0.0",
"version": "2.0.2",
"source": {
"type": "git",
"url": "https://github.com/MarkBaker/PHPComplex.git",
"reference": "9999f1432fae467bc93c53f357105b4c31bb994c"
"reference": "d18272926d58065140314c01e18ec3dd7ae854ea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/9999f1432fae467bc93c53f357105b4c31bb994c",
"reference": "9999f1432fae467bc93c53f357105b4c31bb994c",
"url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/d18272926d58065140314c01e18ec3dd7ae854ea",
"reference": "d18272926d58065140314c01e18ec3dd7ae854ea",
"shasum": ""
},
"require": {
@ -151,11 +151,7 @@
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
"phpcompatibility/php-compatibility": "^9.0",
"phpdocumentor/phpdocumentor": "2.*",
"phploc/phploc": "^4.0",
"phpmd/phpmd": "2.*",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.3",
"sebastian/phpcpd": "^4.0",
"squizlabs/php_codesniffer": "^3.4"
},
"type": "library",
@ -226,22 +222,22 @@
],
"support": {
"issues": "https://github.com/MarkBaker/PHPComplex/issues",
"source": "https://github.com/MarkBaker/PHPComplex/tree/PHP8"
"source": "https://github.com/MarkBaker/PHPComplex/tree/2.0.2"
},
"time": "2020-08-26T10:42:07+00:00"
"time": "2021-05-24T10:53:30+00:00"
},
{
"name": "markbaker/matrix",
"version": "2.1.2",
"version": "2.1.3",
"source": {
"type": "git",
"url": "https://github.com/MarkBaker/PHPMatrix.git",
"reference": "361c0f545c3172ee26c3d596a0aa03f0cef65e6a"
"reference": "174395a901b5ba0925f1d790fa91bab531074b61"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/361c0f545c3172ee26c3d596a0aa03f0cef65e6a",
"reference": "361c0f545c3172ee26c3d596a0aa03f0cef65e6a",
"url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/174395a901b5ba0925f1d790fa91bab531074b61",
"reference": "174395a901b5ba0925f1d790fa91bab531074b61",
"shasum": ""
},
"require": {
@ -300,32 +296,32 @@
],
"support": {
"issues": "https://github.com/MarkBaker/PHPMatrix/issues",
"source": "https://github.com/MarkBaker/PHPMatrix/tree/2.1.2"
"source": "https://github.com/MarkBaker/PHPMatrix/tree/2.1.3"
},
"time": "2021-01-23T16:37:31+00:00"
"time": "2021-05-25T15:42:17+00:00"
},
{
"name": "myclabs/php-enum",
"version": "1.7.7",
"version": "1.8.0",
"source": {
"type": "git",
"url": "https://github.com/myclabs/php-enum.git",
"reference": "d178027d1e679832db9f38248fcc7200647dc2b7"
"reference": "46cf3d8498b095bd33727b13fd5707263af99421"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/php-enum/zipball/d178027d1e679832db9f38248fcc7200647dc2b7",
"reference": "d178027d1e679832db9f38248fcc7200647dc2b7",
"url": "https://api.github.com/repos/myclabs/php-enum/zipball/46cf3d8498b095bd33727b13fd5707263af99421",
"reference": "46cf3d8498b095bd33727b13fd5707263af99421",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": ">=7.1"
"php": "^7.3 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^7",
"phpunit/phpunit": "^9.5",
"squizlabs/php_codesniffer": "1.*",
"vimeo/psalm": "^3.8"
"vimeo/psalm": "^4.5.1"
},
"type": "library",
"autoload": {
@ -350,7 +346,7 @@
],
"support": {
"issues": "https://github.com/myclabs/php-enum/issues",
"source": "https://github.com/myclabs/php-enum/tree/1.7.7"
"source": "https://github.com/myclabs/php-enum/tree/1.8.0"
},
"funding": [
{
@ -362,7 +358,7 @@
"type": "tidelift"
}
],
"time": "2020-11-14T18:14:52+00:00"
"time": "2021-02-15T16:11:48+00:00"
},
{
"name": "psr/http-client",
@ -659,16 +655,16 @@
"packages-dev": [
{
"name": "composer/semver",
"version": "3.2.4",
"version": "3.2.5",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
"reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464"
"reference": "31f3ea725711245195f62e54ffa402d8ef2fdba9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/a02fdf930a3c1c3ed3a49b5f63859c0c20e10464",
"reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464",
"url": "https://api.github.com/repos/composer/semver/zipball/31f3ea725711245195f62e54ffa402d8ef2fdba9",
"reference": "31f3ea725711245195f62e54ffa402d8ef2fdba9",
"shasum": ""
},
"require": {
@ -720,7 +716,7 @@
"support": {
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/semver/issues",
"source": "https://github.com/composer/semver/tree/3.2.4"
"source": "https://github.com/composer/semver/tree/3.2.5"
},
"funding": [
{
@ -736,20 +732,20 @@
"type": "tidelift"
}
],
"time": "2020-11-13T08:59:24+00:00"
"time": "2021-05-24T12:41:47+00:00"
},
{
"name": "composer/xdebug-handler",
"version": "1.4.6",
"version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/composer/xdebug-handler.git",
"reference": "f27e06cd9675801df441b3656569b328e04aa37c"
"reference": "964adcdd3a28bf9ed5d9ac6450064e0d71ed7496"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/f27e06cd9675801df441b3656569b328e04aa37c",
"reference": "f27e06cd9675801df441b3656569b328e04aa37c",
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/964adcdd3a28bf9ed5d9ac6450064e0d71ed7496",
"reference": "964adcdd3a28bf9ed5d9ac6450064e0d71ed7496",
"shasum": ""
},
"require": {
@ -784,7 +780,7 @@
"support": {
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/xdebug-handler/issues",
"source": "https://github.com/composer/xdebug-handler/tree/1.4.6"
"source": "https://github.com/composer/xdebug-handler/tree/2.0.1"
},
"funding": [
{
@ -800,7 +796,7 @@
"type": "tidelift"
}
],
"time": "2021-03-25T17:01:18+00:00"
"time": "2021-05-05T19:37:51+00:00"
},
{
"name": "dealerdirect/phpcodesniffer-composer-installer",
@ -875,28 +871,30 @@
},
{
"name": "doctrine/annotations",
"version": "1.12.1",
"version": "1.13.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/annotations.git",
"reference": "b17c5014ef81d212ac539f07a1001832df1b6d3b"
"reference": "e6e7b7d5b45a2f2abc5460cc6396480b2b1d321f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/b17c5014ef81d212ac539f07a1001832df1b6d3b",
"reference": "b17c5014ef81d212ac539f07a1001832df1b6d3b",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/e6e7b7d5b45a2f2abc5460cc6396480b2b1d321f",
"reference": "e6e7b7d5b45a2f2abc5460cc6396480b2b1d321f",
"shasum": ""
},
"require": {
"doctrine/lexer": "1.*",
"ext-tokenizer": "*",
"php": "^7.1 || ^8.0"
"php": "^7.1 || ^8.0",
"psr/cache": "^1 || ^2 || ^3"
},
"require-dev": {
"doctrine/cache": "1.*",
"doctrine/cache": "^1.11 || ^2.0",
"doctrine/coding-standard": "^6.0 || ^8.1",
"phpstan/phpstan": "^0.12.20",
"phpunit/phpunit": "^7.5 || ^9.1.5"
"phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5",
"symfony/cache": "^4.4 || ^5.2"
},
"type": "library",
"autoload": {
@ -939,9 +937,9 @@
],
"support": {
"issues": "https://github.com/doctrine/annotations/issues",
"source": "https://github.com/doctrine/annotations/tree/1.12.1"
"source": "https://github.com/doctrine/annotations/tree/1.13.1"
},
"time": "2021-02-21T21:00:45+00:00"
"time": "2021-05-16T18:07:53+00:00"
},
{
"name": "doctrine/instantiator",
@ -1166,21 +1164,21 @@
},
{
"name": "friendsofphp/php-cs-fixer",
"version": "v2.18.4",
"version": "v2.19.0",
"source": {
"type": "git",
"url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git",
"reference": "06f764e3cb6d60822d8f5135205f9d32b5508a31"
"reference": "d5b8a9d852b292c2f8a035200fa6844b1f82300b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/06f764e3cb6d60822d8f5135205f9d32b5508a31",
"reference": "06f764e3cb6d60822d8f5135205f9d32b5508a31",
"url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/d5b8a9d852b292c2f8a035200fa6844b1f82300b",
"reference": "d5b8a9d852b292c2f8a035200fa6844b1f82300b",
"shasum": ""
},
"require": {
"composer/semver": "^1.4 || ^2.0 || ^3.0",
"composer/xdebug-handler": "^1.2",
"composer/xdebug-handler": "^1.2 || ^2.0",
"doctrine/annotations": "^1.2",
"ext-json": "*",
"ext-tokenizer": "*",
@ -1223,6 +1221,11 @@
"php-cs-fixer"
],
"type": "application",
"extra": {
"branch-alias": {
"dev-master": "2.19-dev"
}
},
"autoload": {
"psr-4": {
"PhpCsFixer\\": "src/"
@ -1258,7 +1261,7 @@
"description": "A tool to automatically fix PHP code style",
"support": {
"issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues",
"source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v2.18.4"
"source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v2.19.0"
},
"funding": [
{
@ -1266,7 +1269,7 @@
"type": "github"
}
],
"time": "2021-03-20T14:52:33+00:00"
"time": "2021-05-03T21:43:24+00:00"
},
{
"name": "jpgraph/jpgraph",
@ -1315,16 +1318,16 @@
},
{
"name": "mpdf/mpdf",
"version": "v8.0.10",
"version": "v8.0.11",
"source": {
"type": "git",
"url": "https://github.com/mpdf/mpdf.git",
"reference": "1333a962cd2f7ae1a127b7534b7734b58179186f"
"reference": "af17afbbfa0b6ce76defc8da5d02a73d54f94c64"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mpdf/mpdf/zipball/1333a962cd2f7ae1a127b7534b7734b58179186f",
"reference": "1333a962cd2f7ae1a127b7534b7734b58179186f",
"url": "https://api.github.com/repos/mpdf/mpdf/zipball/af17afbbfa0b6ce76defc8da5d02a73d54f94c64",
"reference": "af17afbbfa0b6ce76defc8da5d02a73d54f94c64",
"shasum": ""
},
"require": {
@ -1386,7 +1389,7 @@
"type": "custom"
}
],
"time": "2021-01-08T14:59:28+00:00"
"time": "2021-05-12T14:18:06+00:00"
},
{
"name": "myclabs/deep-copy",
@ -2036,16 +2039,16 @@
},
{
"name": "phpstan/phpstan",
"version": "0.12.82",
"version": "0.12.88",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "3920f0fb0aff39263d3a4cb0bca120a67a1a6a11"
"reference": "464d1a81af49409c41074aa6640ed0c4cbd9bb68"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/3920f0fb0aff39263d3a4cb0bca120a67a1a6a11",
"reference": "3920f0fb0aff39263d3a4cb0bca120a67a1a6a11",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/464d1a81af49409c41074aa6640ed0c4cbd9bb68",
"reference": "464d1a81af49409c41074aa6640ed0c4cbd9bb68",
"shasum": ""
},
"require": {
@ -2076,7 +2079,7 @@
"description": "PHPStan - PHP Static Analysis Tool",
"support": {
"issues": "https://github.com/phpstan/phpstan/issues",
"source": "https://github.com/phpstan/phpstan/tree/0.12.82"
"source": "https://github.com/phpstan/phpstan/tree/0.12.88"
},
"funding": [
{
@ -2092,25 +2095,25 @@
"type": "tidelift"
}
],
"time": "2021-03-19T06:08:17+00:00"
"time": "2021-05-17T12:24:49+00:00"
},
{
"name": "phpstan/phpstan-phpunit",
"version": "0.12.18",
"version": "0.12.19",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-phpunit.git",
"reference": "ab44aec7cfb5cb267b8bc30a8caea86dd50d1f72"
"reference": "52f7072ddc5f81492f9d2de65a24813a48c90b18"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/ab44aec7cfb5cb267b8bc30a8caea86dd50d1f72",
"reference": "ab44aec7cfb5cb267b8bc30a8caea86dd50d1f72",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/52f7072ddc5f81492f9d2de65a24813a48c90b18",
"reference": "52f7072ddc5f81492f9d2de65a24813a48c90b18",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0",
"phpstan/phpstan": "^0.12.60"
"phpstan/phpstan": "^0.12.86"
},
"conflict": {
"phpunit/phpunit": "<7.0"
@ -2145,9 +2148,9 @@
"description": "PHPUnit extensions and rules for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-phpunit/issues",
"source": "https://github.com/phpstan/phpstan-phpunit/tree/0.12.18"
"source": "https://github.com/phpstan/phpstan-phpunit/tree/0.12.19"
},
"time": "2021-03-06T11:51:27+00:00"
"time": "2021-04-30T11:10:37+00:00"
},
{
"name": "phpunit/php-code-coverage",
@ -2388,29 +2391,29 @@
},
{
"name": "phpunit/php-token-stream",
"version": "3.1.2",
"version": "4.0.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
"reference": "472b687829041c24b25f475e14c2f38a09edf1c2"
"reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/472b687829041c24b25f475e14c2f38a09edf1c2",
"reference": "472b687829041c24b25f475e14c2f38a09edf1c2",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/a853a0e183b9db7eed023d7933a858fa1c8d25a3",
"reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
"php": ">=7.1"
"php": "^7.3 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^7.0"
"phpunit/phpunit": "^9.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
"dev-master": "4.0-dev"
}
},
"autoload": {
@ -2435,7 +2438,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-token-stream/issues",
"source": "https://github.com/sebastianbergmann/php-token-stream/tree/3.1.2"
"source": "https://github.com/sebastianbergmann/php-token-stream/tree/master"
},
"funding": [
{
@ -2444,7 +2447,7 @@
}
],
"abandoned": true,
"time": "2020-11-30T08:38:46+00:00"
"time": "2020-08-04T08:28:15+00:00"
},
{
"name": "phpunit/phpunit",
@ -2543,6 +2546,55 @@
],
"time": "2021-03-17T07:27:54+00:00"
},
{
"name": "psr/cache",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/cache.git",
"reference": "d11b50ad223250cf17b86e38383413f5a6764bf8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8",
"reference": "d11b50ad223250cf17b86e38383413f5a6764bf8",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Cache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for caching libraries",
"keywords": [
"cache",
"psr",
"psr-6"
],
"support": {
"source": "https://github.com/php-fig/cache/tree/master"
},
"time": "2016-08-06T20:24:11+00:00"
},
{
"name": "psr/container",
"version": "1.1.1",
@ -2643,16 +2695,16 @@
},
{
"name": "psr/log",
"version": "1.1.3",
"version": "1.1.4",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "0f73288fd15629204f9d42b7055f72dacbe811fc"
"reference": "d49695b909c3b7628b6289db5479a1c204601f11"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc",
"reference": "0f73288fd15629204f9d42b7055f72dacbe811fc",
"url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
"reference": "d49695b909c3b7628b6289db5479a1c204601f11",
"shasum": ""
},
"require": {
@ -2676,7 +2728,7 @@
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
@ -2687,9 +2739,9 @@
"psr-3"
],
"support": {
"source": "https://github.com/php-fig/log/tree/1.1.3"
"source": "https://github.com/php-fig/log/tree/1.1.4"
},
"time": "2020-03-23T09:12:05+00:00"
"time": "2021-05-03T11:20:27+00:00"
},
{
"name": "sabberworm/php-css-parser",
@ -3543,16 +3595,16 @@
},
{
"name": "squizlabs/php_codesniffer",
"version": "3.5.8",
"version": "3.6.0",
"source": {
"type": "git",
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
"reference": "9d583721a7157ee997f235f327de038e7ea6dac4"
"reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/9d583721a7157ee997f235f327de038e7ea6dac4",
"reference": "9d583721a7157ee997f235f327de038e7ea6dac4",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ffced0d2c8fa8e6cdc4d695a743271fab6c38625",
"reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625",
"shasum": ""
},
"require": {
@ -3595,20 +3647,20 @@
"source": "https://github.com/squizlabs/PHP_CodeSniffer",
"wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
},
"time": "2020-10-23T02:01:07+00:00"
"time": "2021-04-09T00:54:41+00:00"
},
{
"name": "symfony/console",
"version": "v5.2.5",
"version": "v5.2.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "938ebbadae1b0a9c9d1ec313f87f9708609f1b79"
"reference": "864568fdc0208b3eba3638b6000b69d2386e6768"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/938ebbadae1b0a9c9d1ec313f87f9708609f1b79",
"reference": "938ebbadae1b0a9c9d1ec313f87f9708609f1b79",
"url": "https://api.github.com/repos/symfony/console/zipball/864568fdc0208b3eba3638b6000b69d2386e6768",
"reference": "864568fdc0208b3eba3638b6000b69d2386e6768",
"shasum": ""
},
"require": {
@ -3676,7 +3728,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v5.2.5"
"source": "https://github.com/symfony/console/tree/v5.2.8"
},
"funding": [
{
@ -3692,20 +3744,20 @@
"type": "tidelift"
}
],
"time": "2021-03-06T13:42:15+00:00"
"time": "2021-05-11T15:45:21+00:00"
},
{
"name": "symfony/deprecation-contracts",
"version": "v2.2.0",
"version": "v2.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665"
"reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5fa56b4074d1ae755beb55617ddafe6f5d78f665",
"reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5f38c8804a9e97d23e0c8d63341088cd8a22d627",
"reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627",
"shasum": ""
},
"require": {
@ -3714,7 +3766,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
"dev-main": "2.4-dev"
},
"thanks": {
"name": "symfony/contracts",
@ -3743,7 +3795,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/master"
"source": "https://github.com/symfony/deprecation-contracts/tree/v2.4.0"
},
"funding": [
{
@ -3759,7 +3811,7 @@
"type": "tidelift"
}
],
"time": "2020-09-07T11:33:47+00:00"
"time": "2021-03-23T23:28:01+00:00"
},
{
"name": "symfony/event-dispatcher",
@ -3848,16 +3900,16 @@
},
{
"name": "symfony/event-dispatcher-contracts",
"version": "v2.2.0",
"version": "v2.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher-contracts.git",
"reference": "0ba7d54483095a198fa51781bc608d17e84dffa2"
"reference": "69fee1ad2332a7cbab3aca13591953da9cdb7a11"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/0ba7d54483095a198fa51781bc608d17e84dffa2",
"reference": "0ba7d54483095a198fa51781bc608d17e84dffa2",
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/69fee1ad2332a7cbab3aca13591953da9cdb7a11",
"reference": "69fee1ad2332a7cbab3aca13591953da9cdb7a11",
"shasum": ""
},
"require": {
@ -3870,7 +3922,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
"dev-main": "2.4-dev"
},
"thanks": {
"name": "symfony/contracts",
@ -3907,7 +3959,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.2.0"
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.4.0"
},
"funding": [
{
@ -3923,20 +3975,20 @@
"type": "tidelift"
}
],
"time": "2020-09-07T11:33:47+00:00"
"time": "2021-03-23T23:28:01+00:00"
},
{
"name": "symfony/filesystem",
"version": "v5.2.4",
"version": "v5.2.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "710d364200997a5afde34d9fe57bd52f3cc1e108"
"reference": "056e92acc21d977c37e6ea8e97374b2a6c8551b0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/710d364200997a5afde34d9fe57bd52f3cc1e108",
"reference": "710d364200997a5afde34d9fe57bd52f3cc1e108",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/056e92acc21d977c37e6ea8e97374b2a6c8551b0",
"reference": "056e92acc21d977c37e6ea8e97374b2a6c8551b0",
"shasum": ""
},
"require": {
@ -3969,7 +4021,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/filesystem/tree/v5.2.4"
"source": "https://github.com/symfony/filesystem/tree/v5.2.7"
},
"funding": [
{
@ -3985,20 +4037,20 @@
"type": "tidelift"
}
],
"time": "2021-02-12T10:38:38+00:00"
"time": "2021-04-01T10:42:13+00:00"
},
{
"name": "symfony/finder",
"version": "v5.2.4",
"version": "v5.2.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "0d639a0943822626290d169965804f79400e6a04"
"reference": "ccccb9d48ca42757dd12f2ca4bf857a4e217d90d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/0d639a0943822626290d169965804f79400e6a04",
"reference": "0d639a0943822626290d169965804f79400e6a04",
"url": "https://api.github.com/repos/symfony/finder/zipball/ccccb9d48ca42757dd12f2ca4bf857a4e217d90d",
"reference": "ccccb9d48ca42757dd12f2ca4bf857a4e217d90d",
"shasum": ""
},
"require": {
@ -4030,7 +4082,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/finder/tree/v5.2.4"
"source": "https://github.com/symfony/finder/tree/v5.2.9"
},
"funding": [
{
@ -4046,7 +4098,7 @@
"type": "tidelift"
}
],
"time": "2021-02-15T18:55:04+00:00"
"time": "2021-05-16T13:07:46+00:00"
},
{
"name": "symfony/options-resolver",
@ -4669,16 +4721,16 @@
},
{
"name": "symfony/process",
"version": "v5.2.4",
"version": "v5.2.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "313a38f09c77fbcdc1d223e57d368cea76a2fd2f"
"reference": "98cb8eeb72e55d4196dd1e36f1f16e7b3a9a088e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/313a38f09c77fbcdc1d223e57d368cea76a2fd2f",
"reference": "313a38f09c77fbcdc1d223e57d368cea76a2fd2f",
"url": "https://api.github.com/repos/symfony/process/zipball/98cb8eeb72e55d4196dd1e36f1f16e7b3a9a088e",
"reference": "98cb8eeb72e55d4196dd1e36f1f16e7b3a9a088e",
"shasum": ""
},
"require": {
@ -4711,7 +4763,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/v5.2.4"
"source": "https://github.com/symfony/process/tree/v5.3.0-BETA1"
},
"funding": [
{
@ -4727,25 +4779,25 @@
"type": "tidelift"
}
],
"time": "2021-01-27T10:15:41+00:00"
"time": "2021-04-08T10:27:02+00:00"
},
{
"name": "symfony/service-contracts",
"version": "v2.2.0",
"version": "v2.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1"
"reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/d15da7ba4957ffb8f1747218be9e1a121fd298a1",
"reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb",
"reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"psr/container": "^1.0"
"psr/container": "^1.1"
},
"suggest": {
"symfony/service-implementation": ""
@ -4753,7 +4805,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
"dev-main": "2.4-dev"
},
"thanks": {
"name": "symfony/contracts",
@ -4790,7 +4842,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/service-contracts/tree/master"
"source": "https://github.com/symfony/service-contracts/tree/v2.4.0"
},
"funding": [
{
@ -4806,20 +4858,20 @@
"type": "tidelift"
}
],
"time": "2020-09-07T11:33:47+00:00"
"time": "2021-04-01T10:43:52+00:00"
},
{
"name": "symfony/stopwatch",
"version": "v5.2.4",
"version": "v5.2.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/stopwatch.git",
"reference": "b12274acfab9d9850c52583d136a24398cdf1a0c"
"reference": "d99310c33e833def36419c284f60e8027d359678"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/stopwatch/zipball/b12274acfab9d9850c52583d136a24398cdf1a0c",
"reference": "b12274acfab9d9850c52583d136a24398cdf1a0c",
"url": "https://api.github.com/repos/symfony/stopwatch/zipball/d99310c33e833def36419c284f60e8027d359678",
"reference": "d99310c33e833def36419c284f60e8027d359678",
"shasum": ""
},
"require": {
@ -4852,7 +4904,7 @@
"description": "Provides a way to profile code",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/stopwatch/tree/v5.2.4"
"source": "https://github.com/symfony/stopwatch/tree/v5.3.0-BETA1"
},
"funding": [
{
@ -4868,20 +4920,20 @@
"type": "tidelift"
}
],
"time": "2021-01-27T10:15:41+00:00"
"time": "2021-03-29T15:28:41+00:00"
},
{
"name": "symfony/string",
"version": "v5.2.4",
"version": "v5.2.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "4e78d7d47061fa183639927ec40d607973699609"
"reference": "01b35eb64cac8467c3f94cd0ce2d0d376bb7d1db"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/4e78d7d47061fa183639927ec40d607973699609",
"reference": "4e78d7d47061fa183639927ec40d607973699609",
"url": "https://api.github.com/repos/symfony/string/zipball/01b35eb64cac8467c3f94cd0ce2d0d376bb7d1db",
"reference": "01b35eb64cac8467c3f94cd0ce2d0d376bb7d1db",
"shasum": ""
},
"require": {
@ -4935,7 +4987,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v5.2.4"
"source": "https://github.com/symfony/string/tree/v5.2.8"
},
"funding": [
{
@ -4951,7 +5003,7 @@
"type": "tidelift"
}
],
"time": "2021-02-16T10:20:28+00:00"
"time": "2021-05-10T14:56:10+00:00"
},
{
"name": "tecnickcom/tcpdf",

View File

@ -71,7 +71,7 @@ library.
### Csv
Comma Separated Value (CSV) file format is a common structuring strategy
for text format files. In CSV flies, each line in the file represents a
for text format files. In CSV files, each line in the file represents a
row of data and (within each line of the file) the different data fields
(or columns) are separated from one another using a comma (`,`). If a
data field contains a comma, then it should be enclosed (typically in

View File

@ -1,6 +1,6 @@
# Memory saving
PhpSpreadsheet uses an average of about 1k per cell in your worksheets, so
PhpSpreadsheet uses an average of about 1k per cell (1.6k on 64-bit PHP) in your worksheets, so
large workbooks can quickly use up available memory. Cell caching
provides a mechanism that allows PhpSpreadsheet to maintain the cell
objects in a smaller size of memory, or off-memory (eg: on disk, in APCu,

View File

@ -139,6 +139,11 @@ $reader->setReadFilter( new MyReadFilter() );
$spreadsheet = $reader->load("06largescale.xlsx");
```
Read Filtering does not renumber cell rows and columns. If you filter to read only rows 100-200, cells that you read will still be numbered A100-A200, not A1-A101. Cells A1-A99 will not be loaded, but if you then try to call `getCell()` for a cell outside your loaded range, then PHPSpreadsheet will create a new cell with a null value.
Methods such as `toArray()` assume that all cells in a spreadsheet has been loaded from A1, so will return null values for rows and columns that fall outside your filter range: it is recommended that you keep track of the range that your filter has requested, and use `rangeToArray()` instead.
### \PhpOffice\PhpSpreadsheet\Writer\Xlsx
#### Writing a spreadsheet
@ -162,6 +167,9 @@ $writer->setPreCalculateFormulas(false);
$writer->save("05featuredemo.xlsx");
```
**Note** Formulas will still be calculated in any column set to be autosized
even if pre-calculated is set to false
#### Office 2003 compatibility pack
Because of a bug in the Office2003 compatibility pack, there can be some
@ -477,6 +485,41 @@ $reader->setSheetIndex(0);
$spreadsheet = $reader->load('sample.csv');
```
You can also set the reader to guess the encoding
rather than calling guessEncoding directly. In this case,
the user-settable fallback encoding is used if nothing else works.
```php
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Csv();
$reader->setInputEncoding(\PhpOffice\PhpSpreadsheet\Reader\Csv::GUESS_ENCODING);
$reader->setFallbackEncoding('ISO-8859-2'); // default CP1252 without this statement
$reader->setDelimiter(';');
$reader->setEnclosure('');
$reader->setSheetIndex(0);
$spreadsheet = $reader->load('sample.csv');
```
Finally, you can set a callback to be invoked when the constructor is executed,
either through `new Csv()` or `IOFactory::load`,
and have that callback set the customizable attributes to whatever
defaults are appropriate for your environment.
```php
function constructorCallback(\PhpOffice\PhpSpreadsheet\Reader\Csv $reader): void
{
$reader->setInputEncoding(\PhpOffice\PhpSpreadsheet\Reader\Csv::GUESS_ENCODING);
$reader->setFallbackEncoding('ISO-8859-2');
$reader->setDelimiter(',');
$reader->setEnclosure('"');
// Following represents how Excel behaves better than the default escape character
$reader->setEscapeCharacter((version_compare(PHP_VERSION, '7.4') < 0) ? "\x0" : '');
}
\PhpOffice\PhpSpreadsheet\Reader\Csv::setConstructorCallback('constructorCallback');
$spreadsheet = \PhpSpreadsheet\IOFactory::load('sample.csv');
```
#### Read a specific worksheet
CSV files can only contain one worksheet. Therefore, you can specify

View File

@ -324,6 +324,10 @@ to read and process a large workbook in "chunks": an example of this
usage might be when transferring data from an Excel worksheet to a
database.
Read Filtering does not renumber cell rows and columns. If you filter to read only rows 100-200, cells that you read will still be numbered A100-A200, not A1-A101. Cells A1-A99 will not be loaded, but if you then try to call `getCell()` for a cell outside your loaded range, then PHPSpreadsheet will create a new cell with a null value.
Methods such as `toArray()` assume that all cells in a spreadsheet has been loaded from A1, so will return null values for rows and columns that fall outside your filter range: it is recommended that you keep track of the range that your filter has requested, and use `rangeToArray()` instead.
```php
$inputFileType = 'Xls';
$inputFileName = './sampleData/example2.xls';

View File

@ -988,6 +988,9 @@ $security->setLockStructure(true);
$security->setWorkbookPassword("PhpSpreadsheet");
```
Note that there are additional methods setLockRevision and setRevisionsPassword
which apply only to change tracking and history for shared workbooks.
### Worksheet
An example on setting worksheet security:

View File

@ -1,6 +1,6 @@
<?php
namespace PhpOffice\PhpSpreadsheet;
namespace PhpOffice\PhpSpreadsheetInfra;
use PhpOffice\PhpSpreadsheet\Calculation\Category;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
@ -78,6 +78,7 @@ class DocumentGenerator
$result = "# Function list by name\n";
$lastAlphabet = null;
foreach ($phpSpreadsheetFunctions as $excelFunction => $functionInfo) {
/** @var string $excelFunction */
$lengths = [25, 31, 37];
if ($lastAlphabet !== $excelFunction[0]) {
$lastAlphabet = $excelFunction[0];

View File

@ -43,6 +43,8 @@ class LocaleGenerator
*/
protected $translationSpreadsheet;
protected $verbose;
/**
* @var Worksheet
*/
@ -64,11 +66,13 @@ class LocaleGenerator
public function __construct(
string $translationBaseFolder,
string $translationSpreadsheetName,
array $phpSpreadsheetFunctions
array $phpSpreadsheetFunctions,
bool $verbose = false
) {
$this->translationBaseFolder = $translationBaseFolder;
$this->translationSpreadsheetName = $translationSpreadsheetName;
$this->phpSpreadsheetFunctions = $phpSpreadsheetFunctions;
$this->verbose = $verbose;
}
public function generateLocales(): void
@ -110,7 +114,7 @@ class LocaleGenerator
} else {
$errorCodeTranslation = "{$errorCode}" . PHP_EOL;
fwrite($configFile, $errorCodeTranslation);
echo "No {$language} translation available for error code {$errorCode}", PHP_EOL;
$this->log("No {$language} translation available for error code {$errorCode}");
}
}
@ -125,7 +129,7 @@ class LocaleGenerator
$functionTranslation = "ArgumentSeparator = {$localeValue}" . PHP_EOL;
fwrite($configFile, $functionTranslation);
} else {
echo 'No Argument Separator defined', PHP_EOL;
$this->log('No Argument Separator defined');
}
}
@ -142,12 +146,12 @@ class LocaleGenerator
if ($this->isFunctionCategoryEntry($translationCell)) {
$this->writeFileSectionHeader($functionFile, "{$translationValue} ({$functionName})");
} elseif (!array_key_exists($functionName, $this->phpSpreadsheetFunctions)) {
echo "Function {$functionName} is not defined in PhpSpreadsheet", PHP_EOL;
$this->log("Function {$functionName} is not defined in PhpSpreadsheet");
} elseif (!empty($translationValue)) {
$functionTranslation = "{$functionName} = {$translationValue}" . PHP_EOL;
fwrite($functionFile, $functionTranslation);
} else {
echo "No {$language} translation available for function {$functionName}", PHP_EOL;
$this->log("No {$language} translation available for function {$functionName}");
}
}
@ -156,11 +160,11 @@ class LocaleGenerator
protected function openConfigFile(string $locale, string $language, string $localeLanguage)
{
echo "Building locale {$locale} ($language) configuration", PHP_EOL;
$this->log("Building locale {$locale} ($language) configuration");
$localeFolder = $this->getLocaleFolder($locale);
$configFileName = realpath($localeFolder . DIRECTORY_SEPARATOR . 'config');
echo "Writing locale configuration to {$configFileName}", PHP_EOL;
$this->log("Writing locale configuration to {$configFileName}");
$configFile = fopen($configFileName, 'wb');
$this->writeFileHeader($configFile, $localeLanguage, $language, 'locale settings');
@ -170,11 +174,11 @@ class LocaleGenerator
protected function openFunctionNameFile(string $locale, string $language, string $localeLanguage)
{
echo "Building locale {$locale} ($language) function names", PHP_EOL;
$this->log("Building locale {$locale} ($language) function names");
$localeFolder = $this->getLocaleFolder($locale);
$functionFileName = realpath($localeFolder . DIRECTORY_SEPARATOR . 'functions');
echo "Writing local function names to {$functionFileName}", PHP_EOL;
$this->log("Writing local function names to {$functionFileName}");
$functionFile = fopen($functionFileName, 'wb');
$this->writeFileHeader($functionFile, $localeLanguage, $language, 'function name translations');
@ -231,7 +235,7 @@ class LocaleGenerator
protected function mapLanguageColumns(Worksheet $translationWorksheet): array
{
$sheetName = $translationWorksheet->getTitle();
echo "Mapping Languages for {$sheetName}:", PHP_EOL;
$this->log("Mapping Languages for {$sheetName}:");
$baseColumn = self::ENGLISH_REFERENCE_COLUMN;
$languagesList = $translationWorksheet->getColumnIterator(++$baseColumn);
@ -245,7 +249,7 @@ class LocaleGenerator
/** @var Cell $cell */
if ($this->localeCanBeSupported($translationWorksheet, $cell)) {
$languageNameMap[$cell->getColumn()] = $cell->getValue();
echo $cell->getColumn(), ' -> ', $cell->getValue(), PHP_EOL;
$this->log($cell->getColumn() . ' -> ' . $cell->getValue());
}
}
}
@ -270,7 +274,7 @@ class LocaleGenerator
protected function mapErrorCodeRows(): void
{
echo 'Mapping Error Codes:', PHP_EOL;
$this->log('Mapping Error Codes:');
$errorList = $this->localeTranslations->getRowIterator(self::ERROR_CODES_FIRST_ROW);
foreach ($errorList as $errorRow) {
@ -280,7 +284,7 @@ class LocaleGenerator
foreach ($cells as $cell) {
/** @var Cell $cell */
if ($cell->getValue() != '') {
echo $cell->getRow(), ' -> ', $cell->getValue(), PHP_EOL;
$this->log($cell->getRow() . ' -> ' . $cell->getValue());
$this->errorCodeMap[$cell->getValue()] = $cell->getRow();
}
}
@ -289,7 +293,7 @@ class LocaleGenerator
protected function mapFunctionNameRows(): void
{
echo 'Mapping Functions:', PHP_EOL;
$this->log('Mapping Functions:');
$functionList = $this->functionNameTranslations->getRowIterator(self::FUNCTION_NAME_LIST_FIRST_ROW);
foreach ($functionList as $functionRow) {
@ -300,7 +304,7 @@ class LocaleGenerator
/** @var Cell $cell */
if ($this->isFunctionCategoryEntry($cell)) {
if (!empty($cell->getValue())) {
echo 'CATEGORY: ', $cell->getValue(), PHP_EOL;
$this->log('CATEGORY: ' . $cell->getValue());
$this->functionNameMap[$cell->getValue()] = $cell->getRow();
}
@ -308,10 +312,10 @@ class LocaleGenerator
}
if ($cell->getValue() != '') {
if (is_bool($cell->getValue())) {
echo $cell->getRow(), ' -> ', ($cell->getValue() ? 'TRUE' : 'FALSE'), PHP_EOL;
$this->log($cell->getRow() . ' -> ' . ($cell->getValue() ? 'TRUE' : 'FALSE'));
$this->functionNameMap[($cell->getValue() ? 'TRUE' : 'FALSE')] = $cell->getRow();
} else {
echo $cell->getRow(), ' -> ', $cell->getValue(), PHP_EOL;
$this->log($cell->getRow() . ' -> ' . $cell->getValue());
$this->functionNameMap[$cell->getValue()] = $cell->getRow();
}
}
@ -328,4 +332,13 @@ class LocaleGenerator
return false;
}
private function log(string $message): void
{
if ($this->verbose === false) {
return;
}
echo $message, PHP_EOL;
}
}

View File

@ -635,46 +635,6 @@ parameters:
count: 1
path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/Periodic.php
-
message: "#^Binary operation \"\\*\" between float\\|string and int results in an error\\.$#"
count: 2
path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php
-
message: "#^Binary operation \"\\*\" between float\\|string and int\\|string results in an error\\.$#"
count: 1
path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:couponFirstPeriodDate\\(\\) has no return typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:couponFirstPeriodDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:couponFirstPeriodDate\\(\\) has parameter \\$next with no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:couponFirstPeriodDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateCouponPeriod\\(\\) has parameter \\$maturity with no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateCouponPeriod\\(\\) has parameter \\$settlement with no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateCost\\(\\) has parameter \\$cost with no typehint specified\\.$#"
count: 1
@ -2205,16 +2165,6 @@ parameters:
count: 1
path: src/PhpSpreadsheet/DefinedName.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\DocumentGenerator\\:\\:getPhpSpreadsheetFunctionText\\(\\) has parameter \\$functionCall with no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/DocumentGenerator.php
-
message: "#^Cannot access offset 0 on \\(int\\|string\\)\\.$#"
count: 2
path: src/PhpSpreadsheet/DocumentGenerator.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\HashTable\\:\\:getIndexForHashCode\\(\\) should return int but returns int\\|string\\|false\\.$#"
count: 1
@ -2415,101 +2365,6 @@ parameters:
count: 1
path: src/PhpSpreadsheet/Reader/BaseReader.php
-
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\:\\:\\$delimiter \\(string\\) does not accept string\\|null\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv.php
-
message: "#^Parameter \\#1 \\$var of function count expects array\\|Countable, array\\|null given\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\:\\:openFileOrMemory\\(\\) has parameter \\$pFilename with no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv.php
-
message: "#^Parameter \\#1 \\$value of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:convertEncoding\\(\\) expects string, string\\|false given\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv.php
-
message: "#^Parameter \\#1 \\$fp of function fwrite expects resource, resource\\|false given\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv.php
-
message: "#^Argument of an invalid type array\\|null supplied for foreach, only iterables are supported\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv.php
-
message: "#^Parameter \\#2 \\$newvalue of function ini_set expects string, string\\|false given\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv.php
-
message: "#^Call to function is_array\\(\\) with string will always evaluate to false\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv.php
-
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:\\$fileHandle has no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php
-
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:\\$escapeCharacter has no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php
-
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:\\$enclosure has no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php
-
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:\\$counts has no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php
-
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:\\$numberLines has no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php
-
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:\\$delimiter has no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:__construct\\(\\) has parameter \\$enclosure with no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:__construct\\(\\) has parameter \\$escapeCharacter with no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:__construct\\(\\) has parameter \\$fileHandle with no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php
-
message: "#^Parameter \\#2 \\$subject of function preg_match expects string, string\\|null given\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:getNextLine\\(\\) should return string\\|false but returns string\\|null\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php
-
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:\\$rowspan has no typehint specified\\.$#"
count: 1
@ -7455,41 +7310,6 @@ parameters:
count: 5
path: tests/PhpSpreadsheetTests/NamedRangeTest.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousFilter\\:\\:setFilterType\\(\\) has parameter \\$type with no typehint specified\\.$#"
count: 1
path: tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousFilter\\:\\:filter1\\(\\) has no return typehint specified\\.$#"
count: 1
path: tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousFilter\\:\\:filter1\\(\\) has parameter \\$row with no typehint specified\\.$#"
count: 1
path: tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousFilter\\:\\:filter0\\(\\) has no return typehint specified\\.$#"
count: 1
path: tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousFilter\\:\\:filter0\\(\\) has parameter \\$row with no typehint specified\\.$#"
count: 1
path: tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php
-
message: "#^Cannot call method getCell\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#"
count: 3
path: tests/PhpSpreadsheetTests/Reader/CsvContiguousTest.php
-
message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertNull\\(\\) with string will always evaluate to false\\.$#"
count: 1
path: tests/PhpSpreadsheetTests/Reader/CsvTest.php
-
message: "#^Unreachable statement \\- code above always terminates\\.$#"
count: 1

View File

@ -0,0 +1,35 @@
<?php
use PhpOffice\PhpSpreadsheet\Spreadsheet;
require __DIR__ . '/../../Header.php';
$helper->log('Searches for a value in the top row of a table or an array of values,
and then returns a value in the same column from a row you specify
in the table or array.');
// Create new PhpSpreadsheet object
$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();
$data = [
['ID', 'First Name', 'Last Name', 'Salary'],
[72, 'Emily', 'Smith', 64901, null, 'ID', 53, 66, 56],
[66, 'James', 'Anderson', 70855, null, 'Salary'],
[14, 'Mia', 'Clark', 188657],
[30, 'John', 'Lewis', 97566],
[53, 'Jessica', 'Walker', 58339],
[56, 'Mark', 'Reed', 125180],
[79, 'Richard', 'Lopez', 91632],
];
$worksheet->fromArray($data, null, 'B2');
$worksheet->getCell('H4')->setValue('=VLOOKUP(H3, B3:E9, 4, FALSE)');
$worksheet->getCell('I4')->setValue('=VLOOKUP(I3, B3:E9, 4, FALSE)');
$worksheet->getCell('J4')->setValue('=VLOOKUP(J3, B3:E9, 4, FALSE)');
for ($column = 'H'; $column !== 'K'; ++$column) {
$cell = $worksheet->getCell("{$column}4");
$helper->log("{$column}4: {$cell->getValue()} => {$cell->getCalculatedValue()}");
}

View File

@ -299,6 +299,11 @@ class Calculation
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '1',
],
'ARRAYTOTEXT' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'ASC' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [Functions::class, 'DUMMY'],
@ -766,6 +771,11 @@ class Calculation
'functionCall' => [DateTimeExcel\Difference::class, 'interval'],
'argumentCount' => '2,3',
],
'DATESTRING' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'DATEVALUE' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTimeExcel\DateValue::class, 'fromString'],
@ -1527,6 +1537,11 @@ class Calculation
'functionCall' => [Functions::class, 'isText'],
'argumentCount' => '1',
],
'ISTHAIDIGIT' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'JIS' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [Functions::class, 'DUMMY'],
@ -1842,6 +1857,11 @@ class Calculation
'functionCall' => [Financial\CashFlow\Variable\Periodic::class, 'presentValue'],
'argumentCount' => '2+',
],
'NUMBERSTRING' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'NUMBERVALUE' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [TextData\Format::class, 'NUMBERVALUE'],
@ -2124,6 +2144,16 @@ class Calculation
'functionCall' => [MathTrig\Round::class, 'round'],
'argumentCount' => '2',
],
'ROUNDBAHTDOWN' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'ROUNDBAHTUP' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'ROUNDDOWN' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig\Round::class, 'down'],
@ -2427,6 +2457,41 @@ class Calculation
'functionCall' => [TextData\Concatenate::class, 'TEXTJOIN'],
'argumentCount' => '3+',
],
'THAIDAYOFWEEK' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'THAIDIGIT' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'THAIMONTHOFYEAR' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'THAINUMSOUND' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'THAINUMSTRING' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'THAISTRINGLENGTH' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'THAIYEAR' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'TIME' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTimeExcel\Time::class, 'fromHMS'],
@ -2532,6 +2597,11 @@ class Calculation
'functionCall' => [TextData\Format::class, 'VALUE'],
'argumentCount' => '1',
],
'VALUETOTEXT' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'VAR' => [
'category' => Category::CATEGORY_STATISTICAL,
'functionCall' => [Statistical\Variances::class, 'VAR'],

View File

@ -2,6 +2,7 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Financial;
use DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Financial\Constants as FinancialConstants;
@ -73,7 +74,7 @@ class Coupons
return abs((float) DateTimeExcel\Days::between($prev, $settlement));
}
return DateTimeExcel\YearFrac::fraction($prev, $settlement, $basis) * $daysPerYear;
return (float) DateTimeExcel\YearFrac::fraction($prev, $settlement, $basis) * $daysPerYear;
}
/**
@ -208,7 +209,7 @@ class Coupons
}
}
return DateTimeExcel\YearFrac::fraction($settlement, $next, $basis) * $daysPerYear;
return (float) DateTimeExcel\YearFrac::fraction($settlement, $next, $basis) * $daysPerYear;
}
/**
@ -322,7 +323,7 @@ class Coupons
FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
);
return (int) ceil($yearsBetweenSettlementAndMaturity * $frequency);
return (int) ceil((float) $yearsBetweenSettlementAndMaturity * $frequency);
}
/**
@ -379,28 +380,33 @@ class Coupons
return self::couponFirstPeriodDate($settlement, $maturity, $frequency, self::PERIOD_DATE_PREVIOUS);
}
private static function couponFirstPeriodDate($settlement, $maturity, int $frequency, $next)
private static function monthsDiff(DateTime $result, int $months, string $plusOrMinus, int $day, bool $lastDayFlag): void
{
$result->setDate((int) $result->format('Y'), (int) $result->format('m'), 1);
$result->modify("$plusOrMinus $months months");
$daysInMonth = (int) $result->format('t');
$result->setDate((int) $result->format('Y'), (int) $result->format('m'), $lastDayFlag ? $daysInMonth : min($day, $daysInMonth));
}
private static function couponFirstPeriodDate(float $settlement, float $maturity, int $frequency, bool $next): float
{
$months = 12 / $frequency;
$result = Date::excelToDateTimeObject($maturity);
$maturityEoM = Helpers::isLastDayOfMonth($result);
$day = (int) $result->format('d');
$lastDayFlag = Helpers::isLastDayOfMonth($result);
while ($settlement < Date::PHPToExcel($result)) {
$result->modify('-' . $months . ' months');
self::monthsDiff($result, $months, '-', $day, $lastDayFlag);
}
if ($next === true) {
$result->modify('+' . $months . ' months');
self::monthsDiff($result, $months, '+', $day, $lastDayFlag);
}
if ($maturityEoM === true) {
$result->modify('-1 day');
return (float) Date::PHPToExcel($result);
}
return Date::PHPToExcel($result);
}
private static function validateCouponPeriod($settlement, $maturity): void
private static function validateCouponPeriod(float $settlement, float $maturity): void
{
if ($settlement >= $maturity) {
throw new Exception(Functions::NAN());

View File

@ -41,7 +41,8 @@ class Address
{
$row = Functions::flattenSingleValue($row);
$column = Functions::flattenSingleValue($column);
$relativity = Functions::flattenSingleValue($relativity);
$relativity = ($relativity === null) ? 1 : Functions::flattenSingleValue($relativity);
$referenceStyle = ($referenceStyle === null) ? true : Functions::flattenSingleValue($referenceStyle);
$sheetName = Functions::flattenSingleValue($sheetName);
if (($row < 1) || ($column < 1)) {

View File

@ -25,7 +25,7 @@ class HLookup extends LookupBase
{
$lookupValue = Functions::flattenSingleValue($lookupValue);
$indexNumber = Functions::flattenSingleValue($indexNumber);
$notExactMatch = Functions::flattenSingleValue($notExactMatch);
$notExactMatch = ($notExactMatch === null) ? true : Functions::flattenSingleValue($notExactMatch);
try {
$indexNumber = self::validateIndexLookup($lookupArray, $indexNumber);

View File

@ -13,7 +13,8 @@ class Indirect
/**
* Determine whether cell address is in A1 (true) or R1C1 (false) format.
*
* @param mixed $a1fmt Expect bool Helpers::CELLADDRESS_USE_A1 or CELLADDRESS_USE_R1C1, but can be provided as numeric which is cast to bool
* @param mixed $a1fmt Expect bool Helpers::CELLADDRESS_USE_A1 or CELLADDRESS_USE_R1C1,
* but can be provided as numeric which is cast to bool
*/
private static function a1Format($a1fmt): bool
{
@ -53,7 +54,8 @@ class Indirect
* =INDIRECT(cellAddress, bool) where the bool argument is optional
*
* @param array|string $cellAddress $cellAddress The cell address of the current cell (containing this formula)
* @param mixed $a1fmt Expect bool Helpers::CELLADDRESS_USE_A1 or CELLADDRESS_USE_R1C1, but can be provided as numeric which is cast to bool
* @param mixed $a1fmt Expect bool Helpers::CELLADDRESS_USE_A1 or CELLADDRESS_USE_R1C1,
* but can be provided as numeric which is cast to bool
* @param Cell $pCell The current cell (containing this formula)
*
* @return array|string An array containing a cell or range of cells, or a string on error
@ -84,7 +86,8 @@ class Indirect
/**
* Extract range values.
*
* @return mixed Array of values in range if range contains more than one element. Otherwise, a single value is returned.
* @return mixed Array of values in range if range contains more than one element.
* Otherwise, a single value is returned.
*/
private static function extractRequiredCells(?Worksheet $pSheet, string $cellAddress)
{

View File

@ -25,7 +25,7 @@ class VLookup extends LookupBase
{
$lookupValue = Functions::flattenSingleValue($lookupValue);
$indexNumber = Functions::flattenSingleValue($indexNumber);
$notExactMatch = Functions::flattenSingleValue($notExactMatch);
$notExactMatch = ($notExactMatch === null) ? true : Functions::flattenSingleValue($notExactMatch);
try {
$indexNumber = self::validateIndexLookup($lookupArray, $indexNumber);

View File

@ -39,6 +39,7 @@ DVARP = DVARIANSP
##
DATE = DATO
DATEDIF = DATO.FORSKEL
DATESTRING = DATOSTRENG
DATEVALUE = DATOVÆRDI
DAY = DAG
DAYS = DAGE
@ -53,6 +54,9 @@ NETWORKDAYS = ANTAL.ARBEJDSDAGE
NETWORKDAYS.INTL = ANTAL.ARBEJDSDAGE.INTL
NOW = NU
SECOND = SEKUND
THAIDAYOFWEEK = THAILANDSKUGEDAG
THAIMONTHOFYEAR = THAILANDSKMÅNED
THAIYEAR = THAILANDSKÅR
TIME = TID
TIMEVALUE = TIDSVÆRDI
TODAY = IDAG
@ -301,6 +305,8 @@ RAND = SLUMP
RANDBETWEEN = SLUMPMELLEM
ROMAN = ROMERTAL
ROUND = AFRUND
ROUNDBAHTDOWN = RUNDBAHTNED
ROUNDBAHTUP = RUNDBAHTOP
ROUNDDOWN = RUND.NED
ROUNDUP = RUND.OP
SEC = SEC
@ -450,10 +456,12 @@ DOLLAR = KR
EXACT = EKSAKT
FIND = FIND
FIXED = FAST
ISTHAIDIGIT = ERTHAILANDSKCIFFER
LEFT = VENSTRE
LEN = LÆNGDE
LOWER = SMÅ.BOGSTAVER
MID = MIDT
NUMBERSTRING = TALSTRENG
NUMBERVALUE = TALVÆRDI
PHONETIC = FONETISK
PROPER = STORT.FORBOGSTAV
@ -465,6 +473,10 @@ SUBSTITUTE = UDSKIFT
T = T
TEXT = TEKST
TEXTJOIN = TEKST.KOMBINER
THAIDIGIT = THAILANDSKCIFFER
THAINUMSOUND = THAILANDSKNUMLYD
THAINUMSTRING = THAILANDSKNUMSTRENG
THAISTRINGLENGTH = THAILANDSKSTRENGLÆNGDE
TRIM = FJERN.OVERFLØDIGE.BLANKE
UNICHAR = UNICHAR
UNICODE = UNICODE

View File

@ -52,6 +52,9 @@ NETWORKDAYS = NETTOARBEITSTAGE
NETWORKDAYS.INTL = NETTOARBEITSTAGE.INTL
NOW = JETZT
SECOND = SEKUNDE
THAIDAYOFWEEK = THAIWOCHENTAG
THAIMONTHOFYEAR = THAIMONATDESJAHRES
THAIYEAR = THAIJAHR
TIME = ZEIT
TIMEVALUE = ZEITWERT
TODAY = HEUTE
@ -300,6 +303,8 @@ RAND = ZUFALLSZAHL
RANDBETWEEN = ZUFALLSBEREICH
ROMAN = RÖMISCH
ROUND = RUNDEN
ROUNDBAHTDOWN = RUNDBAHTNED
ROUNDBAHTUP = BAHTAUFRUNDEN
ROUNDDOWN = ABRUNDEN
ROUNDUP = AUFRUNDEN
SEC = SEC
@ -449,6 +454,7 @@ DOLLAR = DM
EXACT = IDENTISCH
FIND = FINDEN
FIXED = FEST
ISTHAIDIGIT = ISTTHAIZAHLENWORT
LEFT = LINKS
LEN = LÄNGE
LOWER = KLEIN
@ -463,6 +469,10 @@ SUBSTITUTE = WECHSELN
T = T
TEXT = TEXT
TEXTJOIN = TEXTVERKETTEN
THAIDIGIT = THAIZAHLENWORT
THAINUMSOUND = THAIZAHLSOUND
THAINUMSTRING = THAILANDSKNUMSTRENG
THAISTRINGLENGTH = THAIZEICHENFOLGENLÄNGE
TRIM = GLÄTTEN
UNICHAR = UNIZEICHEN
UNICODE = UNICODE

View File

@ -39,6 +39,7 @@ DVARP = BDVARP
##
DATE = FECHA
DATEDIF = SIFECHA
DATESTRING = CADENA.FECHA
DATEVALUE = FECHANUMERO
DAY = DIA
DAYS = DIAS
@ -53,6 +54,9 @@ NETWORKDAYS = DIAS.LAB
NETWORKDAYS.INTL = DIAS.LAB.INTL
NOW = AHORA
SECOND = SEGUNDO
THAIDAYOFWEEK = DIASEMTAI
THAIMONTHOFYEAR = MESAÑOTAI
THAIYEAR = AÑOTAI
TIME = NSHORA
TIMEVALUE = HORANUMERO
TODAY = HOY
@ -301,6 +305,8 @@ RAND = ALEATORIO
RANDBETWEEN = ALEATORIO.ENTRE
ROMAN = NUMERO.ROMANO
ROUND = REDONDEAR
ROUNDBAHTDOWN = REDONDEAR.BAHT.MAS
ROUNDBAHTUP = REDONDEAR.BAHT.MENOS
ROUNDDOWN = REDONDEAR.MENOS
ROUNDUP = REDONDEAR.MAS
SEC = SEC
@ -450,10 +456,12 @@ DOLLAR = MONEDA
EXACT = IGUAL
FIND = ENCONTRAR
FIXED = DECIMAL
ISTHAIDIGIT = ESDIGITOTAI
LEFT = IZQUIERDA
LEN = LARGO
LOWER = MINUSC
MID = EXTRAE
NUMBERSTRING = CADENA.NUMERO
NUMBERVALUE = VALOR.NUMERO
PHONETIC = FONETICO
PROPER = NOMPROPIO
@ -465,6 +473,10 @@ SUBSTITUTE = SUSTITUIR
T = T
TEXT = TEXTO
TEXTJOIN = UNIRCADENAS
THAIDIGIT = DIGITOTAI
THAINUMSOUND = SONNUMTAI
THAINUMSTRING = CADENANUMTAI
THAISTRINGLENGTH = LONGCADENATAI
TRIM = ESPACIOS
UNICHAR = UNICAR
UNICODE = UNICODE

View File

@ -39,6 +39,7 @@ DVARP = TVARIANSSIP
##
DATE = PÄIVÄYS
DATEDIF = PVMERO
DATESTRING = PVMMERKKIJONO
DATEVALUE = PÄIVÄYSARVO
DAY = PÄIVÄ
DAYS = PÄIVÄT
@ -53,6 +54,9 @@ NETWORKDAYS = TYÖPÄIVÄT
NETWORKDAYS.INTL = TYÖPÄIVÄT.KANSVÄL
NOW = NYT
SECOND = SEKUNNIT
THAIDAYOFWEEK = THAI.VIIKONPÄIVÄ
THAIMONTHOFYEAR = THAI.KUUKAUSI
THAIYEAR = THAI.VUOSI
TIME = AIKA
TIMEVALUE = AIKA_ARVO
TODAY = TÄMÄ.PÄIVÄ
@ -301,6 +305,8 @@ RAND = SATUNNAISLUKU
RANDBETWEEN = SATUNNAISLUKU.VÄLILTÄ
ROMAN = ROMAN
ROUND = PYÖRISTÄ
ROUNDBAHTDOWN = PYÖRISTÄ.BAHT.ALAS
ROUNDBAHTUP = PYÖRISTÄ.BAHT.YLÖS
ROUNDDOWN = PYÖRISTÄ.DES.ALAS
ROUNDUP = PYÖRISTÄ.DES.YLÖS
SEC = SEK
@ -450,10 +456,12 @@ DOLLAR = VALUUTTA
EXACT = VERTAA
FIND = ETSI
FIXED = KIINTEÄ
ISTHAIDIGIT = ON.THAI.NUMERO
LEFT = VASEN
LEN = PITUUS
LOWER = PIENET
MID = POIMI.TEKSTI
NUMBERSTRING = NROMERKKIJONO
NUMBERVALUE = NROARVO
PHONETIC = FONEETTINEN
PROPER = ERISNIMI
@ -465,6 +473,10 @@ SUBSTITUTE = VAIHDA
T = T
TEXT = TEKSTI
TEXTJOIN = TEKSTI.YHDISTÄ
THAIDIGIT = THAI.NUMERO
THAINUMSOUND = THAI.LUKU.ÄÄNI
THAINUMSTRING = THAI.LUKU.MERKKIJONO
THAISTRINGLENGTH = THAI.MERKKIJONON.PITUUS
TRIM = POISTA.VÄLIT
UNICHAR = UNICODEMERKKI
UNICODE = UNICODE

View File

@ -39,6 +39,7 @@ DVARP = AB.VAR2
##
DATE = DÁTUM
DATEDIF = DÁTUMTÓLIG
DATESTRING = DÁTUMSZÖVEG
DATEVALUE = DÁTUMÉRTÉK
DAY = NAP
DAYS = NAPOK
@ -53,6 +54,9 @@ NETWORKDAYS = ÖSSZ.MUNKANAP
NETWORKDAYS.INTL = ÖSSZ.MUNKANAP.INTL
NOW = MOST
SECOND = MPERC
THAIDAYOFWEEK = THAIHÉTNAPJA
THAIMONTHOFYEAR = THAIHÓNAP
THAIYEAR = THAIÉV
TIME = IDŐ
TIMEVALUE = IDŐÉRTÉK
TODAY = MA
@ -301,6 +305,8 @@ RAND = VÉL
RANDBETWEEN = VÉLETLEN.KÖZÖTT
ROMAN = RÓMAI
ROUND = KEREKÍTÉS
ROUNDBAHTDOWN = BAHTKEREK.LE
ROUNDBAHTUP = BAHTKEREK.FEL
ROUNDDOWN = KEREK.LE
ROUNDUP = KEREK.FEL
SEC = SEC
@ -450,10 +456,12 @@ DOLLAR = FORINT
EXACT = AZONOS
FIND = SZÖVEG.TALÁL
FIXED = FIX
ISTHAIDIGIT = ON.THAI.NUMERO
LEFT = BAL
LEN = HOSSZ
LOWER = KISBETŰ
MID = KÖZÉP
NUMBERSTRING = SZÁM.BETŰVEL
NUMBERVALUE = SZÁMÉRTÉK
PHONETIC = FONETIKUS
PROPER = TNÉV
@ -465,6 +473,10 @@ SUBSTITUTE = HELYETTE
T = T
TEXT = SZÖVEG
TEXTJOIN = SZÖVEGÖSSZEFŰZÉS
THAIDIGIT = THAISZÁM
THAINUMSOUND = THAISZÁMHANG
THAINUMSTRING = THAISZÁMKAR
THAISTRINGLENGTH = THAIKARHOSSZ
TRIM = KIMETSZ
UNICHAR = UNIKARAKTER
UNICODE = UNICODE

View File

@ -39,6 +39,7 @@ DVARP = DB.VAR.POP
##
DATE = DATA
DATEDIF = DATA.DIFF
DATESTRING = DATA.STRINGA
DATEVALUE = DATA.VALORE
DAY = GIORNO
DAYS = GIORNI
@ -53,6 +54,9 @@ NETWORKDAYS = GIORNI.LAVORATIVI.TOT
NETWORKDAYS.INTL = GIORNI.LAVORATIVI.TOT.INTL
NOW = ADESSO
SECOND = SECONDO
THAIDAYOFWEEK = THAIGIORNODELLASETTIMANA
THAIMONTHOFYEAR = THAIMESEDELLANNO
THAIYEAR = THAIANNO
TIME = ORARIO
TIMEVALUE = ORARIO.VALORE
TODAY = OGGI
@ -301,6 +305,8 @@ RAND = CASUALE
RANDBETWEEN = CASUALE.TRA
ROMAN = ROMANO
ROUND = ARROTONDA
ROUNDBAHTDOWN = ARROTBAHTGIU
ROUNDBAHTUP = ARROTBAHTSU
ROUNDDOWN = ARROTONDA.PER.DIF
ROUNDUP = ARROTONDA.PER.ECC
SEC = SEC
@ -450,10 +456,12 @@ DOLLAR = VALUTA
EXACT = IDENTICO
FIND = TROVA
FIXED = FISSO
ISTHAIDIGIT = ÈTHAICIFRA
LEFT = SINISTRA
LEN = LUNGHEZZA
LOWER = MINUSC
MID = STRINGA.ESTRAI
NUMBERSTRING = NUMERO.STRINGA
NUMBERVALUE = NUMERO.VALORE
PHONETIC = FURIGANA
PROPER = MAIUSC.INIZ
@ -465,6 +473,10 @@ SUBSTITUTE = SOSTITUISCI
T = T
TEXT = TESTO
TEXTJOIN = TESTO.UNISCI
THAIDIGIT = THAICIFRA
THAINUMSOUND = THAINUMSUONO
THAINUMSTRING = THAISZÁMKAR
THAISTRINGLENGTH = THAILUNGSTRINGA
TRIM = ANNULLA.SPAZI
UNICHAR = CARATT.UNI
UNICODE = UNICODE

View File

@ -39,6 +39,7 @@ DVARP = DVARIANSP
##
DATE = DATO
DATEDIF = DATODIFF
DATESTRING = DATOSTRENG
DATEVALUE = DATOVERDI
DAY = DAG
DAYS = DAGER
@ -53,6 +54,9 @@ NETWORKDAYS = NETT.ARBEIDSDAGER
NETWORKDAYS.INTL = NETT.ARBEIDSDAGER.INTL
NOW = NÅ
SECOND = SEKUND
THAIDAYOFWEEK = THAIUKEDAG
THAIMONTHOFYEAR = THAIMÅNED
THAIYEAR = THAIÅR
TIME = TID
TIMEVALUE = TIDSVERDI
TODAY = IDAG
@ -301,6 +305,8 @@ RAND = TILFELDIG
RANDBETWEEN = TILFELDIGMELLOM
ROMAN = ROMERTALL
ROUND = AVRUND
ROUNDBAHTDOWN = RUNDAVBAHTNEDOVER
ROUNDBAHTUP = RUNDAVBAHTOPPOVER
ROUNDDOWN = AVRUND.NED
ROUNDUP = AVRUND.OPP
SEC = SEC
@ -451,10 +457,12 @@ DOLLAR = VALUTA
EXACT = EKSAKT
FIND = FINN
FIXED = FASTSATT
ISTHAIDIGIT = ERTHAISIFFER
LEFT = VENSTRE
LEN = LENGDE
LOWER = SMÅ
MID = DELTEKST
NUMBERSTRING = TALLSTRENG
NUMBERVALUE = TALLVERDI
PHONETIC = FURIGANA
PROPER = STOR.FORBOKSTAV
@ -466,6 +474,10 @@ SUBSTITUTE = BYTT.UT
T = T
TEXT = TEKST
TEXTJOIN = TEKST.KOMBINER
THAIDIGIT = THAISIFFER
THAINUMSOUND = THAINUMLYD
THAINUMSTRING = THAINUMSTRENG
THAISTRINGLENGTH = THAISTRENGLENGDE
TRIM = TRIMME
UNICHAR = UNICODETEGN
UNICODE = UNICODE

View File

@ -38,6 +38,7 @@ DVARP = DBVARP
## Datum- en tijdfuncties (Date & Time Functions)
##
DATE = DATUM
DATESTRING = DATUMNOTATIE
DATEVALUE = DATUMWAARDE
DAY = DAG
DAYS = DAGEN
@ -52,6 +53,9 @@ NETWORKDAYS = NETTO.WERKDAGEN
NETWORKDAYS.INTL = NETWERKDAGEN.INTL
NOW = NU
SECOND = SECONDE
THAIDAYOFWEEK = THAIS.WEEKDAG
THAIMONTHOFYEAR = THAIS.MAAND.VAN.JAAR
THAIYEAR = THAIS.JAAR
TIME = TIJD
TIMEVALUE = TIJDWAARDE
TODAY = VANDAAG
@ -300,6 +304,8 @@ RAND = ASELECT
RANDBETWEEN = ASELECTTUSSEN
ROMAN = ROMEINS
ROUND = AFRONDEN
ROUNDBAHTDOWN = BAHT.AFR.NAAR.BENEDEN
ROUNDBAHTUP = BAHT.AFR.NAAR.BOVEN
ROUNDDOWN = AFRONDEN.NAAR.BENEDEN
ROUNDUP = AFRONDEN.NAAR.BOVEN
SEC = SEC
@ -449,10 +455,12 @@ DOLLAR = EURO
EXACT = GELIJK
FIND = VIND.ALLES
FIXED = VAST
ISTHAIDIGIT = IS.THAIS.CIJFER
LEFT = LINKS
LEN = LENGTE
LOWER = KLEINE.LETTERS
MID = DEEL
NUMBERSTRING = GETALNOTATIE
NUMBERVALUE = NUMERIEKE.WAARDE
PHONETIC = FONETISCH
PROPER = BEGINLETTERS
@ -464,6 +472,10 @@ SUBSTITUTE = SUBSTITUEREN
T = T
TEXT = TEKST
TEXTJOIN = TEKST.COMBINEREN
THAIDIGIT = THAIS.CIJFER
THAINUMSOUND = THAIS.GETAL.GELUID
THAINUMSTRING = THAIS.GETAL.REEKS
THAISTRINGLENGTH = THAIS.REEKS.LENGTE
TRIM = SPATIES.WISSEN
UNICHAR = UNITEKEN
UNICODE = UNICODE

View File

@ -39,6 +39,7 @@ DVARP = BD.WARIANCJA.POPUL
##
DATE = DATA
DATEDIF = DATA.RÓŻNICA
DATESTRING = DATA.CIĄG.ZNAK
DATEVALUE = DATA.WARTOŚĆ
DAY = DZIEŃ
DAYS = DNI
@ -53,6 +54,9 @@ NETWORKDAYS = DNI.ROBOCZE
NETWORKDAYS.INTL = DNI.ROBOCZE.NIESTAND
NOW = TERAZ
SECOND = SEKUNDA
THAIDAYOFWEEK = TAJ.DZIEŃ.TYGODNIA
THAIMONTHOFYEAR = TAJ.MIESIĄC.ROKU
THAIYEAR = TAJ.ROK
TIME = CZAS
TIMEVALUE = CZAS.WARTOŚĆ
TODAY = DZIŚ
@ -301,6 +305,8 @@ RAND = LOS
RANDBETWEEN = LOS.ZAKR
ROMAN = RZYMSKIE
ROUND = ZAOKR
ROUNDBAHTDOWN = ZAOKR.DÓŁ.BAT
ROUNDBAHTUP = ZAOKR.GÓRA.BAT
ROUNDDOWN = ZAOKR.DÓŁ
ROUNDUP = ZAOKR.GÓRA
SEC = SEC
@ -450,10 +456,12 @@ DOLLAR = KWOTA
EXACT = PORÓWNAJ
FIND = ZNAJDŹ
FIXED = ZAOKR.DO.TEKST
ISTHAIDIGIT = CZY.CYFRA.TAJ
LEFT = LEWY
LEN = DŁ
LOWER = LITERY.MAŁE
MID = FRAGMENT.TEKSTU
NUMBERSTRING = LICZBA.CIĄG.ZNAK
NUMBERVALUE = WARTOŚĆ.LICZBOWA
PROPER = Z.WIELKIEJ.LITERY
REPLACE = ZASTĄP
@ -464,6 +472,10 @@ SUBSTITUTE = PODSTAW
T = T
TEXT = TEKST
TEXTJOIN = POŁĄCZ.TEKSTY
THAIDIGIT = TAJ.CYFRA
THAINUMSOUND = TAJ.DŹWIĘK.NUM
THAINUMSTRING = TAJ.CIĄG.NUM
THAISTRINGLENGTH = TAJ.DŁUGOŚĆ.CIĄGU
TRIM = USUŃ.ZBĘDNE.ODSTĘPY
UNICHAR = ZNAK.UNICODE
UNICODE = UNICODE

View File

@ -39,6 +39,7 @@ DVARP = BDVARP
##
DATE = DATA
DATEDIF = DATADIF
DATESTRING = DATA.SÉRIE
DATEVALUE = DATA.VALOR
DAY = DIA
DAYS = DIAS
@ -454,6 +455,7 @@ LEFT = ESQUERDA
LEN = NÚM.CARACT
LOWER = MINÚSCULA
MID = EXT.TEXTO
NUMBERSTRING = SEQÜÊNCIA.NÚMERO
NUMBERVALUE = VALORNUMÉRICO
PHONETIC = FONÉTICA
PROPER = PRI.MAIÚSCULA

View File

@ -39,6 +39,7 @@ DVARP = BDVARP
##
DATE = DATA
DATEDIF = DATADIF
DATESTRING = DATA.CADEIA
DATEVALUE = DATA.VALOR
DAY = DIA
DAYS = DIAS
@ -53,6 +54,9 @@ NETWORKDAYS = DIATRABALHOTOTAL
NETWORKDAYS.INTL = DIATRABALHOTOTAL.INTL
NOW = AGORA
SECOND = SEGUNDO
THAIDAYOFWEEK = DIA.DA.SEMANA.TAILANDÊS
THAIMONTHOFYEAR = MÊS.DO.ANO.TAILANDÊS
THAIYEAR = ANO.TAILANDÊS
TIME = TEMPO
TIMEVALUE = VALOR.TEMPO
TODAY = HOJE
@ -301,6 +305,8 @@ RAND = ALEATÓRIO
RANDBETWEEN = ALEATÓRIOENTRE
ROMAN = ROMANO
ROUND = ARRED
ROUNDBAHTDOWN = ARREDOND.BAHT.BAIXO
ROUNDBAHTUP = ARREDOND.BAHT.CIMA
ROUNDDOWN = ARRED.PARA.BAIXO
ROUNDUP = ARRED.PARA.CIMA
SEC = SEC
@ -450,10 +456,12 @@ DOLLAR = MOEDA
EXACT = EXATO
FIND = LOCALIZAR
FIXED = FIXA
ISTHAIDIGIT = É.DÍGITO.TAILANDÊS
LEFT = ESQUERDA
LEN = NÚM.CARAT
LOWER = MINÚSCULAS
MID = SEG.TEXTO
NUMBERSTRING = NÚMERO.CADEIA
NUMBERVALUE = VALOR.NÚMERO
PHONETIC = FONÉTICA
PROPER = INICIAL.MAIÚSCULA
@ -465,6 +473,10 @@ SUBSTITUTE = SUBST
T = T
TEXT = TEXTO
TEXTJOIN = UNIRTEXTO
THAIDIGIT = DÍGITO.TAILANDÊS
THAINUMSOUND = SOM.NÚM.TAILANDÊS
THAINUMSTRING = CADEIA.NÚM.TAILANDÊS
THAISTRINGLENGTH = COMP.CADEIA.TAILANDÊS
TRIM = COMPACTAR
UNICHAR = UNICARÁT
UNICODE = UNICODE

View File

@ -39,6 +39,7 @@ DVARP = БДДИСПП
##
DATE = ДАТА
DATEDIF = РАЗНДАТ
DATESTRING = СТРОКАДАННЫХ
DATEVALUE = ДАТАЗНАЧ
DAY = ДЕНЬ
DAYS = ДНИ
@ -53,6 +54,9 @@ NETWORKDAYS = ЧИСТРАБДНИ
NETWORKDAYS.INTL = ЧИСТРАБДНИ.МЕЖД
NOW = ТДАТА
SECOND = СЕКУНДЫ
THAIDAYOFWEEK = ТАЙДЕНЬНЕД
THAIMONTHOFYEAR = ТАЙМЕСЯЦ
THAIYEAR = ТАЙГОД
TIME = ВРЕМЯ
TIMEVALUE = ВРЕМЗНАЧ
TODAY = СЕГОДНЯ
@ -301,6 +305,8 @@ RAND = СЛЧИС
RANDBETWEEN = СЛУЧМЕЖДУ
ROMAN = РИМСКОЕ
ROUND = ОКРУГЛ
ROUNDBAHTDOWN = ОКРУГЛБАТВНИЗ
ROUNDBAHTUP = ОКРУГЛБАТВВЕРХ
ROUNDDOWN = ОКРУГЛВНИЗ
ROUNDUP = ОКРУГЛВВЕРХ
SEC = SEC
@ -450,10 +456,12 @@ DOLLAR = РУБЛЬ
EXACT = СОВПАД
FIND = НАЙТИ
FIXED = ФИКСИРОВАННЫЙ
ISTHAIDIGIT = TAYRAKAMIYSA
LEFT = ЛЕВСИМВ
LEN = ДЛСТР
LOWER = СТРОЧН
MID = ПСТР
NUMBERSTRING = СТРОКАЧИСЕЛ
NUMBERVALUE = ЧЗНАЧ
PROPER = ПРОПНАЧ
REPLACE = ЗАМЕНИТЬ
@ -464,6 +472,10 @@ SUBSTITUTE = ПОДСТАВИТЬ
T = Т
TEXT = ТЕКСТ
TEXTJOIN = ОБЪЕДИНИТЬ
THAIDIGIT = ТАЙЦИФРА
THAINUMSOUND = ТАЙЧИСЛОВЗВУК
THAINUMSTRING = ТАЙЧИСЛОВСТРОКУ
THAISTRINGLENGTH = ТАЙДЛИНАСТРОКИ
TRIM = СЖПРОБЕЛЫ
UNICHAR = ЮНИСИМВ
UNICODE = UNICODE

View File

@ -52,6 +52,9 @@ NETWORKDAYS = NETTOARBETSDAGAR
NETWORKDAYS.INTL = NETTOARBETSDAGAR.INT
NOW = NU
SECOND = SEKUND
THAIDAYOFWEEK = THAIVECKODAG
THAIMONTHOFYEAR = THAIMÅNAD
THAIYEAR = THAIÅR
TIME = KLOCKSLAG
TIMEVALUE = TIDVÄRDE
TODAY = IDAG
@ -300,6 +303,8 @@ RAND = SLUMP
RANDBETWEEN = SLUMP.MELLAN
ROMAN = ROMERSK
ROUND = AVRUNDA
ROUNDBAHTDOWN = AVRUNDABAHTNEDÅT
ROUNDBAHTUP = AVRUNDABAHTUPPÅT
ROUNDDOWN = AVRUNDA.NEDÅT
ROUNDUP = AVRUNDA.UPPÅT
SEC = SEK
@ -463,6 +468,10 @@ SUBSTITUTE = BYT.UT
T = T
TEXT = TEXT
TEXTJOIN = TEXTJOIN
THAIDIGIT = THAISIFFRA
THAINUMSOUND = THAITALLJUD
THAINUMSTRING = THAITALSTRÄNG
THAISTRINGLENGTH = THAISTRÄNGLÄNGD
TRIM = RENSA
UNICHAR = UNITECKENKOD
UNICODE = UNICODE

View File

@ -39,6 +39,7 @@ DVARP = VSEÇVARS
##
DATE = TARİH
DATEDIF = ETARİHLİ
DATESTRING = TARİHDİZİ
DATEVALUE = TARİHSAYISI
DAY = GÜN
DAYS = GÜNSAY
@ -53,6 +54,9 @@ NETWORKDAYS = TAMİŞGÜNÜ
NETWORKDAYS.INTL = TAMİŞGÜNÜ.ULUSL
NOW = ŞİMDİ
SECOND = SANİYE
THAIDAYOFWEEK = TAYHAFTANINGÜNÜ
THAIMONTHOFYEAR = TAYYILINAYI
THAIYEAR = TAYYILI
TIME = ZAMAN
TIMEVALUE = ZAMANSAYISI
TODAY = BUGÜN
@ -301,6 +305,8 @@ RAND = S_SAYI_ÜRET
RANDBETWEEN = RASTGELEARADA
ROMAN = ROMEN
ROUND = YUVARLA
ROUNDBAHTDOWN = BAHTAŞAĞIYUVARLA
ROUNDBAHTUP = BAHTYUKARIYUVARLA
ROUNDDOWN = AŞAĞIYUVARLA
ROUNDUP = YUKARIYUVARLA
SEC = SEC
@ -450,10 +456,12 @@ DOLLAR = LİRA
EXACT = ÖZDEŞ
FIND = BUL
FIXED = SAYIDÜZENLE
ISTHAIDIGIT = TAYRAKAMIYSA
LEFT = SOLDAN
LEN = UZUNLUK
LOWER = KÜÇÜKHARF
MID = PARÇAAL
NUMBERSTRING = SAYIDİZİ
NUMBERVALUE = SAYIDEĞERİ
PHONETIC = SES
PROPER = YAZIM.DÜZENİ
@ -465,6 +473,10 @@ SUBSTITUTE = YERİNEKOY
T = M
TEXT = METNEÇEVİR
TEXTJOIN = METİNBİRLEŞTİR
THAIDIGIT = TAYRAKAM
THAINUMSOUND = TAYSAYISES
THAINUMSTRING = TAYSAYIDİZE
THAISTRINGLENGTH = TAYDİZEUZUNLUĞU
TRIM = KIRP
UNICHAR = UNICODEKARAKTERİ
UNICODE = UNICODE

View File

@ -50,156 +50,87 @@ class Security
/**
* Is some sort of document security enabled?
*
* @return bool
*/
public function isSecurityEnabled()
public function isSecurityEnabled(): bool
{
return $this->lockRevision ||
$this->lockStructure ||
$this->lockWindows;
}
/**
* Get LockRevision.
*
* @return bool
*/
public function getLockRevision()
public function getLockRevision(): bool
{
return $this->lockRevision;
}
/**
* Set LockRevision.
*
* @param bool $pValue
*
* @return $this
*/
public function setLockRevision($pValue)
public function setLockRevision(?bool $pValue): self
{
if ($pValue !== null) {
$this->lockRevision = $pValue;
}
return $this;
}
/**
* Get LockStructure.
*
* @return bool
*/
public function getLockStructure()
public function getLockStructure(): bool
{
return $this->lockStructure;
}
/**
* Set LockStructure.
*
* @param bool $pValue
*
* @return $this
*/
public function setLockStructure($pValue)
public function setLockStructure(?bool $pValue): self
{
if ($pValue !== null) {
$this->lockStructure = $pValue;
}
return $this;
}
/**
* Get LockWindows.
*
* @return bool
*/
public function getLockWindows()
public function getLockWindows(): bool
{
return $this->lockWindows;
}
/**
* Set LockWindows.
*
* @param bool $pValue
*
* @return $this
*/
public function setLockWindows($pValue)
public function setLockWindows(?bool $pValue): self
{
if ($pValue !== null) {
$this->lockWindows = $pValue;
}
return $this;
}
/**
* Get RevisionsPassword (hashed).
*
* @return string
*/
public function getRevisionsPassword()
public function getRevisionsPassword(): string
{
return $this->revisionsPassword;
}
/**
* Set RevisionsPassword.
*
* @param string $pValue
* @param bool $pAlreadyHashed If the password has already been hashed, set this to true
*
* @return $this
*/
public function setRevisionsPassword($pValue, $pAlreadyHashed = false)
public function setRevisionsPassword(?string $pValue, bool $pAlreadyHashed = false): self
{
if ($pValue !== null) {
if (!$pAlreadyHashed) {
$pValue = PasswordHasher::hashPassword($pValue);
}
$this->revisionsPassword = $pValue;
}
return $this;
}
/**
* Get WorkbookPassword (hashed).
*
* @return string
*/
public function getWorkbookPassword()
public function getWorkbookPassword(): string
{
return $this->workbookPassword;
}
/**
* Set WorkbookPassword.
*
* @param string $pValue
* @param bool $pAlreadyHashed If the password has already been hashed, set this to true
*
* @return $this
*/
public function setWorkbookPassword($pValue, $pAlreadyHashed = false)
public function setWorkbookPassword(?string $pValue, bool $pAlreadyHashed = false): self
{
if ($pValue !== null) {
if (!$pAlreadyHashed) {
$pValue = PasswordHasher::hashPassword($pValue);
}
$this->workbookPassword = $pValue;
}
return $this;
}
/**
* Implement PHP __clone to create a deep clone, not just a shallow copy.
*/
public function __clone()
{
$vars = get_object_vars($this);
foreach ($vars as $key => $value) {
if (is_object($value)) {
$this->$key = clone $value;
} else {
$this->$key = $value;
}
}
}
}

View File

@ -170,8 +170,15 @@ class HashTable
{
$vars = get_object_vars($this);
foreach ($vars as $key => $value) {
if (is_object($value)) {
$this->$key = clone $value;
// each member of this class is an array
if (is_array($value)) {
$array1 = $value;
foreach ($array1 as $key1 => $value1) {
if (is_object($value1)) {
$array1[$key1] = clone $value1;
}
}
$this->$key = $array1;
}
}
}

View File

@ -10,6 +10,8 @@ use PhpOffice\PhpSpreadsheet\Spreadsheet;
class Csv extends BaseReader
{
const DEFAULT_FALLBACK_ENCODING = 'CP1252';
const GUESS_ENCODING = 'guess';
const UTF8_BOM = "\xEF\xBB\xBF";
const UTF8_BOM_LEN = 3;
const UTF16BE_BOM = "\xfe\xff";
@ -33,10 +35,17 @@ class Csv extends BaseReader
private $inputEncoding = 'UTF-8';
/**
* Delimiter.
* Fallback encoding if 'guess' strikes out.
*
* @var string
*/
private $fallbackEncoding = self::DEFAULT_FALLBACK_ENCODING;
/**
* Delimiter.
*
* @var ?string
*/
private $delimiter;
/**
@ -67,38 +76,65 @@ class Csv extends BaseReader
*/
private $escapeCharacter = '\\';
/**
* Callback for setting defaults in construction.
*
* @var ?callable
*/
private static $constructorCallback;
/**
* Create a new CSV Reader instance.
*/
public function __construct()
{
parent::__construct();
$callback = self::$constructorCallback;
if ($callback !== null) {
$callback($this);
}
}
/**
* Set input encoding.
* Set a callback to change the defaults.
*
* @param string $pValue Input encoding, eg: 'UTF-8'
*
* @return $this
* The callback must accept the Csv Reader object as the first parameter,
* and it should return void.
*/
public function setInputEncoding($pValue)
public static function setConstructorCallback(?callable $callback): void
{
self::$constructorCallback = $callback;
}
public static function getConstructorCallback(): ?callable
{
return self::$constructorCallback;
}
public function setInputEncoding(string $pValue): self
{
$this->inputEncoding = $pValue;
return $this;
}
/**
* Get input encoding.
*
* @return string
*/
public function getInputEncoding()
public function getInputEncoding(): string
{
return $this->inputEncoding;
}
public function setFallbackEncoding(string $pValue): self
{
$this->fallbackEncoding = $pValue;
return $this;
}
public function getFallbackEncoding(): string
{
return $this->fallbackEncoding;
}
/**
* Move filepointer past any BOM marker.
*/
@ -161,12 +197,8 @@ class Csv extends BaseReader
/**
* Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns).
*
* @param string $pFilename
*
* @return array
*/
public function listWorksheetInfo($pFilename)
public function listWorksheetInfo(string $pFilename): array
{
// Open file
$this->openFileOrMemory($pFilename);
@ -185,9 +217,11 @@ class Csv extends BaseReader
$worksheetInfo[0]['totalColumns'] = 0;
// Loop through each line of the file in turn
while (($rowData = fgetcsv($fileHandle, 0, $this->delimiter, $this->enclosure, $this->escapeCharacter)) !== false) {
$rowData = fgetcsv($fileHandle, 0, $this->delimiter ?? '', $this->enclosure, $this->escapeCharacter);
while (is_array($rowData)) {
++$worksheetInfo[0]['totalRows'];
$worksheetInfo[0]['lastColumnIndex'] = max($worksheetInfo[0]['lastColumnIndex'], count($rowData) - 1);
$rowData = fgetcsv($fileHandle, 0, $this->delimiter ?? '', $this->enclosure, $this->escapeCharacter);
}
$worksheetInfo[0]['lastColumnLetter'] = Coordinate::stringFromColumnIndex($worksheetInfo[0]['lastColumnIndex'] + 1);
@ -215,34 +249,35 @@ class Csv extends BaseReader
return $this->loadIntoExisting($pFilename, $spreadsheet);
}
private function openFileOrMemory($pFilename): void
private function openFileOrMemory(string $pFilename): void
{
// Open file
$fhandle = $this->canRead($pFilename);
if (!$fhandle) {
throw new Exception($pFilename . ' is an Invalid Spreadsheet file.');
}
if ($this->inputEncoding === self::GUESS_ENCODING) {
$this->inputEncoding = self::guessEncoding($pFilename, $this->fallbackEncoding);
}
$this->openFile($pFilename);
if ($this->inputEncoding !== 'UTF-8') {
fclose($this->fileHandle);
$entireFile = file_get_contents($pFilename);
$this->fileHandle = fopen('php://memory', 'r+b');
if ($this->fileHandle !== false && $entireFile !== false) {
$data = StringHelper::convertEncoding($entireFile, 'UTF-8', $this->inputEncoding);
fwrite($this->fileHandle, $data);
$this->skipBOM();
}
}
}
/**
* Loads PhpSpreadsheet from file into PhpSpreadsheet instance.
*
* @param string $pFilename
*
* @return Spreadsheet
*/
public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
public function loadIntoExisting(string $pFilename, Spreadsheet $spreadsheet): Spreadsheet
{
$lineEnding = ini_get('auto_detect_line_endings');
$lineEnding = ini_get('auto_detect_line_endings') ?: '0';
ini_set('auto_detect_line_endings', '1');
// Open file
@ -265,7 +300,8 @@ class Csv extends BaseReader
$outRow = 0;
// Loop through each line of the file in turn
while (($rowData = fgetcsv($fileHandle, 0, $this->delimiter, $this->enclosure, $this->escapeCharacter)) !== false) {
$rowData = fgetcsv($fileHandle, 0, $this->delimiter ?? '', $this->enclosure, $this->escapeCharacter);
while (is_array($rowData)) {
$noOutputYet = true;
$columnLetter = 'A';
foreach ($rowData as $rowDatum) {
@ -283,6 +319,7 @@ class Csv extends BaseReader
}
++$columnLetter;
}
$rowData = fgetcsv($fileHandle, 0, $this->delimiter ?? '', $this->enclosure, $this->escapeCharacter);
++$currentRow;
}
@ -295,48 +332,24 @@ class Csv extends BaseReader
return $spreadsheet;
}
/**
* Get delimiter.
*
* @return string
*/
public function getDelimiter()
public function getDelimiter(): ?string
{
return $this->delimiter;
}
/**
* Set delimiter.
*
* @param string $delimiter Delimiter, eg: ','
*
* @return $this
*/
public function setDelimiter($delimiter)
public function setDelimiter(string $delimiter): self
{
$this->delimiter = $delimiter;
return $this;
}
/**
* Get enclosure.
*
* @return string
*/
public function getEnclosure()
public function getEnclosure(): string
{
return $this->enclosure;
}
/**
* Set enclosure.
*
* @param string $enclosure Enclosure, defaults to "
*
* @return $this
*/
public function setEnclosure($enclosure)
public function setEnclosure(string $enclosure): self
{
if ($enclosure == '') {
$enclosure = '"';
@ -346,78 +359,55 @@ class Csv extends BaseReader
return $this;
}
/**
* Get sheet index.
*
* @return int
*/
public function getSheetIndex()
public function getSheetIndex(): int
{
return $this->sheetIndex;
}
/**
* Set sheet index.
*
* @param int $pValue Sheet index
*
* @return $this
*/
public function setSheetIndex($pValue)
public function setSheetIndex(int $pValue): self
{
$this->sheetIndex = $pValue;
return $this;
}
/**
* Set Contiguous.
*
* @param bool $contiguous
*
* @return $this
*/
public function setContiguous($contiguous)
public function setContiguous(bool $contiguous): self
{
$this->contiguous = (bool) $contiguous;
return $this;
}
/**
* Get Contiguous.
*
* @return bool
*/
public function getContiguous()
public function getContiguous(): bool
{
return $this->contiguous;
}
/**
* Set escape backslashes.
*
* @param string $escapeCharacter
*
* @return $this
*/
public function setEscapeCharacter($escapeCharacter)
public function setEscapeCharacter(string $escapeCharacter): self
{
$this->escapeCharacter = $escapeCharacter;
return $this;
}
/**
* Get escape backslashes.
*
* @return string
*/
public function getEscapeCharacter()
public function getEscapeCharacter(): string
{
return $this->escapeCharacter;
}
/**
* Scrutinizer believes, incorrectly, that the specific pathinfo
* call in canRead can return something other than an array.
* Phpstan knows better.
* This function satisfies both.
*
* @param mixed $extension
*/
private static function extractStringLower($extension): string
{
return is_string($extension) ? strtolower($extension) : '';
}
/**
* Can the current IReader read the file?
*
@ -437,8 +427,7 @@ class Csv extends BaseReader
fclose($this->fileHandle);
// Trust file extension if any
$extension = pathinfo($pFilename, PATHINFO_EXTENSION);
$extension = is_array($extension) ? '' : strtolower($extension);
$extension = self::extractStringLower(pathinfo($pFilename, PATHINFO_EXTENSION));
if (in_array($extension, ['csv', 'tsv'])) {
return true;
}
@ -504,7 +493,7 @@ class Csv extends BaseReader
return $encoding;
}
public static function guessEncoding(string $filename, string $dflt = 'CP1252'): string
public static function guessEncoding(string $filename, string $dflt = self::DEFAULT_FALLBACK_ENCODING): string
{
$encoding = self::guessEncodingBom($filename);
if ($encoding === '') {

View File

@ -6,19 +6,28 @@ class Delimiter
{
protected const POTENTIAL_DELIMETERS = [',', ';', "\t", '|', ':', ' ', '~'];
/** @var resource */
protected $fileHandle;
/** @var string */
protected $escapeCharacter;
/** @var string */
protected $enclosure;
/** @var array */
protected $counts = [];
/** @var int */
protected $numberLines = 0;
/** @var ?string */
protected $delimiter;
public function __construct($fileHandle, $escapeCharacter, $enclosure)
/**
* @param resource $fileHandle
*/
public function __construct($fileHandle, string $escapeCharacter, string $enclosure)
{
$this->fileHandle = $fileHandle;
$this->escapeCharacter = $escapeCharacter;
@ -52,10 +61,7 @@ class Delimiter
protected function countDelimiterValues(string $line, array $delimiterKeys): void
{
$splitString = str_split($line, 1);
if (!is_array($splitString)) {
return;
}
if (is_array($splitString)) {
$distribution = array_count_values($splitString);
$countLine = array_intersect_key($distribution, $delimiterKeys);
@ -63,6 +69,7 @@ class Delimiter
$this->counts[$delimiter][] = $countLine[$delimiter] ?? 0;
}
}
}
public function infer(): ?string
{
@ -137,8 +144,8 @@ class Delimiter
// See if we have any enclosures left in the line
// if we still have an enclosure then we need to read the next line as well
} while (preg_match('/(' . $enclosure . ')/', $line) > 0);
} while (preg_match('/(' . $enclosure . ')/', $line ?? '') > 0);
return $line;
return $line ?? false;
}
}

View File

@ -1808,17 +1808,9 @@ class Xlsx extends BaseReader
return;
}
if ($xmlWorkbook->workbookProtection['lockRevision']) {
$excel->getSecurity()->setLockRevision((bool) $xmlWorkbook->workbookProtection['lockRevision']);
}
if ($xmlWorkbook->workbookProtection['lockStructure']) {
$excel->getSecurity()->setLockStructure((bool) $xmlWorkbook->workbookProtection['lockStructure']);
}
if ($xmlWorkbook->workbookProtection['lockWindows']) {
$excel->getSecurity()->setLockWindows((bool) $xmlWorkbook->workbookProtection['lockWindows']);
}
$excel->getSecurity()->setLockRevision(self::getLockValue($xmlWorkbook->workbookProtection, 'lockRevision'));
$excel->getSecurity()->setLockStructure(self::getLockValue($xmlWorkbook->workbookProtection, 'lockStructure'));
$excel->getSecurity()->setLockWindows(self::getLockValue($xmlWorkbook->workbookProtection, 'lockWindows'));
if ($xmlWorkbook->workbookProtection['revisionsPassword']) {
$excel->getSecurity()->setRevisionsPassword(
@ -1835,6 +1827,18 @@ class Xlsx extends BaseReader
}
}
private static function getLockValue(SimpleXmlElement $protection, string $key): ?bool
{
$returnValue = null;
$protectKey = $protection[$key];
if (!empty($protectKey)) {
$protectKey = (string) $protectKey;
$returnValue = $protectKey !== 'false' && (bool) $protectKey;
}
return $returnValue;
}
private function readFormControlProperties(Spreadsheet $excel, ZipArchive $zip, $dir, $fileWorksheet, $docSheet, array &$unparsedLoadedData): void
{
if (!$zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) {

View File

@ -213,20 +213,20 @@ class Font extends Supervisor
/**
* Set Name.
*
* @param string $pValue
* @param string $fontname
*
* @return $this
*/
public function setName($pValue)
public function setName($fontname)
{
if ($pValue == '') {
$pValue = 'Calibri';
if ($fontname == '') {
$fontname = 'Calibri';
}
if ($this->isSupervisor) {
$styleArray = $this->getStyleArray(['name' => $pValue]);
$styleArray = $this->getStyleArray(['name' => $fontname]);
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
} else {
$this->name = $pValue;
$this->name = $fontname;
}
return $this;
@ -249,20 +249,27 @@ class Font extends Supervisor
/**
* Set Size.
*
* @param float $pValue
* @param mixed $sizeInPoints A float representing the value of a positive measurement in points (1/72 of an inch)
*
* @return $this
*/
public function setSize($pValue)
public function setSize($sizeInPoints)
{
if ($pValue == '') {
$pValue = 10;
if (is_string($sizeInPoints) || is_int($sizeInPoints)) {
$sizeInPoints = (float) $sizeInPoints; // $pValue = 0 if given string is not numeric
}
// Size must be a positive floating point number
// ECMA-376-1:2016, part 1, chapter 18.4.11 sz (Font Size), p. 1536
if (!is_float($sizeInPoints) || !($sizeInPoints > 0)) {
$sizeInPoints = 10.0;
}
if ($this->isSupervisor) {
$styleArray = $this->getStyleArray(['size' => $pValue]);
$styleArray = $this->getStyleArray(['size' => $sizeInPoints]);
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
} else {
$this->size = $pValue;
$this->size = $sizeInPoints;
}
return $this;

View File

@ -0,0 +1,75 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Document;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
class SecurityTest extends AbstractFunctional
{
public function testSecurity(): void
{
$spreadsheet = new Spreadsheet();
$spreadsheet->getActiveSheet()->getCell('A1')->setValue('Hello');
$security = $spreadsheet->getSecurity();
$security->setLockRevision(true);
$revisionsPassword = 'revpasswd';
$security->setRevisionsPassword($revisionsPassword);
$hashedRevisionsPassword = $security->getRevisionsPassword();
self::assertNotEquals($revisionsPassword, $hashedRevisionsPassword);
$security->setLockWindows(true);
$security->setLockStructure(true);
$workbookPassword = 'wbpasswd';
$security->setWorkbookPassword($workbookPassword);
$hashedWorkbookPassword = $security->getWorkbookPassword();
self::assertNotEquals($workbookPassword, $hashedWorkbookPassword);
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx');
$reloadedSecurity = $reloadedSpreadsheet->getSecurity();
self::assertTrue($reloadedSecurity->getLockRevision());
self::assertTrue($reloadedSecurity->getLockWindows());
self::assertTrue($reloadedSecurity->getLockStructure());
self::assertSame($hashedWorkbookPassword, $reloadedSecurity->getWorkbookPassword());
self::assertSame($hashedRevisionsPassword, $reloadedSecurity->getRevisionsPassword());
$reloadedSecurity->setRevisionsPassword($hashedWorkbookPassword, true);
self::assertSame($hashedWorkbookPassword, $reloadedSecurity->getRevisionsPassword());
$reloadedSecurity->setWorkbookPassword($hashedRevisionsPassword, true);
self::assertSame($hashedRevisionsPassword, $reloadedSecurity->getWorkbookPassword());
}
public function providerLocks(): array
{
return [
[false, false, false],
[false, false, true],
[false, true, false],
[false, true, true],
[true, false, false],
[true, false, true],
[true, true, false],
[true, true, true],
];
}
/**
* @dataProvider providerLocks
*/
public function testLocks(bool $revision, bool $windows, bool $structure): void
{
$spreadsheet = new Spreadsheet();
$spreadsheet->getActiveSheet()->getCell('A1')->setValue('Hello');
$security = $spreadsheet->getSecurity();
$security->setLockRevision($revision);
$security->setLockWindows($windows);
$security->setLockStructure($structure);
$enabled = $security->isSecurityEnabled();
self::assertSame($enabled, $revision || $windows || $structure);
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx');
$reloadedSecurity = $reloadedSpreadsheet->getSecurity();
self::assertSame($revision, $reloadedSecurity->getLockRevision());
self::assertSame($windows, $reloadedSecurity->getLockWindows());
self::assertSame($structure, $reloadedSecurity->getLockStructure());
}
}

View File

@ -5,7 +5,7 @@ namespace PhpOffice\PhpSpreadsheetTests;
use PhpOffice\PhpSpreadsheet\Calculation\Category as Cat;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
use PhpOffice\PhpSpreadsheet\DocumentGenerator;
use PhpOffice\PhpSpreadsheetInfra\DocumentGenerator;
use PHPUnit\Framework\TestCase;
use UnexpectedValueException;

View File

@ -0,0 +1,92 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests;
use PhpOffice\PhpSpreadsheet\Comment; // need Comparable object
use PhpOffice\PhpSpreadsheet\HashTable;
use PHPUnit\Framework\TestCase;
class HashTableTest extends TestCase
{
public static function createArray(): array
{
$comment1 = new Comment();
$comment1->setAuthor('Author1');
$comment2 = new Comment();
$comment2->setAuthor('Author2');
return [$comment1, $comment2];
}
/**
* @param mixed $comment
*/
public static function getAuthor($comment): string
{
return ($comment instanceof Comment) ? $comment->getAuthor() : '';
}
public function testAddRemoveClear(): void
{
$array1 = self::createArray();
$hash1 = new HashTable($array1);
self::assertSame(2, $hash1->count());
$comment3 = new Comment();
$comment3->setAuthor('Author3');
$hash1->add($comment3);
$comment4 = new Comment();
$comment4->setAuthor('Author4');
$hash1->add($comment4);
$comment5 = new Comment();
$comment5->setAuthor('Author5');
// don't add comment5
self::assertSame(4, $hash1->count());
self::assertNull($hash1->getByIndex(10));
$comment = $hash1->getByIndex(2);
self::assertSame('Author3', self::getAuthor($comment));
$hash1->remove($comment3);
self::assertSame(3, $hash1->count());
$comment = $hash1->getByIndex(2);
self::assertSame('Author4', self::getAuthor($comment));
$hash1->remove($comment5);
self::assertSame(3, $hash1->count(), 'Remove non-hash member');
$comment = $hash1->getByIndex(2);
self::assertSame('Author4', self::getAuthor($comment));
self::assertNull($hash1->getByHashCode('xyz'));
$hash1->clear();
self::AssertSame(0, $hash1->count());
}
public function testToArray(): void
{
$array1 = self::createArray();
$count1 = count($array1);
$hash1 = new HashTable($array1);
$array2 = $hash1->toArray();
self::assertCount($count1, $array2);
$idx = 0;
foreach ($array2 as $key => $value) {
self::assertEquals($array1[$idx], $value, "Item $idx");
self::assertSame($idx, $hash1->getIndexForHashCode($key));
++$idx;
}
}
public function testClone(): void
{
$array1 = self::createArray();
$hash1 = new HashTable($array1);
$hash2 = new HashTable();
self::assertSame(0, $hash2->count());
$hash2->addFromSource();
self::assertSame(0, $hash2->count());
$hash2->addFromSource($array1);
self::assertSame(2, $hash2->count());
self::assertEquals($hash1, $hash2, 'Add in constructor same as addFromSource');
$hash3 = clone $hash1;
self::assertEquals($hash1, $hash3, 'Clone equal to original');
self::assertSame($hash1->getByIndex(0), $hash2->getByIndex(0));
self::assertEquals($hash1->getByIndex(0), $hash3->getByIndex(0));
self::assertNotSame($hash1->getByIndex(0), $hash3->getByIndex(0));
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheetInfra\LocaleGenerator;
use PHPUnit\Framework\TestCase;
use ReflectionClass;
class LocaleGeneratorTest extends TestCase
{
public function testLocaleGenerator(): void
{
$phpSpreadsheetFunctionsProperty = (new ReflectionClass(Calculation::class))
->getProperty('phpSpreadsheetFunctions');
$phpSpreadsheetFunctionsProperty->setAccessible(true);
$phpSpreadsheetFunctions = $phpSpreadsheetFunctionsProperty->getValue();
$localeGenerator = new LocaleGenerator(
(string) realpath(__DIR__ . '/../../src/PhpSpreadsheet/Calculation/locale/'),
'Translations.xlsx',
$phpSpreadsheetFunctions
);
$localeGenerator->generateLocales();
$testLocales = [
'fr',
'nl',
'pt',
'pt_br',
'ru',
];
foreach ($testLocales as $locale) {
$locale = str_replace('_', '/', $locale);
$path = realpath(__DIR__ . "/../../src/PhpSpreadsheet/Calculation/locale/{$locale}");
self::assertFileExists("{$path}/config");
self::assertFileExists("{$path}/functions");
}
}
}

View File

@ -0,0 +1,93 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Reader\Csv;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Reader\Csv;
use PHPUnit\Framework\TestCase;
class CsvCallbackTest extends TestCase
{
protected function tearDown(): void
{
Csv::setConstructorCallback(null);
}
/**
* @param mixed $obj
*/
public function callbackDoNothing($obj): void
{
self::assertInstanceOf(Csv::class, $obj);
}
public function testCallbackDoNothing(): void
{
Csv::setConstructorCallback([$this, 'callbackDoNothing']);
$filename = 'tests/data/Reader/CSV/encoding.iso88591.csv';
$reader = new Csv();
$reader->setInputEncoding(Csv::GUESS_ENCODING);
$spreadsheet = $reader->load($filename);
$sheet = $spreadsheet->getActiveSheet();
self::assertEquals('Å', $sheet->getCell('A1')->getValue());
}
public function callbackSetFallbackEncoding(Csv $reader): void
{
$reader->setFallbackEncoding('ISO-8859-2');
$reader->setInputEncoding(Csv::GUESS_ENCODING);
$reader->setEscapeCharacter((version_compare(PHP_VERSION, '7.4') < 0) ? "\x0" : '');
}
public function testFallbackEncodingDefltIso2(): void
{
Csv::setConstructorCallback([$this, 'callbackSetFallbackEncoding']);
$filename = 'tests/data/Reader/CSV/premiere.win1252.csv';
$reader = new Csv();
$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 testIOFactory(): void
{
Csv::setConstructorCallback([$this, 'callbackSetFallbackEncoding']);
$filename = 'tests/data/Reader/CSV/premiere.win1252.csv';
$spreadsheet = IOFactory::load($filename);
$sheet = $spreadsheet->getActiveSheet();
self::assertEquals('premičre', $sheet->getCell('A1')->getValue());
self::assertEquals('sixičme', $sheet->getCell('C2')->getValue());
}
public function testNonFallbackEncoding(): void
{
Csv::setConstructorCallback([$this, 'callbackSetFallbackEncoding']);
$filename = 'tests/data/Reader/CSV/premiere.utf16be.csv';
$reader = new Csv();
$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 testDefaultEscape(): void
{
self::assertNull(Csv::getConstructorCallback());
$filename = 'tests/data/Reader/CSV/escape.csv';
$spreadsheet = IOFactory::load($filename);
$sheet = $spreadsheet->getActiveSheet();
// this is not how Excel views the file
self::assertEquals('a\"hello', $sheet->getCell('A1')->getValue());
}
public function testBetterEscape(): void
{
Csv::setConstructorCallback([$this, 'callbackSetFallbackEncoding']);
$filename = 'tests/data/Reader/CSV/escape.csv';
$spreadsheet = IOFactory::load($filename);
$sheet = $spreadsheet->getActiveSheet();
// this is how Excel views the file
self::assertEquals('a\"hello;hello;hello;\"', $sheet->getCell('A1')->getValue());
}
}

View File

@ -1,6 +1,6 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Reader;
namespace PhpOffice\PhpSpreadsheetTests\Reader\Csv;
use PhpOffice\PhpSpreadsheet\Reader\IReadFilter;
@ -34,18 +34,18 @@ class CsvContiguousFilter implements IReadFilter
$this->endRow = $startRow + $chunkSize;
}
public function setFilterType($type): void
public function setFilterType(int $type): void
{
$this->filterType = $type;
}
public function filter1($row)
public function filter1(int $row): bool
{
// Include rows 1-10, followed by 100-110, etc.
return $row % 100 <= 10;
}
public function filter0($row)
public function filter0(int $row): bool
{
// Only read the heading row, and the rows that are configured in $this->_startRow and $this->_endRow
if (($row == 1) || ($row >= $this->startRow && $row < $this->endRow)) {

View File

@ -1,6 +1,6 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Reader;
namespace PhpOffice\PhpSpreadsheetTests\Reader\Csv;
use PhpOffice\PhpSpreadsheet\Reader\Csv;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
@ -49,12 +49,19 @@ class CsvContiguousTest extends TestCase
$spreadsheet->getActiveSheet()->setTitle('Country Data #' . (++$sheet));
}
$sheet = $spreadsheet->getSheetByName('Country Data #1');
self::assertEquals('Kabul', $sheet->getCell('A2')->getValue());
$sheet = $spreadsheet->getSheetByName('Country Data #2');
self::assertEquals('Lesotho', $sheet->getCell('B4')->getValue());
$sheet = $spreadsheet->getSheetByName('Country Data #3');
self::assertEquals(-20.1, $sheet->getCell('C6')->getValue());
self::assertSame('Kabul', self::getCellValue($spreadsheet, 'Country Data #1', 'A2'));
self::assertSame('Lesotho', self::getCellValue($spreadsheet, 'Country Data #2', 'B4'));
self::assertSame('-20.1', self::getCellValue($spreadsheet, 'Country Data #3', 'C6'));
}
private static function getCellValue(Spreadsheet $spreadsheet, string $sheetName, string $cellAddress): string
{
$sheet = $spreadsheet->getSheetByName($sheetName);
if ($sheet === null) {
return '';
}
return (string) $sheet->getCell($cellAddress)->getValue();
}
public function testContiguous2(): void

View File

@ -0,0 +1,122 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Reader\Csv;
use PhpOffice\PhpSpreadsheet\Reader\Csv;
use PHPUnit\Framework\TestCase;
class CsvEncodingTest extends TestCase
{
/**
* @dataProvider providerEncodings
*
* @param string $filename
* @param string $encoding
*/
public function testEncodings($filename, $encoding): void
{
$reader = new Csv();
$reader->setInputEncoding($encoding);
$spreadsheet = $reader->load($filename);
$sheet = $spreadsheet->getActiveSheet();
self::assertEquals('Å', $sheet->getCell('A1')->getValue());
}
/**
* @dataProvider providerEncodings
*
* @param string $filename
* @param string $encoding
*/
public function testWorkSheetInfo($filename, $encoding): void
{
$reader = new Csv();
$reader->setInputEncoding($encoding);
$info = $reader->listWorksheetInfo($filename);
self::assertEquals('Worksheet', $info[0]['worksheetName']);
self::assertEquals('B', $info[0]['lastColumnLetter']);
self::assertEquals(1, $info[0]['lastColumnIndex']);
self::assertEquals(2, $info[0]['totalRows']);
self::assertEquals(2, $info[0]['totalColumns']);
}
public function providerEncodings(): array
{
return [
['tests/data/Reader/CSV/encoding.iso88591.csv', 'ISO-8859-1'],
['tests/data/Reader/CSV/encoding.utf8.csv', 'UTF-8'],
['tests/data/Reader/CSV/encoding.utf8bom.csv', 'UTF-8'],
['tests/data/Reader/CSV/encoding.utf16be.csv', 'UTF-16BE'],
['tests/data/Reader/CSV/encoding.utf16le.csv', 'UTF-16LE'],
['tests/data/Reader/CSV/encoding.utf32be.csv', 'UTF-32BE'],
['tests/data/Reader/CSV/encoding.utf32le.csv', 'UTF-32LE'],
];
}
/**
* @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());
}
/**
* @dataProvider providerGuessEncoding
*/
public function testFallbackEncoding(string $filename): void
{
$reader = new Csv();
$reader->setInputEncoding(Csv::GUESS_ENCODING);
$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(): array
{
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());
}
public function testFallbackEncodingDefltIso2(): void
{
$filename = 'tests/data/Reader/CSV/premiere.win1252.csv';
$reader = new Csv();
self::assertSame('CP1252', $reader->getFallbackEncoding());
$reader->setInputEncoding(Csv::GUESS_ENCODING);
$reader->setFallbackEncoding('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());
}
}

View File

@ -1,6 +1,6 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Reader;
namespace PhpOffice\PhpSpreadsheetTests\Reader\Csv;
use PhpOffice\PhpSpreadsheet\Reader\Csv;
use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException;
@ -19,7 +19,8 @@ class CsvTest extends TestCase
public function testDelimiterDetection($filename, $expectedDelimiter, $cell, $expectedValue): void
{
$reader = new Csv();
self::assertNull($reader->getDelimiter());
$delim1 = $reader->getDelimiter();
self::assertNull($delim1);
$spreadsheet = $reader->load($filename);
@ -132,21 +133,6 @@ class CsvTest extends TestCase
self::assertSame($expected, $worksheet->toArray());
}
/**
* @dataProvider providerEncodings
*
* @param string $filename
* @param string $encoding
*/
public function testEncodings($filename, $encoding): void
{
$reader = new Csv();
$reader->setInputEncoding($encoding);
$spreadsheet = $reader->load($filename);
$sheet = $spreadsheet->getActiveSheet();
self::assertEquals('Å', $sheet->getCell('A1')->getValue());
}
public function testInvalidWorkSheetInfo(): void
{
$this->expectException(ReaderException::class);
@ -154,37 +140,6 @@ class CsvTest extends TestCase
$reader->listWorksheetInfo('');
}
/**
* @dataProvider providerEncodings
*
* @param string $filename
* @param string $encoding
*/
public function testWorkSheetInfo($filename, $encoding): void
{
$reader = new Csv();
$reader->setInputEncoding($encoding);
$info = $reader->listWorksheetInfo($filename);
self::assertEquals('Worksheet', $info[0]['worksheetName']);
self::assertEquals('B', $info[0]['lastColumnLetter']);
self::assertEquals(1, $info[0]['lastColumnIndex']);
self::assertEquals(2, $info[0]['totalRows']);
self::assertEquals(2, $info[0]['totalColumns']);
}
public function providerEncodings(): array
{
return [
['tests/data/Reader/CSV/encoding.iso88591.csv', 'ISO-8859-1'],
['tests/data/Reader/CSV/encoding.utf8.csv', 'UTF-8'],
['tests/data/Reader/CSV/encoding.utf8bom.csv', 'UTF-8'],
['tests/data/Reader/CSV/encoding.utf16be.csv', 'UTF-16BE'],
['tests/data/Reader/CSV/encoding.utf16le.csv', 'UTF-16LE'],
['tests/data/Reader/CSV/encoding.utf32be.csv', 'UTF-32BE'],
['tests/data/Reader/CSV/encoding.utf32le.csv', 'UTF-32LE'],
];
}
public function testUtf16LineBreak(): void
{
$reader = new Csv();
@ -296,45 +251,4 @@ EOF;
[(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(): array
{
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());
}
}

View File

@ -39,4 +39,36 @@ class FontTest extends TestCase
self::assertTrue($font->getSuperscript());
self::assertFalse($font->getSubscript(), 'False remains unchanged');
}
public function testSize(): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$cell = $sheet->getCell('A1');
$cell->setValue('Cell A1');
$font = $cell->getStyle()->getFont();
self::assertEquals(11, $font->getSize(), 'The default is 11');
$font->setSize(12);
self::assertEquals(12, $font->getSize(), 'Accepted new font size');
$invalidFontSizeValues = [
'',
false,
true,
'non_numeric_string',
'-1.0',
-1.0,
0,
[],
(object) [],
null,
];
foreach ($invalidFontSizeValues as $invalidFontSizeValue) {
$font->setSize(12);
$font->setSize($invalidFontSizeValue);
self::assertEquals(10, $font->getSize(), 'Set to 10 after trying to set an invalid value.');
}
}
}

View File

@ -0,0 +1,208 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Writer;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Shared\File;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\ColumnDimension;
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
class PreCalcTest extends AbstractFunctional
{
/** @var string */
private $outfile = '';
protected function tearDown(): void
{
if ($this->outfile !== '') {
unlink($this->outfile);
$this->outfile = '';
}
}
public function providerPreCalc(): array
{
return [
[true, 'Xlsx'],
[false, 'Xlsx'],
[null, 'Xlsx'],
[true, 'Xls'],
[false, 'Xls'],
[null, 'Xls'],
[true, 'Ods'],
[false, 'Ods'],
[null, 'Ods'],
[true, 'Html'],
[false, 'Html'],
[null, 'Html'],
[true, 'Csv'],
[false, 'Csv'],
[null, 'Csv'],
];
}
private static function autoSize(?ColumnDimension $columnDimension): void
{
if ($columnDimension === null) {
self::fail('Unable to getColumnDimension');
} else {
$columnDimension->setAutoSize(true);
}
}
private static function verifyA2(Calculation $calculation, string $title, ?bool $preCalc): void
{
$cellValue = 0;
// A2 has no cached calculation value if preCalc is false
if ($preCalc === false) {
self::assertFalse($calculation->getValueFromCache("$title!A2", $cellValue));
} else {
self::assertTrue($calculation->getValueFromCache("$title!A2", $cellValue));
self::assertSame(3, $cellValue);
}
}
private const AUTOSIZE_TYPES = ['Xlsx', 'Xls', 'Html'];
private static function verifyA3B2(Calculation $calculation, string $title, ?bool $preCalc, string $type): void
{
$cellValue = 0;
if (in_array($type, self::AUTOSIZE_TYPES) || $preCalc !== false) {
// These 3 types support auto-sizing.
// A3 has cached calculation value because it is used in B2 calculation
self::assertTrue($calculation->getValueFromCache("$title!A3", $cellValue));
self::assertSame(11, $cellValue);
// B2 has cached calculation value because its column is auto-sized
self::assertTrue($calculation->getValueFromCache("$title!B2", $cellValue));
self::assertSame(14, $cellValue);
} else {
self::assertFalse($calculation->getValueFromCache("$title!A3", $cellValue));
self::assertFalse($calculation->getValueFromCache("$title!B2", $cellValue));
}
}
private static function readFile(string $file): string
{
$dataOut = '';
$data = file_get_contents($file);
// confirm that file contains B2 pre-calculated or not as appropriate
if ($data === false) {
self::fail("Unable to read $file");
} else {
$dataOut = $data;
}
return $dataOut;
}
private function verifyXlsx(?bool $preCalc, string $type): void
{
if ($type === 'Xlsx') {
$file = 'zip://';
$file .= $this->outfile;
$file .= '#xl/worksheets/sheet1.xml';
$data = self::readFile($file);
// confirm that file contains B2 pre-calculated or not as appropriate
if ($preCalc === false) {
self::assertStringContainsString('<c r="B2" t="str"><f>3+A3</f><v>0</v></c>', $data);
} else {
self::assertStringContainsString('<c r="B2"><f>3+A3</f><v>14</v></c>', $data);
}
$file = 'zip://';
$file .= $this->outfile;
$file .= '#xl/workbook.xml';
$data = self::readFile($file);
// confirm whether workbook is set to recalculate
if ($preCalc === false) {
self::assertStringContainsString('<calcPr calcId="999999" calcMode="auto" calcCompleted="0" fullCalcOnLoad="1" forceFullCalc="1"/>', $data);
} else {
self::assertStringContainsString('<calcPr calcId="999999" calcMode="auto" calcCompleted="1" fullCalcOnLoad="0" forceFullCalc="0"/>', $data);
}
}
}
private function verifyOds(?bool $preCalc, string $type): void
{
if ($type === 'Ods') {
$file = 'zip://';
$file .= $this->outfile;
$file .= '#content.xml';
$data = self::readFile($file);
// confirm that file contains B2 pre-calculated or not as appropriate
if ($preCalc === false) {
self::assertStringContainsString('table:formula="of:=3+[.A3]" office:value-type="string" office:value="=3+A3"', $data);
} else {
self::assertStringContainsString(' table:formula="of:=3+[.A3]" office:value-type="float" office:value="14"', $data);
}
}
}
private function verifyHtml(?bool $preCalc, string $type): void
{
if ($type === 'Html') {
$data = self::readFile($this->outfile);
// confirm that file contains B2 pre-calculated or not as appropriate
if ($preCalc === false) {
self::assertStringContainsString('>=1+2</td>', $data);
self::assertStringContainsString('>=3+A3</td>', $data);
self::assertStringContainsString('>=5+6</td>', $data);
} else {
self::assertStringContainsString('>3</td>', $data);
self::assertStringContainsString('>14</td>', $data);
self::assertStringContainsString('>11</td>', $data);
}
}
}
private function verifyCsv(?bool $preCalc, string $type): void
{
if ($type === 'Csv') {
$data = self::readFile($this->outfile);
// confirm that file contains B2 pre-calculated or not as appropriate
if ($preCalc === false) {
self::assertStringContainsString('"=1+2"', $data);
self::assertStringContainsString('"=3+A3"', $data);
self::assertStringContainsString('"=5+6"', $data);
} else {
self::assertStringContainsString('"3"', $data);
self::assertStringContainsString('"14"', $data);
self::assertStringContainsString('"11"', $data);
}
}
}
/**
* @dataProvider providerPreCalc
*/
public function testPreCalc(?bool $preCalc, string $type): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->getCell('A1')->setValue('Column not set to autoSize');
$sheet->getCell('B1')->setValue('Column set to autoSize');
$sheet->getCell('A2')->setValue('=1+2');
$sheet->getCell('A3')->setValue('=5+6');
$sheet->getCell('B2')->setValue('=3+A3');
$columnDimension = $sheet->getColumnDimension('B');
self::autoSize($columnDimension);
$writer = IOFactory::createWriter($spreadsheet, $type);
if ($preCalc !== null) {
$writer->setPreCalculateFormulas($preCalc);
}
$this->outfile = File::temporaryFilename();
$writer->save($this->outfile);
$title = $sheet->getTitle();
$calculation = Calculation::getInstance($spreadsheet);
// verify values in Calculation cache
self::verifyA2($calculation, $title, $preCalc);
self::verifyA3B2($calculation, $title, $preCalc, $type);
// verify values in output file
$this->verifyXlsx($preCalc, $type);
$this->verifyOds($preCalc, $type);
$this->verifyHtml($preCalc, $type);
$this->verifyCsv($preCalc, $type);
}
}

View File

@ -205,4 +205,18 @@ return [
4,
4,
],
[
5,
'05-Apr-2019',
'30-Sep-2021',
2,
0,
],
[
5,
'05-Oct-2019',
'31-Mar-2022',
2,
0,
],
];

View File

@ -219,4 +219,18 @@ return [
4,
4,
],
[
180,
'05-Apr-2019',
'30-Sep-2021',
2,
0,
],
[
180,
'05-Oct-2019',
'31-Mar-2022',
2,
0,
],
];

View File

@ -219,4 +219,21 @@ return [
4,
4,
],
[
175,
'05-Apr-2019',
'30-Sep-2021',
2,
0,
],
// Excel and LibreOffice return 175 for the following calculation.
// Gnumeric returns 176.
// My hand calculation, hardly guaranteed, agrees with Gnumeric.
[
176,
'05-Oct-2019',
'31-Mar-2022',
2,
0,
],
];

View File

@ -219,4 +219,32 @@ return [
4,
4,
],
[
44651,
'30-Sep-2021',
'31-Mar-2022',
2,
0,
],
[
44834,
'31-Mar-2022',
'30-Sep-2022',
2,
0,
],
[
43738,
'05-Apr-2019',
'30-Sep-2021',
2,
0,
],
[
43921,
'05-Oct-2019',
'31-Mar-2022',
2,
0,
],
];

View File

@ -219,4 +219,18 @@ return [
4,
4,
],
[
43555,
'05-Apr-2019',
'30-Sep-2021',
2,
0,
],
[
43738,
'05-Oct-2019',
'31-Mar-2022',
2,
0,
],
];

View File

@ -44,10 +44,18 @@ return [
"'EXCEL SHEET'!R2C3",
2,
3,
1,
null,
false,
'EXCEL SHEET',
],
[
"'EXCEL SHEET'!\$C\$2",
2,
3,
1,
null,
'EXCEL SHEET',
],
[
'#VALUE!',
-2,

View File

@ -1,276 +1,94 @@
<?php
function orderGrid(): array
{
return [
['Order ID', 10247, 10249, 10250, 10251, 10252, 10253],
['Unit Price', 14.00, 18.60, 7.70, 16.80, 16.80, 64.80],
['Quantity', 12, 9, 10, 6, 20, 40],
];
}
function partsGrid(): array
{
return [
['Axles', 'Bearings', 'Bolts'],
[4, 4, 9],
[5, 7, 10],
[6, 8, 11],
];
}
return [
[
16.800000000000001,
16.80,
10251,
[
[
'Order ID',
10247,
10249,
10250,
10251,
10252,
10253,
],
[
'Unit Price',
14.0,
18.600000000000001,
7.7000000000000002,
16.800000000000001,
16.800000000000001,
64.799999999999997,
],
[
'Quantity',
12,
9,
10,
6,
20,
40,
],
],
orderGrid(),
2,
false,
],
[
6.0,
10251,
[
[
'Order ID',
10247,
10249,
10250,
10251,
10252,
10253,
],
[
'Unit Price',
14.0,
18.600000000000001,
7.7000000000000002,
16.800000000000001,
16.800000000000001,
64.799999999999997,
],
[
'Quantity',
12,
9,
10,
6,
20,
40,
],
],
orderGrid(),
3,
false,
],
[
'#N/A',
10248,
[
[
'Order ID',
10247,
10249,
10250,
10251,
10252,
10253,
],
[
'Unit Price',
14.0,
18.600000000000001,
7.7000000000000002,
16.800000000000001,
16.800000000000001,
64.799999999999997,
],
[
'Quantity',
12,
9,
10,
6,
20,
40,
],
],
orderGrid(),
2,
false,
],
[
14.0,
10248,
[
[
'Order ID',
10247,
10249,
10250,
10251,
10252,
10253,
],
[
'Unit Price',
14.0,
18.600000000000001,
7.7000000000000002,
16.800000000000001,
16.800000000000001,
64.799999999999997,
],
[
'Quantity',
12,
9,
10,
6,
20,
40,
],
],
orderGrid(),
2,
true,
],
[
4,
'Axles',
[
[
'Axles',
'Bearings',
'Bolts',
],
[
4,
4,
9,
],
[
5,
7,
10,
],
[
6,
8,
11,
],
],
partsGrid(),
2,
true,
],
[
7,
'Bearings',
[
[
'Axles',
'Bearings',
'Bolts',
],
[
4,
4,
9,
],
[
5,
7,
10,
],
[
6,
8,
11,
],
],
partsGrid(),
3,
false,
],
[
5,
'B',
[
[
'Axles',
'Bearings',
'Bolts',
],
[
4,
4,
9,
],
[
5,
7,
10,
],
[
6,
8,
11,
],
],
partsGrid(),
3,
true,
],
[
11,
'Bolts',
[
[
'Axles',
'Bearings',
'Bolts',
],
[
4,
4,
9,
],
[
5,
7,
10,
'B',
partsGrid(),
3,
null,
],
[
6,
8,
11,
],
],
'Bolts',
partsGrid(),
4,
],
[
'c',
3,
[
[
1,
2,
3,
],
[
'a',
'b',
'c',
],
[
'd',
'e',
'f',
],
[1, 2, 3],
['a', 'b', 'c'],
['d', 'e', 'f'],
],
2,
true,
@ -279,11 +97,7 @@ return [
3,
3,
[
[
1,
2,
3,
],
[1, 2, 3],
],
1,
true,

View File

@ -1,293 +1,54 @@
<?php
function densityGrid(): array
{
return [
['Density', 'Viscosity', 'Temperature'],
[0.457, 3.55, 500],
[0.525, 3.25, 400],
[0.616, 2.93, 300],
[0.675, 2.75, 250],
[0.746, 2.57, 200],
[0.835, 2.38, 150],
[0.946, 2.17, 100],
[1.090, 1.95, 50],
[1.290, 1.71, 0],
];
}
return [
[
'#N/A',
1,
[
[
'Density',
'Viscosity',
'Temperature',
],
[
0.45700000000000002,
3.5499999999999998,
500,
],
[
0.52500000000000002,
3.25,
400,
],
[
0.61599999999999999,
2.9300000000000002,
300,
],
[
0.67500000000000004,
2.75,
250,
],
[
0.746,
2.5699999999999998,
200,
],
[
0.83499999999999996,
2.3799999999999999,
150,
],
[
0.94599999999999995,
2.1699999999999999,
100,
],
[
1.0900000000000001,
1.95,
50,
],
[
1.29,
1.71,
0,
],
],
densityGrid(),
2,
false,
],
[
100,
1,
[
[
'Density',
'Viscosity',
'Temperature',
],
[
0.45700000000000002,
3.5499999999999998,
500,
],
[
0.52500000000000002,
3.25,
400,
],
[
0.61599999999999999,
2.9300000000000002,
300,
],
[
0.67500000000000004,
2.75,
250,
],
[
0.746,
2.5699999999999998,
200,
],
[
0.83499999999999996,
2.3799999999999999,
150,
],
[
0.94599999999999995,
2.1699999999999999,
100,
],
[
1.0900000000000001,
1.95,
50,
],
[
1.29,
1.71,
0,
],
],
densityGrid(),
3,
true,
],
[
'#N/A',
0.69999999999999996,
[
[
'Density',
'Viscosity',
'Temperature',
],
[
0.45700000000000002,
3.5499999999999998,
500,
],
[
0.52500000000000002,
3.25,
400,
],
[
0.61599999999999999,
2.9300000000000002,
300,
],
[
0.67500000000000004,
2.75,
250,
],
[
0.746,
2.5699999999999998,
200,
],
[
0.83499999999999996,
2.3799999999999999,
150,
],
[
0.94599999999999995,
2.1699999999999999,
100,
],
[
1.0900000000000001,
1.95,
50,
],
[
1.29,
1.71,
0,
],
],
0.70,
densityGrid(),
3,
false,
],
[
'#N/A',
0.10000000000000001,
[
[
'Density',
'Viscosity',
'Temperature',
],
[
0.45700000000000002,
3.5499999999999998,
500,
],
[
0.52500000000000002,
3.25,
400,
],
[
0.61599999999999999,
2.9300000000000002,
300,
],
[
0.67500000000000004,
2.75,
250,
],
[
0.746,
2.5699999999999998,
200,
],
[
0.83499999999999996,
2.3799999999999999,
150,
],
[
0.94599999999999995,
2.1699999999999999,
100,
],
[
1.0900000000000001,
1.95,
50,
],
[
1.29,
1.71,
0,
],
],
0.100,
densityGrid(),
2,
true,
],
[
1.71,
2,
[
[
'Density',
'Viscosity',
'Temperature',
],
[
0.45700000000000002,
3.5499999999999998,
500,
],
[
0.52500000000000002,
3.25,
400,
],
[
0.61599999999999999,
2.9300000000000002,
300,
],
[
0.67500000000000004,
2.75,
250,
],
[
0.746,
2.5699999999999998,
200,
],
[
0.83499999999999996,
2.3799999999999999,
150,
],
[
0.94599999999999995,
2.1699999999999999,
100,
],
[
1.0900000000000001,
1.95,
50,
],
[
1.29,
1.71,
0,
],
],
densityGrid(),
2,
true,
],
@ -380,4 +141,19 @@ return [
3,
true,
],
[
'E',
0.52,
[
['Lower', 'Upper', 'Grade'],
[0.00, 0.44, 'F'],
[0.45, 0.54, 'E'],
[0.55, 0.64, 'D'],
[0.65, 0.74, 'C'],
[0.75, 0.84, 'B'],
[0.85, 1.00, 'A'],
],
3,
null,
],
];