Skip to content

Commit 2d493d7

Browse files
authored
Merge commit from fork
1 parent 63ccb02 commit 2d493d7

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

src/PhpSpreadsheet/Writer/Html.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1520,7 +1520,14 @@ private function generateRow(Worksheet $worksheet, array $values, int $row, stri
15201520

15211521
// Hyperlink?
15221522
if ($worksheet->hyperlinkExists($coordinate) && !$worksheet->getHyperlink($coordinate)->isInternal()) {
1523-
$cellData = '<a href="' . htmlspecialchars($worksheet->getHyperlink($coordinate)->getUrl(), Settings::htmlEntityFlags()) . '" title="' . htmlspecialchars($worksheet->getHyperlink($coordinate)->getTooltip(), Settings::htmlEntityFlags()) . '">' . $cellData . '</a>';
1523+
$url = $worksheet->getHyperlink($coordinate)->getUrl();
1524+
$urldecode = strtolower(html_entity_decode(trim($url), encoding: 'UTF-8'));
1525+
$parseScheme = preg_match('/^(\\w+):/', $urldecode, $matches);
1526+
if ($parseScheme === 1 && !in_array($matches[1], ['http', 'https', 'file', 'ftp', 's3'], true)) {
1527+
$cellData = htmlspecialchars($url, Settings::htmlEntityFlags());
1528+
} else {
1529+
$cellData = '<a href="' . htmlspecialchars($url, Settings::htmlEntityFlags()) . '" title="' . htmlspecialchars($worksheet->getHyperlink($coordinate)->getTooltip(), Settings::htmlEntityFlags()) . '">' . $cellData . '</a>';
1530+
}
15241531
}
15251532

15261533
// Should the cell be written or is it swallowed by a rowspan or colspan?
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;
6+
7+
use PhpOffice\PhpSpreadsheet\Cell\Hyperlink;
8+
use PhpOffice\PhpSpreadsheet\Spreadsheet;
9+
use PhpOffice\PhpSpreadsheet\Writer\Html;
10+
use PHPUnit\Framework\TestCase;
11+
12+
class NoJavascriptLinksTest extends TestCase
13+
{
14+
public function testNoJavascriptLinks(): void
15+
{
16+
$spreadsheet = new Spreadsheet();
17+
$sheet = $spreadsheet->getActiveSheet();
18+
$sheet->getCell('A1')->setValue('Click me');
19+
$hyperlink = new Hyperlink('http://www.example.com');
20+
$sheet->getCell('A1')->setHyperlink($hyperlink);
21+
$sheet->getCell('A2')->setValue('JS link');
22+
$hyperlink2 = new Hyperlink('javascript:alert(\'hello1\')');
23+
$sheet->getCell('A2')->setHyperlink($hyperlink2);
24+
$sheet->getCell('A3')->setValue('=HYPERLINK("javascript:alert(\'hello2\')", "jsfunc click")');
25+
26+
$writer = new Html($spreadsheet);
27+
$html = $writer->generateHTMLAll();
28+
self::assertStringContainsString('<td class="column0 style0 s"><a href="http://www.example.com" title="">Click me</a></td>', $html, 'http hyperlink retained');
29+
self::assertStringContainsString('<td class="column0 style0 s">javascript:alert(\'hello1\')</td>', $html, 'javascript hyperlink dropped');
30+
self::assertStringContainsString('<td class="column0 style0 f">javascript:alert(\'hello2\')</td>', $html, 'javascript hyperlink function dropped');
31+
$spreadsheet->disconnectWorksheets();
32+
}
33+
}

0 commit comments

Comments
 (0)