#!/bin/bash set -e echo "=== ThinkPHP Docker权限初始化 ===" # 定义应用根目录,支持参数传入 APP_ROOT="${1:-/var/www/html}" echo "使用应用根目录: $APP_ROOT" if [ $# -eq 1 ]; then echo "✅ 使用传入参数: $1" else echo "✅ 使用默认参数: /var/www/html" fi # 获取正确的用户和组 if [ -n "$USER_ID" ] && [ -n "$GROUP_ID" ]; then # 如果指定了用户ID,修改www-data usermod -u $USER_ID www-data groupmod -g $GROUP_ID www-data fi echo "当前用户: $(whoami)" echo "UID: $(id -u), GID: $(id -g)" # 修复目录所有权和权限 fix_directory_permissions() { local dir=$1 echo "修复PHP目录权限: $dir" # 确保目录存在 mkdir -p "$dir" # 设置所有权 chown -R www-data:www-data "$dir" # 设置权限 chmod -R 775 "$dir" # 设置setgid权限 chmod g+s "$dir" # 尝试设置ACL(如果支持) if command -v setfacl >/dev/null 2>&1; then setfacl -dR -m u:www-data:rwx "$dir" fi find "$dir" -type d -exec chmod 775 {} \; find "$dir" -type f -exec chmod 775 {} \; find "$dir" -type d -exec chmod g+s {} \; find "$dir" -type f -exec chmod g+s {} \; # 设置umask umask 0002 echo "✅ $dir 权限设置完成, 目录权限: $(stat -c '%a %n' "$dir"), setgid权限: $(stat -c '%a %n' "$dir" | grep 's')" } # 处理所有需要权限的目录 directories=("addon" "app" "config" "extend" "public" "runtime" "upload" "runtime/log" "runtime/cache" "runtime/temp") for dir in "${directories[@]}"; do fix_directory_permissions "$APP_ROOT/$dir" done # 验证权限 echo "=== 权限验证 ===" echo "当前用户: $(whoami)" echo "当前UID: $(id -u), GID: $(id -g)" echo "当前umask: $(umask)" # 验证www-data用户是否可以在runtime和upload目录下新建子目录 # 方法1:使用sudo if command -v sudo >/dev/null 2>&1; then echo "使用sudo测试..." if sudo -u www-data mkdir -p $APP_ROOT/runtime/log/test_dir 2>/dev/null; then echo "✅ sudo: runtime目录创建子目录成功 [使用www-data用户]" rm -rf $APP_ROOT/runtime/log/test_dir else echo "❌ sudo: runtime目录创建子目录失败 [使用www-data用户]" fi fi # 方法2:使用su echo "使用su测试..." if su -s /bin/sh -c "mkdir -p $APP_ROOT/runtime/log/test_dir" www-data 2>/dev/null; then echo "✅ su: runtime目录创建子目录成功 [使用www-data用户]" rm -rf $APP_ROOT/runtime/log/test_dir else echo "❌ su: runtime目录创建子目录失败 [使用www-data用户]" fi # 方法3:使用runuser if command -v runuser >/dev/null 2>&1; then echo "使用runuser测试..." if runuser -u www-data -- mkdir -p $APP_ROOT/runtime/log/test_dir 2>/dev/null; then echo "✅ runuser: runtime目录创建子目录成功 [使用www-data用户]" rm -rf $APP_ROOT/runtime/log/test_dir else echo "❌ runuser: runtime目录创建子目录失败 [使用www-data用户]" fi fi # 检查www-data用户和组 echo "检查www-data用户..." id www-data groups www-data # 检查目录的实际权限 echo "检查目录权限..." for dir in "${directories[@]}"; do echo "检查目录权限: $dir" ls -ld "$APP_ROOT/$dir" done echo "检查setgid权限..." for dir in "${directories[@]}"; do echo "检查setgid权限: $dir" stat -c '%a %n' "$APP_ROOT/$dir" | grep 's' done echo "=== 检测 PHP 执行用户 ===" # 检查命令可用性函数 command_exists() { command -v "$1" >/dev/null 2>&1 } # 方法1:通过 PHP 脚本检测当前用户 echo "方法1: 通过 PHP 检测当前执行用户" if command_exists php; then php -r " if (function_exists('get_current_user')) { echo '当前 PHP 执行用户: ' . get_current_user() . PHP_EOL; } else { echo 'get_current_user() 函数不可用' . PHP_EOL; } if (function_exists('getmyuid')) { echo '当前用户 ID: ' . getmyuid() . PHP_EOL; } else { echo 'getmyuid() 函数不可用' . PHP_EOL; } if (function_exists('getmygid')) { echo '当前组 ID: ' . getmygid() . PHP_EOL; } else { echo 'getmygid() 函数不可用' . PHP_EOL; } if (function_exists('posix_geteuid') && function_exists('posix_getpwuid')) { echo '当前进程用户: ' . posix_getpwuid(posix_geteuid())['name'] . PHP_EOL; } else { echo 'posix 函数不可用,尝试系统方法' . PHP_EOL; echo '当前用户: ' . exec('whoami') . PHP_EOL; } " 2>/dev/null || echo "PHP 执行检测失败" else echo "❌ PHP 命令不可用,跳过检测" fi # 方法2:通过进程检测 PHP-FPM 运行用户 echo "方法2: 检测 PHP-FPM 进程用户" if command_exists pgrep; then if pgrep php-fpm > /dev/null 2>&1; then if command_exists ps; then ps aux | grep php-fpm | grep -v grep | head -3 2>/dev/null || echo "进程检测失败" else echo "ps 命令不可用,但找到 PHP-FPM 进程" fi else echo "PHP-FPM 进程未运行" fi else echo "pgrep 命令不可用,尝试其他方法" if command_exists ps; then echo "使用 ps 直接检测:" ps aux | grep php-fpm | grep -v grep | head -3 2>/dev/null || echo "未找到 PHP-FPM 进程" else echo "ps 和 pgrep 命令都不可用,无法检测进程" fi fi # 方法3:检测配置文件中的用户设置 echo "方法3: 检查配置文件中的用户设置" # PHP-FPM 配置检查 php_fpm_configs=( "/usr/local/etc/php-fpm.d/www.conf" "/etc/php-fpm.d/www.conf" "/usr/local/etc/php-fpm.conf" "/etc/php-fpm.conf" ) for config_file in "${php_fpm_configs[@]}"; do if [ -f "$config_file" ]; then echo "找到 PHP-FPM 配置: $config_file" if command_exists grep; then echo "PHP-FPM 用户配置:" grep -E "^user|^group" "$config_file" 2>/dev/null || echo "未找到用户配置行" else echo "grep 命令不可用,但配置文件存在" fi break fi done # Nginx 配置检查 nginx_configs=( "/etc/nginx/nginx.conf" "/usr/local/nginx/conf/nginx.conf" "/etc/nginx/conf/nginx.conf" ) for config_file in "${nginx_configs[@]}"; do if [ -f "$config_file" ]; then echo "找到 Nginx 配置: $config_file" if command_exists grep; then echo "Nginx 用户配置:" grep -E "^user" "$config_file" 2>/dev/null || echo "未找到用户配置行" else echo "grep 命令不可用,但配置文件存在" fi break fi done # 方法4:使用 /proc 文件系统检测(如果其他方法都失败) echo "方法4: 使用 /proc 文件系统检测" if [ -d "/proc" ]; then echo "当前脚本执行用户: $(whoami 2>/dev/null || echo 'whoami 命令不可用')" echo "当前脚本用户 ID: $(id -u 2>/dev/null || echo 'id 命令不可用')" else echo "/proc 目录不可用" fi echo "=== 启动应用 ===" # 执行原有的启动命令 exec "$@"