在 Yii 2.0 中实现:资源服务(复制来源的资源文件至渠道发布的存储目录,返回相对路径)

1、配置文件:\common\config\params-local.php,自媒体为来源

    // 自媒体
    'spider' => [
        'asset' => [ // 资源
            'image' => [ // 图片
                'hostInfo' => 'http://localhost/channel-pub-api/storage/spider', // HOME URL
                'baseUrl' => '/images', // BASE URL
                'basePath' => 'E:/wwwroot/channel-pub-api/storage/spider/images', // BASE PATH
            ],
            'video' => [ // 视频
                'hostInfo' => 'http://localhost/channel-pub-api/storage/spider', // HOME URL
                'baseUrl' => '/videos', // BASE URL
                'basePath' => 'E:/wwwroot/channel-pub-api/storage/spider/videos', // BASE PATH
            ],
        ],
    ],
    // 渠道发布接口
    'channelPubApi' => [
        'asset' => [ // 资源
            'image' => [ // 图片
                'basePath' => 'E:/wwwroot/channel-pub-api/storage/channel-pub-api/images', // BASE PATH
            ],
            'video' => [ // 视频
                'basePath' => 'E:/wwwroot/channel-pub-api/storage/channel-pub-api/videos', // BASE PATH
            ],
        ],
    ],

2、新建服务类,\common\services\AssetService.php,实现静态方法:copyAssets

<?php
/**
 * Created by PhpStorm.
 * User: WangQiang
 * Date: 2018/09/20
 * Time: 14:04
 */
namespace common\services;

use Yii;
use yii\base\Model;
use common\logics\ChannelAppSource;
use yii\db\ActiveRecordInterface;
use yii\helpers\StringHelper;
use yii\helpers\FileHelper;
use yii\web\NotFoundHttpException;
use yii\web\UnprocessableEntityHttpException;
use yii\web\ServerErrorHttpException;
use yii\web\HttpException;

/**
 * 资源服务
 *
 * @author Qiang Wang <shuijingwanwq@163.com>
 * @since 1.0
 */class AssetService extends Service
{
    /**
     * 复制来源的资源文件至渠道发布的资源目录,返回相对路径
     * @param string $source 来源
     * 格式如下:spider
     * @param array $assets 来源的资源文件的绝对URL
     * 格式如下:
     * [
     *     [
     *         'type' => 'image',
     *         'absolute_url' => 'http://localhost/channel-pub-api/storage/spider/images/1.png',
     *     ],
     *     [
     *         'type' => 'video',
     *         'absolute_url' => 'http://localhost/channel-pub-api/storage/spider/videos/7月份北上广深等十大城市租金环比上涨 看东方 20180820 高清_高清.mp4',
     *     ],
     * ]
     *
     * @return array $channelPubApiAssetAbsolutePaths 渠道发布的资源文件的相对路径
     * 格式如下:
     * [
     *     [
     *         'type' => 'image',
     *         'relative_path' => '/2018/09/20/1537439889.2333.1441541478.png',
     *     ],
     *     [
     *         'type' => 'video',
     *         'relative_path' => '/2018/09/20/1537439889.2403.62871268.mp4',
     *     ],
     * ]
     *
     * @throws UnprocessableEntityHttpException 如果来源的资源文件不是以来源的 HOME URL + BASE URL 开头,将抛出 422 HTTP 异常
     * @throws NotFoundHttpException 如果来源的资源文件不存在,将抛出 404 HTTP 异常
     * @throws ServerErrorHttpException 如果创建目录失败,将抛出 500 HTTP 异常
     * @throws ServerErrorHttpException 如果复制来源的资源文件至渠道发布的资源目录失败,将抛出 500 HTTP 异常
     * @throws \yii\base\Exception if the directory could not be created (i.e. php error due to parallel changes)
     */    public static function copyAssets($source, $assets)
    {
        // 不是以来源的 HOME URL + BASE URL 开头的来源的资源文件
        $notAbsoluteUrlStartKeys = [];
        // 不存在的来源的资源文件
        $notExistsKeys = [];
        // 渠道发布的资源文件的相对路径
        $channelPubApiAssetAbsolutePaths = [];

        foreach ($assets as $key => $asset) {
            // 检查来源的资源文件的绝对URL是否以来源的 HOME URL + BASE URL 开头
            if (!StringHelper::startsWith($asset['absolute_url'], Yii::$app->params[$source]['asset'][$asset['type']]['hostInfo'] . Yii::$app->params[$source]['asset'][$asset['type']]['baseUrl'])) {
                $notAbsoluteUrlStartKeys[] = $key;
            } else {
                // 获取来源的资源文件的绝对路径
                $sourceAssetAbsolutePath = Yii::$app->params[$source]['asset'][$asset['type']]['basePath'] . str_replace(Yii::$app->params[$source]['asset'][$asset['type']]['hostInfo'] . Yii::$app->params[$source]['asset'][$asset['type']]['baseUrl'], '', $asset['absolute_url']);

                // 检查来源的资源文件是否存在
                if (!file_exists($sourceAssetAbsolutePath)) {
                    $notExistsKeys[] = $key;
                }
            }
        }

        if (!empty($notAbsoluteUrlStartKeys)) {
            $notAbsoluteUrlStartKeys = implode(",", $notAbsoluteUrlStartKeys);
            throw new UnprocessableEntityHttpException(Yii::t('common/error', Yii::t('common/error', Yii::t('common/error', '35003'), ['not_absolute_url_start_keys' => $notAbsoluteUrlStartKeys])), 35003);
        }

        if (!empty($notExistsKeys)) {
            $notExistsKeys = implode(",", $notExistsKeys);
            throw new NotFoundHttpException(Yii::t('common/error', Yii::t('common/error', Yii::t('common/error', '35004'), ['not_exists_keys' => $notExistsKeys])), 35004);
        }

        foreach ($assets as $key => $asset) {
            // 获取来源的资源文件的绝对路径
            $sourceAssetAbsolutePath = Yii::$app->params[$source]['asset'][$asset['type']]['basePath'] . str_replace(Yii::$app->params[$source]['asset'][$asset['type']]['hostInfo'] . Yii::$app->params[$source]['asset'][$asset['type']]['baseUrl'], '', $asset['absolute_url']);

            // 获取来源的资源文件的路径信息
            $pathInfo = pathinfo($sourceAssetAbsolutePath);
            // 渠道发布的资源文件的相对路径
            $directory = date('Y/m/d');
            $channelPubApiAssetRelativePath = '/' . $directory . '/' . microtime(true) . '.' . mt_rand() . '.' . $pathInfo['extension'];
            // 渠道发布的资源文件的绝对路径
            $channelPubApiAssetAbsolutePath = Yii::$app->params['channelPubApi']['asset'][$asset['type']]['basePath'] . $channelPubApiAssetRelativePath;
            // 创建目录
            if (!FileHelper::createDirectory(Yii::$app->params['channelPubApi']['asset'][$asset['type']]['basePath'] . '/' . $directory)) {
                throw new ServerErrorHttpException(Yii::t('common/error', Yii::t('common/error', Yii::t('common/error', '35005'), ['directory' => Yii::$app->params['channelPubApi']['asset'][$asset['type']]['basePath'] . '/' . $directory])), 35005);
            }
            // 复制来源的资源文件至渠道发布的资源目录
            if (!copy($sourceAssetAbsolutePath, $channelPubApiAssetAbsolutePath)) {
                throw new ServerErrorHttpException(Yii::t('common/error', Yii::t('common/error', Yii::t('common/error', '35006'), ['source_asset_absolute_path' => $sourceAssetAbsolutePath])), 35006);
            }

            $channelPubApiAssetAbsolutePaths[$key] = [
                'type' => $asset['type'],
                'relative_path' => $channelPubApiAssetRelativePath,
            ];
        }

        return $channelPubApiAssetAbsolutePaths;
    }
}

3、引用服务类,\common\services\AssetService.php,调用静态方法:copyAssets

        $assets = [
            [
                'type' => 'image',
                'absolute_url' => 'http://localhost/channel-pub-api/storage/spider/images/1.png',
            ],
            [
                'type' => 'video',
                'absolute_url' => 'http://localhost/channel-pub-api/storage/spider/videos/7月份北上广深等十大城市租金环比上涨 看东方 20180820 高清_高清.mp4',
            ],
        ];
        $assetServiceResult = AssetService::copyAssets('spider', $assets);
        print_r($assetServiceResult);
        exit;

4、运行方法之后,打印出 $assetServiceResult

Array
(
    [0] => Array
        (
            [type] => image
            [relative_path] => /2018/09/21/1537495742.6172.473015079.png
        )

    [1] => Array
        (
            [type] => video
            [relative_path] => /2018/09/21/1537495742.6251.651458618.mp4
        )

)

5、查看复制后的目录与文件,符合预期,如图1

图1

6、升级至开发环境(CentOS)后,复制文件成功,如图2

图2

永夜