Skip to content

Commit 872dfd4

Browse files
authored
Merge branch 'master' into choosecols
2 parents ee7ddf7 + c06d59e commit 872dfd4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+669
-218
lines changed

.github/workflows/main.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ jobs:
2525
- name: Checkout
2626
uses: actions/checkout@v4
2727

28+
- name: Install locales
29+
run: sudo apt-get install -y language-pack-fr language-pack-de
30+
31+
- name: Install single-byte locale
32+
run: sudo sed -i -e 's/# de_DE@euro/de_DE@euro/g' /etc/locale.gen && sudo locale-gen de_DE@euro
33+
2834
- name: Setup PHP, with composer and extensions
2935
uses: shivammathur/setup-php@v2
3036
with:

CHANGELOG.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com)
66
and this project adheres to [Semantic Versioning](https://semver.org).
77

8-
## TBD - 3.7.0
8+
## TBD - 3.8.0
99

1010
### Added
1111

@@ -21,11 +21,27 @@ and this project adheres to [Semantic Versioning](https://semver.org).
2121

2222
### Deprecated
2323

24+
- Nothing yet.
25+
26+
### Fixed
27+
28+
- Xlsx Reader Shared Formula with Boolean Result. Partial solution for [Issue #4280](https://github.com/PHPOffice/PhpSpreadsheet/issues/4280) [PR #4281](https://github.com/PHPOffice/PhpSpreadsheet/pull/4281)
29+
30+
## 2024-12-26 - 3.7.0
31+
32+
### Deprecated
33+
2434
- Drawing::setIsUrl is unneeded. The property is set when setPath determines whether path is a url.
2535

2636
### Fixed
2737

28-
- More context options may be needed for http(s) image. [Php issue 17121](https://github.com/php/php-src/issues/17121) [PR #4276](https://github.com/PHPOffice/PhpSpreadsheet/pull/4276)
38+
- Security patches for Samples.
39+
- Security patches for Html Writer.
40+
- Avoid unexpected charset in currency symbol. [PR #4279](https://github.com/PHPOffice/PhpSpreadsheet/pull/4279)
41+
- Add forceFullCalc option to Xlsx Writer. [Issue #4269](https://github.com/PHPOffice/PhpSpreadsheet/issues/4269) [PR #4271](https://github.com/PHPOffice/PhpSpreadsheet/pull/4271)
42+
- More context options may be needed for http(s) image. [Php issue 17121](https://github.com/php/php-src/issues/17121) [PR #4276](https://github.com/PHPOffice/PhpSpreadsheet/pull/4276)
43+
- Coverage-related tweaks to Xls Reader. [PR #4277](https://github.com/PHPOffice/PhpSpreadsheet/pull/4277)
44+
- Several fixed to ODS Writer. [Issue #4261](https://github.com/PHPOffice/PhpSpreadsheet/issues/4261) [PR #4263](https://github.com/PHPOffice/PhpSpreadsheet/pull/4263) [PR #4264](https://github.com/PHPOffice/PhpSpreadsheet/pull/4264) [PR #4266](https://github.com/PHPOffice/PhpSpreadsheet/pull/4266)
2945

3046
## 2024-12-08 - 3.6.0
3147

composer.lock

Lines changed: 8 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/topics/reading-and-writing-to-file.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,12 @@ $writer->save("05featuredemo.xlsx");
169169
**Note** Formulas will still be calculated in any column set to be autosized
170170
even if pre-calculated is set to false
171171

172+
**Note** Prior to release 3.7.0, the use of this feature will cause Excel to be used in a mode where opening a sheet saved in this manner *might* not automatically recalculate a cell's formula when a cell used it the formula changes. Furthermore, that behavior might be applied to all spreadsheets open at the time. To avoid this behavior, add the following statement after `setPreCalculateFormulas` above:
173+
```php
174+
$writer->setForceFullCalc(false);
175+
```
176+
In a future release, the property's default may change to `false` and that statement may no longer be required.
177+
172178
#### Office 2003 compatibility pack
173179

174180
Because of a bug in the Office2003 compatibility pack, there can be some

samples/Engineering/Convert-Online.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,16 @@
7878
$quantity = $_POST['quantity'];
7979
$fromUnit = $_POST['fromUnit'];
8080
$toUnit = $_POST['toUnit'];
81-
if (isset($units[$_POST['category']][$fromUnit], $units[$_POST['category']][$toUnit])) {
81+
if (!is_numeric($quantity)) {
82+
$helper->log('Quantity is not numeric');
83+
} elseif (isset($units[$_POST['category']][$fromUnit], $units[$_POST['category']][$toUnit])) {
8284
/** @var float|string */
8385
$result = ConvertUOM::CONVERT($quantity, $fromUnit, $toUnit);
8486

85-
echo "{$quantity} {$units[$_POST['category']][$fromUnit]} is {$result} {$units[$_POST['category']][$toUnit]}", PHP_EOL;
87+
$helper->log("{$quantity} {$units[$_POST['category']][$fromUnit]} is {$result} {$units[$_POST['category']][$toUnit]}");
8688
} else {
87-
echo 'Please enter quantity and select From Unit and To Unit', PHP_EOL;
89+
$helper->log('Please enter quantity and select From Unit and To Unit');
8890
}
8991
} else {
90-
echo 'Please enter quantity and select From Unit and To Unit', PHP_EOL;
92+
$helper->log('Please enter quantity and select From Unit and To Unit');
9193
}

samples/Wizards/NumberFormat/Accounting.php

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,6 @@
6464
<input name="position" type="radio" value="0" <?php echo (isset($_POST['position']) && $_POST['position'] === '0') ? 'checked' : ''; ?>>Trailing
6565
</div>
6666
</div>
67-
<div class="mb-3 row">
68-
<label for="spacing" class="col-sm-2 col-form-label">Currency Spacing</label>
69-
<div class="col-sm-10">
70-
<input name="spacing" type="radio" value="1" <?php echo (isset($_POST['spacing']) && $_POST['spacing'] === '1') ? 'checked' : ''; ?>>Yes
71-
<input name="spacing" type="radio" value="0" <?php echo ((isset($_POST['spacing']) === false) || (isset($_POST['spacing']) && $_POST['spacing'] === '0')) ? 'checked' : ''; ?>>No
72-
</div>
73-
</div>
7467
<div class="mb-3 row">
7568
<div class="col-sm-10">
7669
<input class="btn btn-primary" name="submit" type="submit" value="Display Mask"><br />
@@ -85,21 +78,23 @@
8578
$helper->log('The Sample Number Value must be numeric');
8679
} elseif (!is_numeric($_POST['decimals']) || str_contains((string) $_POST['decimals'], '.') || (int) $_POST['decimals'] < 0) {
8780
$helper->log('The Decimal Places value must be positive integer');
81+
} elseif (!in_array($_POST['currency'], array_keys($currencies), true)) {
82+
$helper->log('Unrecognized currency symbol');
8883
} else {
8984
try {
90-
$wizard = new Wizard\Accounting($_POST['currency'], (int) $_POST['decimals'], isset($_POST['thousands']), (bool) $_POST['position'], (bool) $_POST['spacing']);
85+
$wizard = new Wizard\Accounting($_POST['currency'], (int) $_POST['decimals'], isset($_POST['thousands']), (bool) $_POST['position']);
9186
$mask = $wizard->format();
9287
$example = (string) NumberFormat::toFormattedString((float) $_POST['number'], $mask);
9388
$helper->log('<hr /><b>Code:</b><br />');
9489
$helper->log('use PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard;');
9590
$helper->log(
96-
"\$mask = Wizard\\Accounting('{$_POST['currency']}', {$_POST['decimals']}, Wizard\\Number::"
91+
"\$wizard = new Wizard\\Accounting('{$_POST['currency']}', {$_POST['decimals']}, Wizard\\Number::"
9792
. (isset($_POST['thousands']) ? 'WITH_THOUSANDS_SEPARATOR' : 'WITHOUT_THOUSANDS_SEPARATOR')
9893
. ', Wizard\Currency::' . (((bool) $_POST['position']) ? 'LEADING_SYMBOL' : 'TRAILING_SYMBOL')
99-
. ', Wizard\Currency::' . (((bool) $_POST['spacing']) ? 'SYMBOL_WITH_SPACING' : 'SYMBOL_WITHOUT_SPACING')
100-
. ');<br />'
94+
. ');'
10195
);
102-
$helper->log('echo (string) $mask;');
96+
$helper->log('$mask = $wizard->format();');
97+
$helper->log('<br />echo (string) $mask;');
10398
$helper->log('<hr /><b>Mask:</b><br />');
10499
$helper->log($mask . '<br />');
105100
$helper->log('<br /><b>Example:</b><br />');

samples/Wizards/NumberFormat/Currency.php

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
use PhpOffice\PhpSpreadsheet\Settings;
66
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
77
use PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard;
8+
use PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard\CurrencyNegative;
9+
use PhpOffice\PhpSpreadsheet\Writer\Html as HtmlWriter;
810

911
require __DIR__ . '/../Header.php';
1012

@@ -15,6 +17,19 @@
1517
return;
1618
}
1719

20+
$negatives = [
21+
CurrencyNegative::minus,
22+
CurrencyNegative::redMinus,
23+
CurrencyNegative::parentheses,
24+
CurrencyNegative::redParentheses,
25+
];
26+
$negativesString = [
27+
'CurrencyNegative::minus',
28+
'CurrencyNegative::redMinus',
29+
'CurrencyNegative::parentheses',
30+
'CurrencyNegative::redParentheses',
31+
];
32+
1833
$currencies = [
1934
'$' => 'US Dollars ($)',
2035
'' => 'Euro (€)',
@@ -65,10 +80,12 @@
6580
</div>
6681
</div>
6782
<div class="mb-3 row">
68-
<label for="spacing" class="col-sm-2 col-form-label">Currency Spacing</label>
83+
<label for="negative" class="col-sm-2 col-form-label">Negative Numbers</label>
6984
<div class="col-sm-10">
70-
<input name="spacing" type="radio" value="1" <?php echo (isset($_POST['spacing']) && $_POST['spacing'] === '1') ? 'checked' : ''; ?>>Yes
71-
<input name="spacing" type="radio" value="0" <?php echo ((isset($_POST['spacing']) === false) || (isset($_POST['spacing']) && $_POST['spacing'] === '0')) ? 'checked' : ''; ?>>No
85+
<input name="negative" type="radio" value="0" <?php echo (!isset($_POST['negative']) || $_POST['negative'] === '0') ? 'checked' : ''; ?>>Minus Sign
86+
<input name="negative" type="radio" value="1" <?php echo (isset($_POST['negative']) && $_POST['negative'] === '1') ? 'checked' : ''; ?>>Red Minus Sign
87+
<input name="negative" type="radio" value="2" <?php echo (isset($_POST['negative']) && $_POST['negative'] === '2') ? 'checked' : ''; ?>>Parentheses
88+
<input name="negative" type="radio" value="3" <?php echo (isset($_POST['negative']) && $_POST['negative'] === '3') ? 'checked' : ''; ?>>Red Parentheses
7289
</div>
7390
</div>
7491
<div class="mb-3 row">
@@ -85,21 +102,27 @@
85102
$helper->log('The Sample Number Value must be numeric');
86103
} elseif (!is_numeric($_POST['decimals']) || str_contains((string) $_POST['decimals'], '.') || (int) $_POST['decimals'] < 0) {
87104
$helper->log('The Decimal Places value must be positive integer');
105+
} elseif (!in_array($_POST['currency'], array_keys($currencies), true)) {
106+
$helper->log('Unrecognized currency symbol');
88107
} else {
89108
try {
90-
$wizard = new Wizard\Currency($_POST['currency'], (int) $_POST['decimals'], isset($_POST['thousands']), (bool) $_POST['position'], (bool) $_POST['spacing']);
109+
$negative = $negatives[$_POST['negative']] ?? CurrencyNegative::minus;
110+
$wizard = new Wizard\Currency($_POST['currency'], (int) $_POST['decimals'], isset($_POST['thousands']), (bool) $_POST['position']);
111+
$wizard->setNegative($negative);
91112
$mask = $wizard->format();
92-
$example = (string) NumberFormat::toFormattedString((float) $_POST['number'], $mask);
113+
$example = (string) NumberFormat::toFormattedString((float) $_POST['number'], $mask, [HtmlWriter::class, 'formatColorStatic']);
93114
$helper->log('<hr /><b>Code:</b><br />');
94115
$helper->log('use PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard;');
116+
$helper->log('use PhpOffice\PhpSpreadsheet\Style\NumberFormat\CurrencyNegative;');
95117
$helper->log(
96-
"\$mask = Wizard\\Currency('{$_POST['currency']}', {$_POST['decimals']}, Wizard\\Number::"
118+
"\$wizard = new Wizard\\Currency('{$_POST['currency']}', {$_POST['decimals']}, Wizard\\Number::"
97119
. (isset($_POST['thousands']) ? 'WITH_THOUSANDS_SEPARATOR' : 'WITHOUT_THOUSANDS_SEPARATOR')
98120
. ', Wizard\Currency::' . (((bool) $_POST['position']) ? 'LEADING_SYMBOL' : 'TRAILING_SYMBOL')
99-
. ', Wizard\Currency::' . (((bool) $_POST['spacing']) ? 'SYMBOL_WITH_SPACING' : 'SYMBOL_WITHOUT_SPACING')
100-
. ');<br />'
121+
. ');'
101122
);
102-
$helper->log('echo (string) $mask;');
123+
$helper->log('$wizard->setNegative(' . $negativesString[$_POST['negative']] . ');');
124+
$helper->log('$mask = $wizard->format();');
125+
$helper->log('<br />echo (string) $mask;');
103126
$helper->log('<hr /><b>Mask:</b><br />');
104127
$helper->log($mask . '<br />');
105128
$helper->log('<br /><b>Example:</b><br />');

src/PhpSpreadsheet/Collection/Memory/SimpleCache1.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
*
1010
* Alternative implementation should leverage off-memory, non-volatile storage
1111
* to reduce overall memory usage.
12+
*
13+
* Either SimpleCache1 or SimpleCache3, but not both, may be used.
14+
* For code coverage testing, it will always be SimpleCache3.
15+
*
16+
* @codeCoverageIgnore
1217
*/
1318
class SimpleCache1 implements CacheInterface
1419
{

src/PhpSpreadsheet/Helper/Downloader.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,18 @@ class Downloader
3030
public function __construct(string $folder, string $filename, ?string $filetype = null)
3131
{
3232
if ((is_dir($folder) === false) || (is_readable($folder) === false)) {
33-
throw new Exception("Folder {$folder} is not accessable");
33+
throw new Exception('Folder is not accessible');
3434
}
3535
$filepath = "{$folder}/{$filename}";
3636
$this->filepath = (string) realpath($filepath);
3737
$this->filename = basename($filepath);
3838
if ((file_exists($this->filepath) === false) || (is_readable($this->filepath) === false)) {
39-
throw new Exception("{$this->filename} not found, or cannot be read");
39+
throw new Exception('File not found, or cannot be read');
4040
}
4141

4242
$filetype ??= pathinfo($filename, PATHINFO_EXTENSION);
4343
if (array_key_exists(strtolower($filetype), self::CONTENT_TYPES) === false) {
44-
throw new Exception("Invalid filetype: {$filetype} cannot be downloaded");
44+
throw new Exception('Invalid filetype: file cannot be downloaded');
4545
}
4646
$this->filetype = strtolower($filetype);
4747
}

src/PhpSpreadsheet/Reader/Xls/Color.php

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,6 @@ public static function map(int $color, array $palette, int $version): array
2424
return $palette[$color - 8];
2525
}
2626

27-
// default color table
28-
if ($version == Xls::XLS_BIFF8) {
29-
return Color\BIFF8::lookup($color);
30-
}
31-
32-
// BIFF5
33-
return Color\BIFF5::lookup($color);
27+
return ($version === Xls::XLS_BIFF8) ? Color\BIFF8::lookup($color) : Color\BIFF5::lookup($color);
3428
}
3529
}

0 commit comments

Comments
 (0)