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
相关产品推荐
相关产品推荐

