PHP Conference Japan 2024

copy

(PHP 4, PHP 5, PHP 7, PHP 8)

copy复制文件

描述

copy(字符串 $from, 字符串 $to, ?资源 $context = null): 布尔值

将文件 from 复制到 to

如果您希望移动文件,请使用 rename() 函数。

参数

from

源文件的路径。

to

目标路径。如果 to 是一个 URL,则如果封装器不支持覆盖现有文件,则复制操作可能会失败。

警告

如果目标文件已存在,它将被覆盖。

context

使用 stream_context_create() 创建的有效上下文资源。

返回值

成功时返回 true,失败时返回 false

示例

示例 #1 copy() 示例

<?php
$file
= 'example.txt';
$newfile = 'example.txt.bak';

if (!
copy($file, $newfile)) {
echo
"复制 $file失败...\n";
}
?>

参见

添加注释

用户贡献注释 13 个注释

231
simonr_at_orangutan_dot_co_dot_uk
20 年前
在花费数小时追踪 copy() 错误:权限被拒绝,(并适当地担心 winXP 上的 chmod)之后,值得指出的是“目标”需要包含实际的文件名!--- 而不是您希望复制到的文件夹的路径……
哎呀!
希望这能为某些人节省数小时的无用调试时间
128
cooper at asu dot ntu-kpi dot kiev dot ua
18 年前
当我遇到 copy() 错误时,我花了很长时间才找到问题所在。它不会创建任何目录。它只复制到现有路径。因此,请先创建目录。希望我能帮上忙,
60
steve a h
16 年前
别忘了;您可以在远程文件上使用 copy,而不是执行凌乱的 fopen 操作。例如

<?php
if(!@copy('http://someserver.com/somefile.zip','./somefile.zip'))
{
$errors= error_get_last();
echo
"COPY 错误: ".$errors['type'];
echo
"<br />\n".$errors['message'];
} else {
echo
"已从远程复制文件!";
}
?>
28
promaty at gmail dot com
13 年前
这是一个我用于删除和复制非空目录的简单脚本。当您不确定文件类型时非常有用。

我将这些用于管理我的网站插件的文件夹和 zip 存档。

<?php

// 删除文件和非空目录
function rrmdir($dir) {
if (
is_dir($dir)) {
$files = scandir($dir);
foreach (
$files as $file)
if (
$file != "." && $file != "..") rrmdir("$dir/$file");
rmdir($dir);
}
else if (
file_exists($dir)) unlink($dir);
}

// 复制文件和非空目录
function rcopy($src, $dst) {
if (
file_exists($dst)) rrmdir($dst);
if (
is_dir($src)) {
mkdir($dst);
$files = scandir($src);
foreach (
$files as $file)
if (
$file != "." && $file != "..") rcopy("$src/$file", "$dst/$file");
}
else if (
file_exists($src)) copy($src, $dst);
}
?>

干杯!
29
[email protected]
11年前
如果你需要确保文件夹先存在,这是一个简单实用的技巧

<?php

$srcfile
='C:\File\Whatever\Path\Joe.txt';
$dstfile='G:\Shared\Reports\Joe.txt';
mkdir(dirname($dstfile), 0777, true);
copy($srcfile, $dstfile);

?>

就这么简单。
5
[email protected]
3年前
在Windows上,php-7.4.19-Win32-vc15-x64 - copy() 损坏了一个6GB的zip文件。我们唯一的选择是编写

function file_win_copy( $src, $dst ) {
shell_exec( 'COPY "'.$src.'" "'.$dst.'"');
return file_exists($dest);
}
10
[email protected]
16 年前
值得注意的是,copy() 会设置目标文件的最后修改时间/日期。
10
[email protected]
10年前
以下是从网络服务器下载文件到本地文件的代码片段。

它演示了请求的有用自定义(例如设置用户代理和引用者,网络站点通常需要这些),以及如何在网络站点上的副本比本地副本更新时仅下载文件。

它还演示了响应头的处理(如果服务器设置了响应头),以确定时间戳和文件名。检查文件类型是因为某些服务器返回 200 OK 返回代码以及文本“未找到”页面,而不是正确的 404 返回代码。



<?php
// $fURI: 网络服务器上的文件 URL
// $target_file: 本地文件的路径

if ( file_exists( $target_file ) ) {
$ifmodhdr = 'If-Modified-Since: '.date( "r", filemtime( $target_file ) )."\r\n";
}
else {
$ifmodhdr = '';
}

// 设置 GET 请求头,包含 Referer 用于已修改的文件,并跟随重定向
$arrRequestHeaders = array(
'http'=>array(
'method' =>'GET',
'protocol_version' =>1.1,
'follow_location' =>1,
'header'=> "User-Agent: Anamera-Feed/1.0\r\n" .
"Referer: $source\r\n" .
$ifmodhdr
)
);
$rc = copy( $fURI, $target_file, stream_context_create($arrRequestHeaders) );

// HTTP 请求完成,保留系统错误(如果有)
if( $rc ) {
if (
fclose( $rc ) ) {
unset(
$err );
}
else {
$err = error_get_last();
}
}
else {
$err = error_get_last();
}

// 解析 HTTP 响应头以获取 HTTP 状态码,以及文件名、类型、日期信息
// 需要从后往前解析,以获取可能存在的重定向响应头后的最终响应头
if ( $http_response_header ) {
for (
$i = sizeof($http_response_header) - 1; $i >= 0; $i-- ) {
if (
preg_match('@^http/\S+ (\S{3,}) (.+)$@i', $http_response_header[$i], $http_status) > 0 ) {
// HTTP 状态头表示已到达最后一个请求的响应头的开头
break;
}
elseif (
preg_match('@^(\S+):\s*(.+)\s*$@', $http_response_header[$i], $arrHeader) > 0 ) {
switch (
$arrHeader[1] ) {
case
'Last-Modified':
if ( !isset(
$http_content_modtime) ) {
$http_content_modtime = strtotime( $arrHeader[2] );
}
break;
case
'Content-Type':
if ( !isset(
$http_content_image_type) ) {
if (
preg_match('@^image/(\w+)@ims', $arrHeader[2], $arrTokens) > 0 ) {
if (
in_array(strtolower($arrTokens[1]), $arrValidTypes)) {
$http_content_image_type = $arrTokens[1];
break;
}
}
throw new
Exception( "错误访问文件 $fURI; 无效的内容类型: $arrHeader[2]", 2);
}
break;
case
'Content-Disposition':
if ( !isset(
$http_content_filename) && preg_match('@filename\\s*=\\s*(?|"([^"]+)"|([\\S]+));?@ims', $arrHeader[2], $arrTokens) > 0 ) {
$http_content_filename = basename($arrTokens[1]);
}
break;
}
}
}
}

if (
$http_status ) {
// 确保 HTTP 状态码有效
switch ( $http_status[1] ) {
case
'200':
// 成功: HTTP 状态码为 "200 OK"
break;
case
'304':
throw new
Exception( "远程文件没有更新: $fURI", $http_status[1] );
break;
case
'404':
throw new
Exception( "远程文件未找到: $fURI", $http_status[1] );
break;
default:
throw new
Exception( "HTTP 错误,$http_status[2],访问 $fURI", $http_status[1] );
break;
}
}
elseif (
$err ) {
// 协议/通信错误
throw new Exception( $err['message']/*."; 远程文件: $fURI"*/, $err['type'] );
}
else {
// 没有 HTTP 状态码且没有错误
throw new customException( "未知的 HTTP 响应,访问 $fURI: $http_response_header[0]", -1 );
}
?>

注释
1. 目前 copy() 函数 **没有** 正确处理 304 响应代码。它不会停止复制(可能设置 RC),而是会用一个零长度文件覆盖目标文件。
2. 使用 HTTP 1.1 协议访问远程文件列表时可能会出现问题。如果遇到超时错误,请尝试使用默认的 1.0 协议版本。
5
hugo_2000 at gmx dot at
9 年前
如果尝试将文件复制到自身 - 例如,如果目标目录只是源目录的符号链接 - copy 函数将返回 false。就像在命令行中一样。
4
Vinicio Coletti
8 年前
在 Windows 8.1 下复制大文件,从一个 NTFS 文件系统到另一个 NTFS 文件系统,只会复制前 4 GiB,其余文件会被忽略。

因此,如果您需要处理大于 4 GiB 的文件,请不要使用
copy($source,$destination);
而是使用类似以下代码:
exec("xcopy $source $destination");

我将检查此问题在 Linux 下是否也存在。
这是否取决于 PHP 是否以 64 位模式编译?
19
gimmicklessgpt at gmail dot com
15 年前
这是一个复制整个目录的简单递归函数

请注意,您需要自行检查要第一次调用的目录是否存在。



<?php
function recurse_copy($src,$dst) {
$dir = opendir($src);
@
mkdir($dst);
while(
false !== ( $file = readdir($dir)) ) {
if ((
$file != '.' ) && ( $file != '..' )) {
if (
is_dir($src . '/' . $file) ) {
recurse_copy($src . '/' . $file,$dst . '/' . $file);
}
else {
copy($src . '/' . $file,$dst . '/' . $file);
}
}
}
closedir($dir);
}
?>
8
[email protected]
15 年前
一些主机禁用 copy() 函数,并称其出于安全考虑。

而对于某些情况,复制功能非常重要,因此这是一个简单函数,可以实现与 copy 函数相同的效果。

PHP 的智能功能如何帮助我们,就像我喜爱 PHP 一样。

<?php
function copyemz($file1,$file2){
$contentx =@file_get_contents($file1);
$openedfile = fopen($file2, "w");
fwrite($openedfile, $contentx);
fclose($openedfile);
if (
$contentx === FALSE) {
$status=false;
}else
$status=true;

return
$status;
}
?>
0
[email protected]
13 天前
复制文件并保留文件时间戳

<?php
if (copy($from, $to))
touch($to, filemtime($from), fileatime($from));
?>
To Top