ftp_append() 函数用于向 FTP 服务器上的文件追加内容。
该函数可以将数据追加到远程文件的末尾,如果文件不存在,则会创建新文件。与 ftp_put() 函数不同,ftp_append() 不会覆盖现有文件内容,而是在文件末尾添加新内容。
ftp_append ( resource $ftp_stream , string $remote_file , string $local_file [, int $mode = FTP_BINARY ] ) : bool
| 参数 | 类型 | 描述 |
|---|---|---|
$ftp_stream |
resource | 必需的。FTP 连接的标识符,由 ftp_connect() 或 ftp_ssl_connect() 返回。 |
$remote_file |
string | 必需的。远程文件的路径(在 FTP 服务器上),内容将被追加到此文件。 |
$local_file |
string | 必需的。本地文件的路径,其内容将被追加到远程文件。 |
$mode |
int | 可选的。传输模式。必须是 FTP_ASCII 或 FTP_BINARY。默认为 FTP_BINARY。 |
| 返回值 | 描述 |
|---|---|
true |
追加操作成功完成。 |
false |
追加操作失败。可能的原因包括:
|
以下示例展示了如何向 FTP 服务器上的文件追加内容。
<?php
// 连接 FTP 服务器
$ftp_server = "ftp.example.com";
$ftp_user = "username";
$ftp_pass = "password";
$conn = ftp_connect($ftp_server);
if (!$conn) {
die("无法连接到 $ftp_server");
}
// 登录
if (!@ftp_login($conn, $ftp_user, $ftp_pass)) {
die("登录失败");
}
// 创建本地文件内容
$local_file = "log_entry.txt";
$log_content = "[" . date('Y-m-d H:i:s') . "] 用户登录成功\n";
file_put_contents($local_file, $log_content);
// 远程日志文件
$remote_file = "logs/application.log";
// 追加内容到远程文件
if (ftp_append($conn, $remote_file, $local_file, FTP_ASCII)) {
echo "日志条目已成功追加到远程文件\n";
// 获取文件大小以验证追加
$file_size = ftp_size($conn, $remote_file);
if ($file_size != -1) {
echo "远程文件大小: " . $file_size . " 字节\n";
}
} else {
echo "追加内容失败\n";
// 检查远程文件是否存在,如果不存在则创建
if (ftp_size($conn, $remote_file) == -1) {
echo "远程文件不存在,尝试创建新文件...\n";
if (ftp_put($conn, $remote_file, $local_file, FTP_ASCII)) {
echo "已创建新文件并写入内容\n";
}
}
}
// 清理本地临时文件
unlink($local_file);
// 关闭连接
ftp_close($conn);
?>
如果需要追加字符串而不是文件内容,可以先创建临时文件。
<?php
$conn = ftp_connect("ftp.example.com");
ftp_login($conn, "username", "password");
/**
* 向远程文件追加字符串内容
* @param resource $conn FTP连接
* @param string $remote_file 远程文件路径
* @param string $content 要追加的内容
* @param int $mode 传输模式
* @return bool 成功返回true,失败返回false
*/
function ftp_append_string($conn, $remote_file, $content, $mode = FTP_ASCII) {
// 创建临时文件
$temp_file = tempnam(sys_get_temp_dir(), 'ftp_append_');
if ($temp_file === false) {
return false;
}
// 写入内容到临时文件
if (file_put_contents($temp_file, $content) === false) {
unlink($temp_file);
return false;
}
// 追加内容到远程文件
$result = ftp_append($conn, $remote_file, $temp_file, $mode);
// 清理临时文件
unlink($temp_file);
return $result;
}
// 使用示例
$remote_log = "logs/system.log";
$log_entry = sprintf("[%s] %s: %s\n",
date('Y-m-d H:i:s'),
'INFO',
'系统运行正常,内存使用率: 45%'
);
if (ftp_append_string($conn, $remote_log, $log_entry, FTP_ASCII)) {
echo "日志条目已成功追加\n";
// 验证追加结果
$temp_file = tempnam(sys_get_temp_dir(), 'ftp_verify_');
if (ftp_get($conn, $temp_file, $remote_log, FTP_ASCII)) {
$last_line = tail_file($temp_file, 1);
echo "最后一条日志: " . trim($last_line) . "\n";
unlink($temp_file);
}
} else {
echo "追加日志失败\n";
}
/**
* 获取文件最后几行
*/
function tail_file($filename, $lines = 10) {
$file_content = file($filename, FILE_IGNORE_NEW_LINES);
if ($file_content === false) {
return '';
}
$tail = array_slice($file_content, -$lines);
return implode("\n", $tail);
}
ftp_close($conn);
?>
将多个本地文件的内容追加到同一个远程文件。
<?php
// 连接和登录
$conn = ftp_connect("ftp.example.com");
ftp_login($conn, "username", "password");
// 远程合并文件
$remote_merged_file = "data/merged_data.txt";
// 本地文件列表
$local_files = [
"data/file1.txt",
"data/file2.txt",
"data/file3.txt"
];
echo "开始合并文件到远程服务器...\n";
foreach ($local_files as $local_file) {
if (!file_exists($local_file)) {
echo "跳过不存在的文件: $local_file\n";
continue;
}
echo "处理文件: $local_file\n";
if (ftp_append($conn, $remote_merged_file, $local_file, FTP_ASCII)) {
$file_size = filesize($local_file);
echo " 成功追加 ($file_size 字节)\n";
} else {
echo " 追加失败\n";
// 如果是第一个文件且远程文件不存在,使用 ftp_put 创建文件
if (ftp_size($conn, $remote_merged_file) == -1) {
echo " 远程文件不存在,尝试创建...\n";
if (ftp_put($conn, $remote_merged_file, $local_file, FTP_ASCII)) {
echo " 文件创建成功\n";
}
}
}
}
// 验证结果
$final_size = ftp_size($conn, $remote_merged_file);
if ($final_size != -1) {
echo "\n合并完成!\n";
echo "最终文件大小: $final_size 字节\n";
// 计算预期的总大小
$expected_size = 0;
foreach ($local_files as $local_file) {
if (file_exists($local_file)) {
$expected_size += filesize($local_file);
}
}
echo "预期总大小: $expected_size 字节\n";
if ($final_size == $expected_size) {
echo "✓ 文件大小匹配,合并成功!\n";
} else {
echo "⚠ 文件大小不匹配,可能存在数据丢失\n";
}
}
ftp_close($conn);
?>
完整的错误处理机制,包括重试和恢复。
<?php
/**
* 安全的 FTP 追加函数,包含错误处理和重试机制
*/
class SafeFTPAppend {
private $conn;
private $max_retries = 3;
private $retry_delay = 1; // 秒
public function __construct($server, $username, $password, $port = 21) {
$this->conn = ftp_connect($server, $port, 30);
if (!$this->conn) {
throw new Exception("无法连接到 FTP 服务器");
}
if (!ftp_login($this->conn, $username, $password)) {
throw new Exception("FTP 登录失败");
}
// 启用被动模式
ftp_pasv($this->conn, true);
}
/**
* 安全地追加内容到远程文件
*/
public function safeAppend($remote_file, $local_file, $mode = FTP_BINARY) {
$retry_count = 0;
while ($retry_count < $this->max_retries) {
try {
// 检查本地文件
if (!file_exists($local_file) || !is_readable($local_file)) {
throw new Exception("本地文件不存在或不可读: $local_file");
}
// 检查远程文件权限(如果存在)
if (ftp_size($this->conn, $remote_file) != -1) {
// 文件存在,检查是否可写(通过尝试获取文件信息)
$file_info = @ftp_mdtm($this->conn, $remote_file);
if ($file_info === -1) {
throw new Exception("远程文件不可写或权限不足: $remote_file");
}
}
// 执行追加操作
$result = ftp_append($this->conn, $remote_file, $local_file, $mode);
if ($result) {
// 验证追加结果
$initial_size = $this->getRemoteFileSize($remote_file, true);
$local_size = filesize($local_file);
$expected_size = $initial_size + $local_size;
$final_size = $this->getRemoteFileSize($remote_file);
if ($final_size >= $expected_size) {
return [
'success' => true,
'message' => "内容追加成功",
'initial_size' => $initial_size,
'added_size' => $local_size,
'final_size' => $final_size,
'retries' => $retry_count
];
} else {
throw new Exception("文件大小验证失败,可能追加不完整");
}
} else {
throw new Exception("ftp_append() 返回 false");
}
} catch (Exception $e) {
$retry_count++;
if ($retry_count >= $this->max_retries) {
return [
'success' => false,
'message' => "追加失败,已达到最大重试次数",
'error' => $e->getMessage(),
'retries' => $retry_count
];
}
echo "尝试 $retry_count 失败,{$this->retry_delay}秒后重试...\n";
sleep($this->retry_delay);
// 指数退避增加延迟
$this->retry_delay *= 2;
}
}
return [
'success' => false,
'message' => "未知错误",
'retries' => $retry_count
];
}
/**
* 获取远程文件大小,带缓存避免重复调用
*/
private function getRemoteFileSize($remote_file, $use_cache = false) {
static $size_cache = [];
if ($use_cache && isset($size_cache[$remote_file])) {
return $size_cache[$remote_file];
}
$size = ftp_size($this->conn, $remote_file);
if ($size == -1) {
$size = 0; // 文件不存在
}
if ($use_cache) {
$size_cache[$remote_file] = $size;
}
return $size;
}
public function __destruct() {
if ($this->conn) {
ftp_close($this->conn);
}
}
}
// 使用示例
try {
$ftp = new SafeFTPAppend('ftp.example.com', 'username', 'password');
// 准备要追加的内容
$local_file = 'data_to_append.txt';
$data = "这是要追加的数据,生成时间: " . date('Y-m-d H:i:s') . "\n";
file_put_contents($local_file, $data);
// 执行安全追加
$result = $ftp->safeAppend('logs/data.log', $local_file, FTP_ASCII);
if ($result['success']) {
echo "追加成功!\n";
echo "初始大小: " . $result['initial_size'] . " 字节\n";
echo "追加大小: " . $result['added_size'] . " 字节\n";
echo "最终大小: " . $result['final_size'] . " 字节\n";
echo "重试次数: " . $result['retries'] . "\n";
} else {
echo "追加失败: " . $result['message'] . "\n";
if (isset($result['error'])) {
echo "错误详情: " . $result['error'] . "\n";
}
}
// 清理临时文件
unlink($local_file);
} catch (Exception $e) {
echo "FTP 操作异常: " . $e->getMessage() . "\n";
}
?>
ftp_append() 函数需要 PHP 7.2.0 或更高版本。FTP_ASCII 或 FTP_BINARY),特别是处理文本文件时。| 错误/问题 | 可能的原因和解决方案 |
|---|---|
| 函数未定义 | PHP版本低于7.2.0。升级PHP或使用ftp_fput()替代方案。 |
| 追加操作失败 | 服务器不支持追加操作。检查服务器配置或使用下载-修改-上传的方式。 |
| 权限被拒绝 | FTP用户没有写入权限。检查服务器文件权限设置。 |
| 文件不存在错误 | 本地文件不存在。检查文件路径和权限。 |
| 传输不完整 | 网络中断或超时。增加超时时间或实现分块传输。 |
| 并发写入冲突 | 多个进程同时写入同一文件。实现文件锁定机制。 |
如果您的PHP版本低于7.2.0,可以使用以下方法实现类似功能:
<?php
/**
* PHP 7.2以下版本的ftp_append替代函数
*/
function ftp_append_compat($conn, $remote_file, $local_file, $mode = FTP_BINARY) {
// 打开本地文件
$handle = fopen($local_file, 'rb');
if ($handle === false) {
return false;
}
// 使用ftp_fput在追加模式下上传
// 注意:这需要服务器支持 APPE 命令
$result = ftp_fput($conn, $remote_file, $handle, $mode, FTP_APPEND);
fclose($handle);
return $result;
}
// 或者使用下载-修改-上传的方式
function ftp_append_manual($conn, $remote_file, $local_file, $mode = FTP_BINARY) {
// 创建临时文件
$temp_file = tempnam(sys_get_temp_dir(), 'ftp_');
// 如果远程文件存在,先下载
if (@ftp_size($conn, $remote_file) != -1) {
if (!ftp_get($conn, $temp_file, $remote_file, $mode)) {
unlink($temp_file);
return false;
}
} else {
// 文件不存在,创建空临时文件
file_put_contents($temp_file, '');
}
// 追加本地文件内容
$local_content = file_get_contents($local_file);
file_put_contents($temp_file, $local_content, FILE_APPEND);
// 上传回服务器
$result = ftp_put($conn, $remote_file, $temp_file, $mode);
// 清理临时文件
unlink($temp_file);
return $result;
}
?>