添加网站文件

This commit is contained in:
2025-12-22 13:59:40 +08:00
commit 117aaf83d1
19468 changed files with 2111999 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
composer.phar
/vendor/
# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control
# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
composer.lock
.idea
.DS_Store
cache/
*.cache

View File

@@ -0,0 +1,65 @@
<?php
/*
* This document has been generated with
* https://mlocati.github.io/php-cs-fixer-configurator/#version:2.15|configurator
* you can change this configuration by importing this file.
*/
return PhpCsFixer\Config::create()
->setRiskyAllowed(true)
->setIndent(' ')
->setRules([
'@PSR2' => true,
'@PhpCsFixer' => true,
'@Symfony:risky' => true,
'concat_space' => ['spacing' => 'one'],
'array_syntax' => ['syntax' => 'short'],
'array_indentation' => true,
'combine_consecutive_unsets' => true,
'method_separation' => true,
'single_quote' => true,
'declare_equal_normalize' => true,
'function_typehint_space' => true,
'hash_to_slash_comment' => true,
'include' => true,
'lowercase_cast' => true,
'no_multiline_whitespace_before_semicolons' => true,
'no_leading_import_slash' => true,
'no_multiline_whitespace_around_double_arrow' => true,
'no_spaces_around_offset' => true,
'no_unneeded_control_parentheses' => true,
'no_unused_imports' => true,
'no_whitespace_before_comma_in_array' => true,
'no_whitespace_in_blank_line' => true,
'object_operator_without_whitespace' => true,
'single_blank_line_before_namespace' => true,
'single_class_element_per_statement' => true,
'space_after_semicolon' => true,
'standardize_not_equals' => true,
'ternary_operator_spaces' => true,
'trailing_comma_in_multiline_array' => true,
'trim_array_spaces' => true,
'unary_operator_spaces' => true,
'whitespace_after_comma_in_array' => true,
'no_extra_consecutive_blank_lines' => [
'curly_brace_block',
'extra',
'parenthesis_brace_block',
'square_brace_block',
'throw',
'use',
],
'binary_operator_spaces' => [
'align_double_arrow' => true,
'align_equals' => true,
],
'braces' => [
'allow_single_line_closure' => true,
],
])
->setFinder(
PhpCsFixer\Finder::create()
->exclude('vendor')
->exclude('tests')
->in(__DIR__)
);

View File

@@ -0,0 +1,31 @@
English | [简体中文](README-CN.md)
![](https://aliyunsdk-pages.alicdn.com/icons/AlibabaCloud.svg)
## Alibaba Cloud Tea File Library for PHP
## Installation
### Composer
```bash
composer require alibabacloud/tea-fileform
```
## Issues
[Opening an Issue](https://github.com/aliyun/tea-fileform/issues/new), Issues not conforming to the guidelines may be closed immediately.
## Changelog
Detailed changes for each release are documented in the [release notes](./ChangeLog.txt).
## References
* [Latest Release](https://github.com/aliyun/tea-fileform)
## License
[Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0)
Copyright (c) 2009-present, Alibaba Cloud All rights reserved.

View File

@@ -0,0 +1,31 @@
[English](README.md) | 简体中文
![](https://aliyunsdk-pages.alicdn.com/icons/AlibabaCloud.svg)
## Alibaba Cloud Tea File Library for PHP
## 安装
### Composer
```bash
composer require alibabacloud/tea-fileform
```
## 问题
[提交 Issue](https://github.com/aliyun/tea-fileform/issues/new),不符合指南的问题可能会立即关闭。
## 发行说明
每个版本的详细更改记录在[发行说明](./ChangeLog.txt)中。
## 相关
* [最新源码](https://github.com/aliyun/tea-fileform)
## 许可证
[Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0)
Copyright (c) 2009-present, Alibaba Cloud All rights reserved.

View File

@@ -0,0 +1,44 @@
{
"name": "alibabacloud/tea-fileform",
"description": "Alibaba Cloud Tea File Library for PHP",
"type": "library",
"license": "Apache-2.0",
"authors": [
{
"name": "Alibaba Cloud SDK",
"email": "sdk-team@alibabacloud.com"
}
],
"require": {
"php": ">5.5",
"alibabacloud/tea": "^3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35|^5.4.3"
},
"autoload": {
"psr-4": {
"AlibabaCloud\\Tea\\FileForm\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"AlibabaCloud\\Tea\\FileForm\\Tests\\": "tests"
}
},
"scripts": {
"fixer": "php-cs-fixer fix ./",
"test": [
"@clearCache",
"phpunit --colors=always"
],
"clearCache": "rm -rf cache/*"
},
"config": {
"sort-packages": true,
"preferred-install": "dist",
"optimize-autoloader": true
},
"prefer-stable": true,
"minimum-stability": "dev"
}

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="./tests/bootstrap.php" colors="true" processIsolation="false" stopOnFailure="false"
convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true"
testSuiteLoaderFile="phpunit/src/Runner/StandardTestSuiteLoader.php">
<testsuites>
<testsuite name="All">
<directory>tests</directory>
</testsuite>
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
</testsuites>
<groups>
<exclude>
<group>integration</group>
</exclude>
</groups>
<logging>
<log type="coverage-html" target="cache/coverage" lowUpperBound="35" highLowerBound="70"/>
<log type="coverage-clover" target="cache/coverage.clover"/>
</logging>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src</directory>
</whitelist>
</filter>
</phpunit>

View File

@@ -0,0 +1,16 @@
<?php
namespace AlibabaCloud\Tea\FileForm;
class FileForm
{
public static function getBoundary()
{
return (string) (mt_rand(10000000000000, 99999999999999));
}
public static function toFileForm($map, $boundary)
{
return new FileFormStream($map, $boundary);
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace AlibabaCloud\Tea\FileForm\FileForm;
use AlibabaCloud\Tea\Model;
class FileField extends Model
{
public $filename;
public $contentType;
public $content;
public function __construct($config = [])
{
$this->_required = [
'filename' => true,
'contentType' => true,
'content' => true,
];
parent::__construct($config);
}
}

View File

@@ -0,0 +1,321 @@
<?php
namespace AlibabaCloud\Tea\FileForm;
use AlibabaCloud\Tea\FileForm\FileForm\FileField;
use GuzzleHttp\Psr7\Stream;
use Psr\Http\Message\StreamInterface;
/**
* @internal
* @coversNothing
*/
class FileFormStream implements StreamInterface
{
/**
* @var resource
*/
private $stream;
private $index = 0;
private $form = [];
private $boundary = '';
private $streaming = false;
private $keys = [];
/**
* @var Stream
*/
private $currStream;
private $size;
private $uri;
private $seekable;
private $readable = true;
private $writable = true;
public function __construct($map, $boundary)
{
$this->stream = fopen('php://memory', 'a+');
$this->form = $map;
$this->boundary = $boundary;
$this->keys = array_keys($map);
do {
$read = $this->readForm(1024);
} while (null !== $read);
$meta = stream_get_meta_data($this->stream);
$this->seekable = $meta['seekable'];
$this->uri = $this->getMetadata('uri');
$this->seek(0);
$this->seek(0);
}
/**
* Closes the stream when the destructed.
*/
public function __destruct()
{
$this->close();
}
public function __toString()
{
try {
$this->seek(0);
return (string) stream_get_contents($this->stream);
} catch (\Exception $e) {
return '';
}
}
/**
* @param int $length
*
* @return false|int|string
*/
public function readForm($length)
{
if ($this->streaming) {
if (null !== $this->currStream) {
// @var string $content
$content = $this->currStream->read($length);
if (false !== $content && '' !== $content) {
fwrite($this->stream, $content);
return $content;
}
return $this->next("\r\n");
}
return $this->next();
}
$keysCount = \count($this->keys);
if ($this->index > $keysCount) {
return null;
}
if ($keysCount > 0) {
if ($this->index < $keysCount) {
$this->streaming = true;
$name = $this->keys[$this->index];
$field = $this->form[$name];
if (!empty($field) && $field instanceof FileField) {
if (!empty($field->content)) {
$this->currStream = $field->content;
$str = '--' . $this->boundary . "\r\n" .
'Content-Disposition: form-data; name="' . $name . '"; filename="' . $field->filename . "\"\r\n" .
'Content-Type: ' . $field->contentType . "\r\n\r\n";
$this->write($str);
return $str;
}
return $this->next();
}
$val = $field;
$str = '--' . $this->boundary . "\r\n" .
'Content-Disposition: form-data; name="' . $name . "\"\r\n\r\n" .
$val . "\r\n";
fwrite($this->stream, $str);
return $str;
}
if ($this->index == $keysCount) {
return $this->next('--' . $this->boundary . "--\r\n");
}
return null;
}
return null;
}
public function getContents()
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
$contents = stream_get_contents($this->stream);
if (false === $contents) {
throw new \RuntimeException('Unable to read stream contents');
}
return $contents;
}
public function close()
{
if (isset($this->stream)) {
if (\is_resource($this->stream)) {
fclose($this->stream);
}
$this->detach();
}
}
public function detach()
{
if (!isset($this->stream)) {
return null;
}
$result = $this->stream;
unset($this->stream);
$this->size = $this->uri = null;
return $result;
}
public function getSize()
{
if (null !== $this->size) {
return $this->size;
}
if (!isset($this->stream)) {
return null;
}
// Clear the stat cache if the stream has a URI
if ($this->uri) {
clearstatcache(true, $this->uri);
}
$stats = fstat($this->stream);
if (isset($stats['size'])) {
$this->size = $stats['size'];
return $this->size;
}
return null;
}
public function isReadable()
{
return $this->readable;
}
public function isWritable()
{
return $this->writable;
}
public function isSeekable()
{
return $this->seekable;
}
public function eof()
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
return feof($this->stream);
}
public function tell()
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
$result = ftell($this->stream);
if (false === $result) {
throw new \RuntimeException('Unable to determine stream position');
}
return $result;
}
public function rewind()
{
$this->seek(0);
}
public function seek($offset, $whence = SEEK_SET)
{
$whence = (int) $whence;
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
if (!$this->seekable) {
throw new \RuntimeException('Stream is not seekable');
}
if (-1 === fseek($this->stream, $offset, $whence)) {
throw new \RuntimeException('Unable to seek to stream position ' . $offset . ' with whence ' . var_export($whence, true));
}
}
public function read($length)
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
if (!$this->readable) {
throw new \RuntimeException('Cannot read from non-readable stream');
}
if ($length < 0) {
throw new \RuntimeException('Length parameter cannot be negative');
}
if (0 === $length) {
return '';
}
$string = fread($this->stream, $length);
if (false === $string) {
throw new \RuntimeException('Unable to read from stream');
}
return $string;
}
public function write($string)
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
if (!$this->writable) {
throw new \RuntimeException('Cannot write to a non-writable stream');
}
// We can't know the size after writing anything
$this->size = null;
$result = fwrite($this->stream, $string);
if (false === $result) {
throw new \RuntimeException('Unable to write to stream');
}
return $result;
}
public function getMetadata($key = null)
{
if (!isset($this->stream)) {
return $key ? null : [];
}
$meta = stream_get_meta_data($this->stream);
return isset($meta[$key]) ? $meta[$key] : null;
}
private function next($endStr = '')
{
$this->streaming = false;
++$this->index;
$this->write($endStr);
$this->currStream = null;
return $endStr;
}
}

View File

@@ -0,0 +1,81 @@
<?php
namespace AlibabaCloud\Tea\FileForm\Tests;
use AlibabaCloud\Tea\FileForm\FileForm;
use AlibabaCloud\Tea\FileForm\FileForm\FileField;
use AlibabaCloud\Tea\FileForm\FileFormStream;
use GuzzleHttp\Psr7\Stream;
use PHPUnit\Framework\TestCase;
/**
* @internal
* @coversNothing
*/
class FileFormTest extends TestCase
{
public function testFileFromStream()
{
$boundary = FileForm::getBoundary();
$stream = FileForm::toFileForm([], $boundary);
$this->assertTrue($stream instanceof FileFormStream);
$stream->write($boundary);
$this->assertTrue(\strlen($boundary) === $stream->getSize());
}
public function testSet()
{
$fileField = new FileField([
'filename' => 'fake filename',
'contentType' => 'content type',
'content' => null,
]);
$this->assertEquals('fake filename', $fileField->filename);
$this->assertEquals('content type', $fileField->contentType);
}
public function testRead()
{
$fileField = new FileField();
$fileField->filename = 'haveContent';
$fileField->contentType = 'contentType';
$fileField->content = new Stream(fopen('data://text/plain;base64,' . base64_encode('This is file test. This sentence must be long'), 'r'));
$fileFieldNoContent = new FileField();
$fileFieldNoContent->filename = 'noContent';
$fileFieldNoContent->contentType = 'contentType';
$fileFieldNoContent->content = null;
$map = [
'key' => 'value',
'testKey' => 'testValue',
'haveFile' => $fileField,
'noFile' => $fileFieldNoContent,
];
$stream = FileForm::toFileForm($map, 'testBoundary');
$result = $stream->getContents();
$target = "--testBoundary\r\nContent-Disposition: form-data; name=\"key\"\r\n\r\nvalue\r\n--testBoundary\r\nContent-Disposition: form-data; name=\"testKey\"\r\n\r\ntestValue\r\n--testBoundary\r\nContent-Disposition: form-data; name=\"haveFile\"; filename=\"haveContent\"\r\nContent-Type: contentType\r\n\r\nThis is file test. This sentence must be long\r\n--testBoundary--\r\n";
$this->assertEquals($target, $result);
}
public function testReadFile()
{
$fileField = new FileField();
$fileField->filename = 'composer.json';
$fileField->contentType = 'application/json';
$fileField->content = new Stream(fopen(__DIR__ . '/../composer.json', 'r'));
$map = [
'name' => 'json_file',
'type' => 'application/json',
'json_file' => $fileField,
];
$boundary = FileForm::getBoundary();
$fileStream = FileForm::toFileForm($map, $boundary);
$this->assertTrue(false !== strpos($fileStream->getContents(), 'json_file'));
}
}

View File

@@ -0,0 +1,3 @@
<?php
require dirname(__DIR__) . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';