This commit is contained in:
2025-10-29 15:32:26 +08:00
parent d90614805b
commit b7462657cd
78921 changed files with 2753938 additions and 71 deletions

View File

@@ -0,0 +1,28 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
# change these settings to your own preference
indent_style = space
indent_size = 4
# we recommend you to keep these unchanged
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,json,xml}]
indent_size = 2
[package.json]
indent_style = space
indent_size = 2

View File

@@ -0,0 +1,10 @@
# System Files
.DS_Store
Thumbs.db
# editor
.idea/
# project
composer.lock
vendor/

View File

@@ -0,0 +1,13 @@
language: php
php:
- 5.6
- 7.0
- 7.1
- hhvm
before_script:
- composer self-update
- composer --version
script: composer install --prefer-dist --no-interaction

View File

@@ -0,0 +1,91 @@
## Aliyun OSS Adapter For Flysystem.
[![Latest Stable Version](https://poser.pugx.org/xxtime/flysystem-aliyun-oss/v/stable)](https://packagist.org/packages/xxtime/flysystem-aliyun-oss)
[![Build Status](https://travis-ci.org/xxtime/flysystem-aliyun-oss.svg?branch=master)](https://travis-ci.org/xxtime/flysystem-aliyun-oss)
[![Total Downloads](https://poser.pugx.org/xxtime/flysystem-aliyun-oss/downloads)](https://packagist.org/packages/xxtime/flysystem-aliyun-oss)
[![License](https://poser.pugx.org/xxtime/flysystem-aliyun-oss/license)](https://packagist.org/packages/xxtime/flysystem-aliyun-oss)
[![Author](http://img.shields.io/badge/author-Joe-blue.svg?style=flat-square)](https://www.xxtime.com)
[![Code Climate](https://codeclimate.com/github/xxtime/flysystem-aliyun-oss/badges/gpa.svg)](https://codeclimate.com/github/xxtime/flysystem-aliyun-oss)
AliYun OSS Storage adapter for flysystem - a PHP filesystem abstraction.
## Installation
composer require xxtime/flysystem-aliyun-oss
## Logs
##### 1.3.0
1. some args name changed
2. default region oss-cn-hangzhou
## Usage
```php
use League\Flysystem\Filesystem;
use Xxtime\Flysystem\Aliyun\OssAdapter;
$aliyun = new OssAdapter([
'accessId' => '<aliyun access id>',
'accessSecret' => '<aliyun access secret>',
'bucket' => '<bucket name>',
'endpoint' => '<endpoint address>',
// 'timeout' => 3600,
// 'connectTimeout' => 10,
// 'isCName' => false,
// 'token' => '',
]);
$filesystem = new Filesystem($aliyun);
// Write Files
$filesystem->write('path/to/file.txt', 'contents');
// get RAW data from aliYun OSS
$raw = $aliyun->supports->getFlashData();
// Write Use writeStream
$stream = fopen('local/path/to/file.txt', 'r+');
$result = $filesystem->writeStream('path/to/file.txt', $stream);
if (is_resource($stream)) {
fclose($stream);
}
// Update Files
$filesystem->update('path/to/file.txt', 'new contents');
// Check if a file exists
$exists = $filesystem->has('path/to/file.txt');
// Read Files
$contents = $filesystem->read('path/to/file.txt');
// Delete Files
$filesystem->delete('path/to/file.txt');
// Rename Files
$filesystem->rename('filename.txt', 'newname.txt');
// Copy Files
$filesystem->copy('filename.txt', 'duplicate.txt');
// list the contents (not support recursive now)
$filesystem->listContents('path', false);
```
```php
// 说明:此方法返回从阿里云接口返回的原生数据,仅可调用一次
// DESC: this function return AliYun RAW data
$raw = $aliyun->supports->getFlashData();
```
## Document
1. [Region And Endpoint Table](https://help.aliyun.com/document_detail/31837.html)
2. [Aliyun OSS PHP SDK Document](https://help.aliyun.com/document_detail/85580.html)
## Reference
[http://flysystem.thephpleague.com/api/](http://flysystem.thephpleague.com/api/)
[https://github.com/thephpleague/flysystem](https://github.com/thephpleague/flysystem)

View File

@@ -0,0 +1,34 @@
{
"name": "xxtime/flysystem-aliyun-oss",
"type": "library",
"description": "AliYun OSS adapter for flysystem. aliyuncs/oss-sdk-php ~2.3",
"keywords": [
"flysystem-aliyun-oss",
"aliyun-oss",
"flysystem"
],
"homepage": "https://github.com/xxtime/flysystem-aliyun-oss",
"license": "MIT",
"authors": [
{
"name": "Joe",
"email": "joe@xxtime.com",
"homepage": "https://github.com/xxtime",
"role": "Developer"
}
],
"support": {
"email": "joe@xxtime.com",
"wiki": "https://github.com/xxtime"
},
"require": {
"php": ">=5.5.0",
"league/flysystem": "^1.0.49",
"aliyuncs/oss-sdk-php": "~2.3"
},
"autoload": {
"psr-4": {
"Xxtime\\Flysystem\\Aliyun\\": "src/"
}
}
}

View File

@@ -0,0 +1,50 @@
<?php
/**
* 指定上传文件的Content-Type
* 此设置可以不指定文件路径后缀
*/
use League\Flysystem\Filesystem;
use Xxtime\Flysystem\Aliyun\OssAdapter;
use finfo;
class uploadWithContentType
{
public function demo()
{
$fileContent = file_get_contents('/path/to/file.jpg');
// 配置
$adapter = new OssAdapter([
'accessId' => "xxx",
'accessSecret' => "xxx",
'bucket' => "xxx",
'endpoint' => "xxx",
'timeout' => 3600,
'connectTimeout' => 10,
]);
$filesystem = new Filesystem($adapter);
// 设置属性
// 如设置了Content-Type则可以不指定路径的后缀 (即$filePath可以不包含.jpg等后缀名)
$fInfo = new finfo(FILEINFO_MIME_TYPE);
$mimeType = $fInfo->buffer($fileContent);
$config = [
"Content-Type" => $mimeType
];
$filePath = "uploadPathTest/" . time();
// 上传
if (!$filesystem->write($filePath, $fileContent, $config)) {
exit("failed to upload");
}
// 获取信息
$raw = $adapter->supports->getFlashData();
var_dump($raw);
}
}

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="tests/bootstrap.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false">
<testsuites>
<testsuite name="Omnipay MyCard Test Suite">
<directory>./tests/Tests/</directory>
</testsuite>
</testsuites>
<listeners>
<listener class="Mockery\Adapter\Phpunit\TestListener" file="vendor/mockery/mockery/library/Mockery/Adapter/Phpunit/TestListener.php" />
</listeners>
<filter>
<whitelist>
<directory>./src</directory>
</whitelist>
</filter>
</phpunit>

View File

@@ -0,0 +1,441 @@
<?php
namespace Xxtime\Flysystem\Aliyun;
use League\Flysystem\Adapter\AbstractAdapter;
use League\Flysystem\Config;
use League\Flysystem\Util;
use OSS\OssClient;
use Exception;
class OssAdapter extends AbstractAdapter
{
/**
* @var Supports
*/
public $supports;
/**
* @var OssClient
*/
private $oss;
/**
* @var AliYun bucket
*/
private $bucket;
/**
* @var string
*/
private $endpoint = 'oss-cn-hangzhou.aliyuncs.com';
/**
* OssAdapter constructor.
* @param array $config
* @throws Exception
*/
public function __construct($config = [])
{
$isCName = false;
$token = null;
$this->supports = new Supports();
try {
$this->bucket = $config['bucket'];
empty($config['endpoint']) ? null : $this->endpoint = $config['endpoint'];
empty($config['timeout']) ? $config['timeout'] = 3600 : null;
empty($config['connectTimeout']) ? $config['connectTimeout'] = 10 : null;
if (!empty($config['isCName'])) {
$isCName = true;
}
if (!empty($config['token'])) {
$token = $config['token'];
}
$this->oss = new OssClient(
$config['accessId'], $config['accessSecret'], $this->endpoint, $isCName, $token
);
$this->oss->setTimeout($config['timeout']);
$this->oss->setConnectTimeout($config['connectTimeout']);
} catch (Exception $e) {
throw $e;
}
}
/**
* Write a new file.
*
* @param string $path
* @param string $contents
* @param Config $config Config object
*
* @return array|false false on failure file meta data on success
*/
public function write($path, $contents, Config $config)
{
$result = $this->oss->putObject($this->bucket, $path, $contents, $this->getOssOptions($config));
$this->supports->setFlashData($result);
return $result;
}
/**
* Write a new file using a stream.
*
* @param string $path
* @param resource $resource
* @param Config $config Config object
*
* @return array|false false on failure file meta data on success
*/
public function writeStream($path, $resource, Config $config)
{
if (!is_resource($resource)) {
return false;
}
$i = 0;
$bufferSize = 1000000; // 1M
while (!feof($resource)) {
if (false === $buffer = fread($resource, $block = $bufferSize)) {
return false;
}
$position = $i * $bufferSize;
$size = $this->oss->appendObject($this->bucket, $path, $buffer, $position, $this->getOssOptions($config));
$i++;
}
fclose($resource);
return true;
}
/**
* Update a file.
*
* @param string $path
* @param string $contents
* @param Config $config Config object
*
* @return array|false false on failure file meta data on success
*/
public function update($path, $contents, Config $config)
{
$result = $this->oss->putObject($this->bucket, $path, $contents, $this->getOssOptions($config));
$this->supports->setFlashData($result);
return $result;
}
/**
* Update a file using a stream.
*
* @param string $path
* @param resource $resource
* @param Config $config Config object
*
* @return array|false false on failure file meta data on success
*/
public function updateStream($path, $resource, Config $config)
{
$result = $this->write($path, stream_get_contents($resource), $config);
if (is_resource($resource)) {
fclose($resource);
}
return $result;
}
/**
* Rename a file.
*
* @param string $path
* @param string $newpath
*
* @return bool
*/
public function rename($path, $newpath)
{
$this->oss->copyObject($this->bucket, $path, $this->bucket, $newpath);
$this->oss->deleteObject($this->bucket, $path);
return true;
}
/**
* Copy a file.
*
* @param string $path
* @param string $newpath
*
* @return bool
*/
public function copy($path, $newpath)
{
$this->oss->copyObject($this->bucket, $path, $this->bucket, $newpath);
return true;
}
/**
* Delete a file.
*
* @param string $path
*
* @return bool
*/
public function delete($path)
{
$this->oss->deleteObject($this->bucket, $path);
return true;
}
/**
* Delete a directory.
*
* @param string $dirname
*
* @return bool
*/
public function deleteDir($dirname)
{
$lists = $this->listContents($dirname, true);
if (!$lists) {
return false;
}
$objectList = [];
foreach ($lists as $value) {
$objectList[] = $value['path'];
}
$this->oss->deleteObjects($this->bucket, $objectList);
return true;
}
/**
* Create a directory.
*
* @param string $dirname directory name
* @param Config $config
*
* @return array|false
*/
public function createDir($dirname, Config $config)
{
$this->oss->createObjectDir($this->bucket, $dirname);
return true;
}
/**
* Set the visibility for a file.
*
* @param string $path
* @param string $visibility
*
* @return array|false file meta data
*
* Aliyun OSS ACL value: 'default', 'private', 'public-read', 'public-read-write'
*/
public function setVisibility($path, $visibility)
{
$this->oss->putObjectAcl(
$this->bucket,
$path,
($visibility == 'public') ? 'public-read' : 'private'
);
return true;
}
/**
* Check whether a file exists.
*
* @param string $path
*
* @return array|bool|null
*/
public function has($path)
{
return $this->oss->doesObjectExist($this->bucket, $path);
}
/**
* Read a file.
*
* @param string $path
*
* @return array|false
*/
public function read($path)
{
return [
'contents' => $this->oss->getObject($this->bucket, $path)
];
}
/**
* Read a file as a stream.
*
* @param string $path
*
* @return array|false
*/
public function readStream($path)
{
$resource = 'http://' . $this->bucket . '.' . $this->endpoint . '/' . $path;
return [
'stream' => $resource = fopen($resource, 'r')
];
}
/**
* List contents of a directory.
*
* @param string $directory
* @param bool $recursive
*
* @return array
*/
public function listContents($directory = '', $recursive = false)
{
$directory = rtrim($directory, '\\/');
$result = [];
$nextMarker = '';
while (true) {
// max-keys 用于限定此次返回object的最大数如果不设定默认为100max-keys取值不能大于1000。
// prefix 限定返回的object key必须以prefix作为前缀。注意使用prefix查询时返回的key中仍会包含prefix。
// delimiter是一个用于对Object名字进行分组的字符。所有名字包含指定的前缀且第一次出现delimiter字符之间的object作为一组元素
// marker 用户设定结果从marker之后按字母排序的第一个开始返回。
$options = [
'max-keys' => 1000,
'prefix' => $directory . '/',
'delimiter' => '/',
'marker' => $nextMarker,
];
$res = $this->oss->listObjects($this->bucket, $options);
// 得到nextMarker从上一次$res读到的最后一个文件的下一个文件开始继续获取文件列表
$nextMarker = $res->getNextMarker();
$prefixList = $res->getPrefixList(); // 目录列表
$objectList = $res->getObjectList(); // 文件列表
if ($prefixList) {
foreach ($prefixList as $value) {
$result[] = [
'type' => 'dir',
'path' => $value->getPrefix()
];
if ($recursive) {
$result = array_merge($result, $this->listContents($value->getPrefix(), $recursive));
}
}
}
if ($objectList) {
foreach ($objectList as $value) {
if (($value->getSize() === 0) && ($value->getKey() === $directory . '/')) {
continue;
}
$result[] = [
'type' => 'file',
'path' => $value->getKey(),
'timestamp' => strtotime($value->getLastModified()),
'size' => $value->getSize()
];
}
}
if ($nextMarker === '') {
break;
}
}
return $result;
}
/**
* Get all the meta data of a file or directory.
*
* @param string $path
*
* @return array|false
*/
public function getMetadata($path)
{
return $this->oss->getObjectMeta($this->bucket, $path);
}
/**
* Get the size of a file.
*
* @param string $path
*
* @return array|false
*/
public function getSize($path)
{
$response = $this->oss->getObjectMeta($this->bucket, $path);
return [
'size' => $response['content-length']
];
}
/**
* Get the mimetype of a file.
*
* @param string $path
*
* @return array|false
*/
public function getMimetype($path)
{
$response = $this->oss->getObjectMeta($this->bucket, $path);
return [
'mimetype' => $response['content-type']
];
}
/**
* Get the timestamp of a file.
*
* @param string $path
*
* @return array|false
*/
public function getTimestamp($path)
{
$response = $this->oss->getObjectMeta($this->bucket, $path);
return [
'timestamp' => $response['last-modified']
];
}
/**
* Get the visibility of a file.
*
* @param string $path
*
* @return array|false
*/
public function getVisibility($path)
{
$response = $this->oss->getObjectAcl($this->bucket, $path);
return [
'visibility' => $response,
];
}
/**
* Get OSS Options
* @param Config $config
* @return array
*/
private function getOssOptions(Config $config)
{
$options = [];
if ($config->has("headers")) {
$options['headers'] = $config->get("headers");
}
if ($config->has("Content-Type")) {
$options["Content-Type"] = $config->get("Content-Type");
}
if ($config->has("Content-Md5")) {
$options["Content-Md5"] = $config->get("Content-Md5");
$options["checkmd5"] = false;
}
return $options;
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace Xxtime\Flysystem\Aliyun;
use League\Flysystem\Config;
class Supports
{
private $flashData = null;
public function setFlashData($data = null)
{
$this->flashData = $data;
}
public function getFlashData()
{
$flash = $this->flashData;
$this->flashData = null;
return $flash;
}
}

View File

@@ -0,0 +1,6 @@
<?php
error_reporting(E_ALL | E_STRICT);
date_default_timezone_set('UTC');
require_once __DIR__ . '/../vendor/autoload.php';