501 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
			
		
		
	
	
			501 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
| <?php
 | ||
| 
 | ||
| 
 | ||
| namespace app\controller\manager;
 | ||
| 
 | ||
| use app\model\Log;
 | ||
| use app\service\AliOss;
 | ||
| use think\facade\Config;
 | ||
| use Exception;
 | ||
| use app\model\Attachment as AttachmentModel;
 | ||
| use think\db\exception\DataNotFoundException;
 | ||
| use think\db\exception\DbException;
 | ||
| use think\db\exception\ModelNotFoundException;
 | ||
| use think\exception\ValidateException;
 | ||
| use think\response\Json;
 | ||
| use think\response\View;
 | ||
| 
 | ||
| /**
 | ||
|  * 附件管理 - 素材管理
 | ||
|  * Class Attachment
 | ||
|  * @package app\controller\manager
 | ||
|  */
 | ||
| class Attachment extends Base
 | ||
| {
 | ||
|     protected $noNeedLogin = ['file', 'getSize', 'md5List', 'pathDirHandle', 'toOss', 'delLostFile', 'test'];
 | ||
|     protected $DIRECTORY_SEPARATOR = "/";
 | ||
| 
 | ||
|     protected function initialize()
 | ||
|     {
 | ||
|         parent::initialize(); // TODO: Change the autogenerated stub
 | ||
|         $this->DIRECTORY_SEPARATOR = DIRECTORY_SEPARATOR == "\\" ? "/" : DIRECTORY_SEPARATOR;
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 删除
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      * @throws DataNotFoundException
 | ||
|      * @throws DbException
 | ||
|      * @throws ModelNotFoundException
 | ||
|      */
 | ||
|     public function del(): Json
 | ||
|     {
 | ||
|         if ($this->request->isPost()) {
 | ||
|             $ids = input('post.ids/a', []);
 | ||
|             if (empty($ids)) {
 | ||
|                 $ids[] = input('post.id/d');
 | ||
|             }
 | ||
| 
 | ||
|             $items = AttachmentModel::whereIn('id', $ids)->where('is_dir', AttachmentModel::COMMON_ON)->select();
 | ||
|             if ($items->where('is_dir', AttachmentModel::COMMON_ON)->count()) {
 | ||
|                 $dirPaths = [];
 | ||
|                 foreach ($items->toArray() as $item) {
 | ||
|                     $dirPaths[] = $item['path'].$item['name'].$this->DIRECTORY_SEPARATOR;
 | ||
|                 }
 | ||
|                 if (AttachmentModel::where('path', 'in', $dirPaths)->count()) {
 | ||
|                     return $this->json(4001, '待删除目录下存在内容!');
 | ||
|                 }
 | ||
|             }
 | ||
|             AttachmentModel::deleteByIds($ids);
 | ||
| 
 | ||
|             //            Log::write(get_class().'Del', 'del', '涉及到的ID为:'.implode(',', $ids));
 | ||
|             return $this->json();
 | ||
|         }
 | ||
|         return $this->json(4001, '非法请求!');
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 单个字段编辑
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      * @throws Exception
 | ||
|      */
 | ||
|     public function modify(): Json
 | ||
|     {
 | ||
|         if ($this->request->isPost()) {
 | ||
|             $item     = input('post.');
 | ||
|             $validate = $this->validateByApi($item, [
 | ||
|                 'field' => 'require',
 | ||
|                 'value' => 'require',
 | ||
|             ]);
 | ||
| 
 | ||
|             if ($validate !== true) {
 | ||
|                 return $validate;
 | ||
|             }
 | ||
| 
 | ||
|             if (!$info = AttachmentModel::findById($item['id'])) {
 | ||
|                 return $this->json(4001, '记录不存在');
 | ||
|             }
 | ||
| 
 | ||
|             if ($item['field'] == 'name' && $info['is_dir'] == AttachmentModel::COMMON_ON) {
 | ||
|                 return $this->json(4002, '目录名称不能修改');
 | ||
| 
 | ||
|             }
 | ||
| 
 | ||
|             $update = [$item['field'] => $item['value']];
 | ||
| 
 | ||
|             try {
 | ||
|                 $info->save($update);
 | ||
|                 return $this->json();
 | ||
|             } catch (ValidateException $e) {
 | ||
|                 return $this->json(4001, $e->getError());
 | ||
|             }
 | ||
|         }
 | ||
|         return $this->json(4000, '非法请求');
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 添加
 | ||
|      *
 | ||
|      * @return Json|View
 | ||
|      * @throws Exception
 | ||
|      */
 | ||
|     public function add()
 | ||
|     {
 | ||
|         if ($this->request->isPost()) {
 | ||
|             $item = input('post.');
 | ||
| 
 | ||
|             $validate = $this->validateByApi($item, [
 | ||
|                 'title|合集标题'     => 'require',
 | ||
|                 'user|虚拟用户'      => 'require',
 | ||
|                 'headimg|虚拟用户头像' => 'require',
 | ||
|             ]);
 | ||
| 
 | ||
|             if ($validate !== true) {
 | ||
|                 return $validate;
 | ||
|             }
 | ||
| 
 | ||
|             try {
 | ||
|                 $now                = date('Y-m-d H:i:s');
 | ||
|                 $item['created_at'] = $now;
 | ||
|                 $item['created_by'] = $this->auth['user_id'];
 | ||
|                 AttachmentModel::create($item);
 | ||
|                 return $this->json();
 | ||
|             } catch (ValidateException $e) {
 | ||
|                 return $this->json(4001, $e->getError());
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         return $this->view();
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 添加文件夹
 | ||
|      *
 | ||
|      * @return Json|View
 | ||
|      * @throws Exception
 | ||
|      */
 | ||
|     public function addFolder()
 | ||
|     {
 | ||
|         if ($this->request->isPost()) {
 | ||
|             $item = input('post.');
 | ||
| 
 | ||
|             $validate = $this->validateByApi($item, [
 | ||
|                 'name|文件夹名称' => 'require|alphaDash|max:20',
 | ||
|                 'path|文件路径'  => 'require',
 | ||
|             ]);
 | ||
| 
 | ||
|             // 例 name=dir4 path=/storage/dir1/dir2/dir3
 | ||
| 
 | ||
|             // 去首尾/
 | ||
|             $path = trim($item['path'], $this->DIRECTORY_SEPARATOR);
 | ||
|             // 全路径 如 /storage/dir1/dir2/dir3/dir4/  注意前后都有/
 | ||
|             $fullPath = $this->DIRECTORY_SEPARATOR.$path.$this->DIRECTORY_SEPARATOR.$item['name'].$this->DIRECTORY_SEPARATOR;
 | ||
| 
 | ||
|             if ($validate !== true) {
 | ||
|                 return $validate;
 | ||
|             }
 | ||
| 
 | ||
|             AttachmentModel::pathDirHandle($fullPath);
 | ||
|             return $this->json();
 | ||
|         }
 | ||
| 
 | ||
|         $path = input('path/s', AttachmentModel::ROOT_PATH);
 | ||
| 
 | ||
|         $this->data['path'] = $path;
 | ||
|         return $this->view();
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 图片列表
 | ||
|      *
 | ||
|      * @return View|Json
 | ||
|      * @throws Exception
 | ||
|      */
 | ||
|     public function image()
 | ||
|     {
 | ||
|         $path     = input('post.path', AttachmentModel::ROOT_PATH);
 | ||
|         $path     = $this->DIRECTORY_SEPARATOR.trim($path, $this->DIRECTORY_SEPARATOR).$this->DIRECTORY_SEPARATOR;
 | ||
|         $path     = str_replace("\\", "/", $path);
 | ||
|         $type     = input('type/s', 'image');
 | ||
|         $selected = input('selected', false);
 | ||
|         $multiple = input('multiple', false);
 | ||
| 
 | ||
|         Config::load('extra/alioss', 'alioss');
 | ||
|         Config::load('extra/base', 'base');
 | ||
|         $config     = config('alioss');
 | ||
|         $baseConfig = config('base');
 | ||
| 
 | ||
|         $oss = $baseConfig['oss'] == 'true' ? $config['customDomain'] : '';
 | ||
| 
 | ||
|         if ($this->request->isPost()) {
 | ||
|             $items = $this->list($path, ['image']);
 | ||
| 
 | ||
|             return $this->json(0, '操作成功', $items);
 | ||
|         }
 | ||
| 
 | ||
|         $this->data['path']     = $path;
 | ||
|         $this->data['oss']      = $oss;
 | ||
|         $this->data['type']     = $type;
 | ||
|         $this->data['multiple'] = $multiple;
 | ||
|         $this->data['selected'] = $selected;
 | ||
|         return $this->view();
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 视频列表
 | ||
|      *
 | ||
|      * @return View|Json
 | ||
|      * @throws Exception
 | ||
|      */
 | ||
|     public function video()
 | ||
|     {
 | ||
|         $path     = input('post.path', AttachmentModel::ROOT_PATH);
 | ||
|         $path     = $this->DIRECTORY_SEPARATOR.trim($path, $this->DIRECTORY_SEPARATOR).$this->DIRECTORY_SEPARATOR;
 | ||
|         $path     = str_replace("\\", "/", $path);
 | ||
|         $type     = input('type/s', 'video');
 | ||
|         $selected = input('selected', false);
 | ||
|         $multiple = input('multiple', false);
 | ||
| 
 | ||
|         Config::load('extra/alioss', 'alioss');
 | ||
|         Config::load('extra/base', 'base');
 | ||
|         $config     = config('alioss');
 | ||
|         $baseConfig = config('base');
 | ||
|         $oss        = $baseConfig['oss'] == 'true' ? $config['customDomain'] : '';
 | ||
|         if ($this->request->isPost()) {
 | ||
|             $items = $this->list($path, ['video']);
 | ||
| 
 | ||
|             return $this->json(0, '操作成功', $items);
 | ||
|         }
 | ||
| 
 | ||
|         $this->data['path']     = $path;
 | ||
|         $this->data['oss']      = $oss;
 | ||
|         $this->data['type']     = $type;
 | ||
|         $this->data['multiple'] = $multiple;
 | ||
|         $this->data['selected'] = $selected;
 | ||
|         return $this->view();
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 文件列表
 | ||
|      *
 | ||
|      * @return View|Json
 | ||
|      * @throws Exception
 | ||
|      */
 | ||
|     public function file()
 | ||
|     {
 | ||
|         Config::load('extra/alioss', 'alioss');
 | ||
|         $config     = config('alioss');
 | ||
|         $baseConfig = config('base');
 | ||
|         $oss        = $baseConfig['oss'] == 'true' ? $config['customDomain'] : '';
 | ||
|         $type       = input('type/s', 'all');
 | ||
|         $selected   = input('selected', false);
 | ||
|         $multiple   = input('multiple', false);
 | ||
| 
 | ||
|         if ($this->request->isPost()) {
 | ||
|             $page         = input('post.page', 1);
 | ||
|             $size         = input('post.size', 20);
 | ||
|             $searchParams = input('searchParams');
 | ||
|             $where        = [];
 | ||
| 
 | ||
|             if ($searchParams) {
 | ||
|                 foreach ($searchParams as $key => $param) {
 | ||
|                     if (!empty($param)) {
 | ||
|                         if (is_string($param)) {
 | ||
|                             if ($key == 'is_oss') {
 | ||
|                                 if ($param >= 0) {
 | ||
|                                     $where[] = ['is_oss', '=', $param];
 | ||
|                                 }
 | ||
|                             } else {
 | ||
|                                 $where[] = [$key, 'like', '%'.$param.'%'];
 | ||
|                             }
 | ||
|                         } elseif (is_array($param)) {
 | ||
|                             //数组空元素去除
 | ||
|                             foreach ($param as $k => $val) {
 | ||
|                                 if (empty($val)) {
 | ||
|                                     unset($param[$k]);
 | ||
|                                 }
 | ||
|                             }
 | ||
|                             if (!empty($param)) {
 | ||
|                                 $where[] = [$key, 'in', $param];
 | ||
|                             }
 | ||
|                         }
 | ||
|                     }
 | ||
|                 }
 | ||
|             }
 | ||
| 
 | ||
| 
 | ||
|             if ($type !== 'all') {
 | ||
|                 $where[] = ['type', '=', $type];
 | ||
|             }
 | ||
| 
 | ||
|             $items = AttachmentModel::findList($where, [], $page, $size, function ($q) {
 | ||
|                 return $q->where('type', '<>', 'dir')->order('updated_at', 'desc');
 | ||
|             });
 | ||
| 
 | ||
|             $items['list']->each(function ($item) {
 | ||
|                 $item->size_text = getFilesize($item['size'] ?? 0);
 | ||
|             });
 | ||
| 
 | ||
|             return $this->json(0, '操作成功', $items);
 | ||
|         }
 | ||
| 
 | ||
|         $this->data['oss']      = $oss;
 | ||
|         $this->data['type']     = $type;
 | ||
|         $this->data['multiple'] = $multiple;
 | ||
|         $this->data['selected'] = $selected;
 | ||
|         return $this->view();
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 一键删除失效记录 即oss不存在&&本地不存在
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      */
 | ||
|     public function delLostFile(): Json
 | ||
|     {
 | ||
|         if ($this->request->isPost()) {
 | ||
|             $total = AttachmentModel::where('type', '<>', AttachmentModel::TYPE_DIR)
 | ||
|                 ->where('is_dir', AttachmentModel::COMMON_OFF)
 | ||
|                 ->where('is_oss', AttachmentModel::COMMON_OFF)
 | ||
|                 ->where('has_local', AttachmentModel::COMMON_OFF)
 | ||
|                 ->count();
 | ||
|             if ($total === 0) {
 | ||
|                 return $this->json(0, 'success', ['total' => $total]);
 | ||
|             }
 | ||
| 
 | ||
|             if (AttachmentModel::where('type', '<>', AttachmentModel::TYPE_DIR)
 | ||
|                 ->where('is_dir', AttachmentModel::COMMON_OFF)
 | ||
|                 ->where('is_oss', AttachmentModel::COMMON_OFF)
 | ||
|                 ->where('has_local', AttachmentModel::COMMON_OFF)
 | ||
|                 ->delete()) {
 | ||
|                 return $this->json(0, 'success', ['total' => $total]);
 | ||
|             }
 | ||
|             return $this->json(4004, '删除失败');
 | ||
|         }
 | ||
|         return $this->json(4000, '请求错误');
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 一键上传本地文件到OSS
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      */
 | ||
|     public function toOss(): Json
 | ||
|     {
 | ||
|         if ($this->request->isPost()) {
 | ||
|             Config::load('extra/alioss', 'alioss');
 | ||
|             Config::load('extra/base', 'base');
 | ||
|             $config     = config('alioss');
 | ||
|             $baseConfig = config('base');
 | ||
|             if ($baseConfig['oss'] != 'true') {
 | ||
|                 return $this->json('4000', '配置未开启OSS上传');
 | ||
|             }
 | ||
| 
 | ||
|             $ossObject = AliOss::instance();
 | ||
|             $bucket    = $config['bucket'];
 | ||
| 
 | ||
|             $total = AttachmentModel::where('type', '<>', AttachmentModel::TYPE_DIR)
 | ||
|                 ->where('is_dir', AttachmentModel::COMMON_OFF)
 | ||
|                 ->where('is_oss', AttachmentModel::COMMON_OFF)
 | ||
|                 ->field('id')
 | ||
|                 ->count();
 | ||
|             $done  = 0;
 | ||
|             $none  = 0;
 | ||
|             if ($total === 0) {
 | ||
|                 return $this->json(0, 'success', ['total' => $total, 'done' => $done, 'none' => $none]);
 | ||
|             }
 | ||
|             try {
 | ||
|                 AttachmentModel::where('type', '<>', AttachmentModel::TYPE_DIR)
 | ||
|                     ->where('is_dir', AttachmentModel::COMMON_OFF)
 | ||
|                     ->where('is_oss', AttachmentModel::COMMON_OFF)
 | ||
|                     ->field('id,src')
 | ||
|                     ->chunk(3, function ($items) use ($ossObject, $bucket, &$done, &$none) {
 | ||
|                         $doneIds = [];
 | ||
|                         $noneIds = [];
 | ||
|                         foreach ($items as $item) {
 | ||
|                             if ($item['src']) {
 | ||
|                                 $realPath = public_path().ltrim($item['src'], $this->DIRECTORY_SEPARATOR);
 | ||
|                                 if (!file_exists($realPath)) {
 | ||
|                                     $none++;
 | ||
|                                     $noneIds[] = $item['id'];
 | ||
|                                     continue;
 | ||
|                                 }
 | ||
|                                 $pathInfo = pathinfo($item['src']);
 | ||
|                                 $object   = ltrim($item['src'], $this->DIRECTORY_SEPARATOR);
 | ||
|                                 //是否存在
 | ||
|                                 if (!$ossObject->doesObjectExist($bucket, $object)) {
 | ||
|                                     //创建目录
 | ||
|                                     $ossObject->createObjectDir($bucket, ltrim($pathInfo['dirname'], $this->DIRECTORY_SEPARATOR));
 | ||
| 
 | ||
|                                     $ossObject->uploadFile($bucket, $object, $realPath);
 | ||
|                                 }
 | ||
|                                 $doneIds[] = $item['id'];
 | ||
|                                 $done++;
 | ||
|                             }
 | ||
|                         }
 | ||
| 
 | ||
|                         // 失效标记
 | ||
|                         if ($noneIds) {
 | ||
|                             $update = ['is_oss' => AttachmentModel::COMMON_OFF, 'has_local' => AttachmentModel::COMMON_OFF];
 | ||
|                             (new AttachmentModel())->where('id', 'in', $noneIds)->update($update);
 | ||
|                         }
 | ||
| 
 | ||
|                         // 完成标记
 | ||
|                         if ($doneIds) {
 | ||
|                             $update = ['is_oss' => AttachmentModel::COMMON_ON];
 | ||
|                             (new AttachmentModel())->where('id', 'in', $doneIds)->update($update);
 | ||
|                         }
 | ||
|                     });
 | ||
| 
 | ||
|                 return $this->json(0, 'success', ['total' => $total, 'done' => $done, 'none' => $none]);
 | ||
|             } catch (Exception $e) {
 | ||
|                 \think\facade\Log::error('本地文件一键上传OSS失败 '.$e->getMessage());
 | ||
|                 return $this->json(0, 'success', ['total' => $total, 'done' => $done, 'none' => $none]);
 | ||
|             }
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 指定类型附件列表
 | ||
|      *
 | ||
|      * @param  array  $type
 | ||
|      * @param  string  $path
 | ||
|      * @return array
 | ||
|      * @throws Exception
 | ||
|      */
 | ||
|     protected function list(string $path, array $type): array
 | ||
|     {
 | ||
|         $type[]  = 'dir';
 | ||
|         $where[] = ['path', '=', $path];
 | ||
|         $where[] = ['type', 'in', $type];
 | ||
|         $items   = AttachmentModel::findList($where, [], 1, 0, function ($q) {
 | ||
|             return $q->order('is_dir', 'desc')->order('updated_at', 'desc');
 | ||
|         });
 | ||
|         $items['list']->each(function ($item) {
 | ||
|             $item->size_text = getFilesize($item['size'] ?? 0);
 | ||
|         });
 | ||
|         $items['path'] = $path;
 | ||
| 
 | ||
|         return $items;
 | ||
|     }
 | ||
| 
 | ||
|     /**
 | ||
|      * 获取文件大小
 | ||
|      *
 | ||
|      * @return Json
 | ||
|      */
 | ||
|     public function getSize(): Json
 | ||
|     {
 | ||
|         $path  = input('post.path', '');
 | ||
|         $types = input('post.type/a', []);
 | ||
| 
 | ||
|         $size = '';
 | ||
|         if (empty($path)) {
 | ||
|             return $this->json(0, '操作成功', $size);
 | ||
|         }
 | ||
|         $path  = str_replace("\\", "/", $path);
 | ||
|         $total = AttachmentModel::where('path', 'like', $path.'%')
 | ||
|             ->when(!empty($types), function ($q) use ($types) {
 | ||
|                 $q->where('type', 'in', $types);
 | ||
|             })
 | ||
|             ->sum('size');
 | ||
| 
 | ||
|         return $this->json(0, '操作成功', getFilesize($total));
 | ||
|     }
 | ||
| 
 | ||
|     // 将没有md5的文件 更新md5  仅针对本地文件
 | ||
|     public function md5List()
 | ||
|     {
 | ||
|         $noMd5List = AttachmentModel::whereNull('md5')->select();
 | ||
|         $update    = [];
 | ||
|         foreach ($noMd5List as $item) {
 | ||
|             try {
 | ||
|                 if (!empty($item['src'])) {
 | ||
|                     $arr        = [];
 | ||
|                     $path       = public_path().ltrim($item['src'], $this->DIRECTORY_SEPARATOR);
 | ||
|                     $file       = new \think\File($path);
 | ||
|                     $arr['md5'] = $file->md5();
 | ||
|                     $arr['id']  = $item['id'];
 | ||
| 
 | ||
|                     $update[] = $arr;
 | ||
|                 }
 | ||
|             } catch (Exception $e) {
 | ||
|                 continue;
 | ||
|             }
 | ||
| 
 | ||
|         }
 | ||
|         (new AttachmentModel())->saveAll($update);
 | ||
|     }
 | ||
| } |