Files
2026-07-04 16:00:04 +02:00

521 lines
16 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# =============================================================================
# recompile_php.sh
# Weryfikacja i rekompilacja wersji PHP w DirectAdmin CustomBuild
# tak, aby każda aktywna wersja miała rozszerzenia pgsql i pdo_pgsql.
# =============================================================================
set -euo pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
sekcja() { echo -e "\n${BOLD}${CYAN}=== $* ===${NC}\n"; }
die() { echo -e "${RED}[BŁĄD]${NC} $*" >&2; exit 1; }
CB_PHP_WEBSERVER=""
CB_PHP_OPTIONS_CONF=""
CB_PG_PREFIX=""
CB_PG_VERSION=""
CB_PG_CONFIG=""
DA_PG_RUNTIME_LIBDIR=""
DA_PG_RUNTIME_LIBPQ=""
declare -ag CB_PHP_VERSIONS=()
declare -ag CB_PHP_CODES=()
declare -ag CB_PHP_MODES=()
cb_pgsql_reset_php_targets() {
CB_PHP_VERSIONS=()
CB_PHP_CODES=()
CB_PHP_MODES=()
}
cb_pgsql_get_cb_option() {
local options_conf="$1"
local key="$2"
local value=""
[[ -f "$options_conf" ]] || return 1
value="$(awk -F= -v key="$key" '
$1 == key {
sub(/^[[:space:]]+/, "", $2)
sub(/[[:space:]]+$/, "", $2)
print $2
exit
}
' "$options_conf")"
[[ -n "$value" ]] || return 1
printf '%s\n' "$value"
}
cb_pgsql_php_code_from_version() {
printf '%s\n' "${1//./}"
}
cb_pgsql_php_version_from_code() {
local code="$1"
if [[ "$code" == *.* ]]; then
printf '%s\n' "$code"
elif [[ "$code" =~ ^[0-9]{2,3}$ ]]; then
printf '%s.%s\n' "${code:0:1}" "${code:1}"
else
printf '%s\n' "$code"
fi
}
cb_pgsql_add_php_target() {
local version="$1"
local mode="$2"
local code=""
local idx=""
[[ -n "$version" ]] || return 0
code="$(cb_pgsql_php_code_from_version "$version")"
for idx in "${!CB_PHP_CODES[@]}"; do
if [[ "${CB_PHP_CODES[$idx]}" == "$code" ]]; then
return 0
fi
done
CB_PHP_VERSIONS+=("$version")
CB_PHP_CODES+=("$code")
CB_PHP_MODES+=("${mode:-php-fpm}")
}
cb_pgsql_detect_webserver() {
local cb_dir="$1"
CB_PHP_OPTIONS_CONF="${cb_dir}/options.conf"
CB_PHP_WEBSERVER="apache"
if [[ -f "$CB_PHP_OPTIONS_CONF" ]]; then
CB_PHP_WEBSERVER="$(cb_pgsql_get_cb_option "$CB_PHP_OPTIONS_CONF" "webserver" || true)"
[[ -n "$CB_PHP_WEBSERVER" ]] || CB_PHP_WEBSERVER="apache"
fi
}
cb_pgsql_collect_php_targets() {
local cb_dir="$1"
local slot=""
local release=""
local mode=""
local default_mode=""
cb_pgsql_reset_php_targets
cb_pgsql_detect_webserver "$cb_dir"
# CloudLinux może używać lsphp także przy webserver=apache.
# Dlatego najpierw honorujemy phpN_mode/php1_mode z options.conf,
# a dopiero przy ich braku stosujemy domyślny tryb wynikający z webserwera.
case "$CB_PHP_WEBSERVER" in
litespeed|openlitespeed) default_mode="lsphp" ;;
*) default_mode="php-fpm" ;;
esac
for slot in 1 2 3 4 5 6 7 8 9; do
release="$(cb_pgsql_get_cb_option "$CB_PHP_OPTIONS_CONF" "php${slot}_release" || true)"
mode="$(cb_pgsql_get_cb_option "$CB_PHP_OPTIONS_CONF" "php${slot}_mode" || true)"
[[ -n "$mode" ]] || mode="$(cb_pgsql_get_cb_option "$CB_PHP_OPTIONS_CONF" "php1_mode" || true)"
[[ -n "$mode" ]] || mode="$default_mode"
case "${release,,}" in
""|no|off) continue ;;
esac
case "${mode,,}" in
no|off) continue ;;
esac
cb_pgsql_add_php_target "$release" "$mode"
done
}
cb_pgsql_build_file_candidates() {
local cb_dir="$1"
local mode="$2"
local code="$3"
local -n out_ref="$4"
out_ref=()
if [[ "$mode" == "lsphp" ]]; then
case "$CB_PHP_WEBSERVER" in
litespeed)
out_ref+=("${cb_dir}/configure/litespeed/configure.php${code}")
;;
openlitespeed)
out_ref+=("${cb_dir}/configure/openlitespeed/configure.php${code}")
;;
esac
out_ref+=("${cb_dir}/configure/lsphp/configure.lsphp${code}")
out_ref+=("${cb_dir}/configure/lsphp/configure.php${code}")
fi
out_ref+=("${cb_dir}/configure/php/configure.php${code}")
}
cb_pgsql_resolve_config_paths() {
local cb_dir="$1"
local version="$2"
local mode="$3"
local source_ref_name="$4"
local custom_ref_name="$5"
local code=""
local -a candidates=()
local candidate=""
code="$(cb_pgsql_php_code_from_version "$version")"
printf -v "$source_ref_name" '%s' ""
printf -v "$custom_ref_name" '%s' ""
cb_pgsql_build_file_candidates "$cb_dir" "$mode" "$code" candidates
for candidate in "${candidates[@]}"; do
if [[ -f "$candidate" ]]; then
printf -v "$source_ref_name" '%s' "$candidate"
printf -v "$custom_ref_name" '%s' "$(printf '%s\n' "$candidate" | sed "s#^${cb_dir}/configure/#${cb_dir}/custom/#")"
return 0
fi
done
for candidate in "${candidates[@]}"; do
candidate="$(printf '%s\n' "$candidate" | sed "s#^${cb_dir}/configure/#${cb_dir}/custom/#")"
if [[ -f "$candidate" ]]; then
printf -v "$source_ref_name" '%s' "$candidate"
printf -v "$custom_ref_name" '%s' "$candidate"
return 0
fi
done
return 1
}
cb_pgsql_insert_flags() {
local config_file="$1"
local pg_prefix="$2"
local tmp_file="${config_file}.tmp"
sed -i '/--with-pgsql=/d; /--with-pdo-pgsql=/d' "$config_file"
if grep -q -- '--with-pdo-mysql' "$config_file"; then
awk -v prefix="$pg_prefix" '
/--with-pdo-mysql/ {
print
print "\t--with-pgsql=" prefix " \\"
print "\t--with-pdo-pgsql=" prefix " \\"
next
}
{ print }
' "$config_file" > "$tmp_file"
else
awk -v prefix="$pg_prefix" '
/^[[:space:]]*--with/ { last = NR }
{ lines[NR] = $0 }
END {
if (last == 0) {
for (i = 1; i <= NR; i++) print lines[i]
exit
}
for (i = 1; i <= NR; i++) {
print lines[i]
if (i == last) {
print "\t--with-pgsql=" prefix " \\"
print "\t--with-pdo-pgsql=" prefix " \\"
}
}
}
' "$config_file" > "$tmp_file"
fi
mv "$tmp_file" "$config_file"
}
cb_pgsql_prepare_custom_config() {
local cb_dir="$1"
local version="$2"
local mode="$3"
local pg_prefix="$4"
local source_conf=""
local custom_conf=""
local ts=""
if ! cb_pgsql_resolve_config_paths "$cb_dir" "$version" "$mode" source_conf custom_conf; then
warn "Nie znaleziono configure dla PHP ${version} (tryb ${mode}, webserver ${CB_PHP_WEBSERVER})."
return 1
fi
mkdir -p "$(dirname "$custom_conf")"
ts="$(date +%s)"
if [[ "$source_conf" != "$custom_conf" && ! -f "$custom_conf" ]]; then
cp -p "$source_conf" "$custom_conf"
elif [[ -f "$custom_conf" ]]; then
cp -p "$custom_conf" "${custom_conf}.bak.${ts}"
fi
cb_pgsql_insert_flags "$custom_conf" "$pg_prefix"
chmod +x "$custom_conf" || true
info "Przygotowano configure dla PHP ${version}: ${custom_conf}"
return 0
}
cb_pgsql_configure_runtime_libpq() {
local pg_prefix="$1"
local pg_libdir="${pg_prefix}/lib"
local libpq_so="${pg_libdir}/libpq.so.5"
local ld_conf="/etc/ld.so.conf.d/00-da-postgresql-libpq.conf"
local old_ld_conf="/etc/ld.so.conf.d/da-postgresql-libpq.conf"
local preferred=""
[[ -d "$pg_libdir" ]] || die "Nie znaleziono katalogu bibliotek PostgreSQL: ${pg_libdir}"
[[ -r "$libpq_so" ]] || die "Nie znaleziono biblioteki libpq: ${libpq_so}"
printf '%s\n' "$pg_libdir" > "$ld_conf"
chmod 644 "$ld_conf"
[[ "$old_ld_conf" == "$ld_conf" ]] || rm -f "$old_ld_conf"
if command -v ldconfig >/dev/null 2>&1; then
ldconfig || die "Nie udało się odświeżyć cache bibliotek przez ldconfig."
preferred="$(ldconfig -p 2>/dev/null | awk '/libpq\.so\.5/{print $NF; exit}')"
if [[ -n "$preferred" && "$preferred" != "$libpq_so" ]]; then
warn "Domyślna libpq to ${preferred}; wymuszę właściwą bibliotekę przez LD_PRELOAD podczas kompilacji PHP."
fi
else
warn "Brak ldconfig. Kontynuuję z LD_LIBRARY_PATH."
fi
DA_PG_RUNTIME_LIBDIR="$pg_libdir"
DA_PG_RUNTIME_LIBPQ="$libpq_so"
info "Skonfigurowano bibliotekę runtime PostgreSQL: ${pg_libdir}"
}
cb_pgsql_detect_pg_prefix() {
local candidate=""
CB_PG_PREFIX=""
CB_PG_VERSION=""
CB_PG_CONFIG=""
if [[ -x /usr/local/bin/pg_config ]]; then
candidate="$(readlink -f /usr/local/bin/pg_config 2>/dev/null || true)"
if [[ -x "$candidate" ]]; then
CB_PG_CONFIG="$candidate"
fi
fi
if [[ -z "$CB_PG_CONFIG" ]]; then
candidate="$(ls -1 /usr/pgsql-*/bin/pg_config 2>/dev/null | sort -V | tail -n1 || true)"
if [[ -n "$candidate" && -x "$candidate" ]]; then
CB_PG_CONFIG="$candidate"
fi
fi
[[ -n "$CB_PG_CONFIG" ]] || return 1
CB_PG_PREFIX="$(cd "$(dirname "$CB_PG_CONFIG")/.." && pwd)"
if [[ "$CB_PG_PREFIX" =~ /usr/pgsql-([0-9]+)$ ]]; then
CB_PG_VERSION="${BASH_REMATCH[1]}"
fi
[[ -n "$CB_PG_PREFIX" ]] || return 1
return 0
}
cb_pgsql_find_php_bin_for_version() {
local version="$1"
local code=""
local candidate=""
code="$(cb_pgsql_php_code_from_version "$version")"
for candidate in \
"/usr/local/php${code}/bin/php" \
"/usr/local/php${code}/bin/lsphp" \
"/usr/local/lsphp${code}/bin/lsphp" \
"/usr/local/php${code}/bin/php-cgi"; do
if [[ -x "$candidate" ]]; then
printf '%s\n' "$candidate"
return 0
fi
done
return 1
}
cb_pgsql_probe_php_extensions() {
local php_bin="$1"
local pgsql_ref_name="$2"
local pdo_ref_name="$3"
local modules=""
local modules_lc=""
local probe_pgsql_status="NIE"
local probe_pdo_status="NIE"
modules="$("$php_bin" -m 2>/dev/null || true)"
if [[ -z "$modules" ]]; then
probe_pgsql_status="BŁĄD"
probe_pdo_status="BŁĄD"
printf -v "$pgsql_ref_name" '%s' "$probe_pgsql_status"
printf -v "$pdo_ref_name" '%s' "$probe_pdo_status"
return 1
fi
modules_lc="$(printf '%s\n' "$modules" | tr '[:upper:]' '[:lower:]')"
if printf '%s\n' "$modules_lc" | grep -qx 'pgsql'; then
probe_pgsql_status="OK"
fi
if printf '%s\n' "$modules_lc" | grep -qx 'pdo_pgsql'; then
probe_pdo_status="OK"
fi
printf -v "$pgsql_ref_name" '%s' "$probe_pgsql_status"
printf -v "$pdo_ref_name" '%s' "$probe_pdo_status"
return 0
}
cb_pgsql_render_extensions_table() {
local found=0
local idx=""
local version=""
local php_bin=""
local pgsql_status=""
local pdo_pgsql_status=""
echo "+------------+-------+-----------+"
printf "| %-10s | %-5s | %-9s |\n" "Wersja PHP" "PGSQL" "PDO_PGSQL"
echo "+------------+-------+-----------+"
for idx in "${!CB_PHP_VERSIONS[@]}"; do
version="${CB_PHP_VERSIONS[$idx]}"
php_bin="$(cb_pgsql_find_php_bin_for_version "$version" || true)"
if [[ -z "$php_bin" ]]; then
printf "| %-10s | %-5s | %-9s |\n" "PHP ${version}" "BRAK" "BRAK"
found=1
continue
fi
cb_pgsql_probe_php_extensions "$php_bin" pgsql_status pdo_pgsql_status >/dev/null 2>&1 || true
printf "| %-10s | %-5s | %-9s |\n" "PHP ${version}" "$pgsql_status" "$pdo_pgsql_status"
found=1
done
if [[ $found -eq 1 ]]; then
echo "+------------+-------+-----------+"
else
warn "Nie znaleziono wersji PHP do raportu."
fi
}
[[ $EUID -eq 0 ]] || die "Skrypt musi być uruchomiony jako root."
LOGFILE="/var/log/recompile_php_$(date +%Y%m%d_%H%M%S).log"
exec 1> >(tee >(sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' >> "$LOGFILE")) 2>&1
info "Pełny log zapisany w: $LOGFILE"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
CB_DIR="/usr/local/directadmin/custombuild"
[[ -x "${CB_DIR}/build" ]] || die "Nie znaleziono DirectAdmin CustomBuild: ${CB_DIR}/build"
sekcja "Wykrywanie środowiska DirectAdmin"
cb_pgsql_collect_php_targets "$CB_DIR"
[[ ${#CB_PHP_VERSIONS[@]} -gt 0 ]] || die "Nie wykryto aktywnych wersji PHP w DirectAdmin CustomBuild."
info "Web serwer: ${CB_PHP_WEBSERVER}"
info "Wykryte wersje PHP: $(IFS=', '; echo "${CB_PHP_VERSIONS[*]}")"
sekcja "Wykrywanie PostgreSQL dla kompilacji PHP"
cb_pgsql_detect_pg_prefix || die "Nie znaleziono pg_config. Zainstaluj PostgreSQL lub ustaw /usr/local/bin/pg_config."
[[ -n "$CB_PG_VERSION" ]] || die "Nie udało się ustalić wersji PostgreSQL z ${CB_PG_CONFIG}."
info "Wykryty prefix PostgreSQL: ${CB_PG_PREFIX}"
info "Wykryta wersja PostgreSQL: ${CB_PG_VERSION}"
dnf install -y "postgresql${CB_PG_VERSION}-devel" \
"postgresql${CB_PG_VERSION}-libs" \
|| die "Nie udało się zainstalować postgresql${CB_PG_VERSION}-devel/libs."
if [[ -x "$CB_PG_CONFIG" ]]; then
if [[ -e /usr/local/bin/pg_config && ! -L /usr/local/bin/pg_config ]]; then
warn "/usr/local/bin/pg_config istnieje i nie jest dowiązaniem pomijam aktualizację symlinku."
else
ln -sf "$CB_PG_CONFIG" /usr/local/bin/pg_config
info "Zaktualizowano symlink: /usr/local/bin/pg_config -> ${CB_PG_CONFIG}"
fi
fi
cb_pgsql_configure_runtime_libpq "$CB_PG_PREFIX"
sekcja "Analiza rozszerzeń PHP"
declare -a REBUILD_VERSIONS=()
declare -a REBUILD_MODES=()
for idx in "${!CB_PHP_VERSIONS[@]}"; do
php_version="${CB_PHP_VERSIONS[$idx]}"
php_mode="${CB_PHP_MODES[$idx]}"
php_bin="$(cb_pgsql_find_php_bin_for_version "$php_version" || true)"
pgsql_status="BRAK"
pdo_pgsql_status="BRAK"
if [[ -z "$php_bin" ]]; then
warn "Nie znaleziono binarki PHP dla wersji ${php_version}. Dodaję do rekompilacji."
REBUILD_VERSIONS+=("$php_version")
REBUILD_MODES+=("$php_mode")
continue
fi
cb_pgsql_probe_php_extensions "$php_bin" pgsql_status pdo_pgsql_status >/dev/null 2>&1 || true
if [[ "$pgsql_status" != "OK" || "$pdo_pgsql_status" != "OK" ]]; then
info "PHP ${php_version}: brakujące rozszerzenia (PGSQL=${pgsql_status}, PDO_PGSQL=${pdo_pgsql_status})"
REBUILD_VERSIONS+=("$php_version")
REBUILD_MODES+=("$php_mode")
else
info "PHP ${php_version}: rozszerzenia pgsql i pdo_pgsql są już dostępne."
fi
done
if [[ ${#REBUILD_VERSIONS[@]} -eq 0 ]]; then
sekcja "Tabela rozszerzeń PHP"
cb_pgsql_render_extensions_table
info "Pełny log: ${LOGFILE}"
exit 0
fi
sekcja "Przygotowanie configure.phpXX"
prepared_any=0
for idx in "${!REBUILD_VERSIONS[@]}"; do
if cb_pgsql_prepare_custom_config "$CB_DIR" "${REBUILD_VERSIONS[$idx]}" "${REBUILD_MODES[$idx]}" "$CB_PG_PREFIX"; then
prepared_any=1
fi
done
[[ "$prepared_any" -eq 1 ]] || die "Nie udało się przygotować żadnego pliku configure dla rekompilacji PHP."
sekcja "Rekompilacja PHP"
cd "$CB_DIR"
for php_version in "${REBUILD_VERSIONS[@]}"; do
info "Uruchamiam: ./build php ${php_version}"
LD_LIBRARY_PATH="${DA_PG_RUNTIME_LIBDIR}${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}" \
LD_PRELOAD="${DA_PG_RUNTIME_LIBPQ}${LD_PRELOAD:+:${LD_PRELOAD}}" \
LIBRARY_PATH="${DA_PG_RUNTIME_LIBDIR}${LIBRARY_PATH:+:${LIBRARY_PATH}}" \
PKG_CONFIG_PATH="${DA_PG_RUNTIME_LIBDIR}/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}}" \
LDFLAGS="-L${DA_PG_RUNTIME_LIBDIR} ${LDFLAGS:-}" \
CPPFLAGS="-I${CB_PG_PREFIX}/include ${CPPFLAGS:-}" \
./build php "$php_version" \
|| die "Rekompilacja PHP ${php_version} nie powiodła się."
done
./build rewrite_confs \
|| warn "rewrite_confs zakończył się błędem sprawdź konfigurację ręcznie."
cd - >/dev/null
sekcja "Tabela rozszerzeń PHP po rekompilacji"
cb_pgsql_collect_php_targets "$CB_DIR"
cb_pgsql_render_extensions_table
info "Pełny log: ${LOGFILE}"
exit 0