Validate Mime Type of Image Files

This commit is contained in:
oleibman
2024-09-11 07:49:46 -07:00
parent 3e7751e363
commit 83f2d8692c
8 changed files with 114 additions and 43 deletions
+5 -3
View File
@@ -1324,7 +1324,7 @@ class Xlsx extends BaseReader
$hfImages[$shapeId]->setName((string) $imageData['title']);
}
$hfImages[$shapeId]->setPath('zip://' . File::realpath($filename) . '#' . $drawings[(string) $imageData['relid']], false);
$hfImages[$shapeId]->setPath('zip://' . File::realpath($filename) . '#' . $drawings[(string) $imageData['relid']], true, $zip);
$hfImages[$shapeId]->setResizeProportional(false);
$hfImages[$shapeId]->setWidth($style['width']);
$hfImages[$shapeId]->setHeight($style['height']);
@@ -1439,7 +1439,8 @@ class Xlsx extends BaseReader
$objDrawing->setPath(
'zip://' . File::realpath($filename) . '#'
. $images[$embedImageKey],
false
true,
$zip
);
} else {
$linkImageKey = (string) self::getArrayItem(
@@ -1536,7 +1537,8 @@ class Xlsx extends BaseReader
$objDrawing->setPath(
'zip://' . File::realpath($filename) . '#'
. $images[$embedImageKey],
false
true,
$zip
);
} else {
$linkImageKey = (string) self::getArrayItem(
+42 -29
View File
@@ -94,48 +94,61 @@ class Drawing extends BaseDrawing
*/
public function setPath(string $path, bool $verifyFile = true, ?ZipArchive $zip = null): static
{
if ($verifyFile && preg_match('~^data:image/[a-z]+;base64,~', $path) !== 1) {
// Check if a URL has been passed. https://stackoverflow.com/a/2058596/1252979
if (filter_var($path, FILTER_VALIDATE_URL)) {
if (!preg_match('/^(http|https|file|ftp|s3):/', $path)) {
throw new PhpSpreadsheetException('Invalid protocol for linked drawing');
}
$this->path = $path;
// Implicit that it is a URL, rather store info than running check above on value in other places.
$this->isUrl = true;
$imageContents = @file_get_contents($path);
if ($imageContents === false) {
$this->path = '';
} else {
$filePath = tempnam(sys_get_temp_dir(), 'Drawing');
if ($filePath) {
file_put_contents($filePath, $imageContents);
if (file_exists($filePath)) {
if (preg_match('~^data:image/[a-z]+;base64,~', $path) === 1) {
$this->path = $path;
return $this;
}
if ($verifyFile === false && !str_starts_with($path, 'zip:')) {
throw new PhpSpreadsheetException('Only zip files can set verifyFile to false');
}
$this->path = '';
// Check if a URL has been passed. https://stackoverflow.com/a/2058596/1252979
if (filter_var($path, FILTER_VALIDATE_URL)) {
if (!preg_match('/^(http|https|file|ftp|s3):/', $path)) {
throw new PhpSpreadsheetException('Invalid protocol for linked drawing');
}
// Implicit that it is a URL, rather store info than running check above on value in other places.
$this->isUrl = true;
$imageContents = @file_get_contents($path);
if ($imageContents !== false) {
$filePath = tempnam(sys_get_temp_dir(), 'Drawing');
if ($filePath) {
file_put_contents($filePath, $imageContents);
if (file_exists($filePath)) {
if ($this->isImage($filePath)) {
$this->path = $path;
$this->setSizesAndType($filePath);
unlink($filePath);
}
unlink($filePath);
}
}
} elseif (file_exists($path)) {
$this->path = $path;
$this->setSizesAndType($path);
} elseif ($zip instanceof ZipArchive) {
$zipPath = explode('#', $path)[1];
if ($zip->locateName($zipPath) !== false) {
}
} elseif ($zip instanceof ZipArchive) {
$zipPath = explode('#', $path)[1];
if ($zip->locateName($zipPath) !== false) {
if ($this->isImage($path)) {
$this->path = $path;
$this->setSizesAndType($path);
}
} else {
//throw new PhpSpreadsheetException("File $path not found!");
$this->path = '';
}
} else {
$this->path = $path;
} elseif (file_exists($path)) {
if ($this->isImage($path)) {
$this->path = $path;
$this->setSizesAndType($path);
}
}
return $this;
}
private function isImage(string $path): bool
{
return str_starts_with((string) mime_content_type($path), 'image/');
}
/**
* Get isURL.
*/
+7 -4
View File
@@ -629,7 +629,7 @@ class Html extends BaseWriter
}
$filedesc = $drawing->getDescription();
$filedesc = $filedesc ? htmlspecialchars($filedesc, ENT_QUOTES) : 'Embedded image';
if ($drawing instanceof Drawing) {
if ($drawing instanceof Drawing && $drawing->getPath() !== '') {
$filename = $drawing->getPath();
// Strip off eventual '.'
@@ -648,12 +648,15 @@ class Html extends BaseWriter
$imageData = self::winFileToUrl($filename, $this instanceof Pdf\Mpdf);
if ($this->embedImages || str_starts_with($imageData, 'zip://')) {
$imageData = 'data:,';
$picture = @file_get_contents($filename);
if ($picture !== false) {
$imageDetails = getimagesize($filename) ?: ['mime' => ''];
// base64 encode the binary data
$base64 = base64_encode($picture);
$imageData = 'data:' . $imageDetails['mime'] . ';base64,' . $base64;
if (str_starts_with($imageDetails['mime'], 'image/')) {
// base64 encode the binary data
$base64 = base64_encode($picture);
$imageData = 'data:' . $imageDetails['mime'] . ';base64,' . $base64;
}
}
}
+1 -1
View File
@@ -467,7 +467,7 @@ class Xls extends BaseWriter
private function processBaseDrawing(BstoreContainer &$bstoreContainer, BaseDrawing $drawing): void
{
if ($drawing instanceof Drawing) {
if ($drawing instanceof Drawing && $drawing->getPath() !== '') {
$this->processDrawing($bstoreContainer, $drawing);
} elseif ($drawing instanceof MemoryDrawing) {
$this->processMemoryDrawing($bstoreContainer, $drawing, $drawing->getRenderingFunction());
+9 -1
View File
@@ -455,7 +455,9 @@ class Xlsx extends BaseWriter
// Media
foreach ($this->spreadSheet->getSheet($i)->getHeaderFooter()->getImages() as $image) {
$zipContent['xl/media/' . $image->getIndexedFilename()] = file_get_contents($image->getPath());
if ($image->getPath() !== '') {
$zipContent['xl/media/' . $image->getIndexedFilename()] = file_get_contents($image->getPath());
}
}
}
@@ -471,6 +473,9 @@ class Xlsx extends BaseWriter
if ($this->getDrawingHashTable()->getByIndex($i) instanceof WorksheetDrawing) {
$imageContents = null;
$imagePath = $this->getDrawingHashTable()->getByIndex($i)->getPath();
if ($imagePath === '') {
continue;
}
if (str_contains($imagePath, 'zip://')) {
$imagePath = substr($imagePath, 6);
$imagePathSplitted = explode('#', $imagePath);
@@ -664,6 +669,9 @@ class Xlsx extends BaseWriter
{
$data = null;
$filename = $drawing->getPath();
if ($filename === '') {
return null;
}
$imageData = getimagesize($filename);
if (!empty($imageData)) {
@@ -134,7 +134,7 @@ class ContentTypes extends WriterPart
$mimeType = '';
$drawing = $this->getParentWriter()->getDrawingHashTable()->getByIndex($i);
if ($drawing instanceof WorksheetDrawing) {
if ($drawing instanceof WorksheetDrawing && $drawing->getPath() !== '') {
$extension = strtolower($drawing->getExtension());
if ($drawing->getIsUrl()) {
$mimeType = image_type_to_mime_type($drawing->getType());
@@ -149,7 +149,7 @@ class ContentTypes extends WriterPart
$mimeType = $drawing->getMimeType();
}
if (!isset($aMediaContentTypes[$extension])) {
if ($mimeType !== '' && !isset($aMediaContentTypes[$extension])) {
$aMediaContentTypes[$extension] = $mimeType;
$this->writeDefaultContentType($objWriter, $extension, $mimeType);
@@ -168,7 +168,7 @@ class ContentTypes extends WriterPart
for ($i = 0; $i < $sheetCount; ++$i) {
if (count($spreadsheet->getSheet($i)->getHeaderFooter()->getImages()) > 0) {
foreach ($spreadsheet->getSheet($i)->getHeaderFooter()->getImages() as $image) {
if (!isset($aMediaContentTypes[strtolower($image->getExtension())])) {
if ($image->getPath() !== '' && !isset($aMediaContentTypes[strtolower($image->getExtension())])) {
$aMediaContentTypes[strtolower($image->getExtension())] = $this->getImageMimeType($image->getPath());
$this->writeDefaultContentType($objWriter, strtolower($image->getExtension()), $aMediaContentTypes[strtolower($image->getExtension())]);
@@ -59,7 +59,7 @@ class ExtendForChartsAndImagesTest extends Functional\AbstractFunctional
// Add a drawing to the worksheet
$drawing = new Drawing();
$drawing->setPath('foo.png', false);
$drawing->setPath('tests/data/Writer/XLSX/blue_square.png');
$drawing->setCoordinates('A5');
$drawing->setWorksheet($sheet);
@@ -74,7 +74,7 @@ class ExtendForChartsAndImagesTest extends Functional\AbstractFunctional
// Add a drawing to the worksheet
$drawing = new Drawing();
$drawing->setPath('foo.png', false);
$drawing->setPath('tests/data/Writer/XLSX/blue_square.png');
$drawing->setCoordinates('E1');
$drawing->setWorksheet($sheet);
@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
use PhpOffice\PhpSpreadsheet\Writer\Html as HtmlWriter;
use PHPUnit\Framework\TestCase;
class ImageEmbedTest extends TestCase
{
public function testImageEmbed(): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$drawing = new Drawing();
$drawing->setName('Not an image');
$drawing->setDescription('Non-image');
$drawing->setPath(__FILE__);
$drawing->setCoordinates('A1');
$drawing->setCoordinates2('E4');
$drawing->setWorksheet($sheet);
$drawing = new Drawing();
$drawing->setName('Blue Square');
$drawing->setPath('tests/data/Writer/XLSX/blue_square.png');
$drawing->setCoordinates('A5');
$drawing->setCoordinates2('E8');
$drawing->setWorksheet($sheet);
$writer = new HtmlWriter($spreadsheet);
$writer->setEmbedImages(true);
$html = $writer->generateHTMLAll();
self::assertSame(1, substr_count($html, '<img'));
self::assertSame(1, substr_count($html, 'src="data'));
self::assertSame(1, substr_count($html, 'src="data:image/png;base64,'));
self::assertSame(0, substr_count($html, 'blue_square.png'));
//self::assertSame(1, substr_count($html, 'src="data:," alt="Non-image"'));
$spreadsheet->disconnectWorksheets();
}
}