From 2ac6e693ba626979124fcabcbaa75512e365eb74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Przepi=C3=B3ra?= Date: Fri, 2 Oct 2026 13:46:22 +0200 Subject: [PATCH] Ship the ionCube Loader in the image MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A module can be installed into a running OpenMES through the admin panel, so the stock image has to be able to run whatever a licensed module ships. A module distributed as encoded PHP cannot run without the ionCube Loader, and without it in the image, installing one would mean first swapping the whole installation for a different image — which defeats the point of installing a module through the panel at all. The loader is inert without encoded files: it costs a couple of MB and does nothing until something asks it to run one. That is why it goes in the stock image rather than behind a build flag; a flag would split the distribution in two and push the choice onto whoever builds, long before anyone knows which modules the installation will get. Alpine means the musl build. Two things are derived rather than assumed: the architecture, because ionCube publishes no musl loader for arm64 and the step is skipped there with everything else unaffected, and the PHP ABI, because this image exposes PHP_VERSION but not its major/minor parts — hardcoding `8.3` would silently install nothing on the next base-image bump. `php -v | grep ionCube` ends the step, so a download that succeeds but produces an unusable loader fails the build instead of shipping an image that only breaks once a customer installs an encoded module. Verified against php:8.3-fpm-alpine: arch x86_64, ABI 8.3, loader v15.5.1, extension_loaded('ionCube Loader') true. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01QRWsLoNeVWdsSHve6vUmxs --- backend/Dockerfile | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/backend/Dockerfile b/backend/Dockerfile index 1e6a1014..73302e1e 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -30,6 +30,40 @@ RUN docker-php-ext-install \ pcntl \ sockets +# ionCube Loader — required to run modules distributed as encoded PHP. +# +# Inert without encoded files: the extension loads, costs a couple of MB, and +# does nothing until something actually asks it to run an encoded file. It is +# here rather than in a separate image because a module is installed into a +# running OpenMES through the admin panel, so the stock image has to be able to +# run whatever a licensed module ships — otherwise installing one would mean +# first swapping the whole installation for a different image. +# +# The base image is Alpine, so this is the musl build. ionCube publishes no +# musl loader for arm64; on that platform the step below is skipped and encoded +# modules will not run, while everything else is unaffected. +RUN set -eux; \ + arch="$(apk --print-arch)"; \ + if [ "$arch" = "x86_64" ]; then \ + curl -fsSL -o /tmp/ioncube.tar.gz \ + https://downloads.ioncube.com/loader_downloads/ioncube_loaders_lin-musl_x86-64.tar.gz; \ + tar -xzf /tmp/ioncube.tar.gz -C /tmp; \ + # The image exposes PHP_VERSION but not its major/minor parts, so the + # loader's name is derived here rather than assumed. + abi="$(php -r 'echo PHP_MAJOR_VERSION, ".", PHP_MINOR_VERSION;')"; \ + cp "/tmp/ioncube/ioncube_loader_lin-musl_${abi}.so" \ + "$(php -r 'echo ini_get("extension_dir");')/"; \ + # Loaded as a zend_extension and prefixed 00- so it comes before the + # other ini files: ionCube must be in place before anything tries to + # include an encoded file. + echo "zend_extension=ioncube_loader_lin-musl_${abi}.so" \ + > /usr/local/etc/php/conf.d/00-ioncube.ini; \ + rm -rf /tmp/ioncube /tmp/ioncube.tar.gz; \ + php -v | grep -q 'ionCube'; \ + else \ + echo "ionCube: no musl loader for $arch, skipping"; \ + fi + # PHP upload / memory limits COPY backend/docker-php-uploads.ini /usr/local/etc/php/conf.d/uploads.ini