Skip to content

Commit

Permalink
Merge branch 'master' into issue4269
Browse files Browse the repository at this point in the history
  • Loading branch information
oleibman authored Dec 23, 2024
2 parents c744f57 + 08e2260 commit 22c4956
Show file tree
Hide file tree
Showing 16 changed files with 242 additions and 84 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ and this project adheres to [Semantic Versioning](https://semver.org).

### Deprecated

- Nothing yet.
- Drawing::setIsUrl is unneeded. The property is set when setPath determines whether path is a url.

### Fixed

- Add forceFullCalc option to Xlsx Writer. [Issue #4269](https://github.com/PHPOffice/PhpSpreadsheet/issues/4269) [PR #4271](https://github.com/PHPOffice/PhpSpreadsheet/pull/4271)
- 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)
- 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)

## 2024-12-08 - 3.6.0

Expand Down
5 changes: 5 additions & 0 deletions src/PhpSpreadsheet/Collection/Memory/SimpleCache1.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
*
* Alternative implementation should leverage off-memory, non-volatile storage
* to reduce overall memory usage.
*
* Either SimpleCache1 or SimpleCache3, but not both, may be used.
* For code coverage testing, it will always be SimpleCache3.
*
* @codeCoverageIgnore
*/
class SimpleCache1 implements CacheInterface
{
Expand Down
19 changes: 17 additions & 2 deletions src/PhpSpreadsheet/Worksheet/Drawing.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,21 @@ public function setPath(string $path, bool $verifyFile = true, ?ZipArchive $zip
$this->isUrl = true;
$ctx = null;
// https://github.com/php/php-src/issues/16023
if (str_starts_with($path, 'https:')) {
$ctx = stream_context_create(['ssl' => ['crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT]]);
// https://github.com/php/php-src/issues/17121
if (str_starts_with($path, 'https:') || str_starts_with($path, 'http:')) {
$ctxArray = [
'http' => [
'user_agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
'header' => [
//'Connection: keep-alive', // unacceptable performance
'Accept: image/*;q=0.9,*/*;q=0.8',
],
],
];
if (str_starts_with($path, 'https:')) {
$ctxArray['ssl'] = ['crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT];
}
$ctx = stream_context_create($ctxArray);
}
$imageContents = @file_get_contents($path, false, $ctx);
if ($imageContents !== false) {
Expand Down Expand Up @@ -183,6 +196,8 @@ public function getIsURL(): bool
* Set isURL.
*
* @return $this
*
* @deprecated 3.7.0 not needed, property is set by setPath
*/
public function setIsURL(bool $isUrl): self
{
Expand Down
21 changes: 16 additions & 5 deletions src/PhpSpreadsheet/Writer/Ods/Cell/Style.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class Style
public const COLUMN_STYLE_PREFIX = 'co';
public const ROW_STYLE_PREFIX = 'ro';
public const TABLE_STYLE_PREFIX = 'ta';
public const INDENT_TO_INCHES = 0.1043; // undocumented, used trial and error

private XMLWriter $writer;

Expand All @@ -28,12 +29,13 @@ public function __construct(XMLWriter $writer)
$this->writer = $writer;
}

private function mapHorizontalAlignment(string $horizontalAlignment): string
private function mapHorizontalAlignment(?string $horizontalAlignment): string
{
return match ($horizontalAlignment) {
Alignment::HORIZONTAL_CENTER, Alignment::HORIZONTAL_CENTER_CONTINUOUS, Alignment::HORIZONTAL_DISTRIBUTED => 'center',
Alignment::HORIZONTAL_RIGHT => 'end',
Alignment::HORIZONTAL_FILL, Alignment::HORIZONTAL_JUSTIFY => 'justify',
Alignment::HORIZONTAL_GENERAL, '', null => '',
default => 'start',
};
}
Expand Down Expand Up @@ -145,8 +147,10 @@ private function writeCellProperties(CellStyle $style): void
{
// Align
$hAlign = $style->getAlignment()->getHorizontal();
$hAlign = $this->mapHorizontalAlignment($hAlign);
$vAlign = $style->getAlignment()->getVertical();
$wrap = $style->getAlignment()->getWrapText();
$indent = $style->getAlignment()->getIndent();

$this->writer->startElement('style:table-cell-properties');
if (!empty($vAlign) || $wrap) {
Expand All @@ -168,10 +172,16 @@ private function writeCellProperties(CellStyle $style): void

$this->writer->endElement();

if (!empty($hAlign)) {
$hAlign = $this->mapHorizontalAlignment($hAlign);
$this->writer->startElement('style:paragraph-properties');
$this->writer->writeAttribute('fo:text-align', $hAlign);
if ($hAlign !== '' || !empty($indent)) {
$this->writer
->startElement('style:paragraph-properties');
if ($hAlign !== '') {
$this->writer->writeAttribute('fo:text-align', $hAlign);
}
if (!empty($indent)) {
$indentString = sprintf('%.4f', $indent * self::INDENT_TO_INCHES) . 'in';
$this->writer->writeAttribute('fo:margin-left', $indentString);
}
$this->writer->endElement();
}
}
Expand Down Expand Up @@ -289,6 +299,7 @@ public function writeTableStyle(Worksheet $worksheet, int $sheetId): void
'style:name',
sprintf('%s%d', self::TABLE_STYLE_PREFIX, $sheetId)
);
$this->writer->writeAttribute('style:master-page-name', 'Default');

$this->writer->startElement('style:table-properties');

Expand Down
59 changes: 21 additions & 38 deletions src/PhpSpreadsheet/Writer/Ods/Content.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@
*/
class Content extends WriterPart
{
const NUMBER_COLS_REPEATED_MAX = 1024;
const NUMBER_ROWS_REPEATED_MAX = 1048576;

private Formula $formulaConvertor;

/**
Expand Down Expand Up @@ -142,7 +139,6 @@ private function writeSheets(XMLWriter $objWriter): void
sprintf('%s_%d_%d', Style::COLUMN_STYLE_PREFIX, $sheetIndex, $columnDimension->getColumnNumeric())
);
$objWriter->writeAttribute('table:default-cell-style-name', 'ce0');
// $objWriter->writeAttribute('table:number-columns-repeated', self::NUMBER_COLS_REPEATED_MAX);
$objWriter->endElement();
}
$this->writeRows($objWriter, $spreadsheet->getSheet($sheetIndex), $sheetIndex);
Expand All @@ -155,34 +151,33 @@ private function writeSheets(XMLWriter $objWriter): void
*/
private function writeRows(XMLWriter $objWriter, Worksheet $sheet, int $sheetIndex): void
{
$numberRowsRepeated = self::NUMBER_ROWS_REPEATED_MAX;
$span_row = 0;
$spanRow = 0;
$rows = $sheet->getRowIterator();
foreach ($rows as $row) {
$cellIterator = $row->getCellIterator();
--$numberRowsRepeated;
if ($cellIterator->valid()) {
$objWriter->startElement('table:table-row');
if ($span_row) {
if ($span_row > 1) {
$objWriter->writeAttribute('table:number-rows-repeated', (string) $span_row);
}
$objWriter->startElement('table:table-cell');
$objWriter->writeAttribute('table:number-columns-repeated', (string) self::NUMBER_COLS_REPEATED_MAX);
$cellIterator = $row->getCellIterator(iterateOnlyExistingCells: true);
$cellIterator->rewind();
$rowStyleExists = $sheet->rowDimensionExists($row->getRowIndex()) && $sheet->getRowDimension($row->getRowIndex())->getRowHeight() > 0;
if ($cellIterator->valid() || $rowStyleExists) {
if ($spanRow) {
$objWriter->startElement('table:table-row');
$objWriter->writeAttribute(
'table:number-rows-repeated',
(string) $spanRow
);
$objWriter->endElement();
$span_row = 0;
} else {
if ($sheet->rowDimensionExists($row->getRowIndex()) && $sheet->getRowDimension($row->getRowIndex())->getRowHeight() > 0) {
$objWriter->writeAttribute(
'table:style-name',
sprintf('%s_%d_%d', Style::ROW_STYLE_PREFIX, $sheetIndex, $row->getRowIndex())
);
}
$this->writeCells($objWriter, $cellIterator);
$spanRow = 0;
}
$objWriter->startElement('table:table-row');
if ($rowStyleExists) {
$objWriter->writeAttribute(
'table:style-name',
sprintf('%s_%d_%d', Style::ROW_STYLE_PREFIX, $sheetIndex, $row->getRowIndex())
);
}
$this->writeCells($objWriter, $cellIterator);
$objWriter->endElement();
} else {
++$span_row;
++$spanRow;
}
}
}
Expand All @@ -192,7 +187,6 @@ private function writeRows(XMLWriter $objWriter, Worksheet $sheet, int $sheetInd
*/
private function writeCells(XMLWriter $objWriter, RowCellIterator $cells): void
{
$numberColsRepeated = self::NUMBER_COLS_REPEATED_MAX;
$prevColumn = -1;
foreach ($cells as $cell) {
/** @var Cell $cell */
Expand Down Expand Up @@ -293,17 +287,6 @@ private function writeCells(XMLWriter $objWriter, RowCellIterator $cells): void
$objWriter->endElement();
$prevColumn = $column;
}

$numberColsRepeated = $numberColsRepeated - $prevColumn - 1;
if ($numberColsRepeated > 0) {
if ($numberColsRepeated > 1) {
$objWriter->startElement('table:table-cell');
$objWriter->writeAttribute('table:number-columns-repeated', (string) $numberColsRepeated);
$objWriter->endElement();
} else {
$objWriter->writeElement('table:table-cell');
}
}
}

/**
Expand Down
13 changes: 11 additions & 2 deletions src/PhpSpreadsheet/Writer/Ods/Styles.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,17 @@ public function write(): string

$objWriter->writeElement('office:font-face-decls');
$objWriter->writeElement('office:styles');
$objWriter->writeElement('office:automatic-styles');
$objWriter->writeElement('office:master-styles');
$objWriter->startElement('office:automatic-styles');
$objWriter->startElement('style:page-layout');
$objWriter->writeAttribute('style:name', 'Mpm1');
$objWriter->endElement(); // style:page-layout
$objWriter->endElement(); // office:automatic-styles
$objWriter->startElement('office:master-styles');
$objWriter->startElement('style:master-page');
$objWriter->writeAttribute('style:name', 'Default');
$objWriter->writeAttribute('style:page-layout-name', 'Mpm1');
$objWriter->endElement(); //style:master-page
$objWriter->endElement(); //office:master-styles
$objWriter->endElement();

return $objWriter->getData();
Expand Down
6 changes: 6 additions & 0 deletions src/PhpSpreadsheet/Writer/ZipStream2.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
use ZipStream\Option\Archive;
use ZipStream\ZipStream;

/**
* Either ZipStream2 or ZipStream3, but not both, may be used.
* For code coverage testing, it will always be ZipStream3.
*
* @codeCoverageIgnore
*/
class ZipStream2
{
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public static function providerXOR(): array
}

#[\PHPUnit\Framework\Attributes\DataProvider('providerXORLiteral')]
public function xtestXORLiteral(mixed $expectedResult, string $formula): void
public function testXORLiteral(mixed $expectedResult, float|string $formula): void
{
$sheet = $this->getSheet();
$sheet->getCell('A1')->setValue("=XOR($formula)");
Expand Down
4 changes: 2 additions & 2 deletions tests/PhpSpreadsheetTests/Reader/Html/HtmlImage2Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

class HtmlImage2Test extends TestCase
{
public function xtestCanInsertImageGoodProtocol(): void
public function testCanInsertImageGoodProtocol(): void
{
if (getenv('SKIP_URL_IMAGE_TEST') === '1') {
self::markTestSkipped('Skipped due to setting of environment variable');
Expand All @@ -31,7 +31,7 @@ public function xtestCanInsertImageGoodProtocol(): void
self::assertEquals('A1', $drawing->getCoordinates());
}

public function xtestCantInsertImageNotFound(): void
public function testCantInsertImageNotFound(): void
{
if (getenv('SKIP_URL_IMAGE_TEST') === '1') {
self::markTestSkipped('Skipped due to setting of environment variable');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

namespace PhpOffice\PhpSpreadsheetTests\Reader\Ods;

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;

class RepeatEmptyCellsAndRowsTest extends AbstractFunctional
{
public function testSaveAndLoadHyperlinks(): void
{
$spreadsheetOld = new Spreadsheet();
$oldSheet = $spreadsheetOld->getActiveSheet();
$oldSheet->setCellValue('C1', 'xx');
$oldSheet->setCellValue('G1', 'aa');
$oldSheet->setCellValue('BB1', 'bb');
$oldSheet->setCellValue('A6', 'aaa');
$oldSheet->setCellValue('B7', 'bbb');
$oldSheet->getRowDimension(10)->setRowHeight(12);
$oldSheet->setCellValue('A12', 'this is A12');
$style = $oldSheet->getStyle('B14:D14');
$style->getFont()->setBold(true);
$oldSheet->getCell('E15')->setValue('X');
$oldSheet->mergeCells('E15:G16');
$oldSheet->getCell('J15')->setValue('j15');
$oldSheet->getCell('J16')->setValue('j16');
$oldSheet->getCell('A19')->setValue('lastrow');
$spreadsheet = $this->writeAndReload($spreadsheetOld, 'Ods');
$spreadsheetOld->disconnectWorksheets();

$sheet = $spreadsheet->getActiveSheet();
self::assertSame('xx', $sheet->getCell('C1')->getValue());
self::assertSame('aa', $sheet->getCell('G1')->getValue());
self::assertSame('bb', $sheet->getCell('BB1')->getValue());
self::assertSame('aaa', $sheet->getCell('A6')->getValue());
self::assertSame('bbb', $sheet->getCell('B7')->getValue());
self::assertSame('this is A12', $sheet->getCell('A12')->getValue());
// Read styles, including row height, not yet implemented for ODS
self::assertSame('j15', $sheet->getCell('J15')->getValue());
self::assertSame('j16', $sheet->getCell('J16')->getValue());
self::assertSame(['E15:G16' => 'E15:G16'], $sheet->getMergeCells());
self::assertSame('lastrow', $sheet->getCell('A19')->getValue());

$spreadsheet->disconnectWorksheets();
}
}
4 changes: 2 additions & 2 deletions tests/PhpSpreadsheetTests/Reader/Xlsx/URLImageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

class URLImageTest extends TestCase
{
public function xtestURLImageSource(): void
public function testURLImageSource(): void
{
if (getenv('SKIP_URL_IMAGE_TEST') === '1') {
self::markTestSkipped('Skipped due to setting of environment variable');
Expand All @@ -37,7 +37,7 @@ public function xtestURLImageSource(): void
$spreadsheet->disconnectWorksheets();
}

public function xtestURLImageSourceNotFound(): void
public function testURLImageSourceNotFound(): void
{
if (getenv('SKIP_URL_IMAGE_TEST') === '1') {
self::markTestSkipped('Skipped due to setting of environment variable');
Expand Down
Loading

0 comments on commit 22c4956

Please sign in to comment.