You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
662 lines
23 KiB
662 lines
23 KiB
<?php
|
|
/**
|
|
* lvzheAdmin [a web admin based ThinkPHP5]
|
|
* @author xiekunyu<raingad@foxmail.com>
|
|
*/
|
|
namespace app\common\controller;
|
|
|
|
use app\BaseController;
|
|
use app\enterprise\model\{File as FileModel,Message,User,Emoji};
|
|
use app\manage\model\{Config};
|
|
use think\facade\Filesystem;
|
|
use think\facade\Request;
|
|
use think\File;
|
|
use FFMpeg\FFMpeg;
|
|
use FFMpeg\FFProbe;
|
|
use FFMpeg\Coordinate\TimeCode;
|
|
|
|
class Upload extends BaseController
|
|
{
|
|
protected $middleware = ['checkAuth'];
|
|
protected $disk='';
|
|
protected $url='';
|
|
|
|
public function __construct()
|
|
{
|
|
parent::__construct(app());
|
|
$this->disk=env('filesystem.driver','local');
|
|
$this->url=getDiskUrl().'/';
|
|
|
|
}
|
|
|
|
/**
|
|
* 文件上传
|
|
*/
|
|
public function upload($data,$path,$prefix = "",$fileObj = true)
|
|
{
|
|
$message=$data['message'] ?? '';
|
|
if($message){
|
|
$message=json_decode($message,true);
|
|
}
|
|
$uid=request()->userInfo['user_id'] ?? 1;
|
|
if($fileObj){
|
|
$filePath = $path;
|
|
}else{
|
|
$filePath = new File($path);
|
|
}
|
|
$info=$this->getFileInfo($filePath,$path,$fileObj);
|
|
if($info['ext']=='' && $message){
|
|
$pathInfo = pathinfo($message['fileName'] ?? '');
|
|
$info['ext'] = $pathInfo['extension'];
|
|
$info['name'] =$message['fileName'] ?? '';
|
|
}
|
|
$conf=Config::where(['name'=>'fileUpload'])->value('value');
|
|
if($conf['size']*1024*1024 < $info['size']){
|
|
return shutdown(lang('file.uploadLimit',['size'=>$conf['size']]));
|
|
}
|
|
// 兼容uniapp文件上传
|
|
if($info['ext']=='' && isset($data['ext'])){
|
|
$info['ext']=$data['ext'];
|
|
}
|
|
$info['ext']=strtolower($info['ext']);
|
|
if(!in_array($info['ext'],$conf['fileExt'])){
|
|
return shutdown(lang('file.typeNotSupport'));
|
|
}
|
|
$fileType=getFileType($info['ext']);
|
|
$imageInfo=[];
|
|
if($fileType==2){
|
|
$filecate="image";
|
|
$imageInfo=$this->getImageSizeInfo($info['path']);
|
|
}elseif($fileType==3){
|
|
$msgType=$message['type'] ?? '';
|
|
// 如果是语音消息,类型才为语音,否者为文件,主要是兼容发送音频文件
|
|
if($msgType=='voice'){
|
|
$filecate="voice";
|
|
}else{
|
|
$filecate="file";
|
|
}
|
|
}elseif($fileType==4){
|
|
$filecate="video";
|
|
}else{
|
|
$filecate="file";
|
|
}
|
|
if(!$prefix){
|
|
$prefix=$filecate.'/'.date('Y-m-d').'/'.$uid."/";
|
|
}
|
|
$name=str_replace('.'.$info['ext'],'',$info['name']);
|
|
$file=false;//FileModel::where(['md5'=>$info['md5'],'user_id'=>$uid])->find();
|
|
// 判断文件是否存在,如果有则不再上传
|
|
if(!$file){
|
|
$newName = uniqid() . '.' . $info['ext'];
|
|
$object = $prefix . $newName;
|
|
if($this->disk=='local'){
|
|
$object='storage/'.$object;
|
|
}
|
|
Filesystem::disk($this->disk)->putFileAs($prefix, $filePath, $newName);
|
|
}else{
|
|
$object = $file['src'];
|
|
}
|
|
// 把左边的/去掉再加上,避免有些有/有些没有
|
|
$object='/'.ltrim($object,'/');
|
|
// 压缩图片
|
|
$compress_img = $file['compress_img'] ?? '';
|
|
if ($filecate == 'image') {
|
|
$compress_img = $this->getCompressImg($object, $info['ext'], $prefix);
|
|
}
|
|
$ret = [
|
|
"src" => $object,
|
|
"name" => $name,
|
|
"cate" => $fileType,
|
|
"size" => $info['size'],
|
|
"md5" => $info['md5'],
|
|
"file_type" => $info['mime'],
|
|
"ext" => $info['ext'],
|
|
"type" =>2,
|
|
'user_id'=>$uid,
|
|
'compress_img'=>$compress_img,
|
|
'videoInfo'=>$imageInfo
|
|
];
|
|
|
|
if($message){
|
|
// 自动获取视频第一帧,视频并且是使用的阿里云
|
|
if($message['type']=='video'){
|
|
$videoInfo=$this->getVideoCover($filePath);
|
|
if($videoInfo){
|
|
$extends=$videoInfo['videoInfo'];
|
|
$extends['poster']=$this->url.$videoInfo['src'];
|
|
$message['extends']=$extends;
|
|
}else{
|
|
$message['extends']['poster']=getMainHost().'/static/common/img/video.png';
|
|
}
|
|
// if($this->disk=='aliyun'){
|
|
// $message['extends']['poster']=$this->url.$ret['src'].'?x-oss-process=video/snapshot,t_1000,m_fast,w_800,f_png';
|
|
// }else{
|
|
// $message['extends']['poster']=getMainHost().'/static/common/img/video.png';
|
|
// }
|
|
}
|
|
// 如果发送的文件是图片、视频、音频则将消息类型改为对应的类型
|
|
if(in_array($fileType,[2,3,4])){
|
|
$message['type']=$filecate;
|
|
}
|
|
if($message['type']=='image'){
|
|
$message['extends']=$imageInfo;
|
|
}
|
|
$newFile=new FileModel;
|
|
// 录音就不保存了
|
|
if($message['type']!='voice'){
|
|
$newFile->save($ret);
|
|
}
|
|
$message['content']=$ret['compress_img'] ?: $ret['src'];
|
|
$message['file_id']=$newFile->file_id ?? 0;
|
|
$message['file_cate']=$fileType;
|
|
$message['file_size']=$info['size'];
|
|
$message['file_name']= $name.'.'.$info['ext'];
|
|
$message['user_id']= $uid;
|
|
$messageModel=new Message();
|
|
$data=$messageModel->sendMessage($message,$this->globalConfig);
|
|
if(!$data){
|
|
return shutdown($messageModel->getError());
|
|
}
|
|
return $data;
|
|
}else{
|
|
$fileInfo=new FileModel;
|
|
$saveData = $ret;
|
|
if (isset($saveData['type'])) {
|
|
unset($saveData['type']);
|
|
}
|
|
if (isset($saveData['videoInfo'])) {
|
|
unset($saveData['videoInfo']);
|
|
}
|
|
$exists = $fileInfo->where($saveData)->find();
|
|
if (!$exists) {
|
|
$fileInfo->save($saveData);
|
|
}
|
|
// 上传视频切片
|
|
if ($fileType == 4) {
|
|
$videoInfo=$this->getVideoCover($filePath, true);
|
|
if($videoInfo){
|
|
$poster=$this->url.$videoInfo['src'];
|
|
}else{
|
|
$poster=getMainHost().'/static/common/img/video.png';
|
|
}
|
|
$ret['poster'] = $poster;
|
|
}
|
|
return $ret;
|
|
}
|
|
|
|
}
|
|
|
|
// 上传一般文件
|
|
public function uploadFile(){
|
|
$param=$this->request->param();
|
|
try{
|
|
$file=request()->file('file');
|
|
$info=$this->upload($param,$file);
|
|
return success(lang('file.uploadOk'),$info);
|
|
} catch(\Exception $e) {
|
|
return error($e->getMessage().$e->getLine());
|
|
}
|
|
}
|
|
|
|
public function uploadFileImage()
|
|
{
|
|
$param=$this->request->param();
|
|
try{
|
|
$image_url=$param['image_url']??'';
|
|
if (empty($image_url)) {
|
|
throw new \Exception(lang('file.exist'));
|
|
}
|
|
$data = $this->downloadImage($image_url);
|
|
if (!$data['status']) {
|
|
throw new \Exception(lang('file.error'));
|
|
}
|
|
$info=$this->upload($param,$data['path'],'', false);
|
|
return success(lang('file.uploadOk'),$info);
|
|
} catch(\Exception $e) {
|
|
return error($e->getMessage());
|
|
}
|
|
}
|
|
|
|
|
|
// 获取上传文件的信息
|
|
protected function getFileInfo($file,$path,$isObj=false){
|
|
$info= [
|
|
'path'=>$file->getRealPath(),
|
|
'size'=>$file->getSize(),
|
|
'mime'=>$file->getMime(),
|
|
'ext'=>$file->extension(),
|
|
'md5'=>$file->md5(),
|
|
];
|
|
if($isObj){
|
|
$info['name']=$file->getOriginalName();
|
|
}else{
|
|
// 根据路径获取文件名
|
|
$pathInfo = pathinfo($path);
|
|
$info['name'] = $pathInfo['basename'];
|
|
}
|
|
return $info;
|
|
|
|
}
|
|
|
|
// 上传图片
|
|
public function uploadImage(){
|
|
$param=request::param();
|
|
try{
|
|
$file=request()->file('file');
|
|
$info=$this->upload($param,$file,'image/'.date('Y-m-d').'/');
|
|
$url=$this->url.$info['src'];
|
|
return success(lang('file.uploadOk'),$url);
|
|
} catch(\Exception $e) {
|
|
return error($e->getMessage());
|
|
}
|
|
}
|
|
|
|
// 上传朋友圈图片视频
|
|
public function uploadPosts(){
|
|
$param=request::param();
|
|
try{
|
|
$files=request()->file('file');
|
|
$returnData = [];
|
|
if (!is_array($files)) {
|
|
$files = [$files];
|
|
}
|
|
foreach ($files as $file) {
|
|
$info=$this->upload($param,$file);
|
|
$url=$this->url.$info['src'];
|
|
$data = ['url' => $url, 'poster' => ''];
|
|
if (isset($info['poster'])) {
|
|
$data['poster']=$info['poster'];
|
|
}
|
|
$returnData[] = $data;
|
|
}
|
|
return success(lang('file.uploadOk'),$returnData);
|
|
} catch(\Exception $e) {
|
|
return error($e->getMessage());
|
|
}
|
|
}
|
|
|
|
// 普通上传头像
|
|
public function uploadAvatar(){
|
|
$param=request::param();
|
|
try{
|
|
$file=request()->file('file');
|
|
$uid=request()->userInfo['user_id'];
|
|
$info=$this->upload($param,$file,'avatar/'.$uid.'/');
|
|
User::where(['user_id'=>$uid])->update(['avatar'=>$info['src']]);
|
|
$url=$this->url.$info['src'];
|
|
return success(lang('file.uploadOk'),$url);
|
|
} catch(\Exception $e) {
|
|
return error($e->getMessage());
|
|
}
|
|
}
|
|
|
|
// 服务器上传头像
|
|
public function uploadLocalAvatar($file,$param,$uid){
|
|
try{
|
|
$info=$this->upload($param,$file,'avatar/'.$uid.'/',false);
|
|
return $info['src'];
|
|
} catch(\Exception $e) {
|
|
return $e->getMessage().$e->getLine();
|
|
}
|
|
}
|
|
|
|
// 上传表情
|
|
public function uploadEmoji(){
|
|
$param=request::param();
|
|
try{
|
|
$file=request()->file('file');
|
|
$filePath = $file;
|
|
$uid=request()->userInfo['user_id'] ?? 1;
|
|
$info=$this->getFileInfo($filePath,$file,true);
|
|
if($info['ext']==''){
|
|
$pathInfo = pathinfo($message['fileName'] ?? '');
|
|
$info['ext'] = $pathInfo['extension'];
|
|
$info['name'] =$message['fileName'] ?? '';
|
|
}
|
|
// 表情不能大于1m
|
|
if(2*1024*1024 < $info['size']){
|
|
return shutdown(lang('file.uploadLimit',['size'=>2]));
|
|
}
|
|
// 兼容uniapp文件上传
|
|
if($info['ext']=='' && isset($param['ext'])){
|
|
$info['ext']=$param['ext'];
|
|
}
|
|
$info['ext']=strtolower($info['ext']);
|
|
if(!in_array($info['ext'],['jpg','jpeg','gif','png'])){
|
|
return shutdown(lang('file.typeNotSupport'));
|
|
}
|
|
$prefix='emoji/'.$uid.'/';
|
|
$name=str_replace('.'.$info['ext'],'',$info['name']);
|
|
$fileInfo=FileModel::where(['md5'=>$info['md5'],'user_id'=>$uid])->find();
|
|
// 判断文件是否存在,如果有则不再上传
|
|
if(!$fileInfo){
|
|
$newName = uniqid() . '.' . $info['ext'];
|
|
$object = $prefix . $newName;
|
|
if($this->disk=='local'){
|
|
$object='storage/'.$object;
|
|
}
|
|
Filesystem::disk($this->disk)->putFileAs($prefix, $filePath, $newName);
|
|
$ret = [
|
|
"src" => $object,
|
|
"name" => $name,
|
|
"cate" => 1,
|
|
"size" => $info['size'],
|
|
"md5" => $info['md5'],
|
|
"file_type" => $info['mime'],
|
|
"ext" => $info['ext'],
|
|
"type" =>2,
|
|
'user_id'=>$uid,
|
|
];
|
|
$fileInfo=new FileModel;
|
|
$fileInfo->save($ret);
|
|
}else{
|
|
//$object = $fileInfo->src;
|
|
return shutdown(lang('file.emojiExist'));
|
|
}
|
|
// 把左边的/去掉再加上,避免有些有/有些没有
|
|
$object='/'.ltrim($object,'/');
|
|
$emojiInfo=[
|
|
'user_id' => $uid,
|
|
"src" => $object,
|
|
"name" => $name,
|
|
"type" => 2,
|
|
"file_id" => $fileInfo->file_id,
|
|
];
|
|
Emoji::create($emojiInfo);
|
|
return success('',$this->url.$object);
|
|
} catch(\Exception $e) {
|
|
return $e->getMessage().$e->getLine();
|
|
}
|
|
}
|
|
|
|
// 获取图片的尺寸
|
|
protected function getImageSizeInfo($file){
|
|
$extends=[];
|
|
// 如果图片获取图片的尺寸
|
|
$imageSize = getimagesize($file);
|
|
$extends['width']=$imageSize[0];
|
|
$extends['height']=$imageSize[1];
|
|
// 如果宽大于高则为横图,宽度填充模式,否则为竖图,高度填充模式
|
|
if($imageSize[0]>=$imageSize[1]){
|
|
$extends['fixMode']=1; // 宽度填充
|
|
}else{
|
|
$extends['fixMode']=2; // 高度填充
|
|
}
|
|
if($imageSize[0]<200 && $imageSize[1]<240){
|
|
$extends['fixMode']=3; // 小图
|
|
}
|
|
return $extends;
|
|
}
|
|
|
|
// 获取视频封面
|
|
public function getVideoCover($filePath, $is_save = false){
|
|
$fileName=pathinfo($filePath,PATHINFO_FILENAME).'.jpg';
|
|
$ffmpegPath=env('ffmpeg.bin_path','');
|
|
if(!$ffmpegPath){
|
|
return false;
|
|
}
|
|
$path=array(
|
|
'ffmpeg.binaries' => $ffmpegPath.'/ffmpeg',
|
|
'ffprobe.binaries' => $ffmpegPath.'/ffprobe',
|
|
'timeout' => 3600, // 进程超时时间
|
|
'ffmpeg.threads' => 12, // FFMpeg应使用的线程数
|
|
);
|
|
$ffmpeg = FFMpeg::create($path);
|
|
$ffprobe = FFProbe::create($path);
|
|
$duration=$ffprobe->format($filePath)->get('duration');// 获取 duration 属性
|
|
$video = $ffmpeg->open($filePath);
|
|
$frame = $video->frame(TimeCode::fromSeconds(1));
|
|
$tempPath=root_path().'public/temp';
|
|
$savePath=$tempPath. '/' .$fileName;
|
|
$frame->save($savePath);
|
|
$info=$this->upload([],$savePath,'cover/'.date('Y-m-d').'/',false);
|
|
$info['videoInfo']['duration']= ceil($duration);
|
|
unlink($savePath);
|
|
if ($info && $is_save) {
|
|
$fileInfo=new FileModel;
|
|
$saveInfo = $info;
|
|
if (isset($saveInfo['type'])) {
|
|
unset($saveInfo['type']);
|
|
}
|
|
if (isset($saveInfo['videoInfo'])) {
|
|
unset($saveInfo['videoInfo']);
|
|
}
|
|
$exists = $fileInfo->where($saveInfo)->find();
|
|
if (!$exists) {
|
|
$fileInfo->save($saveInfo);
|
|
}
|
|
}
|
|
return $info;
|
|
}
|
|
|
|
// 压缩图片地址
|
|
protected function getCompressImg($src, $ext, $prefix)
|
|
{
|
|
$newName2 = uniqid() . '.' . $ext;
|
|
$compress_path = $prefix . $newName2;
|
|
$fullPath = root_path().'public/';
|
|
if($this->disk=='local'){
|
|
$compress_path='/storage/'.$compress_path;
|
|
$fullPath .= 'storage/';
|
|
}
|
|
|
|
// 提前创建目录
|
|
$fullPath .= $prefix;
|
|
if (!is_dir($fullPath)) {
|
|
mkdir($fullPath, 0755, true);
|
|
}
|
|
|
|
// 原图地址
|
|
$filePath = root_path().'public' . $src;
|
|
if (!file_exists($filePath)) {
|
|
return '';
|
|
}
|
|
// 处理图地址
|
|
$target = root_path().'public/' .ltrim($compress_path,'/');
|
|
// 图片模糊处理
|
|
$compress_res = $this->slightBlurGD($filePath, $target);
|
|
if (!$compress_res) {
|
|
return '';
|
|
}
|
|
return $compress_path;
|
|
}
|
|
|
|
// 使用GD库添加轻微模糊
|
|
protected function slightBlurGD($imageFile, $target)
|
|
{
|
|
// 获取图片信息
|
|
list($imgWidth, $imgHeight, $imageType) = getimagesize($imageFile);
|
|
// 根据图片类型创建图像资源
|
|
switch ($imageType) {
|
|
case IMAGETYPE_JPEG:
|
|
$image = imagecreatefromjpeg($imageFile);
|
|
break;
|
|
case IMAGETYPE_PNG:
|
|
$image = imagecreatefrompng($imageFile);
|
|
// 保留透明通道
|
|
imagealphablending($image, true);
|
|
imagesavealpha($image, true);
|
|
break;
|
|
case IMAGETYPE_GIF:
|
|
$image = imagecreatefromgif($imageFile);
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
// 获取图片尺寸
|
|
|
|
// 调整选择区域确保在图片范围内
|
|
$x = 0;
|
|
$y = 0;
|
|
|
|
// 应用马赛克效果
|
|
$this->applyMosaic($image, $x, $y, $imgWidth, $imgHeight, 5, 2);
|
|
|
|
// 保存图片
|
|
switch ($imageType) {
|
|
case IMAGETYPE_JPEG:
|
|
imagejpeg($image, $target, 85);
|
|
break;
|
|
case IMAGETYPE_PNG:
|
|
imagepng($image, $target, 8);
|
|
break;
|
|
case IMAGETYPE_GIF:
|
|
imagegif($image, $target);
|
|
break;
|
|
case IMAGETYPE_WEBP:
|
|
imagewebp($image, $target, 85);
|
|
break;
|
|
}
|
|
|
|
imagedestroy($image);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 应用马赛克效果
|
|
*
|
|
* @param resource $image 图像资源
|
|
* @param int $x 起始X坐标
|
|
* @param int $y 起始Y坐标
|
|
* @param int $width 区域宽度
|
|
* @param int $height 区域高度
|
|
* @param int $blockSize 马赛克块大小
|
|
* @param int $blurStrength 模糊强度 (1-3)
|
|
*/
|
|
protected function applyMosaic($image, $x, $y, $width, $height, $blockSize, $blurStrength) {
|
|
// 调整马赛克块大小
|
|
$adjustedBlockSize = $blockSize * $blurStrength;
|
|
|
|
// 计算马赛克网格
|
|
$cols = ceil($width / $adjustedBlockSize);
|
|
$rows = ceil($height / $adjustedBlockSize);
|
|
|
|
// 处理每个马赛克块
|
|
for ($row = 0; $row < $rows; $row++) {
|
|
for ($col = 0; $col < $cols; $col++) {
|
|
// 计算当前块的区域
|
|
$blockX = $x + $col * $adjustedBlockSize;
|
|
$blockY = $y + $row * $adjustedBlockSize;
|
|
$blockWidth = min($adjustedBlockSize, $width - $col * $adjustedBlockSize);
|
|
$blockHeight = min($adjustedBlockSize, $height - $row * $adjustedBlockSize);
|
|
|
|
// 计算块内像素的平均颜色
|
|
$avgColor = $this->calculateAverageColor($image, $blockX, $blockY, $blockWidth, $blockHeight);
|
|
|
|
// 填充整个块为平均颜色
|
|
imagefilledrectangle(
|
|
$image,
|
|
$blockX,
|
|
$blockY,
|
|
$blockX + $blockWidth - 1,
|
|
$blockY + $blockHeight - 1,
|
|
$avgColor
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 计算图像区域的平均颜色
|
|
*
|
|
* @param resource $image 图像资源
|
|
* @param int $x 起始X坐标
|
|
* @param int $y 起始Y坐标
|
|
* @param int $width 区域宽度
|
|
* @param int $height 区域高度
|
|
* @return int 颜色标识符
|
|
*/
|
|
protected function calculateAverageColor($image, $x, $y, $width, $height) {
|
|
$totalR = 0;
|
|
$totalG = 0;
|
|
$totalB = 0;
|
|
$totalAlpha = 0;
|
|
$pixelCount = 0;
|
|
|
|
// 遍历区域内的所有像素
|
|
for ($i = 0; $i < $width; $i++) {
|
|
for ($j = 0; $j < $height; $j++) {
|
|
$px = $x + $i;
|
|
$py = $y + $j;
|
|
|
|
// 确保像素在图像范围内
|
|
if ($px >= imagesx($image)) continue;
|
|
if ($py >= imagesy($image)) continue;
|
|
|
|
// 获取像素颜色
|
|
$color = imagecolorat($image, $px, $py);
|
|
$rgba = imagecolorsforindex($image, $color);
|
|
|
|
// 累加颜色值
|
|
$totalR += $rgba['red'];
|
|
$totalG += $rgba['green'];
|
|
$totalB += $rgba['blue'];
|
|
$totalAlpha += $rgba['alpha'];
|
|
$pixelCount++;
|
|
}
|
|
}
|
|
|
|
// 计算平均值
|
|
if ($pixelCount === 0) {
|
|
return imagecolorallocatealpha($image, 0, 0, 0, 127);
|
|
}
|
|
|
|
$avgR = round($totalR / $pixelCount);
|
|
$avgG = round($totalG / $pixelCount);
|
|
$avgB = round($totalB / $pixelCount);
|
|
$avgAlpha = round($totalAlpha / $pixelCount);
|
|
|
|
// 返回平均颜色
|
|
return imagecolorallocatealpha($image, $avgR, $avgG, $avgB, $avgAlpha);
|
|
}
|
|
|
|
protected function downloadImage($url, $savePath = 'temp')
|
|
{
|
|
try {
|
|
// 验证URL有效性
|
|
if (!filter_var($url, FILTER_VALIDATE_URL)) {
|
|
throw new \Exception("无效的图片URL");
|
|
}
|
|
|
|
// 创建存储目录(递归创建)
|
|
$savePath .= '/'. date("Y-m-d");
|
|
$rootPath = public_path();
|
|
$fullPath = $rootPath . $savePath;
|
|
|
|
if (!is_dir($fullPath)) {
|
|
mkdir($fullPath, 0755, true);
|
|
}
|
|
|
|
// 获取图片内容(使用cURL)
|
|
$ch = curl_init();
|
|
curl_setopt($ch, CURLOPT_URL, $url);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
|
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
|
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 跳过SSL验证
|
|
$imageData = curl_exec($ch);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
|
|
if ($httpCode !== 200 || !$imageData) {
|
|
throw new \Exception("图片下载失败,HTTP状态码: {$httpCode}");
|
|
}
|
|
curl_close($ch);
|
|
|
|
// 生成唯一文件名
|
|
$ext = pathinfo(parse_url($url, PHP_URL_PATH), PATHINFO_EXTENSION);
|
|
$ext = $ext ?: 'jpg'; // 默认jpg格式
|
|
$filename = date('YmdHis') . '_' . uniqid() . '.' . $ext;
|
|
|
|
// 保存文件
|
|
$localPath = $fullPath . '/' . $filename;
|
|
if (!file_put_contents($localPath, $imageData)) {
|
|
throw new \Exception("文件保存失败");
|
|
}
|
|
|
|
// 返回相对路径(适用于web访问)
|
|
return ['status' => 1, 'path' => $savePath . '/' . $filename];
|
|
} catch (\Exception $e) {
|
|
return ['status' => 0];
|
|
}
|
|
}
|
|
}
|
|
|