先确认报错函数是否在disable_functions列表中,再针对性解禁;需同步检查Web和CLI环境的php.ini与php-cli.ini配置,站点级解禁更安全,同时验证扩展是否启用及open_basedir等限制。

直接结论:别一股脑全放开,先看报错函数是不是真被禁了,再决定要不要解禁、怎么解禁。
确认报错函数是否在 disable_functions 列表里
很多“未定义函数”错误其实就卡在这一步。宝塔默认禁用 exec、shell_exec、proc_open、putenv 等,但你代码里调用的可能是 pcntl_fork 或 symlink 这类冷门但同样被拦的函数。
- 打开宝塔 → 软件商店 → 找到你站点用的 PHP 版本(比如 84)→ 设置 → 配置修改 → 搜索
disable_functions - 把报错信息里的函数名(比如
putenv)复制进去,挨个对照列表里有没有 - 注意逗号分隔格式:删掉函数名时要连同前后逗号一起处理,否则整行失效,PHP 启动都可能失败
- 改完必须点“重载配置”或“重启 PHP”,只保存不生效
别忽略 CLI 环境下的禁用函数
有些工具(比如 Composer、Laravel 的 php artisan、Zabbix 前端)走的是 PHP CLI 模式,而宝塔对 CLI 和 Web 环境用了两套配置——php.ini 管 Web,php-cli.ini 管命令行。你 Web 端解禁了,CLI 还可能报错。
- 检查路径:
/www/server/php/84/etc/php-cli.ini(版本号按实际替换) - 如果该文件存在,也打开搜
disable_functions,把需要的函数同样删掉 - 终端执行
/www/server/php/84/bin/php -r "echo function_exists('proc_open') ? 'yes' : 'no';",输出yes才算 CLI 层真正解开了 - 常见踩坑:只改了
php.ini,忘了php-cli.ini,结果 Composer 安装卡在proc_open报错
网站级解禁比全局更安全
如果你只是某个站点要用 exec 执行系统命令(比如生成 PDF、调用 ffmpeg),其他站点完全不需要,那就不该全局放开——这等于给所有站点埋雷。
- 进宝塔 → 网站 → 找到目标站点 → 设置 → 配置文件 → 拉到最下面“PHP 配置文件”区域,点编辑
- 新增一行:
disable_functions =(等号后留空,表示清空该站点的禁用列表) - 或者更精细地写:
disable_functions = pcntl_exec,pcntl_signal(只放开真正需要的) - 这种写法优先级高于全局
php.ini,且不影响其他站点 - 注意:这个配置只对当前站点的 PHP-FPM 进程生效,和 CLI 无关
解禁之后还要验证扩展是否加载
函数被禁用只是原因之一;另一个高频原因是函数所属的扩展根本没启用。比如 mb_strlen 报错,不一定是被禁用了,而是 mbstring 扩展压根没装。
- 进宝塔 → 软件商店 → PHP 8.4 → 设置 → 安装扩展,勾选
mbstring、openssl、pdo_mysql、gd等基础项 - 终端运行
/www/server/php/84/bin/php -m | grep mbstring,确认输出中有mbstring - 再跑一次
/www/server/php/84/bin/php -r "print_r(get_defined_functions()['internal']);",搜索目标函数名,确保它真的出现在返回列表里 - 特别注意:某些函数(如
imagettftext)依赖 GD 库编译时带 freetype 支持,光装扩展不一定够,得看宝塔安装时是否选了“完整版”
真正容易被忽略的是:函数解禁了,扩展也启了,但程序仍报错——这时候大概率是 open_basedir 或文件权限卡住了。比如 Laravel 的 storage 目录不可写,或 ThinkPHP 尝试读 /proc/uptime 被 open_basedir 拦住。这些和函数禁用无关,但错误表现高度相似,排查时别死磕一个方向。

















