You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP调用ftp_put上传至vsftpd失败,报错php_connect_nonb() failed

问题描述

尝试通过PHP将文件上传到vsftpd FTP服务器时失败,调用ftp_put()后执行print_r(error_get_last())得到以下错误:

Warning: ftp_put(): php_connect_nonb() failed: No error (0)
Warning: ftp_put(): Switching to Binary mode.
Fatal error: Maximum execution time of 60 seconds exceeded

文件未成功上传,但使用FileZilla可以正常上传相同文件。

vsftpd配置(已开放20、21、990、4000-5000端口)

listen=NO
listen_ipv6=YES
anonymous_enable=NO
local_enable=YES
write_enable=YES
dirmessage_enable=YES
use_localtime=YES
xferlog_enable=YES
connect_from_port_20=YES
chroot_local_user=YES
secure_chroot_dir=/var/run/vsftpd/empty
pam_service_name=vsftpd
rsa_cert_file=/etc/ssl/private/vsftpd.pem
rsa_private_key_file=/etc/ssl/private/vsftpd.pem
ssl_enable=NO
allow_writeable_chroot=YES
pasv_min_port=40000
pasv_max_port=50000
userlist_enable=YES
userlist_file=/etc/vsftpd.userlist
userlist_deny=NO

PHP上传脚本

public function upload($file, $path, $fileName){
        global $ftp_config;

        $conn_id = ftp_connect($ftp_config['host']);
        if($conn_id)
        {
            $login_result = ftp_login($conn_id, $ftp_config['username'], $ftp_config['password']);
            ftp_pasv($conn_id, true);

            print_r('/'.$path.''.$fileName);

            $upload = ftp_put($conn_id, '/'.$path.''.$fileName, $file, FTP_IMAGE);
            print_r(error_get_last());
            return $upload;
        }
        return false;
    }

解决思路
  • 修正被动模式端口范围匹配
    你的vsftpd配置中被动模式端口范围是40000-50000,但你实际开放的是4000-5000,两者完全不匹配。FileZilla能成功可能是因为客户端与服务器处于同一局域网或防火墙有特殊规则,但PHP脚本运行时无法连接到正确的被动端口,最终导致超时。必须开放配置文件中指定的40000-50000端口范围。

  • 添加登录结果校验
    当前脚本未检查ftp_login的返回值,可能登录失败却仍执行后续上传逻辑。修改脚本增加验证:

    $login_result = ftp_login($conn_id, $ftp_config['username'], $ftp_config['password']);
    if (!$login_result) {
        ftp_close($conn_id);
        return false;
    }
    
  • 验证目标路径权限
    确认FTP用户对上传目标路径/'.$path.''.$fileName拥有写入权限,同时检查目标目录是否存在(可通过ftp_mkdir提前创建或ftp_chdir验证)。

  • 尝试切换主动模式
    暂时注释被动模式代码,测试主动模式是否能正常上传:

    // ftp_pasv($conn_id, true); // 注释此行,使用主动模式
    

    若主动模式成功,说明被动模式的端口映射或防火墙配置仍有问题。

  • 改用非阻塞上传排查超时
    使用ftp_nb_put()替代ftp_put(),避免因阻塞导致的超时,同时获取更精准的上传状态:

    $upload = ftp_nb_put($conn_id, '/'.$path.''.$fileName, $file, FTP_IMAGE);
    while ($upload == FTP_MOREDATA) {
        $upload = ftp_nb_continue($conn_id);
    }
    if ($upload != FTP_FINISHED) {
        error_log("FTP上传失败,状态码: {$upload}");
        return false;
    }
    

内容的提问来源于stack exchange,提问作者Maksim Chesnokov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 19:14:55