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

PHP通过fopen写入远程FTP服务器仅生成空文件问题求助

问题描述

将表单数据保存到远程FTP服务器时遇到异常:

  • 本地路径保存完全正常,代码如下:
    $filename = "/home/fvaeytm/test/uploads/user_dirs/$user_login".date("Ymdhis").".txt";
    
  • 修改为FTP路径后:
    $filename = "ftp://pi:pi@ftp.domain.com/home/pi/test/" . $user_login . date("Ymdhis") . ".txt";
    
    远程FTP服务器会创建文件名正确的空文件,且文件生成后约30秒内无法打开。
  • 核心代码逻辑:
    $filename = "/home/fvaeytm/test/uploads/user_dirs/$user_login".date("Ymdhis").".txt";
    
    $myfile = fopen($filename, "w");
    
    fwrite($myfile, $Name."\n");
    fwrite($myfile, $Number."\n");
    fclose($myfile);
    
    echo "<div id='success_page'>";
    echo "<p>OK</p>";
    echo "</div>";
    }
    
  • 已确认信息:
    1. PHP的allow_url_fopen已设置为On
    2. 修改FTP服务器文件权限无效果
    3. 在OVH的FTP服务器测试正常,但自家两台FTP(OpenWrt和Debian树莓派)均出现相同问题
    4. 通过FTP客户端使用外网IP连接自家服务器,可正常创建并写入文件,域名托管在Cloudflare且已关闭SSL
解决方案

针对家用FTP服务器出现的空文件问题,可按以下步骤排查修复:

1. 强制启用被动模式(Passive Mode)

家用FTP服务器通常处于NAT环境下,PHP默认的fopen使用FTP主动模式可能导致数据连接失败,无法写入内容。可以通过stream_context_create指定被动模式:

// 创建FTP上下文,启用被动模式
$context = stream_context_create([
    'ftp' => [
        'passive' => true,
    ]
]);

// 打开文件时传入上下文
$myfile = fopen($filename, "w", false, $context);

// 后续写入、关闭逻辑保持不变
fwrite($myfile, $Name."\n");
fwrite($myfile, $Number."\n");
fclose($myfile);

2. 检查FTP服务器的被动模式端口范围映射

如果启用被动模式后仍有问题,需确认家用路由器是否正确映射了FTP服务器的被动模式端口范围(通常是一段端口,比如21000-22000),并在FTP服务器配置中指定该端口范围:

  • 对于vsftpd(Debian树莓派常用):在/etc/vsftpd.conf中添加
    pasv_min_port=21000
    pasv_max_port=22000
    
    然后重启vsftpd服务
  • 对于OpenWrt上的FTP服务(如pure-ftpd):在配置中指定被动端口范围,同时在路由器防火墙中开放对应端口

3. 替换为FTP扩展函数(更可靠的方式)

PHP的allow_url_fopen通过FTP协议写入的兼容性有限,改用专门的FTP扩展函数(ftp_connect、ftp_login、ftp_put等)能获得更好的兼容性和错误排查能力:

// FTP服务器信息
$ftp_host = 'ftp.domain.com';
$ftp_user = 'pi';
$ftp_pass = 'pi';
$remote_dir = '/home/pi/test/';
$local_temp_file = tempnam(sys_get_temp_dir(), 'form_data');

// 先将内容写入本地临时文件
$temp_handle = fopen($local_temp_file, 'w');
fwrite($temp_handle, $Name."\n");
fwrite($temp_handle, $Number."\n");
fclose($temp_handle);

// 连接FTP服务器
$conn_id = ftp_connect($ftp_host);
$login_result = ftp_login($conn_id, $ftp_user, $ftp_pass);

// 启用被动模式
ftp_pasv($conn_id, true);

// 上传临时文件到远程服务器
$remote_filename = $remote_dir . $user_login . date("Ymdhis") . ".txt";
if (ftp_put($conn_id, $remote_filename, $local_temp_file, FTP_BINARY)) {
    echo "<div id='success_page'><p>OK</p></div>";
} else {
    echo "<div id='error_page'><p>上传失败</p></div>";
}

// 关闭连接并删除临时文件
ftp_close($conn_id);
unlink($local_temp_file);

这种方式能更直观地排查连接、登录、上传各环节的错误,适合家用复杂网络环境。

4. 检查PHP的FTP扩展是否启用

如果使用上述FTP扩展函数时出现错误,需确认PHP的FTP扩展已启用:

  • 在PHP配置文件(php.ini)中确保extension=ftp未被注释
  • 重启Web服务器后,通过phpinfo()查看FTP扩展是否加载成功

5. 禁用Cloudflare的代理(临时测试)

虽然你已关闭SSL,但Cloudflare的DNS代理可能仍会影响FTP连接,可临时将域名切换为「DNS only」模式,直接解析到家用服务器外网IP,测试是否能正常写入。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 16:13:09