<?php
namespace org;
use think\File;
/**
* 远程图片下载
* 依赖http_down函数
*/
class ImgDown extends File {
//下载地址
private $url = '';
private $path = '';
/**
*
* @param string $url 图片地址
* @param boolean $replace 是否覆盖
*/
function __construct($url, $replace = false) {
$path = ROOT_PATH . 'public' . DS;
$this->url = trim(urldecode($url));
//检查域名
$host = parse_url($this->url, PHP_URL_HOST);
if ($host == $_SERVER['HTTP_HOST']) {
$filename = $path . str_replace(request()->domain(), '', $this->url);
} else {
$ext = pathinfo($this->url, PATHINFO_EXTENSION);
//网址中不存在文件扩展名
if (empty($ext)) {
//获取url中的header信息
$head = get_head($this->url);
if (!empty($head)) {
//从headers中获得文件名
$headers = explode("\n", $head);
foreach ($headers as $v) {
$item = explode(':', $v);
if (count($item) > 1) {
$name = strtolower($item[0]);
if ($name == 'location') {
//302跳转
$this->url = count($item) == 2 ? trim($item[1]) : trim($item[1]) . ':' . trim($item[2]); //防止http:被解析
$ext = pathinfo($this->url, PATHINFO_EXTENSION);
break;
} else if ($name == 'content-disposition') {
//可能是Content-Disposition: attachment; filename=".$file_name
//获得MIME: Content-Type
$item[1] = trim($item[1]);
$tmps = explode("filename=", $item[1]);
$tmp = count($tmps) > 1 ? $tmps[1] : $tmps[0];
$ext = pathinfo($tmp, PATHINFO_EXTENSION);
break;
}
}
}
}
}
$filename = $path . 'uploads' . DS . date('Y/m/d') . DS . md5($this->url) . '.' . $ext;
if (!is_file($filename) || $replace) {
if (http_down($this->url, $filename) === false) {
$this->error = '下载文件失败';
}
}
}
parent::__construct($filename, 'r');
$this->setUploadInfo(['name' => pathinfo($filename, PATHINFO_BASENAME)]);
$this->path = $path;
}
/**
* 检测是否合法的下载文件
* @return bool
*/
public function isValid() {
return is_file($this->filename);
}
/**
* 获取文件名
* @param boolean $realpath 是否返回绝对路径
* @return false|string
*/
public function getFileName($realpath = false) {
// 检测合法性
if (!$this->isValid()) {
$this->error = '非法下载文件';
return false;
}
// 验证下载
if (!$this->check()) {
return false;
}
if (!empty($this->error)) {
return false;
}
return $realpath ? $this->filename : substr($this->filename, strlen($this->path));
}
}
以下是依赖的函数/**
* 下载远程文件,默认保存在TEMP_PATH下
* @param string $url 网址
* @param string $filename 保存文件名
* @param integer $timeout 过期时间
* @param bool $repalce 是否覆盖已存在文件
* @return string 本地文件名
*/
function http_down($url, $filename = "", $timeout = 60) {
if (empty($filename)) {
$filename = TEMP_PATH . pathinfo($url, PATHINFO_BASENAME);
}
$path = dirname($filename);
if (!is_dir($path) && !mkdir($path, 0755, true)) {
return false;
}
$url = str_replace(" ", "%20", $url);
if (function_exists('curl_init')) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
// curl_setopt($ch, CURLOPT_MAXREDIRS, 2);
// curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
$temp = curl_exec($ch);
if (file_put_contents($filename, $temp) && !curl_error($ch)) {
return $filename;
} else {
return false;
}
} else {
$opts = [
"http" => [
"method" => "GET",
"header" => "",
"timeout" => $timeout,
],
];
$context = stream_context_create($opts);
if (@copy($url, $filename, $context)) {
//$http_response_header
return $filename;
} else {
return false;
}
}
}
/**
* 获得header
* @param string $url 网址
* @return string
*/
function get_head($url) {
$ch = curl_init();
// 设置请求头, 有时候需要,有时候不用,看请求网址是否有对应的要求
$header[] = "Content-type: application/x-www-form-urlencoded";
$user_agent = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36";
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
// 返回 response_header, 该选项非常重要,如果不为 true, 只会获得响应的正文
curl_setopt($ch, CURLOPT_HEADER, true);
// 是否不需要响应的正文,为了节省带宽及时间,在只需要响应头的情况下可以不要正文
curl_setopt($ch, CURLOPT_NOBODY, true);
// 使用上面定义的 ua
curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// 不用 POST 方式请求, 意思就是通过 GET 请求
curl_setopt($ch, CURLOPT_POST, false);
$sContent = curl_exec($ch);
// 获得响应结果里的:头大小
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
// 根据头大小去获取头信息内容
$header = substr($sContent, 0, $headerSize);
curl_close($ch);
return $header;
}
示例,以下为生成二维码中的远程logo处理部分:$logo = input('param.logo');
if(strpos($logo, '://') === false){
$logo = ROOT_PATH.'public'.DS.'static'.DS.'index'.DS.'images'.DS.$logo;
if(!is_file($logo)){
$logo = false;
}
} else {
$file = new ImgDown($logo);
$logo = $file->getFileName();
}
最佳答案
