district5/slim-psr-upload-handler

一个易于使用、基于提供者的上传处理程序,适用于Slim框架。

1.0.1 2024-03-13 13:58 UTC

This package is auto-updated.

Last update: 2024-09-21 13:31:20 UTC


README

简介...

这是一个简单的Slim框架上传处理程序。它设计为与PSR接口一起使用,并且与Slim 4兼容。

提供者包括以下内容:Google Cloud Storage、AWS S3和本地文件。

只需安装即可

composer require district5/slim-psr-upload-handler

支持的提供者...

  • 本地文件(键:local
    • 此提供者会将文件保存到本地目录。
    • 配置
      • path(字符串)- 保存文件的目录。
      • overwrite(布尔值)- 如果文件已存在,则覆盖文件。
      • appendRandom(布尔值)- 将随机字符串附加到文件名。
      • suppressExceptions(布尔值)- 忽略错误并返回UploadedDto对象。覆盖全局suppressExceptions选项。
  • Google Cloud Storage(键:gcs
    • 此提供者会将文件保存到Google Cloud Storage。
    • 配置
      • projectId(字符串)- Google Cloud项目ID。
      • bucket(字符串)- 您的Google Cloud Storage存储桶名称。
      • path(字符串)- 文件在存储桶中的路径,例如'uploads'或'images'。留空(或null)表示根目录。
      • keyFile(数组)- 服务账户密钥文件的JSON解码(即数组)版本。
      • overwrite(布尔值)- 如果文件已存在,则覆盖文件。
      • appendRandom(布尔值)- 将随机字符串附加到文件名。
      • acl(字符串)- Google Cloud Storage对象的ACL。
      • suppressExceptions(布尔值)- 忽略错误并返回UploadedDto对象。覆盖全局suppressExceptions选项。
  • AWS S3(键:s3
    • 此提供者会将文件保存到Amazon S3。
    • 配置
      • region(字符串)- 存储桶所在的区域。
      • version(字符串)- 要使用的S3 API版本。
      • bucket(字符串)- 存储桶的名称。
      • path(字符串)- 文件在存储桶中的路径,例如'uploads'或'images'。留空(或null)表示根目录。
      • accessKey(字符串)- 存储桶的访问密钥。
      • secretKey(字符串)- 存储桶的秘密密钥。
      • overwrite(布尔值)- 如果文件已存在,则覆盖文件。
      • appendRandom(布尔值)- 将随机字符串附加到文件名。
      • acl(字符串)- 对象的ACL(public-read、private等)。
      • suppressExceptions(布尔值)- 忽略错误并返回UploadedDto对象。覆盖全局suppressExceptions选项。

用法...

<?php
use \District5\UploadHandler\UploadHandler;
use \Slim\Psr7\Request;
use \Slim\Psr7\Response;

$container = new \Slim\Container();
// ... add any other dependencies to the container before or after the upload handler

$uploadHandlerConfig = [
    'options' => [ // these are the core library options. these are the defaults for all handlers, but can be overridden in the handler specific config
        'suppressExceptions' => false, // ignore errors and return the UploadedDto object regardless.
        'appendRandom' => true, // append a random string (using uniqid) to the file, or use the original name
    ],
    'handlers' => [
        'example-google-cloud-storage-provider' => [ // 'my-gcs-provider' is the action name, this can be anything you want
            'provider' => 'gcs', // Or use the class name of GcsProvider::class
            'config' => [
                'suppressExceptions' => false, // Override the global suppressExceptions option
                'appendRandom' => false, // append a random string (using uniqid) to the file, or use the original name.  Overrides the global appendRandom option
                'overwrite' => false, // overwrite the file if it already exists
                'projectId' => $env->get('GCS_PROJECT_ID'), // your GCP project id
                'bucket' => $env->get('GCS_BUCKET'), // your GCS bucket name
                'path' => $env->get('GCS_OBJECT_PATH'), // or null/empty string for root
                'keyFile' => json_decode($env->get('GCS_KEY_FILE_CONTENT'), true), // your GCP service account key file content,
                'acl' => $env->get('GCS_OBJECT_ACL'), // the GCS object ACL
            ]
        ],
        'example-aws-s3-provider' => [ // 'generic-file' is the action name, this can be anything you want
            'provider' => 's3',
            'config' => [
                'suppressExceptions' => false, // suppress exceptions, or let them bubble up
                'appendRandom' => true, // append a random string (using uniqid) to the file, or use the original name.  Overrides the global appendRandom option
                'overwrite' => false, // overwrite the file if it already exists
                'region' => $env->get('S3_REGION'), // the region of the bucket
                'version' => $env->get('S3_VERSION'), // the version of the S3 API to use (typically 'latest')
                'bucket' => $env->get('S3_BUCKET'), // the name of the bucket
                'path' => $env->get('S3_OBJECT_PATH'), // or null/empty string for root
                'accessKey' => $env->get('S3_ACCESS_KEY'), // the access key for the bucket
                'secretKey' => $env->get('S3_SECRET_KEY'), // the secret key for the bucket
                'acl' => $env->get('S3_OBJECT_ACL') // the acl for the object (public-read, private, etc.)
            ]
        ],
        'example-local-file-provider' => [ // 'generic-file' is the action name, this can be anything you want
            'provider' => 'local', // Or use the class name of LocalFileProvider::class
            'config' => [
                // 'suppressExceptions' => false, // Override the global suppressExceptions option
                // 'appendRandom' => false, // append a random string (using uniqid) to the file, or use the original name. Overrides the global appendRandom option
                'overwrite' => false, // overwrite the file if it already exists
                'path' => $env->get('LOCAL_WRITABLE_DIRECTORY'), // the directory to save the file to (trailing slash is stripped)
            ]
        ]
    ]
];
UploadHandler::create($container, $uploadHandlerConfig);

$app = new \Slim\App($container);

$app->post('/upload', function (Request $request, Response $response, $args) {

    $file = $request->getUploadedFiles()['param-key'];
    /* @var $container \DI\Container */
    $uploadHandler = $container->get(UploadHandler::class);
    /* @var $uploadHandler UploadHandler */
    $result = $uploadHandler->handleFromUpload('example-google-cloud-storage-provider', $file);
    // or: $result = $uploadHandler->handleFromUpload('example-local-file-provider', $filePath);
    return $response->withJson($result);
});

同样,您也可以从本地文件路径上传...

$app->post('/upload', function (Request $request, Response $response, $args) {

    $filePath = '/path/to/file.jpg';
    /* @var $container \DI\Container */
    $uploadHandler = $container->get(UploadHandler::class);
    /* @var $uploadHandler UploadHandler */
    $result = $uploadHandler->handleFromLocal('example-google-cloud-storage-provider', $filePath);
    // or: $result = $uploadHandler->handleFromLocal('example-local-file-provider', $filePath);
    return $response->withJson($result);
});

创建自己的提供者...

要创建自己的提供者,您需要扩展District5\UploadHandler\Provider\ProviderAbstract类。该ProviderAbstract类为您提供了大量的样板代码。

最终,需要实现三个方法

  • processFileFromUpload - 当文件上传时调用此方法,并是Slim\Psr7\UploadedFile对象。
  • processFileFromLocal - 当文件从本地文件路径上传时调用此方法。
  • getRequiredConfigKeys - 此方法应返回一个包含必需配置键的数组。

还有可选方法可以覆盖

  • getOptionalConfigKeys - 此方法应返回一个包含配置键到值的数组,这些值不是必需提供的,并且可以默认为某个值。例如,如果您在上传前添加图像缩放,则可以使用...
    protected function getOptionalConfigKeys(): array
    {
         return [
             'allowedExtensions' => ['jpg', 'jpeg', 'png', 'gif'],
             'maxWidth' => 1920,
         ];
     }
    最终,这些值将提供默认值,除非在handlers配置数组中覆盖了提供者在初始配置中的值。
<?php

use Slim\Psr7\UploadedFile;
use District5\UploadHandler\Providers\ProviderAbstract;
use District5\UploadHandler\UploadedDto;

/**
 * Class MyFileProvider
 */
class MyFileProvider extends ProviderAbstract
{
    /**
     * @param UploadedFile $file
     * @return UploadedDto
     */
    protected function processFileFromUpload(UploadedFile $file): UploadedDto
    {
        try {
            $fileName = $file->getClientFilename();
            $newFileName = $this->getFileName($fileName); // this handles the appending of a random string if required

            $localDirectory = $this->getConfig('path');
            $localPath = rtrim($localDirectory, DIRECTORY_SEPARATOR) . '/' . $newFileName;

            $file->moveTo($localPath);

            return new UploadedDto(
                $this,
                null,
                $localPath,
                $file->getClientFilename(),
                $newFileName,
                $file->getClientMediaType(),
                $file->getSize(),
                pathinfo($localPath),
                true
            );
        } catch (Throwable $e) {
            if ($this->suppressException()) {
                return UploadedDto::createError($this, $e);
            }

            throw $e; // re-throw the exception
        }
    }
    
    /**
     * @param string $filePath
     * @return UploadedDto
     */
    protected function processFileFromLocal(string $filePath): UploadedDto
    {
        try {
            $fileName = basename($filePath);
            $newFileName = $this->getFileName($fileName);

            $localDirectory = $this->getConfig('path');
            $localPath = rtrim($localDirectory, DIRECTORY_SEPARATOR) . '/' . $newFileName;

            copy($filePath, $localPath);
            $mime = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $filePath);
            $size = filesize($filePath);

            return new UploadedDto(
                $this,
                null,
                $localPath,
                $baseName,
                $newFileName,
                $mime,
                $size,
                pathinfo($localPath),
                true
            );
        } catch (Throwable $e) {
            if ($this->suppressException()) {
                return UploadedDto::createError($this, $e);
            }

            throw $e; // re-throw the exception
        }
    }

    /**
     * Get an array of required config keys. No values, just the keys.
     *
     * @return array
     */
    protected function getRequiredConfigKeys(): array
    {
        return ['path'];
    }
}

要使用此提供者,您需要在UploadHandler配置中的handlers数组中添加它。

$uploadHandlerConfig = [
    'handlers' => [
        'my-file-provider' => [ // 'my-file-provider' is the action name, this can be anything you want
            'provider' => MyFileProvider::class, // the class name of your provider
            'config' => [ // the configuration for your provider
                'path' => '/tmp'
            ]
        ]
    ]
];