Skip to content

Run on PHP 8.1+ by moving off the pre-PHP-8 dependencies - #23

Merged
tahiralmas merged 4 commits into
ictcorefrom
php83
Oct 9, 2026
Merged

tahiralmas merged 4 commits into
ictcorefrom
php83

Conversation

@tahiralmas

Copy link
Copy Markdown
Member

Why

Every direct dependency was capped below PHP 8, so ICTCore could not be installed on a supported PHP at all. The versions it pinned also carry published security advisories, which composer 2.9+ refuses to resolve without policy.advisories.block=false. Both problems have the same fix.

What moved

was now
swiftmailer 5.4 (end of life) symfony/mailer 6.4
twig 1.35 twig 3
firebase/php-jwt (CVE-2025-45769 affects < 7.0) 7.x
dompdf 0.8 dompdf 3.x
aza/thread (no PHP 8 release, unmaintained) pcntl directly

Dropped as unreferenced: ProcessManager, office-converter, nategood/httpful.

The parts that were not import swaps

  • Forgot_password — symfony's send() returns void and throws on failure, where Swift returned a recipient count. The existing truthiness check would have reported every successful send as a failure.
  • Token — Twig 3 moved setEscaper onto EscaperExtension, but still passes the Environment as the callable's first argument, so the json escaper keeps three parameters and its byte-for-byte output.
  • CoreThread — forks with pcntl_fork, reaps with SIGCHLD set to SIG_IGN, and runs inline when pcntl is unavailable or the SAPI is not cli.

Also fixed: a duplicate FAILED_STATUS constant in Transmission that was a hard syntax error on 8.x, and a SignatureInvalidException caught in Forgot_password without ever being imported, which would have fataled on any invalid token.

Verified on PHP 8.3

151 files lint clean; all migrated classes load; twig escaper output unchanged; JWT round trips under HS256 and RS256 with expiry enforced; symfony/mime accepts the bracketed-IP addresses validate_email() produces; CoreThread forks three children into distinct pids leaving no zombies; composer audit reports no advisories across the resulting 24 packages.

Built and run end to end in the ICTFax container on the Remi 8.3 stream: dashboard serves, FreeSWITCH profile registers, and an SMTP message delivered through SendmailTransport lands in the ictcore mailbox.

Before merging

ictcore.spec requires php unversioned, so an RPM build picks up whatever module stream the host has enabled. Raising the floor to 8.1 means ICTPBX and ICTDialer builds need php:remi-8.3 enabled too. That coordination is why this is a branch rather than a direct push.

Every direct dependency here was capped below PHP 8, so the whole library was
pinned to 7.4 and could not be installed on a supported PHP at all. The four
that mattered are replaced rather than suppressed, because the old versions
also carry published security advisories that composer now refuses to resolve:

  swiftmailer 5.4  -> symfony/mailer 6.4   (swiftmailer is end of life)
  twig 1.35        -> twig 3
  firebase/php-jwt -> 7.x                  (CVE-2025-45769 affects < 7.0)
  dompdf 0.8       -> dompdf 3.x

Two call sites needed real changes rather than an import swap. symfony's
send() returns void and signals failure by throwing, where Swift returned a
recipient count, so Forgot_password's truthiness check would have reported
every successful send as a failure. Twig 3 moved setEscaper off the core
extension onto EscaperExtension, though it still passes the Environment as the
callable's first argument, so Token's json escaper keeps its three parameters
and its byte for byte output.

CoreThread dropped aza/thread, which has no PHP 8 release and is unmaintained.
The used surface was small: wait(), run(), getParam() and the onFork/onShutdown
hooks. It now forks with pcntl directly, reaps with SIGCHLD set to SIG_IGN, and
falls back to running inline when pcntl is unavailable or the SAPI is not cli.

Also removed: four dependencies nothing referenced any more (ProcessManager,
office-converter, httpful and the mcrypt era leftovers), a duplicate
FAILED_STATUS constant in Transmission that was a hard syntax error on 8.x, and
a Swift import block in ForgotpasswordApi. Forgot_password caught
SignatureInvalidException without ever importing it, which would have fataled
on any invalid token; that import is now present.

The two example scripts under tests/ used nategood/httpful, which likewise has
no PHP 8 release and was needed by nothing else. They use ext-curl directly.

Verified on PHP 8.3: 151 files lint clean, all migrated classes load, twig
escaper output unchanged, JWT round trips under HS256 and RS256 with expiry
enforced, symfony/mime accepts the bracketed IP addresses validate_email()
produces, and CoreThread forks three children into distinct pids leaving no
zombies.
@tahiralmas
tahiralmas changed the base branch from master to ictcore August 14, 2026 19:25
The committed lock still pinned twig 1.35 and swiftmailer 5.4, so composer
install would have reinstated the pre-PHP-8 packages that composer.json no
longer allows.
tahiralmas pushed a commit to ictinnovations/ictfax that referenced this pull request Aug 14, 2026
**mod_sofia looked missing.** ICTCore ships sip_profiles/ictcore.xml with a
developer's LAN address hardcoded into all four IP params, with the correct
block commented out directly above them. sofia cannot bind an address the host
does not own, so the profile failed with "Error Creating SIP UA for profile:
ictcore", retried three times and was dropped, leaving "sofia status" to answer
"Command not found". The module had loaded normally the whole time. The four
params now resolve at runtime and vanilla's internal profiles, which contend
for the same 5060, are renamed out of sofia.conf.xml's glob. mod_curl and
mod_flite are uncommented to match %post freeswitch in the spec.

**No email to fax.** The sendmail, poppler-utils, enscript and libreoffice
packages behind ictcore.spec's fax and sendmail subpackages were never
installed, so nothing listened on 25 and the document conversion path had no
binaries. Note that %post writes "$ip localhost" into /etc/hosts, which is
fine on a host with a real FQDN but leaves sendmail unable to qualify itself
in a container: it then loops on "sleeping for retry" and never binds. The
entrypoint writes a qualified name instead. sendmail also runs under a wrapper
because -bD never binds on the 8.15.2 build here and -bd forks, which
supervisord cannot follow.

**PHP 7.4.** Every ICTCore dependency was capped below PHP 8, so the image had
no choice. ictinnovations/ictcore#23 replaces them, and until it lands the
patch is applied at build time against the pinned ICTCORE_REF. That removes
both workarounds this file carried: composer no longer needs its advisory
block disabled, and no longer needs --ignore-platform-reqs. It now runs
composer audit instead, which reports no advisories across the resulting 24
packages.

supervisorctl had no transport configured, so every invocation died with "ini
file does not include supervisorctl section" and an operator had no way to
restart one service inside the container. Fixed alongside.

Verified on the rebuilt image: PHP 8.3.33, the ictcore profile RUNNING on
5060 with no SIP UA errors, an SMTP transaction from outside the container
landing in the ictcore mailbox, and the dashboard serving 200. LibreOffice and
its Java dependencies take the image from 1.25GB to 2.31GB, which is the cost
of the office to fax path working at all.
User::authenticate() still used the v5 three-argument JWT::decode(),
which fatals under the v6+ API this branch moves to:

  JWT::decode(): Argument #3 ($headers) could not be passed by reference

Same change already applied to Forgot_password on this branch. That left
core/User.php as the one remaining v5 call site, so Bearer authentication
would have broken as soon as the dependency bump landed.

Reported by @Nibot1 in #25.
…s to

docker/Dockerfile still pinned the Remi module stream to 7.4, with a comment
saying to bump it once the vendor dependencies were modernised. This branch is
that modernisation, and the line was missed.

The result was that CI installed the new dependency set on PHP 7.4.
thecodingmachine/safe 3.4 requires ^8.1 and uses union types, so PHP 7.4 failed
to parse vendor/thecodingmachine/safe/lib/special_cases.php and every request
died before reaching any ICTCore code. The container built and FreeSWITCH
started, so the failure only showed as the image smoke check exiting 1 with a
log full of PHP Parse error: syntax error, unexpected '|'.

Same class of miss as core/User.php, which issue #25 caught: the dependencies
moved and one file that encodes the old floor stayed behind.
@tahiralmas
tahiralmas merged commit 165ff26 into ictcore Oct 9, 2026
1 check passed
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

Successfully merging this pull request may close these issues.

2 participants