Skip to content

Commit 6d11fd2

Browse files
committed
Html Writer Allow mailto
Fix #4316. A security patch white-listed the protocols that could be used in a hyperlink. This PR adds mailto to the list.
1 parent fb757cf commit 6d11fd2

File tree

3 files changed

+40
-3
lines changed

3 files changed

+40
-3
lines changed

src/PhpSpreadsheet/Writer/Html.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,10 +1589,15 @@ private function generateRow(Worksheet $worksheet, array $values, int $row, stri
15891589
$urlDecode1 = html_entity_decode($url, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
15901590
$urlTrim = preg_replace('/^\\s+/u', '', $urlDecode1) ?? $urlDecode1;
15911591
$parseScheme = preg_match('/^([\\w\\s]+):/u', strtolower($urlTrim), $matches);
1592-
if ($parseScheme === 1 && !in_array($matches[1], ['http', 'https', 'file', 'ftp', 's3'], true)) {
1592+
if ($parseScheme === 1 && !in_array($matches[1], ['http', 'https', 'file', 'ftp', 'mailto', 's3'], true)) {
15931593
$cellData = htmlspecialchars($url, Settings::htmlEntityFlags());
15941594
} else {
1595-
$cellData = '<a href="' . htmlspecialchars($url, Settings::htmlEntityFlags()) . '" title="' . htmlspecialchars($worksheet->getHyperlink($coordinate)->getTooltip(), Settings::htmlEntityFlags()) . '">' . $cellData . '</a>';
1595+
$tooltip = $worksheet->getHyperlink($coordinate)->getTooltip();
1596+
$tooltipOut = empty($tooltip) ? '' : (' title="' . htmlspecialchars($tooltip) . '"');
1597+
$cellData = '<a href="'
1598+
. htmlspecialchars($url) . '"'
1599+
. $tooltipOut
1600+
. '>' . $cellData . '</a>';
15961601
}
15971602
}
15981603

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;
6+
7+
use PhpOffice\PhpSpreadsheet\Spreadsheet;
8+
use PhpOffice\PhpSpreadsheet\Writer\Html as HtmlWriter;
9+
use PHPUnit\Framework\TestCase;
10+
11+
class MailtoTest extends TestCase
12+
{
13+
public function testBadHyperlink(): void
14+
{
15+
$spreadsheet = new Spreadsheet();
16+
$worksheet = $spreadsheet->getActiveSheet();
17+
$worksheet->setCellValue('A1', 'Mail Me!');
18+
$worksheet->getCell('A1')
19+
->getHyperlink()
20+
->setUrl('mailto:[email protected]');
21+
$worksheet->setCellValue('A2', 'Mail You!');
22+
$worksheet->getCell('A2')
23+
->getHyperlink()
24+
->setTooltip('go ahead')
25+
->setUrl('mailto:[email protected]');
26+
$writer = new HtmlWriter($spreadsheet);
27+
$html = $writer->generateHtmlAll();
28+
self::assertStringContainsString('<a href="mailto:[email protected]">Mail Me!</a>', $html);
29+
self::assertStringContainsString('<a href="mailto:[email protected]" title="go ahead">Mail You!</a>', $html);
30+
$spreadsheet->disconnectWorksheets();
31+
}
32+
}

tests/PhpSpreadsheetTests/Writer/Html/NoJavascriptLinksTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public function testNoJavascriptLinks(): void
2525

2626
$writer = new Html($spreadsheet);
2727
$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');
28+
self::assertStringContainsString('<td class="column0 style0 s"><a href="http://www.example.com">Click me</a></td>', $html, 'http hyperlink retained');
2929
self::assertStringContainsString('<td class="column0 style0 s">javascript:alert(\'hello1\')</td>', $html, 'javascript hyperlink dropped');
3030
self::assertStringContainsString('<td class="column0 style0 f">javascript:alert(\'hello2\')</td>', $html, 'javascript hyperlink function dropped');
3131
$spreadsheet->disconnectWorksheets();

0 commit comments

Comments
 (0)