bool copy ( string $source , string $dest [, resource $context ] )
| 参数 | 描述 | 必需 |
|---|---|---|
| source | 源文件路径 | 是 |
| dest | 目标文件路径 | 是 |
| context | 上下文资源,用于流操作 通常用于处理HTTP/FTP等协议 |
否 |
TRUEFALSE<?php
// 源文件路径
$source = "original.txt";
// 目标文件路径
$dest = "copy.txt";
// 创建源文件
file_put_contents($source, "这是原始文件内容");
// 复制文件
if (copy($source, $dest)) {
echo "文件复制成功!\n";
// 验证复制结果
if (file_exists($dest)) {
echo "目标文件已创建,内容:\n";
echo file_get_contents($dest);
}
} else {
echo "文件复制失败!";
}
// 清理
unlink($source);
unlink($dest);
?>
<?php
// 源文件
$source = "data.txt";
file_put_contents($source, "重要数据");
// 目标目录(确保目录存在且有写入权限)
$destination_dir = "backups/";
if (!is_dir($destination_dir)) {
mkdir($destination_dir, 0755, true);
}
// 目标文件路径
$dest = $destination_dir . "data_backup_" . date('Ymd_His') . ".txt";
// 复制文件
if (copy($source, $dest)) {
echo "文件已备份到: $dest\n";
// 显示备份文件信息
echo "备份文件大小: " . filesize($dest) . " 字节\n";
echo "备份时间: " . date('Y-m-d H:i:s', filemtime($dest));
} else {
echo "备份失败!";
echo "错误信息: " . error_get_last()['message'] ?? '未知错误';
}
// 清理
unlink($source);
// 保留备份文件用于演示
?>
<?php
// 创建源文件并设置权限
$source = "config.php";
file_put_contents($source, "<?php\n// 配置文件\n\$config = [];");
chmod($source, 0640); // 设置源文件权限
// 复制文件
$dest = "config_backup.php";
if (copy($source, $dest)) {
echo "文件复制成功!\n";
// 获取源文件和目标文件的权限
$source_perms = fileperms($source);
$dest_perms = fileperms($dest);
echo "源文件权限: " . decoct($source_perms & 0777) . "\n";
echo "目标文件权限(默认): " . decoct($dest_perms & 0777) . "\n";
// 将目标文件权限设置为与源文件相同
if (chmod($dest, $source_perms & 0777)) {
clearstatcache();
$new_dest_perms = fileperms($dest);
echo "目标文件权限(已更新): " . decoct($new_dest_perms & 0777) . "\n";
}
} else {
echo "复制失败!";
}
// 清理
unlink($source);
unlink($dest);
?>
<?php
/**
* 批量复制文件函数
*/
function batch_copy_files($source_dir, $dest_dir, $pattern = "*") {
if (!is_dir($source_dir)) {
return ['error' => '源目录不存在'];
}
if (!is_dir($dest_dir)) {
// 创建目标目录
if (!mkdir($dest_dir, 0755, true)) {
return ['error' => '无法创建目标目录'];
}
}
$results = [
'total' => 0,
'success' => 0,
'failed' => 0,
'files' => []
];
// 获取匹配的文件
$files = glob($source_dir . '/' . $pattern);
foreach ($files as $source_file) {
if (!is_file($source_file)) {
continue;
}
$filename = basename($source_file);
$dest_file = $dest_dir . '/' . $filename;
$results['total']++;
// 检查目标文件是否已存在
if (file_exists($dest_file)) {
$results['files'][] = [
'file' => $filename,
'status' => 'skipped',
'message' => '目标文件已存在'
];
continue;
}
// 复制文件
if (copy($source_file, $dest_file)) {
$results['success']++;
$results['files'][] = [
'file' => $filename,
'status' => 'success',
'size' => filesize($source_file)
];
} else {
$results['failed']++;
$results['files'][] = [
'file' => $filename,
'status' => 'failed',
'error' => error_get_last()['message'] ?? '未知错误'
];
}
}
return $results;
}
// 使用示例
// 创建示例文件
mkdir('source_files', 0755);
mkdir('destination_files', 0755);
$files = ['file1.txt', 'file2.txt', 'file3.txt'];
foreach ($files as $file) {
file_put_contents('source_files/' . $file, "这是 $file 的内容");
}
// 执行批量复制
$result = batch_copy_files('source_files', 'destination_files', '*.txt');
echo "批量复制结果:\n";
echo "总共处理: {$result['total']} 个文件\n";
echo "成功: {$result['success']} 个\n";
echo "失败: {$result['failed']} 个\n";
foreach ($result['files'] as $file) {
echo "- {$file['file']}: {$file['status']}\n";
}
// 清理
foreach ($files as $file) {
unlink('source_files/' . $file);
unlink('destination_files/' . $file);
}
rmdir('source_files');
rmdir('destination_files');
?>
<?php
/**
* 使用流上下文复制文件
* 可用于处理HTTP、FTP等协议的文件复制
*/
function copy_with_context($source, $dest, $context_options = null) {
if ($context_options) {
// 创建流上下文
$context = stream_context_create($context_options);
return copy($source, $dest, $context);
}
return copy($source, $dest);
}
// 示例1:使用HTTP上下文下载文件
$http_options = [
'http' => [
'method' => 'GET',
'header' => "User-Agent: My PHP Script\r\n",
'timeout' => 30
]
];
// 示例:从URL复制文件到本地
/*
$url = "https://example.com/file.zip";
$local_file = "downloaded_file.zip";
if (copy_with_context($url, $local_file, $http_options)) {
echo "文件下载成功!";
} else {
echo "文件下载失败!";
}
*/
// 示例2:复制文件时设置超时
$file_options = [
'socket' => [
'bindto' => '0:0', // 使用所有可用接口
]
];
// 示例:复制大文件时设置超时
$large_source = "large_file.iso";
$large_dest = "large_file_copy.iso";
// 设置脚本执行时间限制
set_time_limit(300); // 5分钟
if (copy_with_context($large_source, $large_dest, $file_options)) {
echo "大文件复制成功!";
} else {
echo "大文件复制失败: " . error_get_last()['message'];
}
// 示例3:复制FTP服务器上的文件(需要PHP支持ftp协议)
$ftp_options = [
'ftp' => [
'overwrite' => true,
'resume_pos' => 0 // 从指定位置恢复下载
]
];
/*
$ftp_source = "ftp://username:password@ftp.example.com/remote/file.txt";
$local_dest = "local_file.txt";
if (copy_with_context($ftp_source, $local_dest, $ftp_options)) {
echo "FTP文件复制成功!";
}
*/
?>
<?php
/**
* 安全的文件复制函数,包含错误处理和验证
*/
function safe_copy($source, $dest, $options = []) {
$defaults = [
'overwrite' => false,
'create_dir' => true,
'preserve_perms' => false,
'max_size' => 0, // 0表示无限制
'allowed_extensions' => [] // 空数组表示允许所有
];
$options = array_merge($defaults, $options);
// 验证源文件
if (!file_exists($source)) {
return ['success' => false, 'error' => '源文件不存在'];
}
if (!is_file($source)) {
return ['success' => false, 'error' => '源文件不是一个普通文件'];
}
if (!is_readable($source)) {
return ['success' => false, 'error' => '源文件不可读'];
}
// 验证文件大小
$source_size = filesize($source);
if ($options['max_size'] > 0 && $source_size > $options['max_size']) {
return ['success' => false, 'error' => "文件大小超过限制: {$options['max_size']} 字节"];
}
// 验证文件扩展名
if (!empty($options['allowed_extensions'])) {
$ext = strtolower(pathinfo($source, PATHINFO_EXTENSION));
if (!in_array($ext, $options['allowed_extensions'])) {
return ['success' => false, 'error' => "不允许的文件类型: .$ext"];
}
}
// 处理目标目录
$dest_dir = dirname($dest);
if (!is_dir($dest_dir)) {
if ($options['create_dir']) {
if (!mkdir($dest_dir, 0755, true)) {
return ['success' => false, 'error' => '无法创建目标目录'];
}
} else {
return ['success' => false, 'error' => '目标目录不存在'];
}
}
// 检查目标文件是否已存在
if (file_exists($dest)) {
if (!$options['overwrite']) {
return ['success' => false, 'error' => '目标文件已存在'];
}
// 检查目标文件是否可写
if (!is_writable($dest)) {
return ['success' => false, 'error' => '目标文件不可写'];
}
} else {
// 检查目标目录是否可写
if (!is_writable($dest_dir)) {
return ['success' => false, 'error' => '目标目录不可写'];
}
}
// 保存源文件信息(如果需要保留权限)
$source_info = [
'perms' => fileperms($source),
'size' => $source_size,
'mtime' => filemtime($source)
];
// 执行复制
if (copy($source, $dest)) {
$result = ['success' => true, 'message' => '文件复制成功'];
// 保留权限
if ($options['preserve_perms']) {
chmod($dest, $source_info['perms']);
}
// 验证复制结果
clearstatcache();
$dest_size = filesize($dest);
if ($dest_size === $source_info['size']) {
$result['verified'] = true;
$result['size'] = $dest_size;
} else {
$result['verified'] = false;
$result['warning'] = "文件大小验证失败: 源文件 {$source_info['size']} 字节, 目标文件 {$dest_size} 字节";
}
return $result;
} else {
$error = error_get_last();
return ['success' => false, 'error' => $error['message'] ?? '复制操作失败'];
}
}
// 使用示例
$result = safe_copy('source.txt', 'backup/source_backup.txt', [
'overwrite' => true,
'create_dir' => true,
'preserve_perms' => true,
'max_size' => 1024 * 1024, // 1MB限制
'allowed_extensions' => ['txt', 'log', 'csv']
]);
if ($result['success']) {
echo "复制成功!\n";
if (isset($result['verified']) && $result['verified']) {
echo "文件验证通过,大小: {$result['size']} 字节";
}
} else {
echo "复制失败: " . $result['error'];
}
?>
| 错误/问题 | 可能原因 | 解决方法 |
|---|---|---|
| Warning: copy(): failed to open stream: Permission denied | 权限不足 | 检查源文件读取权限和目标目录写入权限 |
| Warning: copy(): The first argument to copy() function cannot be a directory | 尝试复制目录 | copy()只能复制文件,使用其他方法复制目录 |
| 目标文件被覆盖但大小不一致 | 复制过程中出错或中断 | 验证复制后的文件大小,使用安全复制函数 |
| 复制大文件超时 | 执行时间限制 | 使用set_time_limit()增加执行时间限制 |
| copy()返回false但没有错误信息 | PHP配置限制 | 检查php.ini中的safe_mode、open_basedir等设置 |
copy()函数只能复制文件,不能复制目录。如果需要复制目录,可以使用以下方法:
<?php
// 递归复制目录的函数
function copy_directory($source, $dest) {
if (!is_dir($source)) {
return false;
}
if (!is_dir($dest)) {
mkdir($dest, 0755, true);
}
$dir = opendir($source);
while (($file = readdir($dir)) !== false) {
if ($file == '.' || $file == '..') {
continue;
}
$source_path = $source . '/' . $file;
$dest_path = $dest . '/' . $file;
if (is_dir($source_path)) {
copy_directory($source_path, $dest_path);
} else {
copy($source_path, $dest_path);
}
}
closedir($dir);
return true;
}
?>