前后端分离 ueditor 上传至腾讯cos

2020-12-04 17:07:26   php分享记录

 

啥都不说,开整

后端框架 laravel

  1. ueditor.config.js 修改

    1. //改成自己的就好
    2. serverUrl: "http://127.0.0.1:8098/api/ueditor/eventHandler"
  2. config目录新增 ueditor.php

    1. return [
    2. // 上传图片配置项
    3. 'imageActionName' => 'uploadimage', // 执行上传图片的action名称
    4. 'imageFieldName' => 'upfile', // 提交的图片表单名称
    5. 'imageMaxSize' => 2048000, // 上传大小限制,单位B
    6. 'imageAllowFiles' => ['.png', '.jpg', '.jpeg', '.gif', '.bmp'], // 上传图片格式显示
    7. 'imageCompressEnable'=> true, // 是否压缩图片,默认是true
    8. 'imageCompressBorder'=> 1600, // 图片压缩最长边限制
    9. 'imageInsertAlign' => 'none', // 插入的图片浮动方式
    10. 'imageUrlPrefix' => '', // 图片访问路径前缀
    11. 'imagePathFormat' => '/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}', // 上传保存路径,可以自定义保存路径和文件名格式
    12. // {filename} 会替换成原文件名,配置这项需要注意中文乱码问题
    13. // {rand=>6} 会替换成随机数,后面的数字是随机数的位数
    14. // {time} 会替换成时间戳
    15. // {yyyy} 会替换成四位年份
    16. // {yy} 会替换成两位年份
    17. // {mm} 会替换成两位月份
    18. // {dd} 会替换成两位日期
    19. // {hh} 会替换成两位小时
    20. // {ii} 会替换成两位分钟
    21. // {ss} 会替换成两位秒
    22. // 非法字符 \ => * ? " < > |
    23. // 具请体看线上文档=> fex.baidu.com/ueditor/#use-format_upload_filename
    24. // 涂鸦图片上传配置项
    25. 'scrawlActionName' => 'uploadscrawl', // 执行上传涂鸦的action名称
    26. 'scrawlFieldName' => 'upfile', // 提交的图片表单名称
    27. 'scrawlPathFormat' => '/ueditor/php/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}', // 上传保存路径,可以自定义保存路径和文件名格式
    28. 'scrawlMaxSize' => 2048000, // 上传大小限制,单位B
    29. 'scrawlUrlPrefix' => '', // 图片访问路径前缀
    30. 'scrawlInsertAlign'=> 'none',
    31. // 截图工具上传
    32. 'snapscreenActionName' => 'uploadimage', // 执行上传截图的action名称
    33. 'snapscreenPathFormat' => '/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}', // 上传保存路径,可以自定义保存路径和文件名格式
    34. 'snapscreenUrlPrefix' => '', // 图片访问路径前缀
    35. 'snapscreenInsertAlign'=> 'none', // 插入的图片浮动方式
    36. // 抓取远程图片配置
    37. 'catcherLocalDomain'=> ['127.0.0.1', 'localhost', 'img.baidu.com'],
    38. 'catcherActionName' => 'catchimage', // 执行抓取远程图片的action名称
    39. 'catcherFieldName' => 'source', // 提交的图片列表表单名称
    40. 'catcherPathFormat' => '/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}', // 上传保存路径,可以自定义保存路径和文件名格式
    41. 'catcherUrlPrefix' => '', // 图片访问路径前缀
    42. 'catcherMaxSize' => 2048000, // 上传大小限制,单位B
    43. 'catcherAllowFiles' => ['.png', '.jpg', '.jpeg', '.gif', '.bmp'], // 抓取图片格式显示
    44. // 上传视频配置
    45. 'videoActionName'=> 'uploadvideo', // 执行上传视频的action名称
    46. 'videoFieldName' => 'upfile', // 提交的视频表单名称
    47. 'videoPathFormat'=> '/upload/video/{yyyy}{mm}{dd}/{time}{rand:6}', // 上传保存路径,可以自定义保存路径和文件名格式
    48. 'videoUrlPrefix' => '', // 视频访问路径前缀
    49. 'videoMaxSize' => 102400000, // 上传大小限制,单位B,默认100MB
    50. 'videoAllowFiles'=> [
    51. '.flv', '.swf', '.mkv', '.avi', '.rm', '.rmvb', '.mpeg', '.mpg',
    52. '.ogg', '.ogv', '.mov', '.wmv', '.mp4', '.webm', '.mp3', '.wav', '.mid', ], // 上传视频格式显示
    53. // 上传文件配置
    54. 'fileActionName'=> 'uploadfile', // controller里,执行上传视频的action名称
    55. 'fileFieldName' => 'upfile', // 提交的文件表单名称
    56. 'filePathFormat'=> '/upload/file/{yyyy}{mm}{dd}/{time}{rand:6}', // 上传保存路径,可以自定义保存路径和文件名格式
    57. 'fileUrlPrefix' => '', // 文件访问路径前缀
    58. 'fileMaxSize' => 51200000, // 上传大小限制,单位B,默认50MB
    59. 'fileAllowFiles'=> [
    60. '.png', '.jpg', '.jpeg', '.gif', '.bmp',
    61. '.flv', '.swf', '.mkv', '.avi', '.rm', '.rmvb', '.mpeg', '.mpg',
    62. '.ogg', '.ogv', '.mov', '.wmv', '.mp4', '.webm', '.mp3', '.wav', '.mid',
    63. '.rar', '.zip', '.tar', '.gz', '.7z', '.bz2', '.cab', '.iso',
    64. '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.pdf', '.txt', '.md', '.xml',
    65. ], // 上传文件格式显示
    66. // 列出指定目录下的图片
    67. 'imageManagerActionName' => 'listimage', // 执行图片管理的action名称
    68. 'imageManagerListPath' => '/upload/image/', // 指定要列出图片的目录
    69. 'imageManagerListSize' => 20, // 每次列出文件数量
    70. 'imageManagerUrlPrefix' => '', // 图片访问路径前缀
    71. 'imageManagerInsertAlign'=> 'none', // 插入的图片浮动方式
    72. 'imageManagerAllowFiles' => ['.png', '.jpg', '.jpeg', '.gif', '.bmp'], // 列出的文件类型
    73. // 列出指定目录下的文件
    74. 'fileManagerActionName'=> 'listfile', // 执行文件管理的action名称
    75. 'fileManagerListPath' => '/upload/file/', // 指定要列出文件的目录
    76. 'fileManagerUrlPrefix' => '', // 文件访问路径前缀
    77. 'fileManagerListSize' => 20, // 每次列出文件数量
    78. 'fileManagerAllowFiles'=> [
    79. '.png', '.jpg', '.jpeg', '.gif', '.bmp',
    80. '.flv', '.swf', '.mkv', '.avi', '.rm', '.rmvb', '.mpeg', '.mpg',
    81. '.ogg', '.ogv', '.mov', '.wmv', '.mp4', '.webm', '.mp3', '.wav', '.mid',
    82. '.rar', '.zip', '.tar', '.gz', '.7z', '.bz2', '.cab', '.iso',
    83. '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.pdf', '.txt', '.md', '.xml',
    84. ], // 列出的文件类型
    85. ];
  1. 后端代码请自行设置允许跨域

    1. namespace App\Http\Controllers;
    2. use App\Http\Service\UeditorService;
    3. use Illuminate\Http\Request;
    4. class UeditorController extends Controller
    5. {
    6. /**
    7. * ueditor 入口程序.
    8. *
    9. * @return false|string
    10. */
    11. public function index(Request $request)
    12. {
    13. $action = $request->input('action', 'uploadimage');
    14. $ueditor = config('ueditor');
    15. switch ($action) {
    16. case 'config':
    17. $result = json_encode($ueditor);
    18. break;
    19. case 'uploadimage':
    20. $config = [
    21. 'pathFormat' => $ueditor['imagePathFormat'],
    22. 'maxSize' => $ueditor['imageMaxSize'],
    23. 'allowFiles' => $ueditor['imageAllowFiles'],
    24. ];
    25. $fieldName = $ueditor['imageFieldName'];
    26. $up = new UeditorService($fieldName, $config, 'upload');
    27. $result = json_encode($up->getFileInfo());
    28. break;
    29. case 'uploadscrawl':
    30. $config = [
    31. 'pathFormat' => $ueditor['scrawlPathFormat'],
    32. 'maxSize' => $ueditor['scrawlMaxSize'],
    33. 'allowFiles' => $ueditor['scrawlAllowFiles'],
    34. 'oriName' => 'scrawl.png',
    35. ];
    36. $fieldName = $ueditor['scrawlFieldName'];
    37. $base64 = 'base64';
    38. $up = new UeditorService($fieldName, $config, $base64);
    39. $result = json_encode($up->getFileInfo());
    40. break;
    41. case 'uploadvideo':
    42. $config = [
    43. 'pathFormat' => $ueditor['videoPathFormat'],
    44. 'maxSize' => $ueditor['videoMaxSize'],
    45. 'allowFiles' => $ueditor['videoAllowFiles'],
    46. ];
    47. $fieldName = $ueditor['videoFieldName'];
    48. $up = new UeditorService($fieldName, $config, 'upload');
    49. $result = json_encode($up->getFileInfo());
    50. break;
    51. case 'uploadfile':
    52. $config = [
    53. 'pathFormat' => $ueditor['filePathFormat'],
    54. 'maxSize' => $ueditor['fileMaxSize'],
    55. 'allowFiles' => $ueditor['fileAllowFiles'],
    56. ];
    57. $fieldName = $ueditor['fileFieldName'];
    58. $up = new UeditorService($fieldName, $config, 'upload');
    59. $result = json_encode($up->getFileInfo());
    60. break;
    61. // 列出图片
    62. case 'listimage':
    63. $result = json_encode(UeditorService::listFiles($request->start, $request->size, 'imagePathFormat'));
    64. break;
    65. // 列出文件
    66. case 'listfile':
    67. $result = json_encode(UeditorService::listFiles($request->start, $request->size, 'filePathFormat'));
    68. break;
    69. // 抓取远程文件
    70. case 'catchimage':
    71. // 上传配置
    72. $config = [
    73. 'pathFormat' => $ueditor['catcherPathFormat'],
    74. 'maxSize' => $ueditor['catcherMaxSize'],
    75. 'allowFiles' => $ueditor['catcherAllowFiles'],
    76. 'oriName' => 'remote.png',
    77. ];
    78. $fieldName = $ueditor['catcherFieldName'];
    79. $up = new UeditorService($fieldName, $config, 'remote');
    80. $result = json_encode($up->getFileInfo());
    81. break;
    82. default:
    83. $result = json_encode([
    84. 'state'=> '请求地址出错',
    85. ]);
    86. break;
    87. }
    88. // 输出结果
    89. if (isset($_GET['callback'])) {
    90. if (preg_match('/^[\\w_]+$/', $_GET['callback'])) {
    91. return htmlspecialchars($_GET['callback']) . '(' . $result . ')';
    92. }
    93. return json_encode([
    94. 'state'=> 'callback参数不合法',
    95. ]);
    96. }
    97. return $result;
    98. }
    99. }
  2. service

  1. namespace App\Http\Service;
  2. use Carbon\Carbon;
  3. class UeditorService
  4. {
  5. private $fileField; //文件域名
  6. private $file; //文件上传对象
  7. private $base64; //文件上传对象
  8. private $config; //配置信息
  9. private $oriName; //原始文件名
  10. private $fileName; //新文件名
  11. private $fullName; //完整文件名,即从当前配置目录开始的URL
  12. private $filePath; //完整文件名,即从当前配置目录开始的URL
  13. private $fileSize; //文件大小
  14. private $fileType; //文件类型
  15. private $stateInfo; //上传状态信息,
  16. private $stateMap = [ //上传状态映射表,国际化用户需考虑此处数据的国际化
  17. 'SUCCESS', //上传成功标记,在UEditor中内不可改变,否则flash判断会出错
  18. '文件大小超出 upload_max_filesize 限制',
  19. '文件大小超出 MAX_FILE_SIZE 限制',
  20. '文件未被完整上传',
  21. '没有文件被上传',
  22. '上传文件为空',
  23. 'ERROR_TMP_FILE' => '临时文件错误',
  24. 'ERROR_TMP_FILE_NOT_FOUND' => '找不到临时文件',
  25. 'ERROR_SIZE_EXCEED' => '文件大小超出网站限制',
  26. 'ERROR_TYPE_NOT_ALLOWED' => '文件类型不允许',
  27. 'ERROR_CREATE_DIR' => '目录创建失败',
  28. 'ERROR_DIR_NOT_WRITEABLE' => '目录没有写权限',
  29. 'ERROR_FILE_MOVE' => '文件保存时出错',
  30. 'ERROR_FILE_NOT_FOUND' => '找不到上传文件',
  31. 'ERROR_WRITE_CONTENT' => '写入文件内容错误',
  32. 'ERROR_UNKNOWN' => '未知错误',
  33. 'ERROR_DEAD_LINK' => '链接不可用',
  34. 'ERROR_HTTP_LINK' => '链接不是http链接',
  35. 'ERROR_HTTP_CONTENTTYPE' => '链接contentType不正确',
  36. ];
  37. /**
  38. * @var UploadService
  39. */
  40. private $ossService;
  41. /**
  42. * @var mixed|string
  43. */
  44. private $path; //自定义文件存储路径
  45. /**
  46. * 构造函数.
  47. *
  48. * @param string $fileField 表单名称
  49. * @param array $config 配置项
  50. * @param string $type 处理文件上传的方式
  51. * @param mixed $path
  52. */
  53. public function __construct($fileField, $config, $type = 'upload', $path = 'upload/news/')
  54. {
  55. parent::__construct();
  56. $this->ossService = new OssService();
  57. $this->path = $path;
  58. $this->fileField = $fileField;
  59. $this->config = $config;
  60. $this->type = $type;
  61. if ('remote' == $type) {
  62. $this->saveRemote();
  63. } elseif ('base64' == $type) {
  64. $this->upBase64();
  65. } else {
  66. $this->upFile();
  67. }
  68. $this->stateMap['ERROR_TYPE_NOT_ALLOWED'] = mb_convert_encoding($this->stateMap['ERROR_TYPE_NOT_ALLOWED'], 'utf-8', 'auto');
  69. }
  70. /**
  71. * 上传文件的主处理方法.
  72. *
  73. * @return mixed
  74. */
  75. private function upFile()
  76. {
  77. $file = $this->file = \Request::capture()->file($this->fileField);
  78. if (!$file) {
  79. $this->stateInfo = $this->getStateInfo('ERROR_FILE_NOT_FOUND');
  80. return;
  81. }
  82. if ($this->file->getError()) {
  83. $this->stateInfo = $this->getStateInfo($file->getError());
  84. return;
  85. }
  86. if (!file_exists($file->getPathname())) {
  87. $this->stateInfo = $this->getStateInfo('ERROR_TMP_FILE_NOT_FOUND');
  88. return;
  89. }
  90. if (!is_uploaded_file($file->getPathname())) {
  91. $this->stateInfo = $this->getStateInfo('ERROR_TMPFILE');
  92. return;
  93. }
  94. $this->oriName = $file->getClientOriginalName();
  95. $this->fileSize = $file->getSize();
  96. $this->fileType = $this->getFileExt();
  97. $this->fullName = $this->getFullName();
  98. $this->filePath = $this->getFilePath();
  99. $this->fileName = $this->getFileName();
  100. $dirname = dirname($this->filePath);
  101. //检查文件大小是否超出限制
  102. if (!$this->checkSize()) {
  103. $this->stateInfo = $this->getStateInfo('ERROR_SIZE_EXCEED');
  104. return;
  105. }
  106. //检查是否不允许的文件格式
  107. if (!$this->checkType()) {
  108. $this->stateInfo = $this->getStateInfo('ERROR_TYPE_NOT_ALLOWED');
  109. return;
  110. }
  111. if ($obj = $this->ossService->put($this->fullName, $file)) {
  112. $this->fullName = $obj;
  113. $this->stateInfo = $this->stateMap[0];
  114. } else {
  115. $this->stateInfo = $this->getStateInfo('ERROR_WRITE_CONTENT');
  116. }
  117. }
  118. /**
  119. * 处理base64编码的图片上传.
  120. *
  121. * @return mixed
  122. */
  123. private function upBase64()
  124. {
  125. $base64Data = $_POST[$this->fileField];
  126. $img = base64_decode($base64Data);
  127. $this->oriName = $this->config['oriName'];
  128. $this->fileSize = strlen($img);
  129. $this->fileType = $this->getFileExt();
  130. $this->fullName = $this->getFullName();
  131. $this->filePath = $this->getFilePath();
  132. $this->fileName = $this->getFileName();
  133. $dirname = dirname($this->filePath);
  134. //检查文件大小是否超出限制
  135. if (!$this->checkSize()) {
  136. $this->stateInfo = $this->getStateInfo('ERROR_SIZE_EXCEED');
  137. return;
  138. }
  139. if ($obj = $this->ossService->putObject($this->fullName, $img)) {
  140. $this->fullName = $obj;
  141. $this->stateInfo = $this->stateMap[0];
  142. } else {
  143. $this->stateInfo = $this->getStateInfo('ERROR_WRITE_CONTENT');
  144. }
  145. }
  146. /**
  147. * 拉取远程图片.
  148. *
  149. * @return mixed
  150. */
  151. private function saveRemote()
  152. {
  153. $imgUrl = htmlspecialchars($this->fileField);
  154. $imgUrl = str_replace('&', '&', $imgUrl);
  155. //获取带有GET参数的真实图片url路径
  156. $pathRes = parse_url($imgUrl);
  157. $queryString = $pathRes['query'] ?? '';
  158. $imgUrl = str_replace('?' . $queryString, '', $imgUrl);
  159. //http开头验证
  160. if (0 !== strpos($imgUrl, 'http')) {
  161. $this->stateInfo = $this->getStateInfo('ERROR_HTTP_LINK');
  162. return;
  163. }
  164. //获取请求头并检测死链
  165. $heads = get_headers($imgUrl, 1);
  166. if (!(stristr($heads[0], '200') && stristr($heads[0], 'OK'))) {
  167. $this->stateInfo = $this->getStateInfo('ERROR_DEAD_LINK');
  168. return;
  169. }
  170. //格式验证(扩展名验证和Content-Type验证)
  171. $fileType = strtolower(strrchr($imgUrl, '.'));
  172. if (!in_array($fileType, $this->config['allowFiles']) || !isset($heads['Content-Type']) || !stristr($heads['Content-Type'], 'image')) {
  173. $this->stateInfo = $this->getStateInfo('ERROR_HTTP_CONTENTTYPE');
  174. return;
  175. }
  176. //打开输出缓冲区并获取远程图片
  177. ob_start();
  178. $context = stream_context_create(
  179. ['http' => [
  180. 'follow_location' => false, // don't follow redirects
  181. ]]
  182. );
  183. readfile($imgUrl . '?' . $queryString, false, $context);
  184. $img = ob_get_contents();
  185. ob_end_clean();
  186. preg_match('/[\\/]([^\\/]*)[\\.]?[^\\.\\/]*$/', $imgUrl, $m);
  187. $this->oriName = $m ? $m[1] : '';
  188. $this->fileSize = strlen($img);
  189. $this->fileType = $this->getFileExt();
  190. $this->fullName = $this->getFullName();
  191. $this->filePath = $this->getFilePath();
  192. $this->fileName = $this->getFileName();
  193. $dirname = dirname($this->filePath);
  194. //检查文件大小是否超出限制
  195. if (!$this->checkSize()) {
  196. $this->stateInfo = $this->getStateInfo('ERROR_SIZE_EXCEED');
  197. return;
  198. }
  199. //检查文件内容是否真的是图片
  200. if ('image' != substr(mime_content_type($this->filePath), 0, 5)) {
  201. $this->stateInfo = $this->getStateInfo('ERROR_TYPE_NOT_ALLOWED');
  202. return;
  203. }
  204. $obj = $this->ossService->putObject($this->fullName, base64_encode($img));
  205. if ($obj) {
  206. $this->fullName = $obj;
  207. $this->stateInfo = $this->stateMap[0];
  208. } else {
  209. $this->stateInfo = $this->getStateInfo('ERROR_WRITE_CONTENT');
  210. }
  211. }
  212. /**
  213. * 上传错误检查.
  214. *
  215. * @param $errCode
  216. *
  217. * @return string
  218. */
  219. private function getStateInfo($errCode)
  220. {
  221. return !$this->stateMap[$errCode] ? $this->stateMap['ERROR_UNKNOWN'] : $this->stateMap[$errCode];
  222. }
  223. /**
  224. * 获取文件扩展名.
  225. *
  226. * @return string
  227. */
  228. private function getFileExt()
  229. {
  230. return strtolower(strrchr($this->oriName, '.'));
  231. }
  232. /**
  233. * 重命名文件.
  234. *
  235. * @return string
  236. */
  237. private function getFullName()
  238. {
  239. //替换日期事件
  240. $t = time();
  241. $d = explode('-', date('Y-y-m-d-H-i-s'));
  242. $format = $this->config['pathFormat'];
  243. $format = str_replace('{yyyy}', $d[0], $format);
  244. $format = str_replace('{yy}', $d[1], $format);
  245. $format = str_replace('{mm}', $d[2], $format);
  246. $format = str_replace('{dd}', $d[3], $format);
  247. $format = str_replace('{hh}', $d[4], $format);
  248. $format = str_replace('{ii}', $d[5], $format);
  249. $format = str_replace('{ss}', $d[6], $format);
  250. $format = str_replace('{time}', $t, $format);
  251. //过滤文件名的非法字符,并替换文件名
  252. $oriName = substr($this->oriName, 0, strrpos($this->oriName, '.'));
  253. $oriName = preg_replace('/[\\|\\?"\\<\\>\\/\\*\\\\]+/', '', $oriName);
  254. $format = str_replace('{filename}', $oriName, $format);
  255. //替换随机字符串
  256. $randNum = mt_rand(1, 1000000000) . mt_rand(1, 1000000000);
  257. if (preg_match('/\\{rand\\:([\\d]*)\\}/i', $format, $matches)) {
  258. $format = preg_replace('/\\{rand\\:[\\d]*\\}/i', substr($randNum, 0, $matches[1]), $format);
  259. }
  260. if ($this->fileType) {
  261. $ext = $this->fileType;
  262. } else {
  263. $ext = $this->getFileExt();
  264. }
  265. return $format . $ext;
  266. }
  267. /**
  268. * 获取文件名.
  269. *
  270. * @return string
  271. */
  272. private function getFileName()
  273. {
  274. return substr($this->filePath, strrpos($this->filePath, '/') + 1);
  275. }
  276. /**
  277. * 获取文件完整路径.
  278. *
  279. * @return string
  280. */
  281. private function getFilePath()
  282. {
  283. $fullname = $this->fullName;
  284. $rootPath = $_SERVER['DOCUMENT_ROOT'];
  285. if ('/' != substr($fullname, 0, 1)) {
  286. $fullname = '/' . $fullname;
  287. }
  288. return $rootPath . $fullname;
  289. }
  290. /**
  291. * 文件类型检测.
  292. *
  293. * @return bool
  294. */
  295. private function checkType()
  296. {
  297. return in_array($this->getFileExt(), $this->config['allowFiles']);
  298. }
  299. /**
  300. * 文件大小检测.
  301. *
  302. * @return bool
  303. */
  304. private function checkSize()
  305. {
  306. return $this->fileSize <= ($this->config['maxSize']);
  307. }
  308. /**
  309. * 获取当前上传成功文件的各项信息.
  310. *
  311. * @return array
  312. */
  313. public function getFileInfo()
  314. {
  315. return [
  316. 'state' => $this->stateInfo,
  317. 'url' => $this->fullName,
  318. 'title' => $this->fileName,
  319. 'original' => $this->oriName,
  320. 'type' => $this->fileType,
  321. 'size' => $this->fileSize,
  322. ];
  323. }
  324. /**
  325. * 列出文件列表.
  326. *
  327. * @param $start
  328. * @param $size
  329. * @param $ueditor_config_path
  330. *
  331. * @return array
  332. */
  333. public static function listFiles($start, $size, $ueditor_config_path)
  334. {
  335. $path = preg_replace('/\\{.*\\}*/', '', config('ueditor.' . $ueditor_config_path));
  336. $oss = new OssService();
  337. $directorys = $oss->getFilesWithDirectory($path);
  338. $list = [];
  339. foreach ($directorys as $key=>$directory) {
  340. if ($key < $start - 1) {
  341. continue;
  342. }
  343. $list[] = [
  344. 'url' => $oss->getUrl($directory['key']),
  345. 'mtime'=> Carbon::parse($directory['last_modified'])->timestamp,
  346. ];
  347. if (count($list) >= $size) {
  348. break;
  349. }
  350. }
  351. return [
  352. 'state' => 'SUCCESS',
  353. 'list' => $list,
  354. 'start' => $start,
  355. 'total' => count($directorys),
  356. ];
  357. }
  358. }
  1. 其中cos上传的service

    1. namespace App\Http\Service;
    2. use Illuminate\Http\UploadedFile;
    3. use Qcloud\Cos\Client;
    4. class OssService extends BaseService
    5. {
    6. public $url;
    7. /**
    8. * 已更改为 tencent cos 沿用以前命名匹配代码
    9. *
    10. * @var object
    11. */
    12. public $ossClient;
    13. public function __construct()
    14. {
    15. $this->url = 'https://' . env('COSV5_BUCKET') . '.cos.' . env('COSV5_REGION') . '.myqcloud.com/';
    16. $this->ossClient = new Client(
    17. [
    18. 'region' => env('COSV5_REGION'),
    19. 'schema' => env('COSV5_SCHEME', 'https'),
    20. 'credentials' => [
    21. 'secretId' => env('COSV5_SECRET_ID'),
    22. 'secretKey' => env('COSV5_SECRET_KEY'),
    23. ],
    24. ]
    25. );
    26. parent::__construct();
    27. }
    28. /**
    29. * 根据文件/文件夹获取文件(包含路径).
    30. *
    31. * @param $directory
    32. *
    33. * @return array
    34. */
    35. public function getFilesWithDirectory($directory,$marker = '')
    36. {
    37. $directory = preg_replace("/^\//",'',$directory);
    38. $result = [];
    39. $param = [
    40. 'Bucket' => env('COSV5_BUCKET'),
    41. 'Prefix' => $directory,
    42. 'MaxKeys' => 1000,
    43. ];
    44. while (true) {
    45. if ($marker) {
    46. $param['Marker'] = $marker;
    47. }
    48. $chunk_result = $this->ossClient->listObjects($param)->toArray();
    49. if (isset($chunk_result['Contents'])) {
    50. foreach ($chunk_result['Contents'] as $file){
    51. if(preg_match("/\/$/",$file['Key'])){
    52. continue;
    53. }
    54. $result[] = [
    55. 'key'=>$file['Key'],
    56. 'last_modified'=>$file['LastModified']
    57. ];
    58. }
    59. $marker = end($chunk_result['Contents'])['Key'];
    60. } else {
    61. break;
    62. }
    63. }
    64. return $result;
    65. }
    66. /**
    67. * 上传文件
    68. *
    69. * @param $ossPath
    70. * @param $realPath
    71. * @param bool $is_path
    72. * @param mixed $files
    73. *
    74. * @return mixed
    75. */
    76. public function put($ossPath, $files)
    77. {
    78. try {
    79. // 请求成功
    80. if ($files instanceof UploadedFile) {
    81. $upload = $this->ossClient->upload(env('COSV5_BUCKET'), $ossPath, $files->openFile('rb'));
    82. } else {
    83. $upload = $this->ossClient->upload(env('COSV5_BUCKET'), $ossPath, $files);
    84. }
    85. $data = $upload->toArray();
    86. return env('COSV5_SCHEME') . '://' . $data['Location'];
    87. } catch (\Exception $e) {
    88. // 请求失败
    89. return false;
    90. }
    91. }
    92. /**
    93. * 上传文件对象
    94. *
    95. * @param $ossPath
    96. * @param $object
    97. * @param string $style
    98. *
    99. * @return bool|mixed
    100. */
    101. public function putObject($ossPath, $object, $style = '')
    102. {
    103. try {
    104. // 请求成功
    105. $upload = $this->ossClient->Upload(env('COSV5_BUCKET'), $ossPath, $object);
    106. $ossPath = $style ? ($ossPath . $style) : $ossPath;
    107. return $this->getUrl($ossPath);
    108. } catch (\Exception $e) {
    109. // 请求失败
    110. return false;
    111. }
    112. }
    113. /**
    114. * 获取远程OSS文件对象
    115. *
    116. * @param $ossPath
    117. *
    118. * @return mixed
    119. */
    120. public function getObjectByPath($ossPath)
    121. {
    122. try {
    123. // 请求成功
    124. $result = $this->ossClient->getObject([
    125. 'Bucket' => env('COSV5_BUCKET'),
    126. 'Key' => $ossPath,
    127. ]);
    128. return ($result->toArray())['Body'];
    129. } catch (\Exception $e) {
    130. // 请求失败
    131. return '';
    132. }
    133. }
    134. /**
    135. * 检查文件是否存在.
    136. *
    137. * @param $ossPath
    138. *
    139. * @return mixed
    140. */
    141. public function exists($ossPath)
    142. {
    143. try {
    144. $result = $this->ossClient->headObject([
    145. 'Bucket' => env('COSV5_BUCKET'),
    146. 'Key' => $ossPath,
    147. ]);
    148. return true;
    149. } catch (\Exception $e) {
    150. return false;
    151. }
    152. }
    153. /**
    154. * 删除文件.
    155. *
    156. * @param array|string $ossPath
    157. *
    158. * @return mixed
    159. */
    160. public function delete($ossPath)
    161. {
    162. if (!$this->exists($ossPath)) {
    163. return false;
    164. }
    165. try {
    166. $result = $this->ossClient->deleteObject([
    167. 'Bucket' => env('COSV5_BUCKET'),
    168. 'Key' => $ossPath,
    169. ]);
    170. // 请求成功
    171. return true;
    172. } catch (\Exception $e) {
    173. // 请求失败
    174. return false;
    175. }
    176. }
    177. /**
    178. * 删除文件夹.
    179. *
    180. * @param $directory
    181. *
    182. * @return mixed
    183. */
    184. public function deleteDirectory($directory)
    185. {
    186. //矫正文件格式
    187. $directory_end_style = strrpos($directory, '/');
    188. if (!$directory_end_style || $directory_end_style != strlen($directory) - 1) {
    189. $directory .= '/';
    190. }
    191. return $this->delete($directory);
    192. }
    193. /**
    194. * 获取远程URL地址
    195. *
    196. * @param $ossPath
    197. * @param $strict:true从远程获取URL地址,false使用本地逻辑生成
    198. *
    199. * @return mixed
    200. */
    201. public function getUrl($ossPath, $strict = false)
    202. {
    203. return env('COSV5_SCHEME') . '://' . env('COSV5_BUCKET') . '.cos.' . env('COSV5_REGION') . '.myqcloud.com/' . $ossPath;
    204. }
    205. /**
    206. * 获取签名url地址
    207. *
    208. * @param $ossPath
    209. * @param mixed $valid_time
    210. * @param mixed $check_exists
    211. *
    212. * @return mixed
    213. */
    214. public function getSignUrl($ossPath, $valid_time = 3600, $check_exists = true)
    215. {
    216. if ($check_exists && !$this->exists($ossPath)) {
    217. return '';
    218. }
    219. try {
    220. // 请求成功
    221. return $this->ossClient->getObjectUrl(env('COSV5_BUCKET'), $ossPath, '+' . ceil($valid_time / 60) . ' minutes');
    222. // if(preg_match("/^http:/", $url)){
    223. // $url = preg_replace("/^http:/", 'https:', $url);
    224. // }
    225. } catch (\Exception $e) {
    226. // 请求失败
    227. return '';
    228. }
    229. }
    230. /**
    231. * 将其他服务器上的文件上传到OSS中.
    232. *
    233. * @param $ossPath
    234. * @param $remotePath
    235. *
    236. * @return bool|mixed|string
    237. */
    238. public function putRemoteFile($ossPath, $remotePath)
    239. {
    240. $client = new \GuzzleHttp\Client();
    241. $res = $client->get($remotePath, [
    242. 'verify'=> false,
    243. ]);
    244. $base_img = $res->getBody()->getContents();
    245. return $this->putObject($ossPath, $base_img);
    246. }
    247. }
  2. 需要用的类包

    1. qcloud/cos-sdk-v5
    2. nesbot/carbon