Skip to content

Commit

Permalink
Check filename, add fallback filename (#1050)
Browse files Browse the repository at this point in the history
* Check filename, add fallback

* Fix static calls

* TWeak phpstan
  • Loading branch information
barryvdh authored May 22, 2024
1 parent 406e56a commit b60e5e3
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 18 deletions.
4 changes: 2 additions & 2 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ parameters:
level: 8
ignoreErrors:
# This is a global alias that cannot be detected by Larastan.
- '#Call to static method loadHtml\(\) on an unknown class PDF\.#'
- '#Call to static method loadHtml\(\) on an unknown class Pdf\.#'
- '#Call to static method loadHTML\(\) on an unknown class PDF\.#'
- '#Call to static method loadHTML\(\) on an unknown class Pdf\.#'
19 changes: 17 additions & 2 deletions src/PDF.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
use Illuminate\Contracts\Config\Repository as ConfigRepository;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\HeaderUtils;

/**
* A Laravel wrapper for Dompdf
Expand Down Expand Up @@ -210,9 +212,11 @@ public function save(string $filename, string $disk = null): self
public function download(string $filename = 'document.pdf'): Response
{
$output = $this->output();
$fallback = $this->fallbackName($filename);

return new Response($output, 200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'attachment; filename="' . $filename . '"',
'Content-Disposition' => HeaderUtils::makeDisposition('attachment', $filename, $fallback),
'Content-Length' => strlen($output),
]);
}
Expand All @@ -223,9 +227,12 @@ public function download(string $filename = 'document.pdf'): Response
public function stream(string $filename = 'document.pdf'): Response
{
$output = $this->output();
$fallback = $this->fallbackName($filename);


return new Response($output, 200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'inline; filename="' . $filename . '"',
'Content-Disposition' => HeaderUtils::makeDisposition('inline', $filename, $fallback),
]);
}

Expand Down Expand Up @@ -301,4 +308,12 @@ public function __call($method, $parameters)

throw new \UnexpectedValueException("Method [{$method}] does not exist on PDF instance.");
}

/**
* Make a safe fallback filename
*/
protected function fallbackName(string $filename): string
{
return str_replace('%', '', Str::ascii($filename));
}
}
52 changes: 38 additions & 14 deletions tests/PdfTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,62 +10,62 @@ class PdfTest extends TestCase
{
public function testAlias(): void
{
$pdf = \Pdf::loadHtml('<h1>Test</h1>');
$pdf = \Pdf::loadHTML('<h1>Test</h1>');
/** @var Response $response */
$response = $pdf->download('test.pdf');

$this->assertInstanceOf(Response::class, $response);
$this->assertNotEmpty($response->getContent());
$this->assertEquals('application/pdf', $response->headers->get('Content-Type'));
$this->assertEquals('attachment; filename="test.pdf"', $response->headers->get('Content-Disposition'));
$this->assertEquals('attachment; filename=test.pdf', $response->headers->get('Content-Disposition'));
}

public function testAliasCaps(): void
{
$pdf = \PDF::loadHtml('<h1>Test</h1>');
$pdf = \PDF::loadHTML('<h1>Test</h1>');
/** @var Response $response */
$response = $pdf->download('test.pdf');

$this->assertInstanceOf(Response::class, $response);
$this->assertNotEmpty($response->getContent());
$this->assertEquals('application/pdf', $response->headers->get('Content-Type'));
$this->assertEquals('attachment; filename="test.pdf"', $response->headers->get('Content-Disposition'));
$this->assertEquals('attachment; filename=test.pdf', $response->headers->get('Content-Disposition'));
}

public function testFacade(): void
{
$pdf = Facade\Pdf::loadHtml('<h1>Test</h1>');
$pdf = Facade\Pdf::loadHTML('<h1>Test</h1>');
/** @var Response $response */
$response = $pdf->download('test.pdf');

$this->assertInstanceOf(Response::class, $response);
$this->assertNotEmpty($response->getContent());
$this->assertEquals('application/pdf', $response->headers->get('Content-Type'));
$this->assertEquals('attachment; filename="test.pdf"', $response->headers->get('Content-Disposition'));
$this->assertEquals('attachment; filename=test.pdf', $response->headers->get('Content-Disposition'));
}

public function testDownload(): void
{
$pdf = Facade\Pdf::loadHtml('<h1>Test</h1>');
$pdf = Facade\Pdf::loadHTML('<h1>Test</h1>');
/** @var Response $response */
$response = $pdf->download('test.pdf');

$this->assertInstanceOf(Response::class, $response);
$this->assertNotEmpty($response->getContent());
$this->assertEquals('application/pdf', $response->headers->get('Content-Type'));
$this->assertEquals('attachment; filename="test.pdf"', $response->headers->get('Content-Disposition'));
$this->assertEquals('attachment; filename=test.pdf', $response->headers->get('Content-Disposition'));
}

public function testStream(): void
{
$pdf = Facade\Pdf::loadHtml('<h1>Test</h1>');
$pdf = Facade\Pdf::loadHTML('<h1>Test</h1>');
/** @var Response $response */
$response = $pdf->stream('test.pdf');

$this->assertInstanceOf(Response::class, $response);
$this->assertNotEmpty($response->getContent());
$this->assertEquals('application/pdf', $response->headers->get('Content-Type'));
$this->assertEquals('inline; filename="test.pdf"', $response->headers->get('Content-Disposition'));
$this->assertEquals('inline; filename=test.pdf', $response->headers->get('Content-Disposition'));
}

public function testView(): void
Expand All @@ -77,7 +77,31 @@ public function testView(): void
$this->assertInstanceOf(Response::class, $response);
$this->assertNotEmpty($response->getContent());
$this->assertEquals('application/pdf', $response->headers->get('Content-Type'));
$this->assertEquals('attachment; filename="test.pdf"', $response->headers->get('Content-Disposition'));
$this->assertEquals('attachment; filename=test.pdf', $response->headers->get('Content-Disposition'));
}

public function testQuoteFilename(): void
{
$pdf = Facade\Pdf::loadHTML('<h1>Test</h1>');
/** @var Response $response */
$response = $pdf->download('Test file.pdf');

$this->assertInstanceOf(Response::class, $response);
$this->assertNotEmpty($response->getContent());
$this->assertEquals('application/pdf', $response->headers->get('Content-Type'));
$this->assertEquals('attachment; filename="Test file.pdf"', $response->headers->get('Content-Disposition'));
}

public function testFallbackFilename(): void
{
$pdf = Facade\Pdf::loadHTML('<h1>Test</h1>');
/** @var Response $response */
$response = $pdf->download('Test%file.pdf');

$this->assertInstanceOf(Response::class, $response);
$this->assertNotEmpty($response->getContent());
$this->assertEquals('application/pdf', $response->headers->get('Content-Type'));
$this->assertEquals("attachment; filename=Testfile.pdf; filename*=utf-8''Test%25file.pdf", $response->headers->get('Content-Disposition'));
}

public function testSaveOnDisk(): void
Expand Down Expand Up @@ -130,8 +154,8 @@ public function testSave(): void

public function testMultipleInstances(): void
{
$pdf1 = Facade\Pdf::loadHtml('<h1>Test</h1>');
$pdf2 = Facade\Pdf::loadHtml('<h1>Test</h1>');
$pdf1 = Facade\Pdf::loadHTML('<h1>Test</h1>');
$pdf2 = Facade\Pdf::loadHTML('<h1>Test</h1>');

$pdf1->getDomPDF()->setBaseHost('host1');
$pdf2->getDomPDF()->setBaseHost('host2');
Expand Down

0 comments on commit b60e5e3

Please sign in to comment.