WordPress sur OxPHP

WordPress est une application en mode traditionnel. Elle possède de nombreux points d'entrée physiques (index.php, wp-login.php, wp-cron.php, ainsi que tout le répertoire wp-admin/), chacun destiné à être atteint comme un véritable fichier. Le mode de routage traditionnel d'OxPHP, celui par défaut lorsque ENTRY_FILE n'est pas défini, les sert exactement de cette façon. Ne définissez pas ENTRY_FILE : le mode framework canaliserait chaque requête vers un unique contrôleur frontal et casserait wp-admin.

Cette recette montre aussi la seconde forme de build. Plutôt que de copier OxPHP dans une base PHP, elle étend directement l'image du runtime OxPHP, en compilant les extensions de WordPress dans un stage de build et en y déposant les fichiers .so.

Vue d'ensemble de la stack

  • Image OxPHP : ghcr.io/oxphp/oxphp:0.10.0 (PHP 8.5), étendue sur place
  • Mode de routage : Traditionnel (pas de ENTRY_FILE)
  • Extensions ajoutées : mysqli, pdo_mysql, gd, zip, intl, exif, bcmath
  • Services : OxPHP + MySQL + un conteneur annexe WP-CLI (profil cli)
  • Durcissement : PHP_DENY_PATHS bloque l'exécution directe de fichiers .php sous wp-content/uploads/
  • URL : http://localhost:8090 · interne http://localhost:9091/health

Organisation du projet

text
wp-oxphp/ ├── Dockerfile ├── docker-compose.yml └── wordpress/ # the WordPress tree (download from wordpress.org) └── wp-config.php # reads WORDPRESS_* environment variables

wordpress/wp-config.php lit ses paramètres depuis l'environnement du conteneur :

wp-config.php
define( 'DB_NAME', getenv( 'WORDPRESS_DB_NAME' ) ?: 'wordpress' ); define( 'DB_USER', getenv( 'WORDPRESS_DB_USER' ) ?: 'wordpress' ); define( 'DB_PASSWORD', getenv( 'WORDPRESS_DB_PASSWORD' ) ?: 'wordpress' ); define( 'DB_HOST', getenv( 'WORDPRESS_DB_HOST' ) ?: 'db:3306' ); $__site_url = getenv( 'WORDPRESS_SITE_URL' ) ?: 'http://localhost:8090'; define( 'WP_HOME', $__site_url ); define( 'WP_SITEURL', $__site_url );

Dockerfile et Compose

Ce Dockerfile compile les extensions contre un php:8.5-zts-alpine correspondant (même ABI que l'image OxPHP, no-debug-zts-20250925) et copie les fichiers .so dans le runtime OxPHP :

Dockerfile
# ── Stage 1: compile WordPress PHP extensions against PHP 8.5 ───── FROM php:8.5-zts-alpine3.23 AS ext-builder RUN apk add --no-cache \ icu-dev libzip-dev libpng-dev libjpeg-turbo-dev freetype-dev oniguruma-dev \ && docker-php-ext-configure gd --with-jpeg --with-freetype \ && docker-php-ext-install -j"$(nproc)" \ mysqli pdo_mysql gd zip intl exif bcmath RUN EXT_DIR=$(php -r 'echo ini_get("extension_dir");') && mkdir -p /ext-out \ && cp "$EXT_DIR"/mysqli.so "$EXT_DIR"/pdo_mysql.so "$EXT_DIR"/gd.so \ "$EXT_DIR"/zip.so "$EXT_DIR"/intl.so "$EXT_DIR"/exif.so \ "$EXT_DIR"/bcmath.so /ext-out/ # ── Stage 2: OxPHP runtime with WordPress extensions ───────────── FROM ghcr.io/oxphp/oxphp:0.10.0 AS runtime USER root RUN apk add --no-cache icu-libs libzip libpng libjpeg-turbo freetype oniguruma # Drop the compiled extensions into OxPHP's PHP 8.5 extension dir COPY --from=ext-builder /ext-out/*.so \ /usr/local/lib/php/extensions/no-debug-zts-20250925/ RUN { \ echo "extension=mysqli.so"; echo "extension=pdo_mysql.so"; \ echo "extension=gd.so"; echo "extension=zip.so"; \ echo "extension=intl.so"; echo "extension=exif.so"; \ echo "extension=bcmath.so"; \ } > /usr/local/etc/php/conf.d/wordpress-extensions.ini RUN { \ echo "upload_max_filesize=64M"; echo "post_max_size=64M"; \ echo "memory_limit=256M"; echo "max_execution_time=300"; \ echo "max_input_vars=3000"; \ } > /usr/local/etc/php/conf.d/wordpress.ini EXPOSE 80
Note

Le répertoire d'extensions (no-debug-zts-20250925) est le tag ABI PHP 8.5 ZTS. Si vous construisez sur l'image OxPHP PHP 8.4, il devient no-debug-zts-20240924. Déduisez-le au moment du build avec php -r 'echo ini_get("extension_dir");' plutôt que de le coder en dur.

Installation et premier démarrage

bash
docker compose up -d --build docker compose run --rm wpcli wp core install \ --url=http://localhost:8090 --title="OxPHP WordPress" \ --admin_user=admin --admin_password=admin [email protected]

Notes OxPHP

Note
  • Le mode traditionnel est obligatoire. WordPress a besoin que wp-admin/, wp-login.php, wp-cron.php, etc. s'exécutent en tant que fichiers physiques. Laissez ENTRY_FILE non défini.
  • L'image du runtime OxPHP ne fournit aucun binaire wp (c'est une image de service minimale). Le travail en CLI passe par le conteneur annexe wpcli sous le profil Compose cli, qui partage le même volume wordpress/ et la même base de données.
  • wp-config.php lit l'environnement du conteneur via getenv(), si bien que les identifiants de la base de données et l'URL du site vivent dans Compose, et non codés en dur dans le fichier.
  • PHP_DENY_PATHS durcit les répertoires d'upload. Parce que le mode traditionnel exécute des fichiers .php physiques, un shell téléversé dans wp-content/uploads/ par un plugin vulnérable s'exécuterait sinon. PHP_DENY_PATHS bloque l'exécution de .php sous ces chemins, en confrontant l'URI avant toute E/S disque, de sorte qu'il n'y a aucun oracle d'existence. Il ne s'applique qu'en modes traditionnel et SPA ; en mode framework, c'est un no-op (le contrôleur frontal empêche déjà l'exécution directe de .php), ce qui explique pourquoi les recettes en mode framework présentées ici n'en ont pas besoin. Voir Liste de refus d'exécution PHP.

Vérification

bash
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8090/ # 200 curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8090/wp-login.php # 200 (physical file) curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8090/wp-content/uploads/x.php # 404 (PHP_DENY_PATHS) curl -s -o /dev/null -w "%{http_code}\n" http://localhost:9091/health # 200

Voir aussi