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);
|
||
}
|
||
} |