在花费数小时追踪 copy() 错误:权限被拒绝,(并适当地担心 winXP 上的 chmod)之后,值得指出的是“目标”需要包含实际的文件名!--- 而不是您希望复制到的文件夹的路径……
哎呀!
希望这能为某些人节省数小时的无用调试时间
(PHP 4, PHP 5, PHP 7, PHP 8)
copy — 复制文件
from
源文件的路径。
to
目标路径。如果 to
是一个 URL,则如果封装器不支持覆盖现有文件,则复制操作可能会失败。
如果目标文件已存在,它将被覆盖。
context
使用 stream_context_create() 创建的有效上下文资源。
示例 #1 copy() 示例
<?php
$file = 'example.txt';
$newfile = 'example.txt.bak';
if (!copy($file, $newfile)) {
echo "复制 $file失败...\n";
}
?>
在花费数小时追踪 copy() 错误:权限被拒绝,(并适当地担心 winXP 上的 chmod)之后,值得指出的是“目标”需要包含实际的文件名!--- 而不是您希望复制到的文件夹的路径……
哎呀!
希望这能为某些人节省数小时的无用调试时间
当我遇到 copy() 错误时,我花了很长时间才找到问题所在。它不会创建任何目录。它只复制到现有路径。因此,请先创建目录。希望我能帮上忙,
别忘了;您可以在远程文件上使用 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 "已从远程复制文件!";
}
?>
这是一个我用于删除和复制非空目录的简单脚本。当您不确定文件类型时非常有用。
我将这些用于管理我的网站插件的文件夹和 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);
}
?>
干杯!
如果你需要确保文件夹先存在,这是一个简单实用的技巧
<?php
$srcfile='C:\File\Whatever\Path\Joe.txt';
$dstfile='G:\Shared\Reports\Joe.txt';
mkdir(dirname($dstfile), 0777, true);
copy($srcfile, $dstfile);
?>
就这么简单。
在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);
}
以下是从网络服务器下载文件到本地文件的代码片段。
它演示了请求的有用自定义(例如设置用户代理和引用者,网络站点通常需要这些),以及如何在网络站点上的副本比本地副本更新时仅下载文件。
它还演示了响应头的处理(如果服务器设置了响应头),以确定时间戳和文件名。检查文件类型是因为某些服务器返回 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 协议版本。
在 Windows 8.1 下复制大文件,从一个 NTFS 文件系统到另一个 NTFS 文件系统,只会复制前 4 GiB,其余文件会被忽略。
因此,如果您需要处理大于 4 GiB 的文件,请不要使用
copy($source,$destination);
而是使用类似以下代码:
exec("xcopy $source $destination");
我将检查此问题在 Linux 下是否也存在。
这是否取决于 PHP 是否以 64 位模式编译?
这是一个复制整个目录的简单递归函数
请注意,您需要自行检查要第一次调用的目录是否存在。
<?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);
}
?>
一些主机禁用 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;
}
?>
复制文件并保留文件时间戳
<?php
if (copy($from, $to))
touch($to, filemtime($from), fileatime($from));
?>