101 lines
2.8 KiB
PHP
101 lines
2.8 KiB
PHP
|
|
<?php
|
|||
|
|
|
|||
|
|
namespace App\Service\common;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 媒体地址规整
|
|||
|
|
*
|
|||
|
|
* 老后台的约定是:入库存相对路径(/storage/xxx.jpg),出库用 asset() 拼成绝对地址;
|
|||
|
|
* 而 OSS 上传拿到的本来就是绝对地址。两种值混在同一列里,读写都得判断一次。
|
|||
|
|
* 这里把判断收在一处,业务 Service 只调 toPublic / toStorage。
|
|||
|
|
*/
|
|||
|
|
class MediaUrlService
|
|||
|
|
{
|
|||
|
|
private static mixed $_instance;
|
|||
|
|
|
|||
|
|
public static function getInstance(): null|static
|
|||
|
|
{
|
|||
|
|
$name = get_called_class();
|
|||
|
|
if (!isset(self::$_instance[$name])) {
|
|||
|
|
self::$_instance[$name] = new static();
|
|||
|
|
}
|
|||
|
|
return self::$_instance[$name];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 出库:相对路径补上站点域名,绝对地址原样返回
|
|||
|
|
*/
|
|||
|
|
public function toPublic(?string $path): string
|
|||
|
|
{
|
|||
|
|
$path = trim((string) $path);
|
|||
|
|
if ($path === '') {
|
|||
|
|
return '';
|
|||
|
|
}
|
|||
|
|
if ($this->isAbsolute($path)) {
|
|||
|
|
return $path;
|
|||
|
|
}
|
|||
|
|
return rtrim((string) config('app.url'), '/') . '/' . ltrim($path, '/');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 入库:本站域名下的地址存成相对路径,避免换域名后历史数据全指向旧域名;
|
|||
|
|
* 第三方 OSS 地址保持原样
|
|||
|
|
*/
|
|||
|
|
public function toStorage(?string $url): string
|
|||
|
|
{
|
|||
|
|
$url = trim((string) $url);
|
|||
|
|
if ($url === '') {
|
|||
|
|
return '';
|
|||
|
|
}
|
|||
|
|
$appUrl = rtrim((string) config('app.url'), '/');
|
|||
|
|
if ($appUrl !== '' && str_starts_with($url, $appUrl)) {
|
|||
|
|
return substr($url, strlen($appUrl)) ?: '';
|
|||
|
|
}
|
|||
|
|
return $url;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 批量出库,给 list 用
|
|||
|
|
*/
|
|||
|
|
public function publicEach(array &$rows, array $fields): void
|
|||
|
|
{
|
|||
|
|
foreach ($rows as &$row) {
|
|||
|
|
foreach ($fields as $field) {
|
|||
|
|
if (array_key_exists($field, $row)) {
|
|||
|
|
$row[$field] = $this->toPublic($row[$field]);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
unset($row);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 前端图片上传组件回传的是数组,取第一个;已是字符串则原样
|
|||
|
|
*/
|
|||
|
|
public function firstOf(mixed $value): string
|
|||
|
|
{
|
|||
|
|
if (is_array($value)) {
|
|||
|
|
$value = $value[0] ?? '';
|
|||
|
|
}
|
|||
|
|
return $this->toStorage(is_string($value) ? $value : '');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 去掉 OSS 处理参数(?imageView2/... 或 ?watermark/...),用于素材库按 path 做引用匹配
|
|||
|
|
*/
|
|||
|
|
public function stripProcessParams(?string $url): string
|
|||
|
|
{
|
|||
|
|
$url = trim((string) $url);
|
|||
|
|
if ($url === '') {
|
|||
|
|
return '';
|
|||
|
|
}
|
|||
|
|
$pos = strpos($url, '?');
|
|||
|
|
return $pos === false ? $url : substr($url, 0, $pos);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private function isAbsolute(string $path): bool
|
|||
|
|
{
|
|||
|
|
return (bool) preg_match('#^(https?:)?//#i', $path);
|
|||
|
|
}
|
|||
|
|
}
|