<?php
namespace Base\Service;

use OSS\Core\OssUtil;
use OSS\OssClient;
use OSS\Core\OSsException;

/**
 * 目前仅支持阿里云OSS
 */
class OssService {

    private $accessKeyId = '';
    private $accessKeySecret = '';
    private $domain = '';
    private $isCName = false;
    private $bucket = '';
    private $bdDomain = '';
    private $client;
    private $errorMessage = '';

    public function __construct()
    {
        Vendor('OSS.autoload');
        $this->accessKeyId = C('oss_storage.accesskeyid');
        $this->accessKeySecret = C('oss_storage.accesskeysecr');
        $this->domain = C('oss_storage.domain');
        $this->isCName = C('oss_storage.is_cname');
        $this->bdDomain = C('oss_storage.bd_domain');
        $this->bucket = C('oss_storage.bucket');
        $this->client = new OssClient($this->accessKeyId, $this->accessKeySecret, $this->domain, $this->isCName);
    }

    public function upload($localFilePath, $saveFileName)
    {
        try {
            $this->multiuploadFile($localFilePath, $saveFileName);
            return [
                'status' => true,
                'message' => '上传OSS成功',
                'data' => [
                    'url' => $this->getUrl($saveFileName)
                ]
            ];
        } catch (OssException $e) {
            return [
                'status' => false,
                'message' => $e->getMessage()
            ];
        }
    }

    private function multiuploadFile($file, $saveFileName)
    {
        $uploadId = $this->client->initiateMultipartUpload($this->bucket, $saveFileName);

        /*
         * step 2. 上传分片
         */
        $partSize = 5 * 1000 * 1024;
        $uploadFile = $file;
        $uploadFileSize = filesize($uploadFile);
        $pieces = $this->client->generateMultiuploadParts($uploadFileSize, $partSize);
        $responseUploadPart = [];
        $uploadPosition = 0;
        $isCheckMd5 = true;
        foreach ($pieces as $i => $piece) {
            $fromPos = $uploadPosition + (integer) $piece[OssClient::OSS_SEEK_TO];
            $toPos = (integer) $piece[OssClient::OSS_LENGTH] + $fromPos - 1;
            $upOptions = [
                    OssClient::OSS_FILE_UPLOAD => $uploadFile,
                    OssClient::OSS_PART_NUM => ($i + 1),
                    OssClient::OSS_SEEK_TO => $fromPos,
                    OssClient::OSS_LENGTH => $toPos - $fromPos + 1,
                    OssClient::OSS_CHECK_MD5 => $isCheckMd5,
            ];
            if ($isCheckMd5) {
                $contentMd5 = OssUtil::getMd5SumForFile($uploadFile, $fromPos, $toPos);
                $upOptions[OssClient::OSS_CONTENT_MD5] = $contentMd5;
            }
            // 2. 将每一分片上传到OSS
            $responseUploadPart[] = $this->client->uploadPart($this->bucket, $saveFileName, $uploadId, $upOptions);
        }
        $uploadParts = [];
        foreach ($responseUploadPart as $i => $eTag) {
            $uploadParts[] = [
                'PartNumber' => ($i + 1),
                'ETag' => $eTag,
            ];
        }

        /**
         * step 3. 完成上传
         */
        $this->client->completeMultipartUpload($this->bucket, $saveFileName, $uploadId, $uploadParts);
    }

    /**
     *删除文件
     */
    public function deleteObject($deleteFile)
    {
        $this->client->deleteObject($this->bucket, $deleteFile);
    }

    private function getUrl($saveFileName)
    {
        $url = '';
        if ($this->isCName) {
            $url = 'http://' . $this->domain . '/' . $saveFileName;
        } else {
            $url = 'https://' . $this->bucket . '.' . $this->domain . '/' . $saveFileName;
            $url = str_replace('-internal', '', $url);
        }
        /**
         * @todo unknown
         */
        if (!empty($this->bdDomain) && strlen($this->bdDomain) > 5) {
            $url = $this->bdDomain . $saveFileName;
        }
        return $url;
    }
}