Skip to content

Commit

Permalink
Deletion of uploaded files moved out to the kernel.terminate listener…
Browse files Browse the repository at this point in the history
…. Added tests to ensure that files have been deleted
  • Loading branch information
luzrain committed May 16, 2024
1 parent 47938c6 commit e381471
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 22 deletions.
26 changes: 26 additions & 0 deletions src/Http/DeleteUploadedFilesListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace Luzrain\PHPStreamServerBundle\Http;

use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpKernel\Event\TerminateEvent;

final class DeleteUploadedFilesListener
{
public function onKernelTerminate(TerminateEvent $event): void
{
if (!$event->isMainRequest()) {
return;
}

$files = $event->getRequest()->files->all();

\array_walk_recursive($files, static function (UploadedFile $file) {
if (\file_exists($file->getRealPath())) {
\unlink($file->getRealPath());
}
});
}
}
24 changes: 5 additions & 19 deletions src/Http/HttpRequestHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,8 @@
use Psr\Http\Message\StreamFactoryInterface;
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
use Symfony\Bridge\PsrHttpMessage\Factory\UploadedFile;
use Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface;
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\HttpKernel\TerminableInterface;

Expand Down Expand Up @@ -70,24 +67,13 @@ private function handle(ServerRequestInterface $request): ResponseInterface
/** @var WorkerProcess $worker */
$worker = $this->kernel->getContainer()->get('phpstreamserver.worker');

$worker->getEventLoop()->defer(fn() => $this->terminate($symfonyRequest, $symfonyResponse));

return $this->psrHttpFactory->createResponse($symfonyResponse);
}

private function terminate(Request $symfonyRequest, Response $symfonyResponse): void
{
if ($this->kernel instanceof TerminableInterface) {
$this->kernel->terminate($symfonyRequest, $symfonyResponse);
}

// Delete all uploaded files
$files = $symfonyRequest->files->all();
\array_walk_recursive($files, static function (UploadedFile $file) {
if (\file_exists($file->getRealPath())) {
\unlink($file->getRealPath());
$worker->getEventLoop()->defer(function () use ($symfonyRequest, $symfonyResponse): void {
if ($this->kernel instanceof TerminableInterface) {
$this->kernel->terminate($symfonyRequest, $symfonyResponse);
}
});

return $this->psrHttpFactory->createResponse($symfonyResponse);
}

private function findFileInPublicDirectory(string $requestPath): string|null
Expand Down
4 changes: 1 addition & 3 deletions src/Internal/Functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ public static function cpuCount(): int
if (\PHP_VERSION_ID >= 80300) {
return \posix_sysconf(\POSIX_SC_NPROCESSORS_ONLN);
} elseif (\DIRECTORY_SEPARATOR === '/' && \function_exists('shell_exec')) {
return \strtolower(\PHP_OS) === 'darwin'
? (int) \shell_exec('sysctl -n machdep.cpu.core_count')
: (int) \shell_exec('nproc');
return \strtolower(\PHP_OS) === 'darwin' ? (int) \shell_exec('sysctl -n machdep.cpu.core_count') : (int) \shell_exec('nproc');
} else {
return 1;
}
Expand Down
10 changes: 10 additions & 0 deletions src/config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Luzrain\PHPStreamServerBundle\ConfigLoader;
use Luzrain\PHPStreamServerBundle\Event\HttpServerStartEvent;
use Luzrain\PHPStreamServerBundle\Http\DeleteUploadedFilesListener;
use Luzrain\PHPStreamServerBundle\Http\HttpRequestHandler;
use Luzrain\PHPStreamServerBundle\Internal\WorkerConfigurator;
use Luzrain\PHPStreamServerBundle\ReloadStrategy\OnEachRequest;
Expand All @@ -15,6 +16,7 @@
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Event\TerminateEvent;

return static function (array $config, ContainerBuilder $container) {
$container
Expand Down Expand Up @@ -48,6 +50,14 @@
->setPublic(true)
;

$container
->register('phpstreamserver.delete_uploaded_files_listener', DeleteUploadedFilesListener::class)
->addTag('kernel.event_listener', [
'event' => TerminateEvent::class,
'priority' => -1024,
])
;

if ($config['reload_strategy']['on_exception']['active']) {
$container
->register('phpstreamserver.on_exception_reload_strategy', OnException::class)
Expand Down
1 change: 1 addition & 0 deletions tests/App/RequestTestController.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ private function normalizeFiles(UploadedFile &$file): void
'filename' => $file->getClientOriginalName(),
'extension' => $file->getClientOriginalExtension(),
'sha1' => \hash_file('sha1', $file->getRealPath()),
'realpath' => $file->getRealPath(),
'size' => $file->getSize(),
];
}
Expand Down
7 changes: 7 additions & 0 deletions tests/RequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ public function testMultipartRequest(): void
]),
]);

\usleep(500000);

// Assert request
$this->assertCount(2, $response['post']);
$this->assertSame('test-1-data', $response['post']['test-1']);
Expand All @@ -161,30 +163,35 @@ public function testMultipartRequest(): void
$this->assertSame('txt', $file['extension']);
$this->assertSame(75, $file['size']);
$this->assertSame('781eaba2e9a92ddf42748bd8f56a9990459ea413', $file['sha1']);
$this->assertFileDoesNotExist($file['realpath']);

$file = $response['files']['file_one'][1];
$this->assertSame('test2.txt', $file['filename']);
$this->assertSame('txt', $file['extension']);
$this->assertSame(47, $file['size']);
$this->assertSame('f69850b7b6dddf24c14581956f5b6aa3ae9cd54e', $file['sha1']);
$this->assertFileDoesNotExist($file['realpath']);

$file = $response['files']['file_three'];
$this->assertSame('test3.txt', $file['filename']);
$this->assertSame('txt', $file['extension']);
$this->assertSame(27, $file['size']);
$this->assertSame('4c129254b51981cba03e4c8aac82bb329880971a', $file['sha1']);
$this->assertFileDoesNotExist($file['realpath']);

$file = $response['files']['image'];
$this->assertSame('dot.png', $file['filename']);
$this->assertSame('png', $file['extension']);
$this->assertSame(70, $file['size']);
$this->assertSame('4a5eb7171b58e08a6881721e3b43d5a44419a2be', $file['sha1']);
$this->assertFileDoesNotExist($file['realpath']);

$file = $response['files']['big_file'];
$this->assertSame('t.bin', $file['filename']);
$this->assertSame('bin', $file['extension']);
$this->assertSame(5000000, $file['size']);
$this->assertSame('1310fa4a837135d0a5d13388a21e49474eea00ac', $file['sha1']);
$this->assertFileDoesNotExist($file['realpath']);
}

public function testRawRequest(): void
Expand Down

0 comments on commit e381471

Please sign in to comment.