File: //bigscoots/wpo/phpfpm/multiphp.sh
#!/bin/bash
# This script is used to manage PHP installations
# and configuration for different domains.
# Using Remi Repo
if [[ -f /bigscoots/php-pools/php-pools ]]; then
if [ "$#" -ne 5 ]; then
echo "invalid arg len" >&2
exit 2
fi
/bigscoots/php-pools/php-pools set $3 $5
exit 0
fi
source /bigscoots/includes/common.sh
# Function to send Slack alert
send_slack_alert_cust() {
local message="$1"
bash /bigscoots/general/slack.sh "#wpo-alerts" ":warning: *WPO MultiPHP*\n*Hostname:* $(hostname)\n *Server IP:* ${serverip}\n *Message:* ${message}"
}
# Function to log actions
log_action() {
local message="$1"
echo "$(date +"%Y-%m-%d %H:%M:%S") : ${message}" >> /root/.bigscoots/logs/multiphp.log
}
update_php_config() {
local phpver="$1"
local php_conf_path="/etc/opt/remi/${phpver}/php-fpm.d/www.conf"
local custom_php_ini="/etc/opt/remi/${phpver}/php.d/zzz_customphp.ini"
local bsdomains_ini="/etc/centminmod/php.d/bsdomains.ini"
local opcache_blacklist="/etc/opt/remi/${phpver}/php.d/opcache-default.blacklist"
# Remve unnecesasry lines
sed -i '/^$/d ; /^;/d ; /php_admin_value\[error_log\]/d ; /php_admin_flag\[log_errors\]/d' "$php_conf_path"
sed -i '/pm.start_servers/d ; /pm.min_spare_servers/d ; /pm.max_spare_servers/d' "$php_conf_path"
sed -i '/pm =/c\pm = ondemand' "$php_conf_path"
sed -i '/slowlog =/c\slowlog = /var/log/php-fpm/www-slow.log' "$php_conf_path"
if ! grep -q "request_slowlog_timeout" "$php_conf_path"
then
sed -i '/slowlog =/i request_slowlog_timeout = 20' "$php_conf_path"
fi
if [[ $2 == maxchild ]]
then
max_children=$(grep -v '^\s*;' /usr/local/etc/php-fpm.conf | grep pm.max_children | grep -o '[0-9]\+')
if [[ $max_children =~ ^[0-9]+$ ]]
then
sed -i "/pm.max_children/c\pm.max_children = $max_children" "$php_conf_path"
fi
fi
if ! grep -q "pm.max_requests" "$php_conf_path"
then
sed -i '/pm.max_children/a\pm.max_requests = 25' "$php_conf_path"
fi
if grep -q pcre.jit "$custom_php_ini"
then
sed -i '/pcre.jit/c\pcre.jit=1' "$custom_php_ini"
else
echo "pcre.jit=1" >> "$custom_php_ini"
fi
if grep -q date.timezone "$custom_php_ini"
then
sed -i '/date.timezone/c\date.timezone = \"America/Chicago\"' "$custom_php_ini"
else
echo "date.timezone = \"America/Chicago\"" >> "$custom_php_ini"
fi
if [ -f "$bsdomains_ini" ]
then
ln -fs "$bsdomains_ini" "/etc/opt/remi/${phpver}/php.d/"
fi
if [ ! -L "$opcache_blacklist" ]
then
ln -fs /root/.bigscoots/php/opcache-blacklist.txt "$opcache_blacklist"
fi
}
allinfo() {
specific_domain=$1 # The specific domain argument passed (if any)
# Check if a specific domain is passed and if it exists
if [ -n "$specific_domain" ]
then
if [ ! -d "/home/nginx/domains/$specific_domain" ]
then
echo "Error: The specified domain does not exist."
return 1
fi
domains=($specific_domain)
else
# Get all domains if none specified
domains=($(find /home/nginx/domains/ -mindepth 1 -maxdepth 1 -type d -not -path '*/\.*' -name '*.*' | sed 's|/home/nginx/domains/||g'))
fi
for domain in "${domains[@]}"; do
DPHPV=$(grep -i "^ \+ include /usr/local/nginx/conf/php" "/usr/local/nginx/conf/conf.d/${domain}.ssl.conf" | awk '{print $2}' | sort | uniq)
if [[ $(grep -i "^ \+ include /usr/local/nginx/conf/php" "/usr/local/nginx/conf/conf.d/${domain}.ssl.conf" | awk '{print $2}' | sort | uniq | wc -l) -gt 1 ]]
then
echo "Detected multiple versions of PHP in /usr/local/nginx/conf/conf.d/${domain}.ssl.conf please fix."
elif [[ $DPHPV == *"php-wpsc.conf"* ]]
then
echo "Native PHP: $(php -v 2>/dev/null | head -1 | awk '{print $2}') - ${domain}"
elif [[ $DPHPV == *"php-fastcgicache.conf"* ]]
then
echo "Native PHP: $(php -v 2>/dev/null | head -1 | awk '{print $2}') with FastCGI caching - ${domain}"
elif [[ "$DPHPV" =~ php[0-9][0-9]-remi.conf ]]
then
echo "Multi PHP: $(/opt/remi/php$(echo $DPHPV | sed 's|/usr/local/nginx/conf/php||g ; s|-remi.conf;||g')/root/bin/php -v 2>/dev/null | head -1 | awk '{print $2}') - ${domain}"
elif [[ "$DPHPV" =~ php-fastcgicache[0-9][0-9].conf ]]
then
echo "Multi PHP: $(/opt/remi/php$(echo $DPHPV | sed 's|/usr/local/nginx/conf/php||g ; s|-remi.conf;||g')/root/bin/php -v 2>/dev/null | head -1 | awk '{print $2}') with FastCGI caching - ${domain}"
else
echo "Not sure what PHP version is running, using a custom config? - ${domain}"
fi
done
}
update_php_versions_json() {
local json_file="/root/.bigscoots/php_versions.json"
local domain=$1
local php_version=""
# Determine PHP version for each domain
DPHPV=$(grep -i "^ \+ include /usr/local/nginx/conf/php" "/usr/local/nginx/conf/conf.d/${domain}.ssl.conf" | awk '{print $2}' | sort | uniq)
if [[ $DPHPV == *"php74-remi.conf"* ]]; then
php_version="7.4"
elif [[ $DPHPV == *"php81-remi.conf"* ]]; then
php_version="8.1"
elif [[ $DPHPV == *"php82-remi.conf"* ]]; then
php_version="8.2"
else
php_version="native"
fi
# Update the JSON file with the new PHP version
if [[ -f $json_file ]]; then
jq --arg domain "$domain" --arg php_version "$php_version" '.[$domain] = $php_version' $json_file > temp.json && mv temp.json $json_file
else
echo "{\"$domain\": \"$php_version\"}" > $json_file
fi
}
generate_nginx_map() {
local json_file="/root/.bigscoots/php_versions.json"
local nginx_map="/usr/local/nginx/conf/php_map.conf"
# Start the map block
echo "map \$host \$php_conf {" > $nginx_map
echo " default \"/usr/local/nginx/conf/php-wpsc.conf\";" >> $nginx_map
# Read the JSON file and generate the map entries
jq -r 'to_entries[] | if .value == "native" then " \(.key) \"/usr/local/nginx/conf/php-wpsc.conf\";" else " \(.key) \"/usr/local/nginx/conf/php\(.value | gsub("\\."; ""))-remi.conf\";" end' $json_file >> $nginx_map
# Close the map block
echo "}" >> $nginx_map
# Reload NGINX to apply changes
nginx -t && systemctl reload nginx
}
phpinstall() {
if [ ! -d /root/.biscoots ]
then
mkdir -p /root/.bigscoots
fi
if [ -d /root/.bigscoots/centminmod-multiphp ]
then
git --git-dir=/root/.bigscoots/centminmod-multiphp/.git --work-tree=/root/.bigscoots/centminmod-multiphp pull
else
if ! git_clone_output=$(git clone https://github.com/jcatello/centminmod-multiphp /root/.bigscoots/centminmod-multiphp 2>&1)
then
send_slack_alert_cust "Git clone of repo https://github.com/jcatello/centminmod-multiphp failed.\nError:\`\`\`${git_clone_output}\`\`\`"
fi
fi
if grep -q "CentOS" /etc/redhat-release; then
skip_php84=true
else
skip_php84=false
fi
ls -1 /root/.bigscoots/centminmod-multiphp/php[0-9][0-9].sh | sed 's/.sh//g' | grep 'php74\|php81\|php82\|php83\|php84\|php85' | xargs -n 1 basename | while read -r phpver
do
# Skip php84 if running CentOS
if [ "$skip_php84" = true ] && { [ "$phpver" = "php84" ] || [ "$phpver" = "php85" ]; }; then
continue
fi
# "Checking to see if PHP ${phpver} installed"
if ! bash /root/.bigscoots/centminmod-multiphp/"${phpver}".sh status >/dev/null 2>&1
then
yum_check
if [ -f "/etc/opt/remi/${phpver}/php-fpm.d/www.conf" ]
then
bash /root/.bigscoots/centminmod-multiphp/"${phpver}".sh install >/dev/null 2>&1
update_php_config "${phpver}"
bash /root/.bigscoots/centminmod-multiphp/"${phpver}".sh restart
else
bash /root/.bigscoots/centminmod-multiphp/"${phpver}".sh install >/dev/null 2>&1
update_php_config "${phpver}" maxchild
bash /root/.bigscoots/centminmod-multiphp/"${phpver}".sh restart
fi
else
update_php_config "${phpver}"
fi
done
find /var/opt/remi/php*/lib/php -group apache -exec chgrp nginx {} \;
bash /bigscoots/wpo/phpfpm/create_pools.sh
# Add action to log
log_action "PHP Install completed successfully"
}
checkphp() {
if [[ -z "$domain" || -z "$phpver" ]]; then
echo "{\"success\": false, \"error\": \"Domain or PHP version is not set.\"}"
echo "Error: domain or phpver is not set." >> /root/.bigscoots/logs/multiphp.log
exit 1
elif [[ "$phpver" == 'native' ]]; then
echo "{\"success\": true, \"message\": \"PHP Version is set to 'native.' Skipping PHP installation.\"}"
echo "PHP Version is set to 'native.' Skipping PHP installation." >> /root/.bigscoots/logs/multiphp.log
return
fi
validate_domain_in_path "$domain" multiphp.sh || {
echo "{\"success\": false, \"error\": \"Domain has failed validation!\"}"
echo "Domain validation failed for $domain" >> /root/.bigscoots/logs/multiphp.log
exit 1
}
if [ ! -d /root/.bigscoots/centminmod-multiphp ]; then
phpinstall
fi
echo "Checking required PHP files for PHP $phpver..." >> /root/.bigscoots/logs/multiphp.log
required_files=(
"/root/.bigscoots/centminmod-multiphp/php${phpver}.sh"
"/usr/bin/php${phpver}"
"/etc/opt/remi/php${phpver}/php-fpm.d/www.conf"
"/etc/opt/remi/php${phpver}/php.d/zzz_customphp.ini"
"/etc/opt/remi/php${phpver}/php.ini"
"/var/opt/remi/php${phpver}/log/php-fpm/www-error.log"
"/usr/local/nginx/conf/php${phpver}-remi.conf"
"/etc/yum.repos.d/remi.repo"
)
missing_files=()
for file in "${required_files[@]}"; do
if [[ ! -f "$file" ]]; then
missing_files+=("$file")
fi
done
if [[ ${#missing_files[@]} -gt 0 ]]; then
echo "Missing files detected for PHP ${phpver}:" >> /root/.bigscoots/logs/multiphp.log
printf '%s\n' "${missing_files[@]}" >> /root/.bigscoots/logs/multiphp.log
echo "Running PHP ${phpver} installer script..." >> /root/.bigscoots/logs/multiphp.log
git --git-dir=/root/.bigscoots/centminmod-multiphp/.git --work-tree=/root/.bigscoots/centminmod-multiphp pull >/dev/null 2>&1
bash /root/.bigscoots/centminmod-multiphp/php"${phpver}".sh install >/dev/null 2>&1
else
echo "All required files exist for PHP $phpver." >> /root/.bigscoots/logs/multiphp.log
fi
attempt=1
while true; do
echo "Checking if PHP $phpver is running (Attempt: $attempt)..." >> /root/.bigscoots/logs/multiphp.log
if ! bash /root/.bigscoots/centminmod-multiphp/php"${phpver}".sh status >/dev/null 2>&1; then
echo "PHP $phpver not running, reinstalling..." >> /root/.bigscoots/logs/multiphp.log
git --git-dir=/root/.bigscoots/centminmod-multiphp/.git --work-tree=/root/.bigscoots/centminmod-multiphp pull >/dev/null 2>&1
bash /root/.bigscoots/centminmod-multiphp/php"${phpver}".sh install >/dev/null 2>&1
if ! bash /root/.bigscoots/centminmod-multiphp/php"${phpver}".sh status >/dev/null 2>&1; then
echo "PHP $phpver failed to install after retry." >> /root/.bigscoots/logs/multiphp.log
echo "{\"success\": false, \"error\": \"PHP Version installation failed for ${phpver}\"}"
exit 1
else
break
fi
else
echo "PHP $phpver is running successfully." >> /root/.bigscoots/logs/multiphp.log
break
fi
attempt=$((attempt + 1))
if [[ $attempt -gt 1 ]]; then
echo "PHP Version change failed!" >> /root/.bigscoots/logs/multiphp.log
send_slack_alert_cust "PHP Version change failed for \`${phpver}\`."
echo "{\"success\": false, \"error\": \"PHP Version change failed for ${phpver}\"}"
exit 1
fi
done
}
setphp() {
validate_domain_in_path "$domain" multiphp.sh || { echo "{\"success\": false, \"error\": \"Domain has failed validation!\"}"; exit 1; }
if ls -1 /home/nginx/domains/ | grep -q "$domain" && [[ "$phpver" == *'56'* || $phpver == *'70'* || $phpver == *'71'* || $phpver == *'72'* || $phpver == *'73'* || $phpver == *'74'* || $phpver == *'80'* || $phpver == *'81'* || $phpver == *'82'* || $phpver == *'83'* || $phpver == *'84'* || $phpver == *'85'* || $phpver == *'native'* ]]
then
SSLCONF="/usr/local/nginx/conf/conf.d/${domain}.ssl.conf"
WPSECURECONF="/usr/local/nginx/conf/wpincludes/${domain}/wpsecure_${domain}.conf"
if [[ "$phpver" == 'native' ]]
then
PHPCONF="/usr/local/nginx/conf/php-wpsc.conf"
else
PHPCONF="/usr/local/nginx/conf/php${phpver}-remi.conf"
fi
if [[ -f ${PHPCONF} ]]
then
if ! sed_output=$(sed -ri "s#/usr/local/nginx/conf/(php.conf|php-wpsc.conf|php[0-9]{2}-remi.conf)#${PHPCONF}#g" "${SSLCONF}" "${WPSECURECONF}" 2>&1)
then
echo "{\"success\": false, \"error\": \"PHP Version changed failed, contacting support!\"}"
send_slack_alert_cust "Replacing phpver using sed failed in files: \n\`${SSLCONF}\`\n \`${WPSECURECONF}\`\n *Error:*\`\`\`${sed_output}\`\`\`"
exit 1
fi
else
echo "{\"success\": false, \"error\": \"PHP Version changed failed, contacting support!\"}"
send_slack_alert_cust "${PHPCONF} is missing."
exit 1
fi
fi
# Add action to log
log_action "PHP version for $domain set to $phpver successfully"
}
nginxreload() {
if nginx -t > /dev/null 2>&1
then
ngxreload > /dev/null 2>&1
else
send_slack_alert_cust "Nginx Conf failed after changing PHP on $domain to PHP ${phpver} \n \`\`\`$(nginx -t 2>&1)\`\`\`"
echo "{\"success\": false, \"error\": \"PHP Version changed failed, contacting support!\"}"
exit 1
fi
# Add action to log
log_action "Nginx reloaded successfully"
}
update_wpo_api() {
# sync php version wpo api endpoint
URL="https://patchstack-wpo.bigscoots.com/versions/sync_php_version"
AUTHORIZATION=$(get_wpo_api_hash)
# Get the JSON data from the info.sh script
DATA=$(bash /bigscoots/wpo/manage/info.sh --domain $domain phpver)
# Send the POST request using curl with quiet mode (-s) and store the response in a variable
response=$(curl -s -X POST -H "Authorization: ${AUTHORIZATION}" -H "Content-Type: application/json" -d "${DATA}" "${URL}")
# Check the response for success or failure
if ! echo "$response" | grep -q '"success":true'
then
escaped_response=$(echo "$response" | sed 's/"/\\"/g')
send_slack_alert "#wpo-alerts" ":warning:" "Function: \`update_wpo_api\`" "$domain" "\`\`\`$escaped_response\`\`\`"
fi
}
update_php() {
# Check if /opt/remi/php* folders exist
if ls -d /opt/remi/php* >/dev/null 2>&1
then
# Get the list of PHP versions
php_versions=(/opt/remi/php*/)
# Loop through each PHP version and run the update script
for php_path in "${php_versions[@]}"
do
phpver="$(basename "$php_path")"
bash /root/.bigscoots/centminmod-multiphp/"$phpver".sh update
done
if [[ "$REBOOT" == true ]]
then
bash /bigscoots/wpo/manage/php.sh --reboot
else
bash /bigscoots/wpo/manage/php.sh
fi
fi
}
## Enable PHP‑FPM access logging ##
enable_access_logs() {
local logs=()
for pool in /etc/opt/remi/php*/php-fpm.d/www.conf; do
[[ -f "$pool" ]] || continue
version="${pool#*/php}"
version="${version%%/*}"
logdir="/var/opt/remi/php${version}/log/php-fpm"
logfile="${logdir}/access.log"
mkdir -p "$logdir"
if ! grep -q '^access\.log' "$pool"; then
cat <<EOF >> "$pool"
access.log = ${logfile}
access.format = "%{HTTP_X_FORWARDED_FOR}e - [%t] \"%m %r%Q%q\" %s %l - %P %p %{seconds}d %{bytes}M %{user}C%% %{system}C%% \"%{REQUEST_URI}e\" \"%{HTTP_USER_AGENT}e\" %{HTTP_HOST}e"
EOF
scoots php reload all > /dev/null 2>&1
fi
logs+=("$logfile")
done
echo "Access log files are located at:"
for lf in "${logs[@]}"; do
echo " $lf"
done
}
show_help() {
cat << EOF
Usage: $0 COMMAND [OPTIONS]
Commands:
set Set PHP version for a domain
info Display PHP information
check Check PHP installs
update_configs Update PHP configs
enable-logs Enable PHP‑FPM access logs
update Update all PHP versions
Options:
--domain DOMAIN
--phpver PHPVER
--bulk
--reboot
EOF
}
BULK=false
REBOOT=false
# Initialize JSON string
json_output="{\"success\": true, "
# Parse command line arguments
command=$1
shift
while (( "$#" ))
do
case "$1" in
--domain)
domain=$2
json_output+="\"domain\": \"$domain\","
shift 2 # Remove --domain and the actual domain
;;
--phpver)
phpver=$2
json_output+="\"phpver\": \"$phpver\","
shift 2 # Remove --phpver and the actual phpver
;;
--bulk)
BULK=true
shift # skip nginx check
;;
--reboot)
REBOOT=true
shift # skip nginx check
;;
*)
echo "Invalid command"
show_help
exit 1
;;
esac
done
case $command in
set)
fix_mariadb103_repo
[[ "$BULK" == false ]] && checkphp
setphp
[[ "$BULK" == false ]] && nginxreload
update_wpo_api
;;
info)
allinfo "$domain" # Pass $2 (if it exists) to allinfo
;;
check)
checkphp
;;
update_configs)
fix_mariadb103_repo
phpinstall
;;
update)
fix_mariadb103_repo
update_php
phpinstall
;;
enable-logs)
enable_access_logs
;;
v2_gen_json)
domains=($(find /home/nginx/domains/ -mindepth 1 -maxdepth 1 -type d -not -path '*/\.*' -name '*.*' | sed 's|/home/nginx/domains/||g'))
# Iterate over domains and update JSON file
for domain in "${domains[@]}"; do
update_php_versions_json "$domain"
done
generate_nginx_map
;;
*)
echo "Invalid command"
show_help
exit 1
;;
esac
# Remove trailing comma and close JSON object
json_output=$(echo "$json_output" | sed 's/,$//')
json_output+="}"
echo "$json_output"