Skip to content

Commit

Permalink
Html Writer Allow mailto
Browse files Browse the repository at this point in the history
Fix PHPOffice#4316. A security patch white-listed the protocols that could be used in a hyperlink. This PR adds mailto to the list.
  • Loading branch information
oleibman committed Jan 15, 2025
1 parent fb757cf commit 6d11fd2
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 3 deletions.
9 changes: 7 additions & 2 deletions src/PhpSpreadsheet/Writer/Html.php
Original file line number Diff line number Diff line change
Expand Up @@ -1589,10 +1589,15 @@ private function generateRow(Worksheet $worksheet, array $values, int $row, stri
$urlDecode1 = html_entity_decode($url, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
$urlTrim = preg_replace('/^\\s+/u', '', $urlDecode1) ?? $urlDecode1;
$parseScheme = preg_match('/^([\\w\\s]+):/u', strtolower($urlTrim), $matches);
if ($parseScheme === 1 && !in_array($matches[1], ['http', 'https', 'file', 'ftp', 's3'], true)) {
if ($parseScheme === 1 && !in_array($matches[1], ['http', 'https', 'file', 'ftp', 'mailto', 's3'], true)) {
$cellData = htmlspecialchars($url, Settings::htmlEntityFlags());
} else {
$cellData = '<a href="' . htmlspecialchars($url, Settings::htmlEntityFlags()) . '" title="' . htmlspecialchars($worksheet->getHyperlink($coordinate)->getTooltip(), Settings::htmlEntityFlags()) . '">' . $cellData . '</a>';
$tooltip = $worksheet->getHyperlink($coordinate)->getTooltip();
$tooltipOut = empty($tooltip) ? '' : (' title="' . htmlspecialchars($tooltip) . '"');
$cellData = '<a href="'
. htmlspecialchars($url) . '"'
. $tooltipOut
. '>' . $cellData . '</a>';
}
}

Expand Down
32 changes: 32 additions & 0 deletions tests/PhpSpreadsheetTests/Writer/Html/MailtoTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Html as HtmlWriter;
use PHPUnit\Framework\TestCase;

class MailtoTest extends TestCase
{
public function testBadHyperlink(): void
{
$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();
$worksheet->setCellValue('A1', 'Mail Me!');
$worksheet->getCell('A1')
->getHyperlink()
->setUrl('mailto:[email protected]');
$worksheet->setCellValue('A2', 'Mail You!');
$worksheet->getCell('A2')
->getHyperlink()
->setTooltip('go ahead')
->setUrl('mailto:[email protected]');
$writer = new HtmlWriter($spreadsheet);
$html = $writer->generateHtmlAll();
self::assertStringContainsString('<a href="mailto:[email protected]">Mail Me!</a>', $html);
self::assertStringContainsString('<a href="mailto:[email protected]" title="go ahead">Mail You!</a>', $html);
$spreadsheet->disconnectWorksheets();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public function testNoJavascriptLinks(): void

$writer = new Html($spreadsheet);
$html = $writer->generateHTMLAll();
self::assertStringContainsString('<td class="column0 style0 s"><a href="http://www.example.com" title="">Click me</a></td>', $html, 'http hyperlink retained');
self::assertStringContainsString('<td class="column0 style0 s"><a href="http://www.example.com">Click me</a></td>', $html, 'http hyperlink retained');
self::assertStringContainsString('<td class="column0 style0 s">javascript:alert(\'hello1\')</td>', $html, 'javascript hyperlink dropped');
self::assertStringContainsString('<td class="column0 style0 f">javascript:alert(\'hello2\')</td>', $html, 'javascript hyperlink function dropped');
$spreadsheet->disconnectWorksheets();
Expand Down

0 comments on commit 6d11fd2

Please sign in to comment.