原生php操作minio,创建bucket删除bucket上传文件删除文件,拷贝文件,设置存储桶策略

1、原理

通过php curl请求minio, 操作minio,实现创建bucket,删除bucket,上传文件,删除文件,拷贝文件,设置存储桶策略等功能

2、原文件下载

原代码下载地址:
https://github.com/gusijin/minio-php-sdk

3、php操作minio方法

bucket操作,和object操作,包括:实现创建bucket,删除bucket,上传文件,删除文件,拷贝文件,设置存储桶策略

require_once 'Minio.php';

// Instantiate an Minio client.
$minioClient = Minio::getInstance();

// Bucket

$res = $minioClient->listBuckets();

$res = $minioClient->getBucket('file');

$res = $minioClient->createBucket('my'.rand(1000,9999));

$res = $minioClient->putBucketPolicy('my3833');

$res = $minioClient->deleteBucket('1111');


// File

// Upload a publicly accessible file. The file size and type are determined by the SDK.
$res = $minioClient->putObject( '/www/php/www.gsj.com/minio/Dingtalk_0913104610.jpg','my3833/0913104610_0007.jpg' );

$res = $minioClient->getObjectInfo('my-bucket/202210/1633571028_57616.jpg');

$res = $minioClient->getObjectUrl('/my-bucket/20220913104610_0001.jpg');


$res = $minioClient->getObject( '/my-bucket/20220913104610_0001.jpg');

$res = $minioClient->deleteObject('/my-bucket/20220913104610_0001.jpg');

$res = $minioClient->copyObject('/my-bucket/202210/1633571028_57616.jpg','/other-bucket/202210/1633571028_57616.jpg');

Minio.php 操作类

请将Minio.php文件中的endpoint,key, secret, Bucket修改为你的本地配置。

<?php

require_once 'Request.php';
require_once 'Response.php';


class Minio
{
    const CODE_SUCCESS = 200;
    const CODE_DEL_SUCCESS = 204;

    private $endpoint = 'http://minio.xxx.com';
    private $accessKey = 'minioadmin';
    private $secretKey = 'minioadmin';

    private $multiCurl;
    private $curlOpts = [
        CURLOPT_CONNECTTIMEOUT => 30,
        CURLOPT_LOW_SPEED_LIMIT => 1,
        CURLOPT_LOW_SPEED_TIME => 30
    ];
    private static $instance;

    public function __construct()
    {
        $this->multiCurl = curl_multi_init();
    }

    public function __destruct()
    {
        curl_multi_close($this->multiCurl);
    }

    /**
     * 单例模式 获取实例
     * @return Minio
     */
    public static function getInstance()
    {
        if (self::$instance == null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * 获取bucket列表
     * @return array
     */
    public function listBuckets()
    {
        $res = $this->requestBucket('GET', '');
        if ($res && $res['code'] == self::CODE_SUCCESS) {
            $res['data'] = ['bucket' => array_column($res['data']['Buckets']['Bucket'], 'Name')];
            return $res;
        } else {
            return $res;
        }
    }

    /**
     * 获取bucket目录文件信息
     * @param $bucket
     * @return Response
     */
    public function getBucket(string $bucket)
    {
        return $this->requestBucket('GET', $bucket);
    }

    /**
     * 创建bucket目录
     * @param $bucket
     * @return bool true创建成功,false失败
     */
    public function createBucket(string $bucket)
    {
        $res = $this->requestBucket('PUT', $bucket);
        if ($res['code'] == self::CODE_SUCCESS) {
            $this->putBucketPolicy($bucket);
            return true;
        }

        return false;
    }

    /**
     * 策略设置存储目录
     * @param $bucket bucket目录
     * @return mixed
     */
    public function putBucketPolicy($bucket)
    {
        //该策略设置存储桶为只读
        $policyReadOnly = '{
          "Version": "2012-10-17",
          "Statement": [
            {
              "Action": [
                "s3:GetBucketLocation",
                "s3:ListBucket"
              ],
              "Effect": "Deny",
              "Principal": {
                "AWS": [
                  "*"
                ]
              },
              "Resource": [
                "arn:aws:s3:::%s"
              ],
              "Sid": ""
            },
            {
              "Action": [
                "s3:GetObject"
              ],
              "Effect": "Allow",
              "Principal": {
                "AWS": [
                  "*"
                ]
              },
              "Resource": [
                "arn:aws:s3:::%s/*"
              ],
              "Sid": ""
            }
          ]
        }
        ';
        $policy = sprintf($policyReadOnly, $bucket, $bucket);

        $res = $this->requestBucket('PUT', $bucket . '?policy', $policy);

        return $res;
    }

    /**
     * 删除bucket目录
     * @param $bucket
     * @return bool true删除成功,false失败
     */
    public function deleteBucket(string $bucket)
    {
        $res = $this->requestBucket('DELETE', $bucket);
        if ($res['code'] == self::CODE_DEL_SUCCESS) {
            return true;
        }

        return false;
    }

    /**
     * 上传文件
     * @param string $file 本地需要上传的全路径文件
     * @param string $uri 保存路径名称
     * @return Response
     */
    public function putObject(string $file, string $uri)
    {
        //判断bucket是否存在,不存在则创建
        $uri = ltrim($uri, DIRECTORY_SEPARATOR);
        $uriArr = explode(DIRECTORY_SEPARATOR, $uri);
        $bucket = $uriArr[0];

        $listBuckets = $this->listBuckets();
        $bucketArr = $listBuckets['data']['bucket'];

        if (!in_array($bucket, $bucketArr)) {
            $this->createBucket($bucket);
        }

        $request = (new Request('PUT', $this->endpoint, $uri))
            ->setHeaders(['x-amz-acl' => 'public-read-write'])
            ->setFileContents(fopen($file, 'r'))
            ->setMultiCurl($this->multiCurl)
            ->setCurlOpts($this->curlOpts)
            ->sign($this->accessKey, $this->secretKey);

        $res = $this->objectToArray($request->getResponse());

        return $res;
    }

    /**
     * 获取文件链接
     * @param string $uri 保存路径名称
     * @return string
     */
    public function getObjectUrl(string $uri)
    {
        return $this->endpoint . $uri;
    }


    /**
     * 获取文件类型,header中体现
     * @param string $uri 保存路径名称
     * @return Response code=200为文件存在
     */
    public function getObjectInfo(string $uri)
    {
        $uri = ltrim($uri, DIRECTORY_SEPARATOR);

        $request = (new Request('HEAD', $this->endpoint, $uri))
            ->setMultiCurl($this->multiCurl)
            ->setCurlOpts($this->curlOpts)
            ->sign($this->accessKey, $this->secretKey);

        return $this->objectToArray($request->getResponse());
    }

    /**
     * 获取文件 ,data返回二进制数据流
     * @param string $uri 保存路径名称
     * @param null $resource
     * @param array $headers
     * @return Response
     */
    public function getObject(string $uri)
    {
        $uri = ltrim($uri, DIRECTORY_SEPARATOR);

        $request = (new Request('GET', $this->endpoint, $uri))
            ->setMultiCurl($this->multiCurl)
            ->setCurlOpts($this->curlOpts)
            ->sign($this->accessKey, $this->secretKey);

        return $this->objectToArray($request->getResponse());
    }

    /**
     * 删除文件
     * @param string $uri 保存路径名称
     * @return bool true删除成功,false删除失败
     */
    public function deleteObject(string $uri)
    {
        $uri = ltrim($uri, DIRECTORY_SEPARATOR);

        $request = (new Request('DELETE', $this->endpoint, $uri))
            ->setMultiCurl($this->multiCurl)
            ->setCurlOpts($this->curlOpts)
            ->sign($this->accessKey, $this->secretKey);

        $res = $this->objectToArray($request->getResponse());
        if ($res['code'] == self::CODE_DEL_SUCCESS) {
            return true;
        }

        return false;
    }

    /**
     * 拷贝文件
     * @param $fromObject 源文件
     * @param $toObject 目标文件
     * @return array|mixed {"code":200}
     */
    public function copyObject($fromObject, $toObject)
    {
        $fromObject = ltrim($fromObject, DIRECTORY_SEPARATOR);
        $toObject = ltrim($toObject, DIRECTORY_SEPARATOR);

        //判断目标bucket是否存在,不存在则创建
        $toArr = explode(DIRECTORY_SEPARATOR, $toObject);
        $toBucket = $toArr[0];
        $listBuckets = $this->listBuckets();
        $bucketArr = $listBuckets['data']['bucket'];
        if (!in_array($toBucket, $bucketArr)) {
            $this->createBucket($toBucket);
        }

        $request = (new Request('PUT', $this->endpoint, $toObject))
            ->setHeaders(['x-amz-copy-source' => $fromObject])
            ->setMultiCurl($this->multiCurl)
            ->setCurlOpts($this->curlOpts)
            ->sign($this->accessKey, $this->secretKey);

        $res = $this->objectToArray($request->getResponse());

        return $res;
    }

    /**
     * bucket目录请求
     * @param string $method
     * @param string $bucket
     * @param array $headers
     * @return mixed
     */
    protected function requestBucket(string $method = 'GET', string $bucket = '', string $postFields = '')
    {
        $request = (new Request($method, $this->endpoint, $bucket))
            ->setPostField($postFields)
            ->setMultiCurl($this->multiCurl)
            ->setCurlOpts($this->curlOpts)
            ->sign($this->accessKey, $this->secretKey);

        return $this->objectToArray($request->getResponse());
    }

    /**
     * 对象转数组
     * @param $object
     * @return mixed
     */
    private function objectToArray($object)
    {
        $arr = is_object($object) ? get_object_vars($object) : $object;
        $returnArr = [];
        foreach ($arr as $key => $val) {
            $val = (is_array($val)) || is_object($val) ? $this->objectToArray($val) : $val;
            $returnArr[$key] = $val;
        }
        return $returnArr;
    }

}

Request.php 请求类

<?php

class Request
{
    private $action;
    private $endpoint;
    private $uri;
    private $headers;
    private $curl;
    private $response;

    private $multi_curl;
    private $secure;

    public function __construct($action, $endpoint, $uri)
    {
        $this->action = $action;
        $this->uri = $uri;
        $url = parse_url($endpoint);
        $this->endpoint = $url['host'];
        $url['scheme'] === 'http' || $this->secure = true;
        $this->headers = [
            'Content-MD5' => '',
            'Content-Type' => '',
            'Date' => gmdate('D, d M Y H:i:s T'),
            'Host' => $this->endpoint
        ];

        $this->curl = curl_init();
        $this->response = new Response();

        $this->multi_curl = null;
    }

    /**
     * 设置文件内容
     * @param $file
     * @return $this
     */
    public function setFileContents($file)
    {
        if (is_resource($file)) {
            $hash_ctx = hash_init('md5');
            $length = hash_update_stream($hash_ctx, $file);
            $md5 = hash_final($hash_ctx, true);

            rewind($file);
            $this->headers['Content-Type'] = mime_content_type($file);

            curl_setopt($this->curl, CURLOPT_PUT, true);
            curl_setopt($this->curl, CURLOPT_INFILE, $file);
            curl_setopt($this->curl, CURLOPT_INFILESIZE, $length);
        } else {
            curl_setopt($this->curl, CURLOPT_POSTFIELDS, $file);
            $md5 = md5($file, true);
        }
        $this->headers['Content-MD5'] = base64_encode($md5);
        return $this;
    }

    public function setPostField($postFields)
    {
        if (!empty($postFields)) {
            curl_setopt($this->curl, CURLOPT_POSTFIELDS, $postFields);
            $md5 = md5($postFields, true);
            $this->headers['Content-MD5'] = base64_encode($md5);
        }

        return $this;
    }

    public function setHeaders($headers)
    {
        if (!empty($headers)) {
            $this->headers = array_merge($this->headers, $headers);
        }
        return $this;
    }

    /**
     * 生成签名
     * @param $access_key
     * @param $secret_key
     * @return $this
     */
    public function sign($access_key, $secret_key)
    {
        $canonical_amz_headers = $this->getCanonicalAmzHeaders();
        $string_to_sign = '';
        $string_to_sign .= "{$this->action}\n";
        $string_to_sign .= "{$this->headers['Content-MD5']}\n";
        $string_to_sign .= "{$this->headers['Content-Type']}\n";
        $string_to_sign .= "{$this->headers['Date']}\n";

        if (!empty($canonical_amz_headers)) {
            $string_to_sign .= implode($canonical_amz_headers, "\n") . "\n";
        }

        $string_to_sign .= "/{$this->uri}";
        $signature = base64_encode(
            hash_hmac('sha1', $string_to_sign, $secret_key, true)
        );

        $this->headers['Authorization'] = "AWS $access_key:$signature";

        return $this;
    }

    /**
     * multi_curl设置
     * @param $mh
     * @return $this
     */
    public function setMultiCurl($mh)
    {
        $this->multi_curl = $mh;
        return $this;
    }

    /**
     * opt设置
     * @param $curl_opts
     * @return $this
     */
    public function setCurlOpts($curl_opts)
    {
        curl_setopt_array($this->curl, $curl_opts);

        return $this;
    }

    /**
     * 获取返回内容
     * @return Response
     */
    public function getResponse()
    {
        $http_headers = array_map(
            function ($header, $value) {
                return "$header: $value";
            },
            array_keys($this->headers),
            array_values($this->headers)
        );
        $url = "{$this->endpoint}/{$this->uri}";
        if ($this->secure) {
            $url = 'https://' . $url;
        } else {
            $url = 'http://' . $url;
        }
        curl_setopt_array($this->curl, [
            CURLOPT_URL => $url,
            CURLOPT_HTTPHEADER => $http_headers,
            CURLOPT_HEADER => false,
            CURLOPT_RETURNTRANSFER => false,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_WRITEFUNCTION => [
                $this->response, '__curlWriteFunction'
            ],
            CURLOPT_HEADERFUNCTION => [
                $this->response, '__curlHeaderFunction'
            ]
        ]);

        switch ($this->action) {
            case 'DELETE':
                curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
                break;
            case 'HEAD':
                curl_setopt($this->curl, CURLOPT_NOBODY, true);
                break;
            case 'POST':
                curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, 'POST');
                break;
            case 'PUT':
                curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, 'PUT');
                break;
            default:
                curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, $this->action);
                break;
        }


        if (isset($this->multi_curl)) {
            curl_multi_add_handle($this->multi_curl, $this->curl);

            $running = null;
            do {
                curl_multi_exec($this->multi_curl, $running);
                curl_multi_select($this->multi_curl);
            } while ($running > 0);

            curl_multi_remove_handle($this->multi_curl, $this->curl);
        } else {
            curl_exec($this->curl);
        }

        $this->response->finalize($this->curl);
        curl_close($this->curl);
        return $this->response;
    }

    /**
     * 头部处理
     * @return array
     */
    private function getCanonicalAmzHeaders()
    {
        $canonical_amz_headers = [];
        foreach ($this->headers as $header => $value) {
            $header = trim(strtolower($header));
            $value = trim($value);

            if (strpos($header, 'x-amz-') === 0) {
                $canonical_amz_headers[$header] = "$header:$value";
            }
        }
        ksort($canonical_amz_headers);
        return $canonical_amz_headers;
    }
}

Response.php 返回类

<?php

class Response
{
    public $code; //200为成功
    public $error;
    public $headers;
    public $data;

    public function __construct()
    {
        $this->code = null;
        $this->error = null;
        $this->headers = [];
        $this->data = null;
    }

    public function saveToResource($resource)
    {
        $this->data = $resource;
    }

    /**
     * 返回内容回调
     * @param $ch
     * @param $data
     * @return false|int
     */
    public function __curlWriteFunction($ch, $data)
    {
        if (is_resource($this->data)) {
            return fwrite($this->data, $data);
        } else {
            $this->data .= $data;
            return strlen($data);
        }
    }

    /**
     * 头部信息回调
     * @param $ch
     * @param $data
     * @return int
     */
    public function __curlHeaderFunction($ch, $data)
    {
        $header = explode(':', $data);

        if (count($header) == 2) {
            list($key, $value) = $header;
            $this->headers[$key] = trim($value);
        }

        return strlen($data);
    }

    /**
     * 返回内容处理
     * @param $ch
     */
    public function finalize($ch)
    {
        if (is_resource($this->data)) {
            rewind($this->data);
        }

        if (curl_errno($ch) || curl_error($ch)) {
            $this->error = [
                'code' => curl_errno($ch),
                'message' => curl_error($ch),
            ];
        } else {
            $this->code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            $content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);

            if ($content_type == 'application/xml') {
                $obj = simplexml_load_string($this->data, "SimpleXMLElement", LIBXML_NOCDATA);
                $this->data = json_decode(json_encode($obj), true);
            }
        }
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值