Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Call to undefined function dirname() #578

Closed
tsantos84 opened this issue Feb 26, 2024 · 9 comments
Closed

Call to undefined function dirname() #578

tsantos84 opened this issue Feb 26, 2024 · 9 comments

Comments

@tsantos84
Copy link

I'm adapting an existing Symfony 7 application to use Docker + Frankenphp based on your setup. The dev environment works nicely but when I try to run the prod environment, which uses workers to handle the requests, I'm getting the strange error PHP Fatal error: Uncaught Error: Call to undefined function dirname() in /app/public/index.php. This is strange because dirname is a built-in PHP's function.

Full error:

{"level":"error","ts":1708965354.3759089,"msg":"PHP Fatal error:  Uncaught Error: Call to undefined function dirname() in /app/public/index.php:5\nStack trace:\n#0 {main}\n  thrown in /app/public/index.php on line 5","syslog_level":"err"}

Caddyfile:

{
	{$CADDY_GLOBAL_OPTIONS}

	frankenphp {
		{$FRANKENPHP_CONFIG}
	}

	# https://caddyserver.com/docs/caddyfile/directives#sorting-algorithm
	order vulcain after reverse_proxy
	order php_server before file_server
}

{$CADDY_EXTRA_CONFIG}

{$SERVER_NAME:localhost} {
	log {
		# Redact the authorization query parameter that can be set by Mercure
		format filter {
			wrap console
			fields {
				uri query {
					replace authorization REDACTED
				}
			}
		}
	}

	root * /app/public
	encode zstd br gzip

	vulcain

	{$CADDY_SERVER_EXTRA_DIRECTIVES}

	# Disable Topics tracking if not enabled explicitly: https://github.com/jkarlin/topics
	header ?Permissions-Policy "browsing-topics=()"

	php_server
}

worker.Caddyfile

worker {
	file ./public/index.php
	num 2
	env APP_RUNTIME Runtime\FrankenPhpSymfony\Runtime
}

FRANKENPHP_CONFIG

FRANKENPHP_CONFIG="import worker.Caddyfile"

Dockerfile

#syntax=docker/dockerfile:1.4

# Versions
FROM dunglas/frankenphp:1-php8.3-alpine 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

# persistent / runtime deps
# hadolint ignore=DL3018
RUN apk add --no-cache \
		acl \
		file \
		gettext \
		git \
	;

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

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

###> recipes ###
###< recipes ###

COPY --link docker/php/conf.d/app.ini $PHP_INI_DIR/conf.d/
COPY --link --chmod=755 docker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint
COPY --link docker/caddy/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 XDEBUG_MODE=off
VOLUME /app/var/

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

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

COPY --link docker/php/conf.d/app.dev.ini $PHP_INI_DIR/conf.d/

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

# Prod FrankenPHP image
FROM frankenphp_base AS frankenphp_prod

ENV APP_ENV=prod
ENV FRANKENPHP_CONFIG="import worker.Caddyfile"

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

COPY --link docker/php/conf.d/app.prod.ini $PHP_INI_DIR/conf.d/
COPY --link docker/caddy/worker.Caddyfile /etc/caddy/worker.Caddyfile

# 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 docker/

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;
@7-zete-7
Copy link

@tsantos84 hello!

Can you show content of your public/index.php file?

@tsantos84
Copy link
Author

Sure.

<?php

use App\Kernel;

require_once dirname(__DIR__).'/vendor/autoload_runtime.php';

return function (array $context) {
    return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
};

But, after debugging the problem I found that opcache is causing the error. I've just comment the opcache line on Dockerfile and the error stopped. I'm assuming that on production the absense of opcache wont impact on performance once the app is loaded in memory with Frankenphp worker mode, right?

@dunglas
Copy link
Owner

dunglas commented Feb 28, 2024

Yes, but having Opcache still has benefits (faster worker boot time etc), and that's a very weird issue. Are you able to provide a reproducer? That would be nice to report this issue to PHP.

@tsantos84
Copy link
Author

Sure, I will try to create a reproducer. Basically the same Dockerfile, it means based on dunglas/frankenphp:1-alpine, right?

@dunglas
Copy link
Owner

dunglas commented Feb 28, 2024

Anything allowing them to reproduce would likely interest them!

@dunglas
Copy link
Owner

dunglas commented Feb 28, 2024

Could you check if switching to Debian fixes the issue by the way? Moving to Debian is on the roadmap: #555

@tsantos84
Copy link
Author

tsantos84 commented Feb 28, 2024

Anything allowing them to reproduce would likely interest them!

@dunglas , I've found the issue. The problem happens when we provide a nonexistent file to opcache.preload (and that was my case).

I've managed to reproduce the issue by using this repo and make a small change on it. The step 3 is the offender.

  1. Install a fresh Symfony app following the dunglas/symfony-docker instructions and run the app on dev environment
  2. Stop the app with docker compose down
  3. Change the file frankenphp/conf.d/app.prod.ini and provide a nonexistent file to opcache.preload (eg. /foo/bar.php)
  4. Rebuild the image to prod env: docker compose -f compose.yaml -f compose.prod.yaml build --no-cache
  5. Provide JWT keys on compose.prod.yaml
  6. Run the app for production: docker compose -f compose.yaml -f compose.prod.yaml up -d

After that you will see the following log on app's container:

{"level":"error","ts":1709164144.1067986,"msg":"PHP Fatal error:  Uncaught Error: Call to undefined function dirname() in /app/public/index.php:5\nStack trace:\n#0 {main}\n  thrown in /app/public/index.php on line 5","syslog_level":"err"}

@tsantos84
Copy link
Author

Could you check if switching to Debian fixes the issue by the way? Moving to Debian is on the roadmap: #555

No, the weird behavior happens on Debian as well. I've tried to build an official PHP image, install opcache and provide a wrong filename for opcache.preload but the issue does not happen. 🫤

I don't know if the issue resides on Frankenphp + Opcache + wrong filename or just PHP + Opcache + wrong filename. In this case, I don't believe that dunglas/symfony-docker should fix the issue and this issue could be closed. I'll let you decide what to do with it, ok? (close it or keep it opened)

Let me know if I should open an issue directly on Frankenphp repository or official PHP.

@dunglas
Copy link
Owner

dunglas commented Mar 1, 2024

I think that official PHP is more appropriate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants