Commit Graph

667 Commits

Author SHA1 Message Date
Adrien Crivelli
5e64479c06
Document the callback 2020-06-28 17:34:50 +09:00
oleibman
360c8d8284
Merge branch 'master' into htmledit 2020-06-09 00:39:52 -07:00
Owen Leibman
c47b407e39 Different Example for Callback
Replace default gridlines with different style. Usable in PDF
as well as HTML.

Documentation mentioned use of setUseBOM with Html, but that method
does not exist, and there is no real reason to support it.
Removed it from documentation.
2020-06-09 00:22:22 -07:00
Mark Baker
5c18bb5798
Range operator tests (#1501)
* Improved handling of named ranges, although there are still some issues (names ranges using a union type with an overlap don't handle the overlap twice, which as the MS Excel approach to set overlaps as opposed to the mathematical approach which only applies overlap values once)

* Fix tests that misused space and comma as simple separators in cell ranges
2020-06-02 07:38:35 +02:00
Adrien Crivelli
b9a59660d0
Password and hash are exclusive
As specified in https://docs.microsoft.com/en-us/openspecs/office_standards/ms-xlsx/85f5567f-2599-41ad-ae26-8cfab23ce754
password and hashValue are exlusive and thus should be treated
transparently with a single API in our model.
2020-05-31 22:36:37 +09:00
Reijn
dfa6f77178
Add support protection of worksheet by a specific hash algorithm 2020-05-31 20:29:20 +09:00
Adrien Crivelli
c434e9b137
Stricter typing for mergeCells
Closes #1494
2020-05-31 15:58:57 +09:00
Owen Leibman
edc411e6dd Add ability to save edited Html/Pdf
We give users the ability to edit Html/Pdf, but it's a little cumbersome
to use the edited Html for an Html file, and difficult to use it
for a Pdf. I believe we could make it fairly painless in both cases
by allowing the user to set a callback to edit the generated Html.
This can be accomplished with fewer than a dozen lines of very simple code.
I think this would be easier than grabbing the Html in pieces,
editing it, and reassembling it. I think it would also be simpler
than an alternative I considered, namely the addition of a new method
(e.g. saveEditedHtml) to each of the Html and Pdf writers.

One edit that users might like to make when editing html is to add
fallback fonts, something that is not currently available in
PhpSpreadsheet, and might be difficult to add. A natural extension to
that idea would be the use of webfonts, something which is guaranteed
difficult to add. See samples/Basic/17b_Html for an example of this.

None of the PDF writers support webfonts yet. That doesn't mean they
won't do so in future, but, for now, samples/Pdf/21a_Pdf is a prosaic
example of something you could do with this callback. In fact, this
opens the door to letting the user replace the entire body with data
of their choosing, effectively allowing PhpSpreadsheet (where you can
set things like paper size and orientation) to be used as a front-end to
the Pdf processor without the user having to be be overly familiar with
the vagaries of the PDF processor. I think this is actually a pretty
nice idea. YMMV. See samples/Basic/21b_Pdf for an example.
2020-05-30 21:27:35 -07:00
Mark Baker
8b2bba9bdb
Range operator tests (#1498)
* Fix intersection operator when working with named ranges
2020-05-29 21:53:28 +02:00
Alban Duval
7ed96e0be1
Calcualtion - DATEDIF - fix result for Y & YM units (#1466)
Bugfix for negative results and too small results

2000-02-02 => 2001-02-01
 > DATEDIF with Y unit: 0 year (returned -1 before fix)
 > DATEDIF with YM unit: 11 months (returned -1 before fix)
2020-05-25 21:33:48 +02:00
oleibman
5dd7e883c6
Fix Issue 1441 (isDateTime and Formulas) (#1480)
* Fix Issue 1441 (isDateTime and Formulas)

When you have a date-field which is a formula, isDateTime returns false.
https://github.com/PHPOffice/PhpSpreadsheet/issues/1441

Report makes sense; fixed as suggested. Also fixed a few minor
related issues, and added tests so that Shared/Date and Shared/TimeZone
are now completely covered.

Date/setDefaultTimeZone and TimeZone/setTimeZone were not consistent
about what to do in event of failure - return false or throw.
They will now both return false, which is what Date's function
said it would do in its doc block anyhow. Date/validateTimeZone will
continue to throw; it was protected, but was never called outside
Date, so I changed it to private.

TimeZone/getTimeZoneAdjustment checked for 'UST' when it probably
meant 'UTC', and, as it turns out, the check is not even needed.

The most serious problem was that TimeZone/validateTimeZone does not
check the backwards-compatible time zones. The timezone project
aggressively, and very controversially, "demotes" timezones;
such timezones eventually wind up in the PHP backwards-compatible list.
We want to make sure to check that list so that our applications do not
break when this happens.
2020-05-24 20:02:39 +02:00
oleibman
84e03da5c7
Code Coverage for Shared\CodePage (#1491)
While investigating something else in Shared, I noticed that CodePage
had poor test coverage and a high complexity rating. This change
addresses both; Scrutinizer would love it, although its interface on
GitHub seems broken at the moment (all PRs show "Waiting for External
Code Coverage").
2020-05-24 19:51:28 +09:00
Mark Baker
8ca7bfe53c
Range operator tests (#1487)
* Range Operator Tests
* Correct handling for range intersections that result in an empty array
2020-05-24 00:25:54 +02:00
Vagir
3446bb0ef7
Fix saving XLSX with drawings (#1462)
* Fix incorrect behaviour when saving XLSX file with drawings
2020-05-23 13:09:10 +02:00
Collie-IT
6c23de78d8
Fix Warning if $relsVML->Relationship is NULL (#1420)
Fix Warning if $relsVML->Relationship is NULL (#1420)
2020-05-23 12:56:26 +02:00
F0Rt04ka
0945e87b6d
Fix "Undefined offset" if border style is "none" (#1423) 2020-05-23 12:51:48 +02:00
Gianni Genovesi
7b1957f996
fix: issue #1476 crash with numeric string value terminating with new line (#1481)
* fix: issue #1476 crash with numeric string value terminating with new line
* test: provided tests for issue #1476
2020-05-23 12:49:54 +02:00
Adrien Crivelli
137268d61a
Remove undesired annotations 2020-05-18 15:49:29 +09:00
Adrien Crivelli
fcd9f10663
Update PHP-CS-Fixer rules 2020-05-18 13:49:57 +09:00
oleibman
97a80f383c
Improve HTML Writer (#1464)
There are a number of situations where HTML write was producing
HTML which could not be validated. These include:

  - inconsistent use of backslash terminating META, IMG, and COL tags
  - @page style tags in body rather than header. Aside from being
    non-standard, HTML Reader treats those as spreadsheet data.
  - <div style="page-break-before:always" />, a construct which is
    usually better handled through css anyhow.
  - no alt tag for images (drawings and charts)

Other problems:

  - Windows file names not handled correctly for images
  - Memory drawings not handled in extendRowsForChartsAndImages
  - No handling of different values for showing gridlines
    for screen and print
  - Mpdf and Dompdf do not require the use of inline css.
    Tcpdf remains a holdout in the use of this inferior approach.
  - no need to chunk base64 encoding of embedded images
  - support for colors in number format was buggy (html tags
    run through htmlspecialchars)

Code has been refactored when practical to reduce the number of
very large functions.

Coverage is now 100% for the entire HTML Writer module,
from 75% lines and 39% methods beforehand.

All functions dealing only with charts
are bypassed for coverage because the version of Jpgraph available in
Composer is not suitable for PHP7. The code will, nevertheless,
run successfully, but with warning messages. I have confirmed that
the code is entirely covered, without warnings, when the current
version of Jpgraph is used in lieu of the one available in Composer.
I will be glad to revisit this when the Jpgraph problem is resolved.

Directory PhpSpreadsheetTests/Writer/Html was created to house
the new tests. It seemed logical to move HtmlCommentsTest to
the new directory from PhpSpreadsheetTests/Functional.

A function to generate all the HTML is useful, especially for testing,
but also in lieu of the multiple other generate* functions. I have
added and documented generateHTMLAll.

The documentation for the generate* functions (a) produces invalid html,
(b) produces html which cannot be handled correctly by HTML reader,
and (c) even if those were correct, does not actually affect
the display of the spreadsheet. The documentation has been replaced
by a valid, and more instructive, example.

The (undocumented) useEmbeddedCss property, and the functions
to test and set it are no longer needed. Rather than breaking
existing code by deleting them, I marked the functions deprecated.

This change borrows a change to LocaleFloatsTest from
pull request 1456, submitted a little over a week before this one.


## Improve NumberFormat Support

First phase of this change included correcting NumberFormat handling
in HTML Writer. Certain complex formats could not be handled without
changes to Style/NumberFormat, and I did not wish to combine those changes.

Once the original change had been pushed, I took this part of it back up.
HTML Writer can now handle conditions in formats like:
[Blue][>=3000.5]$#,##0.00;[Red][<0]$#,##0.00;$#,##0.00
In testing, I discovered several errors and omissions
in handling of some other formats.
These are now corrected, and tests added.
2020-05-18 12:43:18 +09:00
Owen Leibman
4f6d4af396
Save Excel 2010+ Functions Properly
For functions introduced in Excel 2010 and beyond, Excel saves them
in formulas with the xlfn_ prefix. PhpSpreadsheet does not do this;
as a result, when a spreadsheet so created is opened, the cells
which use the new functions display a #NAME? error.
This the cause of bug report 1246:
https://github.com/PHPOffice/PhpSpreadsheet/issues/1246
This change corrects that problem when the Xlsx writer encounters
a 2010+ formula for a cell or a conditional style. A new class
Writer/Xlsx/Xlfn, with 2 static methods,
is introduced to facilitate this change.

As part of the testing for this, I found some additional problems.
When an unknown function name is used, Excel generates a #NAME? error.
However, when an unknown function is used in PhpSpreadsheet:
  - if there are no parameters, it returns #VALUE!, which is wrong
  - if there are parameters, it throws an exception, which is horrible
Both of these situations will now return #NAME?
Tests have been added for these situations.

The MODE (and MODE.SNGL) function is not quite in alignment with Excel.
MODE(3, 3, 4, 4) returns 3 in both Excel and PhpSpreadsheet.
However, MODE(4, 3, 3, 4) returns 4 in Excel, but 3 in PhpSpreadsheet.
Both situations will now match Excel's result.
Also, Excel allows its parameters for MODE to be an array,
but PhpSpreadsheet did not; it now will.
There had not been any tests for MODE. Now there are.

The SHEET and SHEETS functions were introduced in Excel 2013,
but were not introduced in PhpSpreadsheet. They are now introduced
as DUMMY functions so that they can be parsed appropriately.

Finally, in common with the "rate" changes for which I am
creating a pull request at the same time as this one:
samples/Basic/13_CalculationCyclicFormulae
PhpUnit started reporting an error like "too much regression".
The test deals with an infinite cyclic formula, and allowed
the calculation engine to run for 100 cycles. The actual number of cycles
seems irrelevant for the purpose of this test. I changed it to 15,
and PhpUnit no longer complains.
2020-05-18 12:37:35 +09:00
oleibman
9ae521cdd4
Fix RATE, PRICE, XIRR, and XNPV Functions (#1456)
There were about 20 skipped tests for RATE and PRICE marked
"This test should be fixed". This change does that by fixing
the code for those functions, validating the existing tests,
and adding new ones. XIRR and XNPV are also substantially changed.
As part of this change, the following functions also have minor changes:

  - isValidFrequency
  - COUPDAYBS
  - COUPNUM (additional tests)
  - DB
  - DDB

PhpUnit reports 100% coverage for all the changed functions.

Since I was dealing with skipped tests, I also fixed
tests/PhpSpreadsheetTests/Writer/Xlsx/LocaleFloatsTest,
which was being skipped in Windows. I also delete the temporary
file which it creates.
There is now only one remaining test which is skipped -
ODS Reader is not complete enough to run some tests against it.
Unfortunately, that test is too complicated for me to deal with now.

In researching this change, I found several places in the code where special code was added for Gnumeric claiming:

   - Gnumeric does not handle free-format string dates
   - Gnumeric adds extra options, not available in Excel,
     for the frequency parameter for functions such as YIELD
   - Gnumeric rounds the results for DB and DDB to 2 decimal places

None of these claims is true, at least not on a recent version
of Gnumeric, and the code which supports these differences is removed.
There did not appear to be any tests targeted for
these supposed properties of Gnumeric.

The PRICE function needed relatively minor changes - mostly
additional tests for invalid input. The main problem with the PRICE
tests is that Excel appears to have a bug. The algorithm is published:
https://support.office.com/en-us/article/price-function-3ea9deac-8dfa-436f-a7c8-17ea02c21b0a
The results that Excel returns for basis codes 2 and 3 appear to be
incorrect in many cases. I have segregated these tests into a
new test PRICE3. The results of these tests agree with the published
algorithm, and to the results for LibreOffice and Gnumeric.
The results returned by Excel do not agree with them.
The tests which remain in the test PRICE all use basis codes other
than 2 or 3, and all agree with Excel, LibreOffice, and Gnumeric.

For the RATE function, there appears to be a problem with how the
secant method was implemented. I studied the implementation of RATE
in Python numpy, and adapted its implementation of secant method.
The results now agree with numpy, and, more important, with Excel.

XIRR, which calls XNPV, permits its dates to be earlier than the
start date, whereas XNPV does not. I dealt with this by renaming
the existing XNPV function to xnpvOrdered, adding a parameter to
indicate whether start date has to be earliest. XNPV calls the new
function with that parameter set to TRUE, and XIRR calls it with
the parameter set to FALSE. Some additional error checking was
added to xnpvOrdered, and also to XIRR. XIRR tests benefited
from increasing the value of FINANCIAL_MAX_ITERATIONS.

Finally, since this change is very test-related:
samples/Basic/13_CalculationCyclicFormulae
PhpUnit started reporting an error like "too much regression".
The test deals with an infinite cyclic formula, and allowed
the calculation engine to run for 100 cycles. The actual number of cycles
seems irrelevant for the purpose of this test. I changed it to 15,
and PhpUnit no longer complains.
2020-05-17 19:50:01 +09:00
Adrien Crivelli
8eaceb0f92
Fix return type docblock for the Cells::get()
PHPStorm inspections and PHPStan display an incorrect hint or
error if the special type `null` is not specified.

Closes #1398
2020-05-17 19:42:28 +09:00
Adrien Crivelli
15bd764a08
A few more invalid displayBlanksAs 2020-05-17 19:35:18 +09:00
Chris Wolcott
d49567aad0
File containing a chart can be opened by Excel 2003/2013/2019
All chart examples passed the displayBlanksAs parameter as 0 instead of 'gap'.
I added a constants EMPTY_AS_GAP, EMPTY_AS_ZERO and EMPTY_AS_SPAN to the
DataSeries and then change all chart samples to use this new constant.

Fixes #1337
Closes #1448
2020-05-17 19:28:27 +09:00
Adrien Crivelli
c725128a68
CSV writer also use common code to open file 2020-05-17 18:58:32 +09:00
Adrien Crivelli
5f413b8a58
Keep sample bootstrap purely in samples 2020-05-17 18:51:13 +09:00
oleibman
7517cdd008
Improve Coverage for CSV (#1475)
I believe that both CSV Reader and Writer are 100% covered now.

There were some errors uncovered during development.

The reader specifically permits encodings other than UTF-8 to be used.
However, fgetcsv will not properly handle other encodings.
I tried replacing it with fgets/iconv/strgetcsv, but that could not
handle line breaks within a cell, even for UTF-8.
This is, I'm sure, a very rare use case.
I eventually handled it by using php://memory to hold the translated
file contents for non-UTF8. There were no tests for this situation,
and now there are (probably too many).

"Contiguous" read was not handle correctly. There is a file
in samples which uses it. It was designed to read a large sheet,
and split it into three. The first sheet was corrrect, but the
second and third were almost entirely empty. This has been corrected,
and the sample code was adapted into a formal test with assertions
to confirm that it works as designed.

I made a minor documentation change. Unlike HTML, where you never
need a BOM because you can declare the encoding in the file,
a CSV with non-ASCII characters must explicitly include a BOM
for Excel to handle it correctly. This was explained in the Reading CSV
section, but was glossed over in the Writing CSV section, which I
have updated.
2020-05-17 18:15:18 +09:00
drewblin
3090c1e73f
Support CSV files with data wrapping a lot of lines
If there is "line" splited on lot of lines we can reach limit of recursion
nesting. It's better to use while instead of recursion.

Closes #1468
2020-05-17 17:58:08 +09:00
Adrien Crivelli
7e79782dae
Remove @throws comment
Those are extremely hard to maintain properly and bring almost
no value, especially if they are outdated
2020-05-16 20:33:25 +09:00
Adrien Crivelli
8967696095
Merge pull request #1292 from basbl/write-to-stream-support
Support writing to resource handles in all IWriter implementations
2020-05-16 20:25:53 +09:00
Adrien Crivelli
e34535329d
Remove obsolete arguments 2020-05-16 20:25:01 +09:00
Adrien Crivelli
fcf7820467
All writers can write to stream 2020-05-16 20:12:28 +09:00
Adrien Crivelli
9cdbddf3bf
Early bail out if resource cannot be opened 2020-05-16 18:08:10 +09:00
Adrien Crivelli
588ca6beb3
Replace migration tool with RectorPHP
Fixes #1445
2020-05-02 12:34:50 +09:00
basbl
b60b1d25c0
Test scrutinizer 2020-04-27 21:48:56 +02:00
basbl
11499aad9a
Add resource parameter handling to html, csv and xls writers 2020-04-27 21:26:55 +02:00
basbl
ccb49de301
Add support for streaming zip files in the xlsx and ods writers 2020-04-27 21:26:55 +02:00
Collie-IT
973011921d
Add Missing Operator NOTBETWEEN (#1390) 2020-04-27 12:01:36 +02:00
Adrien Crivelli
03c587fe0b
Drop PHP 7.1
This is according to our formal, published, policy to only support
eol PHP after 6 months.

See https://phpspreadsheet.readthedocs.io/en/latest/#php-version-support
2020-04-27 18:42:32 +09:00
n-longcape
f9f9f4cacf
Fix ROUNDUP and ROUNDDOWN for negative number
Closes #1417
2020-04-27 17:03:07 +09:00
bbinotto
e2f87e8b7a
Load with styles should not default to black fill color
Fixes #1353
Closes #1361
2020-04-26 22:33:30 +09:00
Paul Kievits
a6c56d0f81
Added support for the FLOOR.MATH and FLOOR.PRECISE functions 2020-04-26 22:19:33 +09:00
Owen Leibman
c4895b9468
MATCH with a static array should return the position of the found value based on the values submitted.
Returns #N/A, unless the element searched for is at the end of the array.

The problem is in Calculation.php line 4231:
                    if (!is_array($functionCall)) {
                        foreach ($args as &$arg) {
                            $arg = Functions::flattenSingleValue($arg);
                        }
                        unset($arg);
                    }

I believe this code is intended to handle functions where PhpSpreadsheet just passes
the call on to PHP without implementing the code on its own, e.g. for atan or acos.
In the bug report, the following code fails:
  $flat_rate = "=MATCH(6,{4,5,6,2}, 0)";
  $sheet->getCell('A1')->setValue($flat_rate);
The expected value is 3, but the actual result is "#N/A".
The reason for this result is that the parser replaces the braces with calls
to the MKMATRIX internal function, whose value for functioncall was:
'self::MKMATRIX'. Since this isn't an array, the flattening code is executed,
and the unintended result occurs. The fix is to change the definition for
functioncall in that case to [__CLASS__, 'mkMatrix'], avoiding the flattening.

However, there is also another part to this bug. The flattening should be
returning the first entry in the array, but is in fact returning the last.
This explains why the bug report specified "unless ... end of the array".
I confirmed that Excel does use the first item in the array rather than the last,
e.g. =atan({1,2,3}) entered into a cell will return atan(1), not atan(3).
The problem here is that flattenSingleValue, which says in its comments that
it is supposed to be returning the first item, uses array_pop rather than array_shift.
I have changed that as well. The same mistake was also present in
Cell.php function getCalculatedValue. The correct behavior can be verified
by entering =minverse({-2.5,1.5;2,-1}) into an Excel cell'
Excel flattens the result ({2,3;4,5}) to 2, and so should PhpSpreadsheet.

Fixes #1271
Closes #1332
2020-04-26 22:09:31 +09:00
Jon Dufresne
6788869a40
Fix typo: occured → occurred (#1435) 2020-04-26 21:09:56 +09:00
Tim Gavryutenko
3dcc5ca753
Fix removing last row incorrect behavior
`$highestRow = $this->getHighestDataRow();` was calculated after `$this->getCellCollection()->removeRow($pRow + $r);` - this is the root reason for incorrect rows removal because removing last row will change '$this->getHighestDataRow()' value, but removing row from the middle will not change it. So, removing last row causes incorrect `$highestRow` value that is used for wiping out empty rows from the bottom of the table:
```php
for ($r = 0; $r < $pNumRows; ++$r) {
    $this->getCellCollection()->removeRow($highestRow);
    --$highestRow;
}
```
To prevent this incorrect behavior I've moved highest row calculation before row removal.
But this still doesn't solve another problem when trying remove non existing rows: in this case the code above will remove `$pNumRows` rows from below of the table, e.g. if `$highestRow=4` and `$pNumRows=6`, than rows 4, 3, 2, 1, 0, -1 will be deleted. Obviously, this is not good, that is why I've added `$removedRowsCounter` to fix this issue.
And finally, moved Exception to early if statement to get away from unnecessary 'if-else'.

Fixes #1364
Closes #1365
2020-04-26 11:00:43 +09:00
Matthijs Alles
87f71e1930 Support whitespaces in CSS style in Xlsx
Indentation in the xml leaves spaces in style string even after
replacing newlines. Replacing the spaces ensures no spaces in keys
of the resulting style-array

Fixes #1347
2020-04-05 19:50:57 +09:00
Adrien Crivelli
57c36e01d5
Replace Sami with phpDocumentor 3
Because Sami is deprecated and now raise errors. We lose API
docs for multiple versions but we still have latest version with low
maintenance cost.
2020-04-05 17:47:25 +09:00
youkan
a79b344d53
Fix ROUNDUP and ROUNDDOWN for floating-point rounding error (#1404)
Closes #1404
2020-03-07 12:48:54 +07:00
Paul Kievits
a08415a7b5 Improved the ARABIC function to handle short-form roman numerals 2020-03-07 12:43:59 +07:00