diff --git a/src/Model.php b/src/Model.php index 8d410fd..b48b54c 100644 --- a/src/Model.php +++ b/src/Model.php @@ -7,7 +7,7 @@ * @category Library * @package Barcode * @author Nicola Asuni - * @copyright 2015-2023 Nicola Asuni - Tecnick.com LTD + * @copyright 2015-2024 Nicola Asuni - Tecnick.com LTD * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) * @link https://github.com/tecnickcom/tc-lib-barcode * @@ -29,7 +29,7 @@ * @category Library * @package Barcode * @author Nicola Asuni - * @copyright 2015-2023 Nicola Asuni - Tecnick.com LTD + * @copyright 2015-2024 Nicola Asuni - Tecnick.com LTD * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) * @link https://github.com/tecnickcom/tc-lib-barcode */ @@ -103,8 +103,13 @@ public function getExtendedCode(): string; /** * Get the barcode as SVG image object + * + * @param string|null $filename The file name without extension (optional). + * Only allows alphanumeric characters, underscores and hyphens. + * Defaults to a md5 hash of the data. + * The file extension is always '.svg'. */ - public function getSvg(): void; + public function getSvg(?string $filename = null): void; /** * Get the barcode as SVG code @@ -122,8 +127,13 @@ public function getHtmlDiv(): string; /** * Get Barcode as PNG Image (requires GD or Imagick library) + * + * @param string|null $filename The file name without extension (optional). + * Only allows alphanumeric characters, underscores and hyphens. + * Defaults to a md5 hash of the data. + * The file extension is always '.png'. */ - public function getPng(): void; + public function getPng(?string $filename = null): void; /** * Get the barcode as PNG image (requires GD or Imagick library) diff --git a/src/Type.php b/src/Type.php index a85c9b0..f46d06e 100644 --- a/src/Type.php +++ b/src/Type.php @@ -7,7 +7,7 @@ * @category Library * @package Barcode * @author Nicola Asuni - * @copyright 2015-2023 Nicola Asuni - Tecnick.com LTD + * @copyright 2015-2024 Nicola Asuni - Tecnick.com LTD * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) * @link https://github.com/tecnickcom/tc-lib-barcode * @@ -30,7 +30,7 @@ * @category Library * @package Barcode * @author Nicola Asuni - * @copyright 2015-2023 Nicola Asuni - Tecnick.com LTD + * @copyright 2015-2024 Nicola Asuni - Tecnick.com LTD * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) * @link https://github.com/tecnickcom/tc-lib-barcode * @@ -269,23 +269,52 @@ public function getExtendedCode(): string } /** - * Get the barcode as SVG image object + * Sends the data as file to the browser. + * + * @param string $data The file data. + * @param string $mime The file MIME type (i.e. 'application/svg+xml' or 'image/png'). + * @param string $fileext The file extension (i.e. 'svg' or 'png'). + * @param string|null $filename The file name without extension (optional). + * Only allows alphanumeric characters, underscores and hyphens. + * Defaults to a md5 hash of the data. + * + * @return void */ - public function getSvg(): void - { - $svgCode = $this->getSvgCode(); - header('Content-Type: application/svg+xml'); + protected function getHTTPFile( + string $data, + string $mime, + string $fileext, + ?string $filename = null, + ): void { + if (is_null($filename) || (preg_match('/^[a-zA-Z0-9_\-]{1,250}$/', $filename) !== 1)) { + $filename = md5($data); + } + + header('Content-Type: ' . $mime); header('Cache-Control: private, must-revalidate, post-check=0, pre-check=0, max-age=1'); header('Pragma: public'); header('Expires: Thu, 04 jan 1973 00:00:00 GMT'); // Date in the past header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); - header('Content-Disposition: inline; filename="' . md5($svgCode) . '.svg";'); + header('Content-Disposition: inline; filename="' . $filename . '.' . $fileext . '";'); if (empty($_SERVER['HTTP_ACCEPT_ENCODING'])) { // the content length may vary if the server is using compression - header('Content-Length: ' . strlen($svgCode)); + header('Content-Length: ' . strlen($data)); } - echo $svgCode; + echo $data; + } + + /** + * Get the barcode as SVG image object + * + * @param string|null $filename The file name without extension (optional). + * Only allows alphanumeric characters, underscores and hyphens. + * Defaults to a md5 hash of the data. + * The file extension is always '.svg'. + */ + public function getSvg(?string $filename = null): void + { + $this->getHTTPFile($this->getSvgCode(), 'application/svg+xml', 'svg', $filename); } /** @@ -380,22 +409,15 @@ public function getHtmlDiv(): string /** * Get Barcode as PNG Image (requires GD or Imagick library) + * + * @param string|null $filename The file name without extension (optional). + * Only allows alphanumeric characters, underscores and hyphens. + * Defaults to a md5 hash of the data. + * The file extension is always '.png'. */ - public function getPng(): void + public function getPng(?string $filename = null): void { - $pngData = $this->getPngData(); - header('Content-Type: image/png'); - header('Cache-Control: private, must-revalidate, post-check=0, pre-check=0, max-age=1'); - header('Pragma: public'); - header('Expires: Thu, 04 jan 1973 00:00:00 GMT'); // Date in the past - header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); - header('Content-Disposition: inline; filename="' . md5($pngData) . '.png";'); - if (empty($_SERVER['HTTP_ACCEPT_ENCODING'])) { - // the content length may vary if the server is using compression - header('Content-Length: ' . strlen($pngData)); - } - - echo $pngData; + $this->getHTTPFile($this->getPngData(), 'image/png', 'png', $filename); } /** diff --git a/test/BarcodeTest.php b/test/BarcodeTest.php index 8ad4e84..6827bda 100644 --- a/test/BarcodeTest.php +++ b/test/BarcodeTest.php @@ -7,7 +7,7 @@ * @category Library * @package Barcode * @author Nicola Asuni - * @copyright 2015-2023 Nicola Asuni - Tecnick.com LTD + * @copyright 2015-2024 Nicola Asuni - Tecnick.com LTD * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) * @link https://github.com/tecnickcom/tc-lib-barcode * @@ -23,7 +23,7 @@ * @category Library * @package Barcode * @author Nicola Asuni - * @copyright 2015-2023 Nicola Asuni - Tecnick.com LTD + * @copyright 2015-2024 Nicola Asuni - Tecnick.com LTD * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) * @link https://github.com/tecnickcom/tc-lib-barcode */ @@ -300,11 +300,33 @@ public function testGetSvg(): void -2, 'purple' ); + + // empty filename ob_start(); $type->getSvg(); $svg = ob_get_clean(); $this->assertNotFalse($svg); $this->assertEquals('86e0362768e8b1b26032381232c0367f', md5($svg)); + $headers = xdebug_get_headers(); + $this->assertEquals('Content-Disposition: inline; filename="86e0362768e8b1b26032381232c0367f.svg";', $headers[5]); + + // invalid filename + ob_start(); + $type->getSvg('#~'); + $svg = ob_get_clean(); + $this->assertNotFalse($svg); + $this->assertEquals('86e0362768e8b1b26032381232c0367f', md5($svg)); + $headers = xdebug_get_headers(); + $this->assertEquals('Content-Disposition: inline; filename="86e0362768e8b1b26032381232c0367f.svg";', $headers[5]); + + // valid filename + ob_start(); + $type->getSvg('test_SVG_filename-001'); + $svg = ob_get_clean(); + $this->assertNotFalse($svg); + $this->assertEquals('86e0362768e8b1b26032381232c0367f', md5($svg)); + $headers = xdebug_get_headers(); + $this->assertEquals('Content-Disposition: inline; filename="test_SVG_filename-001.svg";', $headers[5]); } public function testGetPng(): void @@ -317,10 +339,32 @@ public function testGetPng(): void -2, 'purple' ); + + // empty filename ob_start(); $type->getPng(); $png = ob_get_clean(); $this->assertNotFalse($png); $this->assertEquals('PNG', substr($png, 1, 3)); + $headers = xdebug_get_headers(); + $this->assertEquals('Content-Disposition: inline; filename="474e4eb4cfd145be38fe1657909b21b2.png";', $headers[5]); + + // invalid filename + ob_start(); + $type->getPng('#~'); + $png = ob_get_clean(); + $this->assertNotFalse($png); + $this->assertEquals('PNG', substr($png, 1, 3)); + $headers = xdebug_get_headers(); + $this->assertEquals('Content-Disposition: inline; filename="474e4eb4cfd145be38fe1657909b21b2.png";', $headers[5]); + + // valid filename + ob_start(); + $type->getPng('test_PNG_filename-001'); + $png = ob_get_clean(); + $this->assertNotFalse($png); + $this->assertEquals('PNG', substr($png, 1, 3)); + $headers = xdebug_get_headers(); + $this->assertEquals('Content-Disposition: inline; filename="test_PNG_filename-001.png";', $headers[5]); } }