488 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			PHP
		
	
	
			
		
		
	
	
			488 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			PHP
		
	
	
<?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 = config('alioss');
 | 
						||
        $oss    = $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 = config('alioss');
 | 
						||
        $oss    = $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');
 | 
						||
        $oss      = $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 = config('alioss');
 | 
						||
 | 
						||
            $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);
 | 
						||
    }
 | 
						||
} |