使用PHP copy函数跨服务器复制大文件失败求助
解决PHP复制大文件后损坏的问题
先排查权限问题
不一定是权限,但先快速排除:
- 检查
datafile目录的权限:确保运行PHP的用户(通常是www-data、apache或nginx)有写入权限。可以用命令行执行chmod 755 datafile(给所有用户读/执行权限,所有者写权限),或者chown www-data:www-data datafile(把目录所有权转给PHP进程用户)。 - 对比本地生成的文件大小和原文件(10GB):如果本地文件远小于10GB,说明是传输中断/未完成,不是权限问题;如果大小一致但仍损坏,再考虑权限或文件系统问题。
为什么copy()函数会失败?
copy()函数仅适合小文件,处理大文件时容易触发以下问题:
- PHP的
max_execution_time限制:默认执行时间通常是30秒,10GB文件下载远超这个时间,会被强制中断导致文件不完整。 - 内存限制:
copy()会尝试把文件内容加载到内存,大文件直接撑爆memory_limit。 - 网络不稳定:无断点续传机制,中途断连后文件直接损坏。
可行解决方案
方案1:用cURL流式下载(推荐,稳定且可控)
cURL支持流式传输,不会一次性加载整个文件到内存,还能设置超时、跟随跳转等:
<?php // 源文件URL $remote_file_url = 'http://speedtest.tele2.net/10GB.zip'; // 本地保存路径 $local_file = 'datafile/DL-10GB.zip'; // 临时调整PHP执行限制(避免超时) ini_set('max_execution_time', 0); // 0表示无时间限制,也可设36000(10小时) ini_set('memory_limit', '256M'); // 流式下载内存占用低,256M足够 // 初始化cURL $ch = curl_init($remote_file_url); // 打开本地文件句柄 $fp = fopen($local_file, 'wb'); // 设置cURL选项 curl_setopt($ch, CURLOPT_FILE, $fp); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // 跟随重定向 curl_setopt($ch, CURLOPT_TIMEOUT, 0); // 无超时限制 curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0'); // 模拟浏览器UA,避免被源站拦截 // 执行下载 $success = curl_exec($ch); // 关闭资源 fclose($fp); curl_close($ch); // 检查结果 if (!$success) { echo "下载失败:" . curl_error($ch); } else { // 可选:验证文件完整性(源站10GB.zip的SHA256哈希值:53d6fe6b4d79938e48780a42e81b0578500d45e407412f91a9ed2b439425d3f5) $local_hash = hash_file('sha256', $local_file); $source_hash = '53d6fe6b4d79938e48780a42e81b0578500d45e407412f91a9ed2b439425d3f5'; if ($local_hash === $source_hash) { echo "下载成功且文件完整!"; } else { echo "下载完成但文件损坏,请重新下载!"; } } ?>
方案2:用PHP原生fopen分段读写
如果服务器未启用cURL,可以用分段读写的方式,每次读取一小块数据写入本地:
<?php $remote_file_url = 'http://speedtest.tele2.net/10GB.zip'; $local_file = 'datafile/DL-10GB.zip'; ini_set('max_execution_time', 0); ini_set('memory_limit', '256M'); // 打开远程文件(需开启allow_url_fopen) $remote_fp = fopen($remote_file_url, 'rb'); if (!$remote_fp) { die("无法打开远程文件"); } // 打开本地文件 $local_fp = fopen($local_file, 'wb'); if (!$local_fp) { fclose($remote_fp); die("无法创建本地文件"); } // 分段读写,每次1MB $chunk_size = 1024 * 1024; while (!feof($remote_fp)) { $chunk = fread($remote_fp, $chunk_size); fwrite($local_fp, $chunk); } // 关闭资源 fclose($remote_fp); fclose($local_fp); // 验证完整性 $local_hash = hash_file('sha256', $local_file); $source_hash = '53d6fe6b4d79938e48780a42e81b0578500d45e407412f91a9ed2b439425d3f5'; if ($local_hash === $source_hash) { echo "下载成功且文件完整!"; } else { echo "下载完成但文件损坏,请重新下载!"; } ?>
额外注意事项
- 确保服务器开启
allow_url_fopen(方案2需要),或者开启cURL扩展(方案1需要),可通过phpinfo()查看配置。 - 检查服务器磁盘空间是否足够(至少10GB剩余)。
- 大文件下载建议用CLI模式后台执行,避免网页超时中断。
内容的提问来源于stack exchange,提问作者Nimesh
相关产品推荐
相关产品推荐

