安装php7.4.33的shell脚本

保存文件:deploy_php7.sh

执行:chmod +x deploy_php7.sh

执行:./deploy_php7.sh

bash 复制代码
#!/bin/bash

# PHP 7.4.33自动化部署脚本 for CentOS 7
# 日期:$(date +%Y-%m-%d)
# 如果中途失败,请根据失败步骤,注释一运行步骤,继续部署下一步的步骤

set -e  # 遇到错误时退出脚本

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
MAGENTA='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color

# 日志函数
log_info() {
    echo -e "${GREEN}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}

log_step() {
    echo -e "${BLUE}[STEP]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}

log_debug() {
    if [ "$DEBUG" = "true" ]; then
        echo -e "${CYAN}[DEBUG]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
    fi
}

# 检查是否以root用户运行
check_root() {
    if [[ $EUID -ne 0 ]]; then
        log_error "此脚本必须以root用户运行"
        exit 1
    fi
}

# 检查CentOS版本
check_centos_version() {
    if ! grep -q "CentOS Linux release 7" /etc/redhat-release; then
        log_error "此脚本仅支持CentOS 7"
        exit 1
    fi
}

# 配置参数
PHP_VERSION="7.4.33"
PHP_TAR="php-${PHP_VERSION}.tar.gz"
# https://windows.php.net/downloads/releases/archives/php-7.4.33-src.zip
# https://www.php.net/distributions/php-7.4.33.tar.gz
PHP_DOWNLOAD_URL="https://www.php.net/distributions/${PHP_TAR}"

INSTALL_DIR="/usr/local/php7"
CONF_DIR="${INSTALL_DIR}/etc"
LOG_DIR="/var/log/php"
NGINX_HTML="/usr/share/nginx/html"
TMP_DIR="/tmp/php_build"
PHP_USER="www"
PHP_GROUP="www"
PHP_FPM_PORT="9000"

# PHP依赖库版本
LIBXML_VERSION="2.9.12"
SQLITE_VERSION="3380500"
ONIGURUMA_VERSION="6.9.8"
LIBZIP_VERSION="1.10.1"

# 编译选项
PHP_COMPILE_OPTIONS="
--prefix=${INSTALL_DIR}
--with-config-file-path=${CONF_DIR}
--with-config-file-scan-dir=${CONF_DIR}/php.d
--enable-fpm
--with-fpm-user=${PHP_USER}
--with-fpm-group=${PHP_GROUP}
--enable-mysqlnd
--with-mysqli=mysqlnd
--with-pdo-mysql=mysqlnd
--with-pdo-sqlite
--with-sqlite3
--with-openssl
--with-curl
--with-zlib
--with-bz2
--with-gettext
--with-readline
--with-xmlrpc
--with-libxml-dir
--with-jpeg
--with-freetype
--with-webp
--enable-gd
--with-avif
--with-xpm
--enable-exif
--enable-zip
--enable-bcmath
--enable-calendar
--enable-ftp
--enable-mbstring
--enable-intl
--enable-shmop
--enable-soap
--enable-sockets
--enable-sysvmsg
--enable-sysvsem
--enable-sysvshm
--with-pear
--with-mhash
--with-pcre-regex
--with-pcre-jit
--with-iconv
--enable-pcntl
--enable-opcache
--with-openssl-dir
--with-system-ciphers
--with-password-argon2
--with-sodium
--enable-maintainer-zts
"

# 创建目录
create_directories() {
    log_step "创建必要的目录..."
    
    mkdir -p ${INSTALL_DIR}
    mkdir -p ${CONF_DIR}/php.d
    mkdir -p ${LOG_DIR}/{fpm,cli}
    mkdir -p ${TMP_DIR}
    mkdir -p /var/run/php-fpm
    mkdir -p /var/lib/php/{session,wsdlcache}
    
    # 设置权限
    chmod 777 ${LOG_DIR}
    chmod 777 /var/run/php-fpm
    chmod 777 /var/lib/php
    
    log_info "目录创建完成"
}

# 创建PHP运行用户
create_php_user() {
    log_step "创建PHP运行用户..."
    
    if ! id -u ${PHP_USER} >/dev/null 2>&1; then
        groupadd ${PHP_GROUP}
        useradd -r -g ${PHP_GROUP} -s /sbin/nologin ${PHP_USER}
        log_info "已创建用户: ${PHP_USER}:${PHP_GROUP}"
    else
        log_info "用户 ${PHP_USER} 已存在"
    fi
    
    # 设置目录权限
    chown -R ${PHP_USER}:${PHP_GROUP} ${LOG_DIR}
    chown -R ${PHP_USER}:${PHP_GROUP} /var/run/php-fpm
    chown -R ${PHP_USER}:${PHP_GROUP} /var/lib/php
    
    log_info "用户权限设置完成"
}

# 更健壮的依赖安装方式
install_dependencies() {
   log_step "安装系统依赖..."
    
    # 启用EPEL仓库
    yum install -y epel-release
    
    # 安装开发工具
    yum groupinstall -y "Development Tools"
    yum install -y python-devel python3-devel
    
    # 检查是否已有MySQL安装
    local has_mysql_installed=false
    if [ -d "/usr/local/mysql" ] || rpm -qa | grep -i mysql | grep -v lib; then
        has_mysql_installed=true
        log_warn "检测到已安装的MySQL,跳过可能冲突的MySQL包安装"
    fi
    
    # 安装基础依赖(排除MySQL相关包以保护现有安装)
    local packages=(
        wget curl git gcc gcc-c++ make autoconf automake libtool pkgconfig
        libxml2-devel openssl-devel curl-devel libjpeg-devel libpng-devel
        freetype-devel libwebp-devel libXpm-devel libavif-devel libicu-devel
        libxslt-devel bzip2-devel readline-devel sqlite-devel oniguruma-devel
        libzip-devel gmp-devel libmcrypt-devel mhash-devel enchant-devel
        aspell-devel libedit-devel recode-devel libc-client-devel krb5-devel
        openldap-devel postgresql-devel unixODBC-devel libtidy-devel gd-devel
        libpng libjpeg-turbo freetype libwebp libXpm libicu libxslt bzip2
        sqlite oniguruma libzip gmp libmcrypt mhash enchant aspell libedit
        recode libc-client krb5-workstation openldap postgresql unixODBC
        libtidy libevent-devel ImageMagick-devel ImageMagick libmemcached-devel
        memcached rabbitmq-c-devel librabbitmq-devel geoip-devel libmaxminddb-devel
        yaml-cpp-devel libyaml-devel hiredis-devel re2c libargon2-devel libsodium-devel
    )
    
    # 安装主要依赖包
    yum install -y "${packages[@]}"
    
    # 只有在没有MySQL安装时才安装MySQL兼容库
    if [ "$has_mysql_installed" = false ]; then
        # 先尝试安装 mariadb-libs,如果失败则跳过
        yum install -y mariadb-libs || log_warn "mariadb-libs安装失败,继续执行"
    else
        log_info "跳过MySQL相关库安装以保护现有MySQL安装"
    fi
    
    # 单独安装 net-snmp 相关包(放在最后)
    yum install -y net-snmp-devel net-snmp || true
    
    log_info "系统依赖安装完成"
}

# 下载PHP源码
download_php_source() {
    log_step "下载PHP源码..."
    
    cd ${TMP_DIR}
    
    if [ ! -f "${PHP_TAR}" ]; then
        log_info "下载PHP ${PHP_VERSION}..."
        wget --no-check-certificate ${PHP_DOWNLOAD_URL} -O ${PHP_TAR}
        
        if [ $? -ne 0 ]; then
            log_error "下载PHP失败"
            exit 1
        fi
    else
        log_info "PHP源码包已存在"
    fi
    
    # 解压源码包
    log_info "解压源码包..."
    tar -xzf ${PHP_TAR}
    
    log_info "PHP源码下载完成"
}

# 编译安装依赖库 添加对GD所需库的支持
compile_dependencies() {
    log_step "编译安装PHP依赖库..."
    cd ${TMP_DIR}
    
    # 安装libxml2(如果需要更新版本)
    if [ ! -d "libxml2-${LIBXML_VERSION}" ]; then
        log_info "下载libxml2 ${LIBXML_VERSION}..."
        if [ ! -f "libxml2-${LIBXML_VERSION}.tar.gz" ]; then
            wget http://xmlsoft.org/sources/libxml2-${LIBXML_VERSION}.tar.gz
            else
            log_info "libxml2 ${LIBXML_VERSION}.tar.gz已存在..."
        fi
        tar -xzf libxml2-${LIBXML_VERSION}.tar.gz
        cd libxml2-${LIBXML_VERSION}
        ./configure --prefix=/usr/local/libxml2
        make -j$(nproc)
        make install
        cd ..
    fi
    
    # 安装oniguruma(正则表达式库)
    if [ ! -d "onig-${ONIGURUMA_VERSION}" ]; then
        log_info "下载oniguruma ${ONIGURUMA_VERSION}..."
        if [ ! -f "onig-${ONIGURUMA_VERSION}.tar.gz" ]; then
            wget https://github.com/kkos/oniguruma/releases/download/v${ONIGURUMA_VERSION}/onig-${ONIGURUMA_VERSION}.tar.gz
            else
            log_info "onig-${ONIGURUMA_VERSION}.tar.gz已存在..."
        fi
        tar -xzf onig-${ONIGURUMA_VERSION}.tar.gz
        cd onig-${ONIGURUMA_VERSION}
        ./configure --prefix=/usr/local/oniguruma
        make -j$(nproc)
        make install
        cd ..
    fi
    
    # 安装libzip
    if [ ! -d "libzip-${LIBZIP_VERSION}" ]; then
        log_info "下载libzip ${LIBZIP_VERSION}..."
        if [ ! -f "libzip-${LIBZIP_VERSION}.tar.gz" ]; then
            wget https://libzip.org/download/libzip-${LIBZIP_VERSION}.tar.gz
            else
            log_info "libzip-${LIBZIP_VERSION}.tar.gz已存在..."
        fi
        tar -xzf libzip-${LIBZIP_VERSION}.tar.gz
        cd libzip-${LIBZIP_VERSION}
        mkdir build && cd build
        cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local/libzip
        make -j$(nproc)
        make install
        cd ../..
    fi
    
    # 更新动态库链接
    echo "/usr/local/libxml2/lib" >> /etc/ld.so.conf.d/local.conf
    echo "/usr/local/oniguruma/lib" >> /etc/ld.so.conf.d/local.conf
    echo "/usr/local/libzip/lib" >> /etc/ld.so.conf.d/local.conf
    ldconfig
    
    log_info "依赖库编译安装完成"
}

# 编译安装PHP
compile_php() {
    log_step "编译安装PHP..."
    
    cd ${TMP_DIR}/php-${PHP_VERSION}
    
    # 清理之前的编译
    make clean 2>/dev/null || true
    make distclean 2>/dev/null || true
    
    # 配置PHP
    log_info "配置PHP编译选项..."
    
    # 准备配置参数
    CONFIG_CMD="./configure ${PHP_COMPILE_OPTIONS} \
        --with-libxml-dir=/usr/local/libxml2 \
        --with-onig=/usr/local/oniguruma \
        --with-libzip=/usr/local/libzip \
        --with-webp-dir \
        --with-freetype-dir \
        --with-jpeg-dir \
        --with-png-dir"
    
    log_debug "配置命令: ${CONFIG_CMD}"
    
    # 执行配置
    eval ${CONFIG_CMD}
    
    if [ $? -ne 0 ]; then
        log_error "PHP配置失败"
        exit 1
    fi
    
    # 获取CPU核心数
    CPU_CORES=$(nproc)
    log_info "使用 ${CPU_CORES} 个CPU核心进行编译"
    
    # 编译
    log_info "开始编译PHP..."
    make -j${CPU_CORES}
    
    if [ $? -ne 0 ]; then
        log_error "PHP编译失败"
        exit 1
    fi
    
    # 安装
    log_info "开始安装PHP..."
    make install
    
    if [ $? -ne 0 ]; then
        log_error "PHP安装失败"
        exit 1
    fi
    
    log_info "PHP编译安装完成"
}

# 配置PHP
configure_php() {
    log_step "配置PHP..."
    
    # 复制配置文件
    cp ${TMP_DIR}/php-${PHP_VERSION}/php.ini-production ${CONF_DIR}/php.ini
    cp ${INSTALL_DIR}/etc/php-fpm.conf.default ${CONF_DIR}/php-fpm.conf
    cp ${INSTALL_DIR}/etc/php-fpm.d/www.conf.default ${CONF_DIR}/php-fpm.d/www.conf
    
    # 备份原始配置
    cp ${CONF_DIR}/php.ini ${CONF_DIR}/php.ini.bak
    cp ${CONF_DIR}/php-fpm.conf ${CONF_DIR}/php-fpm.conf.bak
    cp ${CONF_DIR}/php-fpm.d/www.conf ${CONF_DIR}/php-fpm.d/www.conf.bak
    
    # 配置php.ini
    log_info "配置php.ini..."
    
    # 创建优化的php.ini
    cat > ${CONF_DIR}/php.ini << EOF
[PHP]
; PHP配置优化

; 错误处理
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors = Off
display_startup_errors = Off
log_errors = On
error_log = /var/log/php/cli/error.log

; 时区设置
date.timezone = Asia/Shanghai

; 文件上传
upload_max_filesize = 100M
post_max_size = 100M
max_file_uploads = 20

; 内存限制
memory_limit = 256M

; 执行时间
max_execution_time = 300
max_input_time = 300

; 会话设置
session.save_handler = files
session.save_path = "/var/lib/php/session"
session.use_strict_mode = 1
session.cookie_httponly = 1
session.cookie_secure = 1
session.use_only_cookies = 1
session.cookie_lifetime = 0
session.gc_maxlifetime = 1440

; 输出缓冲
output_buffering = 4096

; 路径设置
include_path = ".:/usr/share/pear"

; 禁用危险函数,phpinfo
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source

; 禁用危险类
disable_classes = 

; 资源限制
max_input_nesting_level = 64
max_input_vars = 1000

; 数据过滤
filter.default = unsafe_raw
filter.default_flags = 

; 性能优化
realpath_cache_size = 4096K
realpath_cache_ttl = 600

; Zend OPcache
[opcache]
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.revalidate_freq=2
opcache.fast_shutdown=1
opcache.enable_file_override=1
opcache.validate_timestamps=0
opcache.revalidate_path=0
opcache.save_comments=1
opcache.load_comments=1
opcache.dups_fix=0
opcache.blacklist_filename=${INSTALL_DIR}/etc/php.d/opcache.blacklist

; Xdebug (默认禁用)
;[xdebug]
;zend_extension=xdebug.so
;xdebug.remote_enable=0
;xdebug.profiler_enable=0
;xdebug.remote_host=127.0.0.1
;xdebug.remote_port=9000
;xdebug.remote_handler=dbgp
;xdebug.remote_mode=req
;xdebug.remote_autostart=0
;xdebug.remote_connect_back=0
;xdebug.idekey=PHPSTORM
;xdebug.max_nesting_level=512

; 其他扩展配置
[curl]
[date]
[filter]
[iconv]
[intl]
[json]
[sodium]
[zlib]
; 自定义安装的扩展配置
; extension=redis.so
; extension=imagick.so
; extension_dir = "${INSTALL_DIR}/etc/php.d/*.ini"
EOF

    # 配置php-fpm.conf
    log_info "配置php-fpm.conf..."
    
    cat > ${CONF_DIR}/php-fpm.conf << EOF
[global]
pid = /var/run/php-fpm/php-fpm.pid
error_log = /var/log/php/fpm/error.log
log_level = notice
emergency_restart_threshold = 10
emergency_restart_interval = 1m
process_control_timeout = 10s
daemonize = yes

; 进程管理器设置
process.max = 0
process.priority = 0
rlimit_files = 65535
rlimit_core = 0
events.mechanism = epoll

; 系统日志
syslog.facility = daemon
syslog.ident = php-fpm

; 包含池配置
include = ${INSTALL_DIR}/etc/php-fpm.d/*.conf
EOF

    # 配置www池
    log_info "配置www池..."
    
    cat > ${CONF_DIR}/php-fpm.d/www.conf << EOF
[www]
user = ${PHP_USER}
group = ${PHP_GROUP}

; 监听方式
listen = 127.0.0.1:${PHP_FPM_PORT}
listen.backlog = 65535
listen.allowed_clients = 127.0.0.1

; 进程管理
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500
pm.process_idle_timeout = 10s

; 环境变量
env[HOSTNAME] = \$HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp

; 请求设置
request_terminate_timeout = 300
request_slowlog_timeout = 10s
slowlog = /var/log/php/fpm/www-slow.log

; 进程设置
rlimit_files = 65535
rlimit_core = 0

; 安全设置
security.limit_extensions = .php .php3 .php4 .php5 .php7

; 性能优化
php_flag[display_errors] = off
php_admin_flag[log_errors] = on
php_admin_value[error_log] = /var/log/php/fpm/www-error.log
php_admin_value[memory_limit] = 256M
php_admin_value[upload_max_filesize] = 100M
php_admin_value[post_max_size] = 100M
php_admin_value[max_execution_time] = 300

; 会话设置
php_value[session.save_handler] = files
php_value[session.save_path]    = /var/lib/php/session
php_value[session.use_strict_mode] = 1
php_value[session.cookie_httponly] = 1
php_value[session.cookie_secure] = 1
php_value[session.use_only_cookies] = 1
EOF

    # 创建opcache黑名单
    cat > ${CONF_DIR}/php.d/opcache.blacklist << EOF
; OPcache黑名单文件
; 格式: 每行一个文件路径或模式

; 测试文件
*/test/*
*/tests/*
*/Testing/*

; 版本控制目录
*/.git/*
*/.svn/*
*/.hg/*

; 临时文件
*/tmp/*
*/temp/*

; 日志文件
*/logs/*
*/log/*

; 缓存文件
*/cache/*
*/caches/*
*/smarty/cache/*
*/smarty/templates_c/*

; 用户上传文件
*/uploads/*
*/attachments/*
EOF

    # 创建环境配置文件
    cat > /etc/profile.d/php.sh << EOF
# PHP环境变量
export PATH=\$PATH:${INSTALL_DIR}/bin:${INSTALL_DIR}/sbin
export PHP_INI_SCAN_DIR=${CONF_DIR}/php.d
EOF

# 或者创建一个测试文件
cat > /usr/share/nginx/html/gd_check.php << 'EOF'
<?php
if (extension_loaded('gd')) {
    echo "GD库已安装\n";
    echo "GD版本: " . gd_info()['GD Version'] . "\n";
    print_r(gd_info());
} else {
    echo "GD库未安装\n";
}
?>
EOF

    # 设置权限
    chown -R ${PHP_USER}:${PHP_GROUP} ${LOG_DIR}
    chown -R ${PHP_USER}:${PHP_GROUP} /var/run/php-fpm
    chown -R ${PHP_USER}:${PHP_GROUP} /var/lib/php
    chmod 755 ${CONF_DIR}/php.d
    
    log_info "PHP配置完成"
}

# 创建systemd服务文件
create_systemd_service() {
    log_step "创建systemd服务文件..."
    
    cat > /lib/systemd/system/php-fpm.service << EOF
[Unit]
Description=PHP FastCGI Process Manager
After=network.target nss-lookup.target

[Service]
# 增加操作权限
PermissionsStartOnly=true
Type=forking
PIDFile=/var/run/php-fpm/php-fpm.pid
ExecStartPre=/usr/bin/mkdir -p /var/run/php-fpm
ExecStartPre=/usr/bin/chmod 777 /var/run/php-fpm
ExecStartPre=/usr/bin/touch /var/run/php-fpm/php-fpm.pid
ExecStartPre=/usr/bin/chmod 777 /var/run/php-fpm/php-fpm.pid
ExecStart=${INSTALL_DIR}/sbin/php-fpm --daemonize --fpm-config ${CONF_DIR}/php-fpm.conf
ExecReload=/bin/kill -USR2 \$MAINPID
ExecStop=/bin/kill -QUIT \$MAINPID
PrivateTmp=true
Restart=on-failure
RestartSec=5s
StartLimitInterval=60s
StartLimitBurst=3
User=${PHP_USER}
Group=${PHP_GROUP}

# Security
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=${LOG_DIR} /var/run/php-fpm /var/lib/php
ReadOnlyPaths=/
PrivateDevices=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictNamespaces=true
RestrictRealtime=true
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM
LockPersonality=true
MemoryDenyWriteExecute=true

# 资源限制
LimitNOFILE=65535
LimitNPROC=65535

[Install]
WantedBy=multi-user.target
EOF
    
    # 重新加载systemd配置
    systemctl daemon-reload
    log_info "systemd服务文件创建完成"
}

# 安装PHP扩展
install_php_extensions() {
    log_step "安装常用PHP扩展..."
    
    cd ${TMP_DIR}
    
    # 安装Redis扩展(使用Gitee镜像)
    log_info "安装Redis扩展..."
    if [ ! -d "phpredis" ]; then
        # 克隆指定分支(例如 main 分支)
        # git clone -b develop https://gitee.com/mirrors/phpredis.git
        # 或者克隆特定版本
        git clone -b 6.2.0 https://gitee.com/mirrors/phpredis.git
        cd phpredis
        ${INSTALL_DIR}/bin/phpize
        ./configure --with-php-config=${INSTALL_DIR}/bin/php-config
        make -j$(nproc)
        make install
        cd ..
        echo "extension=redis.so" > ${CONF_DIR}/php.d/redis.ini
        chmod 777 ${CONF_DIR}/php.d/redis.ini
        else
        cd phpredis
        ${INSTALL_DIR}/bin/phpize
        ./configure --with-php-config=${INSTALL_DIR}/bin/php-config
        make -j$(nproc)
        make install
        cd ..
        echo "extension=redis.so" > ${CONF_DIR}/php.d/redis.ini
        chmod 777 ${CONF_DIR}/php.d/redis.ini

    fi
    
    # 安装Memcached扩展(使用Gitee镜像)
    # log_info "安装Memcached扩展..."
    # if [ ! -d "php-memcached" ]; then
    #     git clone https://gitee.com/mirrors/php-memcached.git
    #     cd php-memcached
    #     ${INSTALL_DIR}/bin/phpize
    #     ./configure --with-php-config=${INSTALL_DIR}/bin/php-config --with-libmemcached-dir=/usr
    #     make -j$(nproc)
    #     make install
    #     cd ..
    #     echo "extension=memcached.so" > ${CONF_DIR}/php.d/memcached.ini
    #     chmod 777 ${CONF_DIR}/php.d/memcached.ini
    # fi
    
    # 安装MongoDB扩展(使用Gitee镜像)
    # log_info "安装MongoDB扩展..."
    # if [ ! -d "mongo-php-driver" ]; then
    #     git clone https://gitee.com/mirrors/mongo-php-driver.git
    #     cd mongo-php-driver
    #     git submodule sync && git submodule update --init
    #     ${INSTALL_DIR}/bin/phpize
    #     ./configure --with-php-config=${INSTALL_DIR}/bin/php-config
    #     make -j$(nproc)
    #     make install
    #     cd ..
    #     echo "extension=mongodb.so" > ${CONF_DIR}/php.d/mongodb.ini
    #     chmod 777 ${CONF_DIR}/php.d/mongodb.ini
    # fi
    
    # 安装ImageMagick扩展(使用Gitee镜像)
    log_info "安装ImageMagick扩展..."
    if [ ! -d "imagick" ]; then
        git clone https://gitee.com/mirrors/imagick.git
        cd imagick
        ${INSTALL_DIR}/bin/phpize
        ./configure --with-php-config=${INSTALL_DIR}/bin/php-config
        make -j$(nproc)
        make install
        cd ..
        echo "extension=imagick.so" > ${CONF_DIR}/php.d/imagick.ini
        chmod 777 ${CONF_DIR}/php.d/imagick.ini
        else
        cd imagick
        ${INSTALL_DIR}/bin/phpize
        ./configure --with-php-config=${INSTALL_DIR}/bin/php-config
        make -j$(nproc)
        make install
        cd ..
        echo "extension=imagick.so" > ${CONF_DIR}/php.d/imagick.ini
        chmod 777 ${CONF_DIR}/php.d/imagick.ini
    fi
    
    # 安装yaml扩展
    # log_info "安装yaml扩展..."
    # if [ ! -d "pecl-file_formats-yaml" ]; then
    #     git clone https://gitee.com/mirrors/pecl-file_formats-yaml.git
    #     cd pecl-file_formats-yaml
    #     ${INSTALL_DIR}/bin/phpize
    #     ./configure --with-php-config=${INSTALL_DIR}/bin/php-config --with-yaml=/usr
    #     make -j$(nproc)
    #     make install
    #     cd ..
    #     echo "extension=yaml.so" > ${CONF_DIR}/php.d/yaml.ini
    #   chmod 777 ${CONF_DIR}/php.d/yaml.ini
    # fi
    
    log_info "PHP扩展安装完成"
}

# 安装Composer
install_composer() {
    log_step "安装Composer..."
    
    cd ${TMP_DIR}
    
    # 下载Composer
    ${INSTALL_DIR}/bin/php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
    ${INSTALL_DIR}/bin/php -r "if (hash_file('sha384', 'composer-setup.php') === '906a84df04cea2aa72f40b5f787e49f22d4c2f19492ac310e8cba5b96ac8b64115ac402c8cd292b8a03482574915d1a8') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
    ${INSTALL_DIR}/bin/php composer-setup.php --install-dir=/usr/local/bin --filename=composer
    ${INSTALL_DIR}/bin/php -r "unlink('composer-setup.php');"
    
    # 配置Composer
    composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
    composer config -g secure-http false
    
    log_info "Composer安装完成"
}

# 启动PHP-FPM服务
start_php_fpm() {
    log_step "启动PHP-FPM服务..."
    # 测试配置文件
    ${INSTALL_DIR}/sbin/php-fpm -t
    if [ $? -ne 0 ]; then
        log_error "PHP-FPM配置文件测试失败"
        exit 1
    fi
    log_step "给php-fpm进程相关文件赋予777权限:${LOG_DIR}..."
    chmod -R 777 ${LOG_DIR}/*


    

    # 启动服务
    systemctl start php-fpm
    
    if [ $? -ne 0 ]; then
        log_error "PHP-FPM启动失败"
        journalctl -xe | tail -50
        exit 1
    fi
    
    # 设置开机自启
    systemctl enable php-fpm
    
    # 检查服务状态
    sleep 2
    if systemctl is-active --quiet php-fpm; then
        log_info "PHP-FPM服务运行正常"
    else
        log_error "PHP-FPM服务未运行"
        exit 1
    fi
}

# 设置PHP软链接
setup_php_symlinks() {
    log_info "设置PHP软链接..."

    # 创建全局 PHP 命令链接
    # sudo ln -s ${INSTALL_DIR}/bin/php /usr/bin/php
    # # 创建 phpize 链接
    # sudo ln -s ${INSTALL_DIR}/bin/phpize /usr/bin/phpize
    # # 创建 php-config 链接
    # sudo ln -s ${INSTALL_DIR}/bin/php-config /usr/bin/php-config
    # # 创建 PHP-FPM 链接
    # sudo ln -s ${INSTALL_DIR}/sbin/php-fpm /usr/sbin/php-fpm
    
    for cmd in php phpize php-config; do
        src="${INSTALL_DIR}/bin/$cmd"
        dst="/usr/bin/$cmd"
        
        if [ -f "$src" ]; then
            if [ ! -e "$dst" ] || [ "$(readlink "$dst")" != "$src" ]; then
                echo "创建: $src -> $dst"
                ln -sf "$src" "$dst"
            fi
        fi
    done
    # PHP-FPM
    if [ -f "${INSTALL_DIR}/sbin/php-fpm" ]; then
        ln -sf "${INSTALL_DIR}/sbin/php-fpm" "/usr/sbin/php-fpm"
    fi
}

# 验证安装
# 修改 verify_installation 函数,添加GD库检查
verify_installation() {
    log_step "验证安装..."
    
    # 检查PHP版本
    PHP_VER=$(${INSTALL_DIR}/bin/php -v 2>&1 | head -1)
    log_info "PHP版本: ${PHP_VER}"
    
    # 检查PHP配置
    PHP_CONFIG=$(${INSTALL_DIR}/bin/php --ini 2>&1 | grep "Loaded Configuration File")
    log_info "${PHP_CONFIG}"
    
    # 检查PHP-FPM状态
    PHP_FPM_STATUS=$(systemctl status php-fpm 2>&1 | grep "Active:" | cut -d':' -f2-)
    log_info "PHP-FPM状态: ${PHP_FPM_STATUS}"
    
    # 检查PHP模块
    log_info "已加载的PHP模块:"
    ${INSTALL_DIR}/bin/php -m | grep -E "(^[a-zA-Z])" | sort
    
    # 检查GD库是否正确安装
    if ${INSTALL_DIR}/bin/php -m | grep -q "gd"; then
        log_info "✓ GD库已正确安装"
        # 显示GD库详细信息
        ${INSTALL_DIR}/bin/php -r "if (extension_loaded('gd')) { echo 'GD Version: ' . gd_info()['GD Version'] . PHP_EOL; }"
    else
        log_warn "✗ GD库未安装或未正确加载"
    fi
    
    # 创建测试脚本
    cat > ${NGINX_HTML}/phpinfo.php << 'EOF'
<?php

$client_ip = $_SERVER['REMOTE_ADDR'];
echo "客户端IP: $client_ip" . PHP_EOL;

phpinfo();
EOF
    
    chown ${PHP_USER}:${PHP_GROUP} ${NGINX_HTML}/phpinfo.php
    chmod 644 ${NGINX_HTML}/phpinfo.php
    
    log_info "测试文件已创建: ${NGINX_HTML}/phpinfo.php"
    
    # 测试PHP解析
    log_info "测试PHP解析..."
    if ${INSTALL_DIR}/bin/php -f ${NGINX_HTML}/phpinfo.php > /dev/null 2>&1; then
        log_info "PHP解析测试成功"
    else
        log_warn "PHP解析测试失败"
    fi
}

# 配置防火墙
configure_firewall() {
    log_step "配置防火墙..."
    
    if systemctl is-active --quiet firewalld; then
        log_info "防火墙正在运行"
        # PHP-FPM通常不需要外部端口,仅用于内部通信
    else
        log_warn "防火墙未运行"
    fi
}

# 配置SELinux
configure_selinux() {
    log_step "配置SELinux..."
    
    if command -v sestatus >/dev/null 2>&1 && sestatus | grep -q "enabled"; then
        log_info "SELinux已启用,设置规则..."
        
        # 安装SELinux工具
        yum install -y policycoreutils-python
        
        # 设置PHP相关目录的SELinux上下文
        semanage fcontext -a -t httpd_sys_rw_content_t "${LOG_DIR}(/.*)?"
        semanage fcontext -a -t httpd_sys_rw_content_t "/var/lib/php(/.*)?"
        semanage fcontext -a -t httpd_sys_rw_content_t "/var/run/php-fpm(/.*)?"
        
        restorecon -Rv ${LOG_DIR}
        restorecon -Rv /var/lib/php
        restorecon -Rv /var/run/php-fpm
        
        # 允许PHP-FPM访问网络
        setsebool -P httpd_can_network_connect 1
        
        log_info "SELinux配置完成"
    else
        log_info "SELinux已禁用或未安装"
    fi
}

# 优化系统参数
optimize_system() {
    log_step "优化系统参数..."
    
    # 调整文件描述符限制
    cat >> /etc/security/limits.conf << EOF
* soft nofile 65535
* hard nofile 65535
${PHP_USER} soft nofile 65535
${PHP_USER} hard nofile 65535
EOF
    
    # 调整内核参数
    cat >> /etc/sysctl.conf << EOF
# PHP优化参数
net.core.somaxconn = 32768
net.ipv4.tcp_max_syn_backlog = 262144
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 0
net.ipv4.ip_local_port_range = 20000 65000
fs.file-max = 65535
EOF
    
    # 应用内核参数
    sysctl -p
    
    log_info "系统参数优化完成"
}

# 显示安装信息
show_installation_info() {
    systemctl reload php-fpm
    log_step "==================== PHP安装完成 ===================="
    echo "PHP版本: ${PHP_VERSION}"
    echo "安装目录: ${INSTALL_DIR}"
    echo "配置目录: ${CONF_DIR}"
    echo "日志目录: ${LOG_DIR}"
    echo "运行用户: ${PHP_USER}:${PHP_GROUP}"
    echo "PHP-FPM端口: ${PHP_FPM_PORT}"
    echo "服务状态: $(systemctl is-active php-fpm)"
    echo "开机自启: $(systemctl is-enabled php-fpm)"
    echo ""
    echo "配置文件:"
    echo "  php.ini: ${CONF_DIR}/php.ini"
    echo "  php-fpm.conf: ${CONF_DIR}/php-fpm.conf"
    echo "  www.conf: ${CONF_DIR}/php-fpm.d/www.conf"
    echo "  扩展配置: ${CONF_DIR}/php.d/"
    echo ""
    echo "常用命令:"
    echo "  启动: systemctl start php-fpm"
    echo "  停止: systemctl stop php-fpm"
    echo "  重启: systemctl restart php-fpm"
    echo "  重载: systemctl reload php-fpm"
    echo "  状态: systemctl status php-fpm"
    echo "  测试: ${INSTALL_DIR}/sbin/php-fpm -t"
    echo "  版本: ${INSTALL_DIR}/bin/php -v"
    echo "  模块: ${INSTALL_DIR}/bin/php -m"
    echo ""
    echo "环境变量:"
    echo "  PHP路径已添加到系统PATH"
    echo "  Composer已安装: /usr/local/bin/composer"
    echo ""
    echo "日志文件:"
    echo "  PHP-FPM错误日志: ${LOG_DIR}/fpm/error.log"
    echo "  PHP-FPM慢日志: ${LOG_DIR}/fpm/www-slow.log"
    echo "  PHP CLI错误日志: ${LOG_DIR}/cli/error.log"
    echo ""
    echo "测试脚本: ${NGINX_HTML}/phpinfo.php (仅限本地访问)"
    log_step "======================================================"
}

# 清理临时文件
cleanup() {
    log_step "清理临时文件..."
    
    if [ -d "${TMP_DIR}" ]; then
        rm -rf ${TMP_DIR}
        log_info "已清理临时目录: ${TMP_DIR}"
    fi
    
    # 清理yum缓存
    yum clean all
    
    log_info "清理完成"
}

# 主函数
main() {
    log_step "开始安装PHP ${PHP_VERSION}"
    
    # 执行安装步骤
    check_root
    check_centos_version
    create_directories
    create_php_user
    install_dependencies
    download_php_source
    compile_dependencies
    compile_php
    configure_php
    install_php_extensions
    create_systemd_service
    configure_firewall
    #统一安装SELinux,有独立的安装步骤
    # configure_selinux
    optimize_system
    start_php_fpm
    setup_php_symlinks
    # install_composer
    verify_installation
    show_installation_info
    # cleanup
    log_step "PHP ${PHP_VERSION} 安装完成!"
}

# 执行主函数
main "$@"
相关推荐
ServBay18 分钟前
垃圾堆里编码?真的不要怪 PHP 不行
后端·php
用户962377954483 小时前
CTF 伪协议
php
BingoGo2 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php
JaguarJack2 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php·服务端
BingoGo3 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php
JaguarJack3 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php·服务端
JaguarJack4 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
后端·php·服务端
BingoGo4 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
php
JaguarJack5 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·php·laravel
郑州光合科技余经理6 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php