使用PHP fopen和/或cURL下载外部文件
我无法使我的下载脚本与外部文件一起工作,该文件将下载,但已损坏/无法工作。我想这是因为我无法使用filesize()函数获取外部文件的文件大小 这是我的剧本:使用PHP fopen和/或cURL下载外部文件,php,curl,http-headers,download,fopen,Php,Curl,Http Headers,Download,Fopen,我无法使我的下载脚本与外部文件一起工作,该文件将下载,但已损坏/无法工作。我想这是因为我无法使用filesize()函数获取外部文件的文件大小 这是我的剧本: function getMimeType($filename){ $ext = pathinfo($filename, PATHINFO_EXTENSION); $ext = strtolower($ext); $mime_types=array( "pdf" => "application
function getMimeType($filename){
$ext = pathinfo($filename, PATHINFO_EXTENSION);
$ext = strtolower($ext);
$mime_types=array(
"pdf" => "application/pdf",
"txt" => "text/plain",
"html" => "text/html",
"htm" => "text/html",
"exe" => "application/octet-stream",
"zip" => "application/zip",
"doc" => "application/msword",
"xls" => "application/vnd.ms-excel",
"ppt" => "application/vnd.ms-powerpoint",
"gif" => "image/gif",
"png" => "image/png",
"jpeg"=> "image/jpg",
"jpg" => "image/jpg",
"php" => "text/plain",
"csv" => "text/csv",
"xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
"docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
);
if(isset($mime_types[$ext])){
return $mime_types[$ext];
} else {
return 'application/octet-stream';
}
}
$path = "http://www.example.com/file.zip";
/* Does not work on external files
// check file is readable or not exists
if (!is_readable($path))
die('File is not readable or does not exists!');
*/
$file_headers = @get_headers($path);
if($file_headers[0] == 'HTTP/1.1 404 Not Found') {
echo "Files does not exist.";
} else {
$filename = pathinfo($path, PATHINFO_BASENAME);
// get mime type of file by extension
$mime_type = getMimeType($filename);
// set headers
header('Pragma: public');
header('Expires: -1');
header('Cache-Control: public, must-revalidate, post-check=0, pre-check=0');
header('Content-Transfer-Encoding: binary');
header("Content-Disposition: attachment; filename=\"$filename\"");
header("Content-Length: " . filesize($path));
header("Content-Type: $mime_type");
header("Content-Description: File Transfer");
// read file as chunk
if ( $fp = fopen($path, 'rb') ) {
ob_end_clean();
while( !feof($fp) and (connection_status()==0) ) {
print(fread($fp, 8192));
flush();
}
@fclose($fp);
exit;
}
}
我相信卷发可以做到,但我的知识是缺乏的。
我想知道的是:
- 如何检查文件是否存在,如何使用cURL获取文件大小
- 使用cURL而忘记fopen会更好吗
- 标题设置是否正确
任何建议都将不胜感激 问题来自设置为
0
的内容长度。
由于您已经从get\u headers
调用中获得了内容长度,只需更改以下行:
header("Content-Length: " . filesize($path));
致:
请注意,$file\u headers
的内容可能会有所不同(我用了8个),请查看详细信息,或执行打印($file\u headers)
以查看其中的内容
如果您不关心内容长度标题,只需将其注释掉即可,大多数浏览器应该可以毫无问题地处理此问题。功能:
尝试使用以下方法:
function get_data($url)
{
$ch = curl_init();
$timeout = 5;
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
不幸的是,由于您缺乏关于特定查询或文件的详细信息,我无法提供更精确的代码来匹配您的情况。
上面(或下面)
curl\u get\u file\u size
将帮助您调整大小,以备您需要。此代码可以从url下载:
set_time_limit(0);
//File to save the contents to
$fp = fopen ('r.jpg', 'w+');
$url = "http://cgr.ir/test.jpg";
//Here is the file we are downloading, replace spaces with %20
$ch = curl_init(str_replace(" ","%20",$url));
curl_setopt($ch, CURLOPT_TIMEOUT, 50);
//give curl the file pointer so that it can write to it
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$data = curl_exec($ch);//get curl response
//done
curl_close($ch);
?>
您也可以尝试这个过程,我假设您的源url是
$sourceUrl
,保存文件的目标/路径是$destinationPath
$destFilename = 'my_file_name.ext';
$destinationPath = 'your/destination/path/'.$destFilename;
if(ini_get('allow_url_fopen')) {
if( ! @file_put_contents($destinationPath, file_get_contents($sourceUrl))){
$http_status = $http_response_header[0];
sprintf('%s encountered while attempting to download %s',$http_status, $sourceUrl );
break;
}
} elseif(function_exists('curl_init')) {
$ch = curl_init($sourceUrl);
$fp = fopen($destinationPath, "wb");
$options = array(
CURLOPT_FILE => $fp,
CURLOPT_HEADER => 0,
CURLOPT_FOLLOWLOCATION => 1,
CURLOPT_TIMEOUT => 120); // in seconds
curl_setopt_array($ch, $options);
curl_exec($ch);
$http_status = intval(curl_getinfo($ch, CURLINFO_HTTP_CODE));
curl_close($ch);
fclose($fp);
//delete the file if the download was unsuccessful
if($http_status != 200) {
unlink($destinationPath);
sprintf('HTTP status %s encountered while attempting to download %s', $http_status, $sourceUrl );
}
} else {
sprintf('Looks like %s is off and %s is not enabled. No images were imported.', '<code>allow_url_fopen</code>', '<code>cURL</code>' );
break;
}
您可以使用
curl\u getinfo($ch,CURLINFO\u CONTENT\u TYPE)
如果是curl,请获取文件信息并根据您的要求使用。我认为最好不要依赖php curl模块的可用性。您的代码片段只需稍加修改即可工作:
第一次改变
$file_headers = @get_headers($path);
到
获取命名数组键(请参见)
通过此修改,http状态代码仍然以$file_头[0]的形式出现,但您将获得更多有用的数据,这些数据可以通过(建议进行验证):内容长度,甚至内容类型(这允许您放弃对文件后缀进行mime类型检测的方法)
改变
header("Content-Length: " . filesize($path));
到
及
到
即使您的“路径”是一个受信任的源,您也可能需要添加一些验证,因为您不应该相信外部数据是您所期望的类型。当您取消内容长度:标题时会发生什么。您能在输出之前下载整个文件吗?请提供调试问题时的一些输出。答案是肯定的,忘记
fopen
并使用curl
。您应该意识到,设置正在执行的脚本标题对他试图通过fopen对外部url进行的查询没有太大影响。他的代码工作正常,使用fopen没有错,他唯一的问题是,他将0作为内容长度头传递。但我的问题是,为当前的php脚本将返回的设置的头(意思是使用头()
),以及它对他在外部url上使用fopen进行的查询的影响。我希望我能澄清一下。
$file_headers = @get_headers($path,1);
header("Content-Length: " . filesize($path));
header("Content-Length: " . $file_headers['Content-Length']);
header("Content-Type: $mime_type");
header("Content-Type: " . $file_headers['Content-Type']);