Skip to content

tmp file not found during file upload #811

@LinkNexus

Description

@LinkNexus

Hello,

i created an api endpoint where i upload a file and i move it to a specific directory in my project. The thing is, the temp file of the uploaded file is not created hence, php cannot obtain its information when i try to move it. Here's the part of the error:

{
    "type": "https:\/\/tools.ietf.org\/html\/rfc2616#section-10",
    "title": "An error occurred",
    "status": 500,
    "detail": "The \"\/tmp\/php6c6dw1\" file does not exist or is not readable.",
    "class": "Symfony\\Component\\Mime\\Exception\\InvalidArgumentException",
    "trace": [
        {
            "namespace": "",
            "short_class": "",
            "class": "",
            "type": "",
            "function": "",
            "file": "\/app\/vendor\/symfony\/mime\/FileinfoMimeTypeGuesser.php",
            "line": 48,
            "args": []
        },
...

I use a similar approch as the example of file upload as in the Symfony Documentation here: https://symfony.com/doc/current/controller/upload_file.html

Here is the logic of my controller:

#[Route(path: "/attachments", name: "tasks_attachments.")]
final class TasksAttachmentsController extends AbstractController
{
    public function __construct(
        private readonly EntityManagerInterface $entityManager
    )
    {
    }

    #[Route('/{task_id}', name: "add", methods: ["POST"])]
    #[IsGranted("IS_AUTHENTICATED_FULLY")]
    public function addNew(
        #[MapEntity(mapping: ["task_id" => "id"])] Task $task,
        FileUploader                                    $fileUploader,
        #[MapUploadedFile] UploadedFile                 $attachment
    ): JsonResponse
    {
        $uploadResult = $fileUploader->upload(
            $attachment,
            '/uploads/attachments'
        );

        $taskAttachment = new TaskAttachment();
        $taskAttachment->setOwner($this->getUser())
            ->setOriginalName($uploadResult["originalName"])
            ->setName($uploadResult["fileName"]);
        $task->addAttachment($taskAttachment);

        $this->entityManager->persist($taskAttachment);
        $this->entityManager->flush();

        return $this->json($attachment, 200, [], [
            'groups' => ['attachment:read']
        ]);
    }
}

The content of my FileUploader:

final readonly class FileUploader
{

    public function __construct(
        #[Autowire("%kernel.project_dir%")] private string $projectDir,
        private SluggerInterface                           $slugger
    )
    {
    }

    /**
     * Handles the uploading of a file to a specified directory.
     *
     * @param UploadedFile $file The file to upload.
     * @param string $directory The directory where the file should be uploaded.
     *
     * @return array<"originalName"|"fileName", string> An associative array containing the original name of the file and the new file name.
     *
     */
    public function upload(UploadedFile $file, string $directory): array
    {
        $originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
        $safeFilename = $this->slugger->slug($originalFilename);
        $fileName = $safeFilename . '-' . uniqid() . '.' . $file->guessExtension();

        $file->move($this->projectDir . $directory, $fileName);

        return [
            "originalName" => $originalFilename,
            "fileName" => $fileName,
        ];
    }

}

I thought it is maybe a problem of permissions, in my containr while it was running, i set the ownership of the content of the tmp folder to that of the www-data user using these commands:

chown -R www-data:www-data /tmp

chmod -R u+rwX /tmp

The ownership changed, but i encounter the exact same error when i tried a file upload again. I did not mount the tmp directory on my host machine. The compose.yaml file content is basically the same as that of this repository.

Here is my Dockerfile content:

#syntax=docker/dockerfile:1

# Versions
FROM dunglas/frankenphp:1-php8.3 AS frankenphp_upstream

# The different stages of this Dockerfile are meant to be built into separate images
# https://docs.docker.com/develop/develop-images/multistage-build/#stop-at-a-specific-build-stage
# https://docs.docker.com/compose/compose-file/#target


# Base FrankenPHP image
FROM frankenphp_upstream AS frankenphp_base

WORKDIR /app

VOLUME /app/var/

# persistent / runtime deps
# hadolint ignore=DL3008
RUN apt-get update && apt-get install -y --no-install-recommends \
	acl \
	file \
	gettext \
	git \
	&& rm -rf /var/lib/apt/lists/*

RUN set -eux; \
	install-php-extensions \
	@composer \
	apcu \
	intl \
	opcache \
	zip \
	xsl \
	;

# https://getcomposer.org/doc/03-cli.md#composer-allow-superuser
ENV COMPOSER_ALLOW_SUPERUSER=1

# Transport to use by Mercure (default to Bolt)
ENV MERCURE_TRANSPORT_URL=bolt:///data/mercure.db

ENV PHP_INI_SCAN_DIR=":$PHP_INI_DIR/app.conf.d"

###> recipes ###
###> doctrine/doctrine-bundle ###
RUN install-php-extensions pdo_pgsql
###< doctrine/doctrine-bundle ###
###< recipes ###

COPY --link frankenphp/conf.d/10-app.ini $PHP_INI_DIR/app.conf.d/
COPY --link --chmod=755 frankenphp/docker-entrypoint.sh /usr/local/bin/docker-entrypoint
COPY --link frankenphp/Caddyfile /etc/caddy/Caddyfile

ENTRYPOINT ["docker-entrypoint"]

HEALTHCHECK --start-period=60s CMD curl -f http://localhost:2019/metrics || exit 1
CMD [ "frankenphp", "run", "--config", "/etc/caddy/Caddyfile" ]

# Dev FrankenPHP image
FROM frankenphp_base AS frankenphp_dev

ENV APP_ENV=dev
ENV XDEBUG_MODE=off
ENV FRANKENPHP_WORKER_CONFIG=watch

RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"

RUN set -eux; \
	install-php-extensions \
	xdebug \
	;

COPY --link frankenphp/conf.d/20-app.dev.ini $PHP_INI_DIR/app.conf.d/

CMD [ "frankenphp", "run", "--config", "/etc/caddy/Caddyfile", "--watch" ]

# Prod FrankenPHP image
FROM frankenphp_base AS frankenphp_prod

ENV APP_ENV=prod

RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"

COPY --link frankenphp/conf.d/20-app.prod.ini $PHP_INI_DIR/app.conf.d/

# prevent the reinstallation of vendors at every changes in the source code
COPY --link composer.* symfony.* ./
RUN set -eux; \
	composer install --no-cache --prefer-dist --no-dev --no-autoloader --no-scripts --no-progress

# copy sources
COPY --link . ./
RUN rm -Rf frankenphp/

RUN set -eux; \
	mkdir -p var/cache var/log; \
	composer dump-autoload --classmap-authoritative --no-dev; \
	composer dump-env prod; \
	composer run-script --no-dev post-install-cmd; \
	chmod +x bin/console; sync;

Metadata

Metadata

Assignees

No one assigned

    Labels

    supportSupport requested

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions