Created
January 23, 2026 01:20
-
-
Save JohnRDOrazio/10728742dd22bfbeb3de90a89e6e4357 to your computer and use it in GitHub Desktop.
A bash script that downloads the latest ICU release, the shivammathur intl binaries for PHP, and automates restoring them when Plesk updates PHP and reloads PHP-FPM
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # install-latest-icu-and-php-intl.sh | |
| # Idempotent installer for latest ICU and PHP intl for Plesk | |
| set -euo pipefail | |
| # ----------------------------- | |
| # Configuration | |
| # ----------------------------- | |
| INSTALL_PREFIX="/opt" | |
| TMP_DIR="/tmp/icu-build" | |
| PHP_INTL_DIR="/usr/local/php-intl" | |
| mkdir -p "$TMP_DIR" | |
| mkdir -p "$PHP_INTL_DIR" | |
| # ----------------------------- | |
| # Detect latest ICU release from GitHub | |
| # ----------------------------- | |
| echo "[INFO] Fetching latest ICU release info from GitHub..." | |
| LATEST_TAG=$(curl -s https://api.github.com/repos/unicode-org/icu/releases/latest \ | |
| | grep -Po '"tag_name": "\K.*?(?=")') | |
| if [ -z "$LATEST_TAG" ]; then | |
| echo "[ERROR] Could not fetch latest ICU release." | |
| exit 1 | |
| fi | |
| ICU_VERSION="${LATEST_TAG#release-}" | |
| ICU_DIR="$INSTALL_PREFIX/icu-$ICU_VERSION" | |
| echo "[INFO] Latest ICU release: $ICU_VERSION" | |
| # ----------------------------- | |
| # Install ICU if not already present | |
| # ----------------------------- | |
| if [ -d "$ICU_DIR" ] && [ -x "$ICU_DIR/bin/icu-config" ]; then | |
| echo "[INFO] ICU $ICU_VERSION already installed at $ICU_DIR. Skipping build." | |
| else | |
| echo "[INFO] Installing ICU $ICU_VERSION..." | |
| cd "$TMP_DIR" | |
| SRC_TGZ="icu4c-${ICU_VERSION}-sources.tgz" | |
| DOWNLOAD_URL="https://github.com/unicode-org/icu/releases/download/$LATEST_TAG/$SRC_TGZ" | |
| wget -q --show-progress "$DOWNLOAD_URL" -O "$TMP_DIR/$SRC_TGZ" | |
| tar -xvf "$SRC_TGZ" | |
| cd icu/source | |
| ./configure --prefix="$ICU_DIR" | |
| make -j"$(nproc)" | |
| make -j"$(nproc)" check || echo "[WARN] ICU tests failed" | |
| sudo make install | |
| echo "[INFO] ICU installation complete: $($ICU_DIR/bin/icu-config --version)" | |
| # Make libraries visible system-wide | |
| CONF_FILE="/etc/ld.so.conf.d/icu-$ICU_VERSION.conf" | |
| if [ ! -f "$CONF_FILE" ]; then | |
| echo "$ICU_DIR/lib" | sudo tee "$CONF_FILE" >/dev/null | |
| sudo ldconfig | |
| echo "[INFO] Registered $ICU_DIR/lib via ldconfig" | |
| else | |
| echo "[INFO] ld.so.conf for ICU already exists: $CONF_FILE" | |
| fi | |
| cd / | |
| rm -rf "$TMP_DIR" | |
| fi | |
| # ----------------------------- | |
| # Detect installed Plesk PHP versions | |
| # ----------------------------- | |
| PHP_VERSIONS=() | |
| for PHP_BIN in /opt/plesk/php/*/bin/php; do | |
| if [ -x "$PHP_BIN" ]; then | |
| PHP_VER=$("$PHP_BIN" -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;') | |
| PHP_VERSIONS+=("$PHP_VER") | |
| fi | |
| done | |
| if [ ${#PHP_VERSIONS[@]} -eq 0 ]; then | |
| echo "[ERROR] No Plesk PHP versions detected under /opt/plesk/php/" | |
| exit 1 | |
| fi | |
| echo "[INFO] Detected Plesk PHP versions: ${PHP_VERSIONS[*]}" | |
| # ----------------------------- | |
| # Download shivammathur PHP intl binaries | |
| # ----------------------------- | |
| for PHP in "${PHP_VERSIONS[@]}"; do | |
| TARGET_DIR="$PHP_INTL_DIR/php$PHP" | |
| mkdir -p "$TARGET_DIR" | |
| TARGET_SO="$TARGET_DIR/intl.so" | |
| BINARY_URL="https://github.com/shivammathur/icu-intl/releases/download/intl-$ICU_VERSION/php${PHP}-intl-$ICU_VERSION.so" | |
| if [ -f "$TARGET_SO" ]; then | |
| echo "[INFO] PHP $PHP intl.so already exists at $TARGET_SO. Skipping download." | |
| else | |
| echo "[INFO] Downloading PHP $PHP intl.so for ICU $ICU_VERSION..." | |
| curl -L --fail -o "$TARGET_SO" "$BINARY_URL" | |
| chmod 664 "$TARGET_SO" | |
| chown "$USER":"$USER" "$TARGET_SO" | |
| echo "[INFO] Saved $TARGET_SO" | |
| fi | |
| done | |
| # ----------------------------- | |
| # Create fix-plesk-intl.sh restore script | |
| # ----------------------------- | |
| RESTORE_SCRIPT="/usr/local/bin/fix-plesk-intl.sh" | |
| if [ ! -f "$RESTORE_SCRIPT" ]; then | |
| echo "[INFO] Creating restore script at $RESTORE_SCRIPT..." | |
| sudo tee "$RESTORE_SCRIPT" >/dev/null <<EOF | |
| #!/bin/bash | |
| # Restore ICU $ICU_VERSION intl.so for a specific Plesk PHP version | |
| PHP_VERSION="\$1" | |
| if [ -z "\$PHP_VERSION" ]; then | |
| echo "Usage: \$0 <PHP_VERSION>" | |
| exit 1 | |
| fi | |
| ICU_BIN_DIR="$PHP_INTL_DIR" | |
| MODULE_PATH="/opt/plesk/php/\$PHP_VERSION/lib/php/modules/intl.so" | |
| BACKUP="\$ICU_BIN_DIR/php\$PHP_VERSION/intl.so" | |
| if [ -f "\$BACKUP" ]; then | |
| if [ -f "\$MODULE_PATH" ]; then | |
| PLESK_SHA=\$(sha256sum "\$MODULE_PATH" | awk '{print \$1}') | |
| else | |
| PLESK_SHA="" | |
| fi | |
| BACKUP_SHA=\$(sha256sum "\$BACKUP" | awk '{print \$1}') | |
| if [ "\$PLESK_SHA" != "\$BACKUP_SHA" ]; then | |
| echo "[\$(date)] Restoring intl.so for PHP \$PHP_VERSION" | |
| [ -f "\$MODULE_PATH" ] && mv "\$MODULE_PATH" "\$MODULE_PATH.bak" | |
| cp -f "\$BACKUP" "\$MODULE_PATH" | |
| fi | |
| else | |
| echo "[\$(date)] Backup for PHP \$PHP_VERSION not found: \$BACKUP" | |
| fi | |
| EOF | |
| sudo chmod +x "$RESTORE_SCRIPT" | |
| echo "[INFO] Restore script created." | |
| else | |
| echo "[INFO] Restore script already exists at $RESTORE_SCRIPT. Skipping creation." | |
| fi | |
| # ----------------------------- | |
| # Create hook-plesk-php-intl.sh script | |
| # ----------------------------- | |
| HOOK_SCRIPT="/usr/local/bin/hook-plesk-php-intl.sh" | |
| if [ ! -f "$HOOK_SCRIPT" ]; then | |
| echo "[INFO] Creating PHP-FPM hook script at $HOOK_SCRIPT..." | |
| sudo tee "$HOOK_SCRIPT" >/dev/null <<'HOOK' | |
| #!/bin/bash | |
| # Automatically hook fix-plesk-intl.sh into all Plesk PHP-FPM services | |
| for PHP_DIR in /opt/plesk/php/*; do | |
| PHP_VERSION=$(basename "$PHP_DIR") | |
| SERVICE="plesk-php${PHP_VERSION}-fpm" | |
| if systemctl list-unit-files | grep -q "$SERVICE"; then | |
| OVERRIDE_DIR="/etc/systemd/system/$SERVICE.service.d" | |
| OVERRIDE_FILE="$OVERRIDE_DIR/override.conf" | |
| if [ ! -f "$OVERRIDE_FILE" ]; then | |
| echo "[INFO] Configuring $SERVICE to run fix-plesk-intl.sh on start..." | |
| sudo mkdir -p "$OVERRIDE_DIR" | |
| sudo tee "$OVERRIDE_FILE" >/dev/null <<OVERRIDE | |
| [Service] | |
| ExecStartPre=/usr/local/bin/fix-plesk-intl.sh $PHP_VERSION | |
| OVERRIDE | |
| else | |
| echo "[INFO] Override already exists for $SERVICE, skipping." | |
| fi | |
| fi | |
| done | |
| sudo systemctl daemon-reload | |
| HOOK | |
| sudo chmod +x "$HOOK_SCRIPT" | |
| echo "[INFO] Hook script created." | |
| else | |
| echo "[INFO] Hook script already exists at $HOOK_SCRIPT. Skipping creation." | |
| fi | |
| # ----------------------------- | |
| # Optionally hook all PHP-FPM services now | |
| # ----------------------------- | |
| read -rp "Do you want to automatically hook fix-plesk-intl.sh into all Plesk PHP-FPM services now? [y/N] " answer | |
| case "$answer" in | |
| [Yy]* ) | |
| echo "[INFO] Running hook-plesk-php-intl.sh..." | |
| sudo /usr/local/bin/hook-plesk-php-intl.sh | |
| echo "[DONE] All detected PHP-FPM services now call fix-plesk-intl.sh on start." | |
| ;; | |
| * ) | |
| echo "[INFO] Skipping automatic service hooks. You can run /usr/local/bin/hook-plesk-php-intl.sh manually later." | |
| ;; | |
| esac | |
| echo "[DONE] ICU $ICU_VERSION and PHP intl binaries are ready." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment