mirror of
https://github.com/itflow-org/itflow
synced 2026-03-19 20:24:51 +00:00
Add new optional beta email parser thats based on ImapEngine instead of Webklex
This commit is contained in:
3
plugins/vendor/zbateson/stream-decorators/.github/FUNDING.yml
vendored
Normal file
3
plugins/vendor/zbateson/stream-decorators/.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: zbateson
|
||||
37
plugins/vendor/zbateson/stream-decorators/.github/workflows/tests.yml
vendored
Normal file
37
plugins/vendor/zbateson/stream-decorators/.github/workflows/tests.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
name: Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
php: [8.3, 8.2, 8.1, 8.0]
|
||||
stability: [prefer-stable]
|
||||
|
||||
name: P${{ matrix.php }} - ${{ matrix.stability }} - ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo
|
||||
coverage: none
|
||||
|
||||
- name: Setup problem matchers
|
||||
run: |
|
||||
echo "::add-matcher::${{ runner.tool_cache }}/php.json"
|
||||
echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer update --${{ matrix.stability }} --prefer-dist --no-interaction
|
||||
|
||||
- name: Execute tests
|
||||
run: ./vendor/bin/phpunit -c tests/phpunit.xml
|
||||
15
plugins/vendor/zbateson/stream-decorators/.php-cs-fixer.dist.php
vendored
Normal file
15
plugins/vendor/zbateson/stream-decorators/.php-cs-fixer.dist.php
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
/*
|
||||
* This document has been generated with
|
||||
* https://mlocati.github.io/php-cs-fixer-configurator/#version:3.0.0-rc.1|configurator
|
||||
* you can change this configuration by importing this file.
|
||||
*
|
||||
*/
|
||||
|
||||
$config = include 'vendor/zbateson/mb-wrapper/PhpCsFixer.php';
|
||||
|
||||
return $config->setFinder(PhpCsFixer\Finder::create()
|
||||
->exclude('vendor')
|
||||
->in(__DIR__.'\src')
|
||||
->in(__DIR__.'\tests')
|
||||
);
|
||||
25
plugins/vendor/zbateson/stream-decorators/LICENSE
vendored
Normal file
25
plugins/vendor/zbateson/stream-decorators/LICENSE
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2017, Zaahid Bateson
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
5
plugins/vendor/zbateson/stream-decorators/PhpCsFixer.php
vendored
Normal file
5
plugins/vendor/zbateson/stream-decorators/PhpCsFixer.php
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
// see vendor/zbateson/mb-wrapper/PhpCsFixer.php master version
|
||||
|
||||
|
||||
|
||||
78
plugins/vendor/zbateson/stream-decorators/README.md
vendored
Normal file
78
plugins/vendor/zbateson/stream-decorators/README.md
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
# zbateson/stream-decorators
|
||||
|
||||
Psr7 stream decorators for character set conversion and common mail format content encodings.
|
||||
|
||||
[](https://github.com/zbateson/stream-decorators/actions/workflows/tests.yml)
|
||||
[](https://scrutinizer-ci.com/g/zbateson/stream-decorators/?branch=master)
|
||||
[](https://scrutinizer-ci.com/g/zbateson/stream-decorators/?branch=master)
|
||||
[](//packagist.org/packages/zbateson/stream-decorators)
|
||||
[](//packagist.org/packages/zbateson/stream-decorators)
|
||||
|
||||
The goals of this project are to be:
|
||||
|
||||
* Well written
|
||||
* Standards-compliant but forgiving
|
||||
* Tested where possible
|
||||
|
||||
To include it for use in your project, please install via composer:
|
||||
|
||||
```
|
||||
composer require zbateson/stream-decorators
|
||||
```
|
||||
|
||||
## Php 7 Support Dropped
|
||||
|
||||
As of stream-decorators 2.0, support for php 7 has been dropped.
|
||||
|
||||
## Requirements
|
||||
|
||||
stream-decorators requires PHP 8.0 or newer. Tested on 8.0, 8.1, 8.2 and 8.3.
|
||||
|
||||
## New in 2.0 and 2.1
|
||||
|
||||
Support for guzzlehttp/psr7 1.9 dropped, min supported version is 2.0.
|
||||
|
||||
zbateson/mb-wrapper has been updated to 2.0 as well, which throws an UnsupportedCharsetException converting from/to an unsupported charset, which changes the behaviour of CharsetStream.
|
||||
|
||||
Two new classes are introduced in 2.1, DecoratedCachingStream and a TellZeroStream.
|
||||
|
||||
## Usage
|
||||
|
||||
```php
|
||||
$stream = GuzzleHttp\Psr7\Utils::streamFor($handle);
|
||||
$b64Stream = new ZBateson\StreamDecorators\Base64Stream($stream);
|
||||
$charsetStream = new ZBateson\StreamDecorators\CharsetStream($b64Stream, 'UTF-32', 'UTF-8');
|
||||
|
||||
while (($line = GuzzleHttp\Psr7\Utils::readLine()) !== false) {
|
||||
echo $line, "\r\n";
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Note that CharsetStream, depending on the target encoding, may return multiple bytes when a single 'char' is read. If using php's 'fread', this will result in a warning:
|
||||
|
||||
'read x bytes more data than requested (xxxx read, xxxx max) - excess data will be lost
|
||||
|
||||
This is because the parameter to 'fread' is bytes, and so when CharsetStream returns, say, 4 bytes representing a single UTF-32 character, fread will truncate to the first byte when requesting '1' byte. It is recommended to **not** convert to a stream handle (with StreamWrapper) for this reason when using CharsetStream.
|
||||
|
||||
The library consists of the following Psr\Http\Message\StreamInterface implementations:
|
||||
* ZBateson\StreamDecorators\Base64Stream - decodes on read and encodes on write to base64.
|
||||
* ZBateson\StreamDecorators\CharsetStream - encodes from $streamCharset to $stringCharset on read, and vice-versa on write.
|
||||
* ZBateson\StreamDecorators\ChunkSplitStream - splits written characters into lines of $lineLength long (stream implementation of php's chunk_split).
|
||||
* ZBateson\StreamDecorators\DecoratedCachingStream - a caching stream that writes to a decorated stream, and reads from the cached undecorated stream, so for instance a stream could be passed, and decorated with a Base64Stream, and when read, the returned bytes would be base64 encoded.
|
||||
* ZBateson\StreamDecorators\NonClosingStream - overrides close() and detach(), and simply unsets the attached stream without closing it.
|
||||
* ZBateson\StreamDecorators\PregReplaceFilterStream - calls preg_replace on with passed arguments on every read() call.
|
||||
* ZBateson\StreamDecorators\QuotedPrintableStream - decodes on read and encodes on write to quoted-printable.
|
||||
* ZBateson\StreamDecorators\SeekingLimitStream - similar to GuzzleHttp's LimitStream, but maintains an internal current read position, seeking to it when read() is called, and seeking back to the wrapped stream's position after reading.
|
||||
* ZBateson\StreamDecorators\TellZeroStream - tell() always returns '0' -- used by DecoratedCachingStream to wrap a BufferStream in a CachingStream. CachingStream calls tell() on its wrapped stream, and BufferStream throws an exception, so TellZeroStream is used to wrap the internal BufferStream to mitigate that.
|
||||
* ZBateson\StreamDecorators\UUStream - decodes on read, encodes on write to uu-encoded.
|
||||
|
||||
QuotedPrintableStream, Base64Stream and UUStream's constructors take a single argument of a StreamInterface.
|
||||
CharsetStreams's constructor also takes $streamCharset and $stringCharset as arguments respectively, ChunkSplitStream
|
||||
optionally takes a $lineLength argument (defaults to 76) and a $lineEnding argument (defaults to CRLF).
|
||||
PregReplaceFilterStream takes a $pattern argument and a $replacement argument. SeekingLimitStream takes optional
|
||||
$limit and $offset parameters, similar to GuzzleHttp's LimitStream.
|
||||
|
||||
## License
|
||||
|
||||
BSD licensed - please see [license agreement](https://github.com/zbateson/stream-decorators/blob/master/LICENSE).
|
||||
31
plugins/vendor/zbateson/stream-decorators/composer.json
vendored
Normal file
31
plugins/vendor/zbateson/stream-decorators/composer.json
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "zbateson/stream-decorators",
|
||||
"description": "PHP psr7 stream decorators for mime message part streams",
|
||||
"keywords": ["psr7", "stream", "decorators", "mail", "mime", "base64", "quoted-printable", "uuencode", "charset"],
|
||||
"license": "BSD-2-Clause",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Zaahid Bateson"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
"guzzlehttp/psr7": "^2.5",
|
||||
"zbateson/mb-wrapper": "^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.6|^10.0",
|
||||
"friendsofphp/php-cs-fixer": "*",
|
||||
"phpstan/phpstan": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"ZBateson\\StreamDecorators\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"ZBateson\\StreamDecorators\\": "tests/StreamDecorators"
|
||||
}
|
||||
}
|
||||
}
|
||||
8
plugins/vendor/zbateson/stream-decorators/phpstan.neon
vendored
Normal file
8
plugins/vendor/zbateson/stream-decorators/phpstan.neon
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
parameters:
|
||||
level: 6
|
||||
errorFormat: raw
|
||||
editorUrl: '%%file%% %%line%% %%column%%: %%error%%'
|
||||
paths:
|
||||
- src
|
||||
- tests
|
||||
|
||||
222
plugins/vendor/zbateson/stream-decorators/src/Base64Stream.php
vendored
Normal file
222
plugins/vendor/zbateson/stream-decorators/src/Base64Stream.php
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\StreamDecorators project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\StreamDecorators;
|
||||
|
||||
use GuzzleHttp\Psr7\BufferStream;
|
||||
use GuzzleHttp\Psr7\StreamDecoratorTrait;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* GuzzleHttp\Psr7 stream decoder extension for base64 streams.
|
||||
*
|
||||
* Note that it's expected the underlying stream will only contain valid base64
|
||||
* characters (normally the stream should be wrapped in a
|
||||
* PregReplaceFilterStream to filter out non-base64 characters for reading).
|
||||
*
|
||||
* ```
|
||||
* $f = fopen(...);
|
||||
* $stream = new Base64Stream(new PregReplaceFilterStream(
|
||||
* Psr7\Utils::streamFor($f), '/[^a-zA-Z0-9\/\+=]/', ''
|
||||
* ));
|
||||
* //...
|
||||
* ```
|
||||
*
|
||||
* For writing, a ChunkSplitStream could come in handy so the output is split
|
||||
* into lines:
|
||||
*
|
||||
* ```
|
||||
* $f = fopen(...);
|
||||
* $stream = new Base64Stream(new ChunkSplitStream(new PregReplaceFilterStream(
|
||||
* Psr7\Utils::streamFor($f), '/[^a-zA-Z0-9\/\+=]/', ''
|
||||
* )));
|
||||
* //...
|
||||
* ```
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class Base64Stream implements StreamInterface
|
||||
{
|
||||
use StreamDecoratorTrait;
|
||||
|
||||
/**
|
||||
* @var BufferStream buffered bytes
|
||||
*/
|
||||
private BufferStream $buffer;
|
||||
|
||||
/**
|
||||
* @var string remainder of write operation if the bytes didn't align to 3
|
||||
* bytes
|
||||
*/
|
||||
private string $remainder = '';
|
||||
|
||||
/**
|
||||
* @var int current number of read/written bytes (for tell())
|
||||
*/
|
||||
private int $position = 0;
|
||||
|
||||
/**
|
||||
* @var StreamInterface $stream
|
||||
*/
|
||||
private StreamInterface $stream;
|
||||
|
||||
public function __construct(StreamInterface $stream)
|
||||
{
|
||||
$this->stream = $stream;
|
||||
$this->buffer = new BufferStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current position of the file read/write pointer
|
||||
*/
|
||||
public function tell() : int
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null, getSize isn't supported
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function getSize() : ?int
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not implemented (yet).
|
||||
*
|
||||
* Seek position can be calculated.
|
||||
*
|
||||
* @param int $offset
|
||||
* @param int $whence
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function seek($offset, $whence = SEEK_SET) : void
|
||||
{
|
||||
throw new RuntimeException('Cannot seek a Base64Stream');
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to return false
|
||||
*/
|
||||
public function isSeekable() : bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the end of stream has been reached.
|
||||
*/
|
||||
public function eof() : bool
|
||||
{
|
||||
return ($this->buffer->eof() && $this->stream->eof());
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the internal byte buffer after reading and decoding data from the
|
||||
* underlying stream.
|
||||
*
|
||||
* Note that it's expected the underlying stream will only contain valid
|
||||
* base64 characters (normally the stream should be wrapped in a
|
||||
* PregReplaceFilterStream to filter out non-base64 characters).
|
||||
*/
|
||||
private function fillBuffer(int $length) : void
|
||||
{
|
||||
$fill = 8192;
|
||||
while ($this->buffer->getSize() < $length) {
|
||||
$read = $this->stream->read($fill);
|
||||
if ($read === '') {
|
||||
break;
|
||||
}
|
||||
$this->buffer->write(\base64_decode($read));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to read $length bytes after decoding them, and returns them.
|
||||
*
|
||||
* Note that reading and writing to the same stream may result in wrongly
|
||||
* encoded data and is not supported.
|
||||
*
|
||||
* @param int $length
|
||||
*/
|
||||
public function read($length) : string
|
||||
{
|
||||
// let Guzzle decide what to do.
|
||||
if ($length <= 0 || $this->eof()) {
|
||||
return $this->stream->read($length);
|
||||
}
|
||||
$this->fillBuffer($length);
|
||||
$ret = $this->buffer->read($length);
|
||||
$this->position += \strlen($ret);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the passed string to the underlying stream after encoding it to
|
||||
* base64.
|
||||
*
|
||||
* Base64Stream::close or detach must be called. Failing to do so may
|
||||
* result in 1-2 bytes missing from the end of the stream if there's a
|
||||
* remainder. Note that the default Stream destructor calls close as well.
|
||||
*
|
||||
* Note that reading and writing to the same stream may result in wrongly
|
||||
* encoded data and is not supported.
|
||||
*
|
||||
* @param string $string
|
||||
* @return int the number of bytes written
|
||||
*/
|
||||
public function write($string) : int
|
||||
{
|
||||
$bytes = $this->remainder . $string;
|
||||
$len = \strlen($bytes);
|
||||
if (($len % 3) !== 0) {
|
||||
$this->remainder = \substr($bytes, -($len % 3));
|
||||
$bytes = \substr($bytes, 0, $len - ($len % 3));
|
||||
} else {
|
||||
$this->remainder = '';
|
||||
}
|
||||
$this->stream->write(\base64_encode($bytes));
|
||||
$written = \strlen($string);
|
||||
$this->position += $len;
|
||||
return $written;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes out any remaining bytes at the end of the stream and closes.
|
||||
*/
|
||||
private function beforeClose() : void
|
||||
{
|
||||
if ($this->isWritable() && $this->remainder !== '') {
|
||||
$this->stream->write(\base64_encode($this->remainder));
|
||||
$this->remainder = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function close() : void
|
||||
{
|
||||
$this->beforeClose();
|
||||
$this->stream->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function detach()
|
||||
{
|
||||
$this->beforeClose();
|
||||
$this->stream->detach();
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
179
plugins/vendor/zbateson/stream-decorators/src/CharsetStream.php
vendored
Normal file
179
plugins/vendor/zbateson/stream-decorators/src/CharsetStream.php
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\StreamDecorator project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\StreamDecorators;
|
||||
|
||||
use GuzzleHttp\Psr7\StreamDecoratorTrait;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use RuntimeException;
|
||||
use ZBateson\MbWrapper\MbWrapper;
|
||||
|
||||
/**
|
||||
* GuzzleHttp\Psr7 stream decoder extension for charset conversion.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class CharsetStream implements StreamInterface
|
||||
{
|
||||
use StreamDecoratorTrait;
|
||||
|
||||
/**
|
||||
* @var MbWrapper the charset converter
|
||||
*/
|
||||
protected MbWrapper $converter;
|
||||
|
||||
/**
|
||||
* @var string charset of the source stream
|
||||
*/
|
||||
protected string $streamCharset = 'ISO-8859-1';
|
||||
|
||||
/**
|
||||
* @var string charset of strings passed in write operations, and returned
|
||||
* in read operations.
|
||||
*/
|
||||
protected string $stringCharset = 'UTF-8';
|
||||
|
||||
/**
|
||||
* @var int current read/write position
|
||||
*/
|
||||
private int $position = 0;
|
||||
|
||||
/**
|
||||
* @var int number of $stringCharset characters in $buffer
|
||||
*/
|
||||
private int $bufferLength = 0;
|
||||
|
||||
/**
|
||||
* @var string a buffer of characters read in the original $streamCharset
|
||||
* encoding
|
||||
*/
|
||||
private string $buffer = '';
|
||||
|
||||
/**
|
||||
* @var StreamInterface $stream
|
||||
*/
|
||||
private StreamInterface $stream;
|
||||
|
||||
/**
|
||||
* @param StreamInterface $stream Stream to decorate
|
||||
* @param string $streamCharset The underlying stream's charset
|
||||
* @param string $stringCharset The charset to encode strings to (or
|
||||
* expected for write)
|
||||
*/
|
||||
public function __construct(StreamInterface $stream, string $streamCharset = 'ISO-8859-1', string $stringCharset = 'UTF-8')
|
||||
{
|
||||
$this->stream = $stream;
|
||||
$this->converter = new MbWrapper();
|
||||
$this->streamCharset = $streamCharset;
|
||||
$this->stringCharset = $stringCharset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to return the position in the target encoding.
|
||||
*/
|
||||
public function tell() : int
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null, getSize isn't supported
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function getSize() : ?int
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @param int $offset
|
||||
* @param int $whence
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function seek($offset, $whence = SEEK_SET) : void
|
||||
{
|
||||
throw new RuntimeException('Cannot seek a CharsetStream');
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to return false
|
||||
*/
|
||||
public function isSeekable() : bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a minimum of $length characters from the underlying stream in its
|
||||
* encoding into $this->buffer.
|
||||
*
|
||||
* Aligning to 4 bytes seemed to solve an issue reading from UTF-16LE
|
||||
* streams and pass testReadUtf16LeToEof, although the buffered string
|
||||
* should've solved that on its own.
|
||||
*/
|
||||
private function readRawCharsIntoBuffer(int $length) : void
|
||||
{
|
||||
$n = (int) \ceil(($length + 32) / 4.0) * 4;
|
||||
while ($this->bufferLength < $n) {
|
||||
$raw = $this->stream->read($n + 512);
|
||||
if ($raw === '') {
|
||||
return;
|
||||
}
|
||||
$this->buffer .= $raw;
|
||||
$this->bufferLength = $this->converter->getLength($this->buffer, $this->streamCharset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the end of stream has been reached.
|
||||
*/
|
||||
public function eof() : bool
|
||||
{
|
||||
return ($this->bufferLength === 0 && $this->stream->eof());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads up to $length decoded chars from the underlying stream and returns
|
||||
* them after converting to the target string charset.
|
||||
*
|
||||
* @param int $length
|
||||
*/
|
||||
public function read($length) : string
|
||||
{
|
||||
// let Guzzle decide what to do.
|
||||
if ($length <= 0 || $this->eof()) {
|
||||
return $this->stream->read($length);
|
||||
}
|
||||
$this->readRawCharsIntoBuffer($length);
|
||||
$numChars = \min([$this->bufferLength, $length]);
|
||||
$chars = $this->converter->getSubstr($this->buffer, $this->streamCharset, 0, $numChars);
|
||||
|
||||
$this->position += $numChars;
|
||||
$this->buffer = $this->converter->getSubstr($this->buffer, $this->streamCharset, $numChars);
|
||||
$this->bufferLength -= $numChars;
|
||||
|
||||
return $this->converter->convert($chars, $this->streamCharset, $this->stringCharset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the passed string to the underlying stream after converting it to
|
||||
* the target stream encoding.
|
||||
*
|
||||
* @param string $string
|
||||
* @return int the number of bytes written
|
||||
*/
|
||||
public function write($string) : int
|
||||
{
|
||||
$converted = $this->converter->convert($string, $this->stringCharset, $this->streamCharset);
|
||||
$written = $this->converter->getLength($converted, $this->streamCharset);
|
||||
$this->position += $written;
|
||||
return $this->stream->write($converted);
|
||||
}
|
||||
}
|
||||
122
plugins/vendor/zbateson/stream-decorators/src/ChunkSplitStream.php
vendored
Normal file
122
plugins/vendor/zbateson/stream-decorators/src/ChunkSplitStream.php
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\StreamDecorators project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\StreamDecorators;
|
||||
|
||||
use GuzzleHttp\Psr7\StreamDecoratorTrait;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Inserts line ending characters after the set number of characters have been
|
||||
* written to the underlying stream.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class ChunkSplitStream implements StreamInterface
|
||||
{
|
||||
use StreamDecoratorTrait;
|
||||
|
||||
/**
|
||||
* @var int Number of bytes written, and importantly, if non-zero, writes a
|
||||
* final $lineEnding on close (and so maintained instead of using
|
||||
* tell() directly)
|
||||
*/
|
||||
private int $position;
|
||||
|
||||
/**
|
||||
* @var int The number of characters in a line before inserting $lineEnding.
|
||||
*/
|
||||
private int $lineLength;
|
||||
|
||||
/**
|
||||
* @var string The line ending characters to insert.
|
||||
*/
|
||||
private string $lineEnding;
|
||||
|
||||
/**
|
||||
* @var int The strlen() of $lineEnding
|
||||
*/
|
||||
private int $lineEndingLength;
|
||||
|
||||
/**
|
||||
* @var StreamInterface $stream
|
||||
*/
|
||||
private StreamInterface $stream;
|
||||
|
||||
public function __construct(StreamInterface $stream, int $lineLength = 76, string $lineEnding = "\r\n")
|
||||
{
|
||||
$this->stream = $stream;
|
||||
$this->position = 0;
|
||||
$this->lineLength = $lineLength;
|
||||
$this->lineEnding = $lineEnding;
|
||||
$this->lineEndingLength = \strlen($this->lineEnding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the line ending character after each line length characters in
|
||||
* the passed string, making sure previously written bytes are taken into
|
||||
* account.
|
||||
*/
|
||||
private function getChunkedString(string $string) : string
|
||||
{
|
||||
$firstLine = '';
|
||||
if ($this->tell() !== 0) {
|
||||
$next = $this->lineLength - ($this->position % ($this->lineLength + $this->lineEndingLength));
|
||||
if (\strlen($string) > $next) {
|
||||
$firstLine = \substr($string, 0, $next) . $this->lineEnding;
|
||||
$string = \substr($string, $next);
|
||||
}
|
||||
}
|
||||
// chunk_split always ends with the passed line ending
|
||||
$chunked = $firstLine . \chunk_split($string, $this->lineLength, $this->lineEnding);
|
||||
return \substr($chunked, 0, \strlen($chunked) - $this->lineEndingLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the passed string to the underlying stream, ensuring line endings
|
||||
* are inserted every "line length" characters in the string.
|
||||
*
|
||||
* @param string $string
|
||||
* @return int number of bytes written
|
||||
*/
|
||||
public function write($string) : int
|
||||
{
|
||||
$chunked = $this->getChunkedString($string);
|
||||
$this->position += \strlen($chunked);
|
||||
return $this->stream->write($chunked);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a final line ending character.
|
||||
*/
|
||||
private function beforeClose() : void
|
||||
{
|
||||
if ($this->position !== 0) {
|
||||
$this->stream->write($this->lineEnding);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function close() : void
|
||||
{
|
||||
$this->beforeClose();
|
||||
$this->stream->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function detach()
|
||||
{
|
||||
$this->beforeClose();
|
||||
$this->stream->detach();
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
175
plugins/vendor/zbateson/stream-decorators/src/DecoratedCachingStream.php
vendored
Normal file
175
plugins/vendor/zbateson/stream-decorators/src/DecoratedCachingStream.php
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\StreamDecorators project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\StreamDecorators;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use GuzzleHttp\Psr7\StreamDecoratorTrait;
|
||||
use GuzzleHttp\Psr7\BufferStream;
|
||||
use GuzzleHttp\Psr7\CachingStream;
|
||||
use GuzzleHttp\Psr7\FnStream;
|
||||
use GuzzleHttp\Psr7\Utils;
|
||||
|
||||
/**
|
||||
* A version of Guzzle's CachingStream that will read bytes from one stream,
|
||||
* write them into another decorated stream, and read them back from a 3rd,
|
||||
* undecorated, buffered stream where the bytes are written to.
|
||||
*
|
||||
* A read operation is basically:
|
||||
*
|
||||
* Read from A, write to B (which decorates C), read and return from C (which is
|
||||
* backed by a BufferedStream).
|
||||
*
|
||||
* Note that the DecoratedCachingStream doesn't support write operations.
|
||||
*/
|
||||
class DecoratedCachingStream implements StreamInterface
|
||||
{
|
||||
use StreamDecoratorTrait;
|
||||
|
||||
/**
|
||||
* @var StreamInterface the stream to read from and fill writeStream with
|
||||
*/
|
||||
private StreamInterface $readStream;
|
||||
|
||||
/**
|
||||
* @var StreamInterface the underlying undecorated stream to read from,
|
||||
* where $writeStream is being written to
|
||||
*/
|
||||
private StreamInterface $stream;
|
||||
|
||||
/**
|
||||
* @var StreamInterface decorated $stream that will be written to for
|
||||
* caching that wraps $stream. Once filled, the stream is closed so it
|
||||
* supports a Base64Stream which writes bytes at the end.
|
||||
*/
|
||||
private ?StreamInterface $writeStream;
|
||||
|
||||
/**
|
||||
* @var int Minimum buffer read length. At least this many bytes will be
|
||||
* read and cached into $writeStream on each call to read from
|
||||
* $readStream
|
||||
*/
|
||||
private int $minBytesCache;
|
||||
|
||||
/**
|
||||
* @param StreamInterface $stream Stream to cache. The cursor is assumed to
|
||||
* be at the beginning of the stream.
|
||||
* @param callable(StreamInterface) : StreamInterface $decorator takes the
|
||||
* passed StreamInterface and decorates it, and returns the decorated
|
||||
* StreamInterface
|
||||
*/
|
||||
public function __construct(
|
||||
StreamInterface $stream,
|
||||
callable $decorator,
|
||||
int $minBytesCache = 16384
|
||||
) {
|
||||
$this->readStream = $stream;
|
||||
$bufferStream = new TellZeroStream(new BufferStream());
|
||||
$this->stream = new CachingStream($bufferStream);
|
||||
$this->writeStream = $decorator(new NonClosingStream($bufferStream));
|
||||
$this->minBytesCache = $minBytesCache;
|
||||
}
|
||||
|
||||
public function getSize(): ?int
|
||||
{
|
||||
// the decorated stream could be a different size
|
||||
$this->cacheEntireStream();
|
||||
return $this->stream->getSize();
|
||||
}
|
||||
|
||||
public function rewind(): void
|
||||
{
|
||||
$this->seek(0);
|
||||
}
|
||||
|
||||
public function seek($offset, $whence = SEEK_SET): void
|
||||
{
|
||||
if ($whence === SEEK_SET) {
|
||||
$byte = $offset;
|
||||
} elseif ($whence === SEEK_CUR) {
|
||||
$byte = $offset + $this->tell();
|
||||
} elseif ($whence === SEEK_END) {
|
||||
$size = $this->getSize();
|
||||
$byte = $size + $offset;
|
||||
} else {
|
||||
throw new \InvalidArgumentException('Invalid whence');
|
||||
}
|
||||
|
||||
$diff = $byte - $this->stream->getSize();
|
||||
|
||||
if ($diff > 0) {
|
||||
// Read the remoteStream until we have read in at least the amount
|
||||
// of bytes requested, or we reach the end of the file.
|
||||
while ($diff > 0 && !$this->readStream->eof()) {
|
||||
$this->read($diff);
|
||||
$diff = $byte - $this->stream->getSize();
|
||||
}
|
||||
} else {
|
||||
// We can just do a normal seek since we've already seen this byte.
|
||||
$this->stream->seek($byte);
|
||||
}
|
||||
}
|
||||
|
||||
private function cacheBytes(int $size) : void {
|
||||
if (!$this->readStream->eof()) {
|
||||
$data = $this->readStream->read(max($this->minBytesCache, $size));
|
||||
$this->writeStream->write($data);
|
||||
if ($this->readStream->eof()) {
|
||||
// needed because Base64Stream writes bytes on closing
|
||||
$this->writeStream->close();
|
||||
$this->writeStream = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function read($length): string
|
||||
{
|
||||
$data = $this->stream->read($length);
|
||||
$remaining = $length - strlen($data);
|
||||
if ($remaining > 0) {
|
||||
$this->cacheBytes($remaining);
|
||||
$data .= $this->stream->read($remaining);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function isWritable(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function write($string): int
|
||||
{
|
||||
throw new \RuntimeException('Cannot write to a DecoratedCachingStream');
|
||||
}
|
||||
|
||||
public function eof(): bool
|
||||
{
|
||||
return $this->stream->eof() && $this->readStream->eof();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close both the remote stream and buffer stream
|
||||
*/
|
||||
public function close(): void
|
||||
{
|
||||
$this->readStream->close();
|
||||
$this->stream->close();
|
||||
if ($this->writeStream !== null) {
|
||||
$this->writeStream->close();
|
||||
}
|
||||
}
|
||||
|
||||
private function cacheEntireStream(): int
|
||||
{
|
||||
// as-is from CachingStream
|
||||
$target = new FnStream(['write' => 'strlen']);
|
||||
Utils::copyToStream($this, $target);
|
||||
|
||||
return $this->tell();
|
||||
}
|
||||
}
|
||||
67
plugins/vendor/zbateson/stream-decorators/src/NonClosingStream.php
vendored
Normal file
67
plugins/vendor/zbateson/stream-decorators/src/NonClosingStream.php
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\StreamDecorators project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\StreamDecorators;
|
||||
|
||||
use GuzzleHttp\Psr7\StreamDecoratorTrait;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Doesn't close the underlying stream when 'close' is called on it. Instead,
|
||||
* calling close simply removes any reference to the underlying stream. Note
|
||||
* that GuzzleHttp\Psr7\Stream calls close in __destruct, so a reference to the
|
||||
* Stream needs to be kept. For example:
|
||||
*
|
||||
* ```
|
||||
* $f = fopen('php://temp', 'r+');
|
||||
* $test = new NonClosingStream(Psr7\Utils::streamFor('test'));
|
||||
* // work
|
||||
* $test->close();
|
||||
* rewind($f); // error, $f is a closed resource
|
||||
* ```
|
||||
*
|
||||
* Instead, this would work:
|
||||
*
|
||||
* ```
|
||||
* $stream = Psr7\Utils::streamFor(fopen('php://temp', 'r+'));
|
||||
* $test = new NonClosingStream($stream);
|
||||
* // work
|
||||
* $test->close();
|
||||
* $stream->rewind(); // works
|
||||
* ```
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class NonClosingStream implements StreamInterface
|
||||
{
|
||||
use StreamDecoratorTrait;
|
||||
|
||||
/**
|
||||
* @var ?StreamInterface $stream
|
||||
* @phpstan-ignore-next-line
|
||||
*/
|
||||
private ?StreamInterface $stream;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function close() : void
|
||||
{
|
||||
$this->stream = null; // @phpstan-ignore-line
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to detach the underlying stream without closing it.
|
||||
*
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function detach()
|
||||
{
|
||||
$this->stream = null; // @phpstan-ignore-line
|
||||
return null;
|
||||
}
|
||||
}
|
||||
110
plugins/vendor/zbateson/stream-decorators/src/PregReplaceFilterStream.php
vendored
Normal file
110
plugins/vendor/zbateson/stream-decorators/src/PregReplaceFilterStream.php
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\StreamDecorators project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\StreamDecorators;
|
||||
|
||||
use GuzzleHttp\Psr7\BufferStream;
|
||||
use GuzzleHttp\Psr7\StreamDecoratorTrait;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Calls preg_replace on each read operation with the passed pattern and
|
||||
* replacement string. Should only really be used to find single characters,
|
||||
* since a pattern intended to match more may be split across multiple read()
|
||||
* operations.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class PregReplaceFilterStream implements StreamInterface
|
||||
{
|
||||
use StreamDecoratorTrait;
|
||||
|
||||
/**
|
||||
* @var string The regex pattern
|
||||
*/
|
||||
private string $pattern;
|
||||
|
||||
/**
|
||||
* @var string The replacement
|
||||
*/
|
||||
private string $replacement;
|
||||
|
||||
/**
|
||||
* @var BufferStream Buffered stream of input from the underlying stream
|
||||
*/
|
||||
private BufferStream $buffer;
|
||||
|
||||
/**
|
||||
* @var StreamInterface $stream
|
||||
*/
|
||||
private StreamInterface $stream;
|
||||
|
||||
public function __construct(StreamInterface $stream, string $pattern, string $replacement)
|
||||
{
|
||||
$this->stream = $stream;
|
||||
$this->pattern = $pattern;
|
||||
$this->replacement = $replacement;
|
||||
$this->buffer = new BufferStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the end of stream has been reached.
|
||||
*/
|
||||
public function eof() : bool
|
||||
{
|
||||
return ($this->buffer->eof() && $this->stream->eof());
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported by PregReplaceFilterStream
|
||||
*
|
||||
* @param int $offset
|
||||
* @param int $whence
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function seek($offset, $whence = SEEK_SET) : void
|
||||
{
|
||||
throw new RuntimeException('Cannot seek a PregReplaceFilterStream');
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to return false
|
||||
*/
|
||||
public function isSeekable() : bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the BufferStream with at least 8192 characters of input for future
|
||||
* read operations.
|
||||
*/
|
||||
private function fillBuffer(int $length) : void
|
||||
{
|
||||
$fill = (int) \max([$length, 8192]);
|
||||
while ($this->buffer->getSize() < $length) {
|
||||
$read = $this->stream->read($fill);
|
||||
if ($read === '') {
|
||||
break;
|
||||
}
|
||||
$this->buffer->write(\preg_replace($this->pattern, $this->replacement, $read));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads from the underlying stream, filters it and returns up to $length
|
||||
* bytes.
|
||||
*
|
||||
* @param int $length
|
||||
*/
|
||||
public function read($length) : string
|
||||
{
|
||||
$this->fillBuffer($length);
|
||||
return $this->buffer->read($length);
|
||||
}
|
||||
}
|
||||
222
plugins/vendor/zbateson/stream-decorators/src/QuotedPrintableStream.php
vendored
Normal file
222
plugins/vendor/zbateson/stream-decorators/src/QuotedPrintableStream.php
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\StreamDecorators project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\StreamDecorators;
|
||||
|
||||
use GuzzleHttp\Psr7\StreamDecoratorTrait;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* GuzzleHttp\Psr7 stream decoder decorator for quoted printable streams.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class QuotedPrintableStream implements StreamInterface
|
||||
{
|
||||
use StreamDecoratorTrait;
|
||||
|
||||
/**
|
||||
* @var int current read/write position
|
||||
*/
|
||||
private int $position = 0;
|
||||
|
||||
/**
|
||||
* @var string Last line of written text (used to maintain good line-breaks)
|
||||
*/
|
||||
private string $lastLine = '';
|
||||
|
||||
/**
|
||||
* @var StreamInterface $stream
|
||||
* @phpstan-ignore-next-line
|
||||
*/
|
||||
private StreamInterface $stream;
|
||||
|
||||
/**
|
||||
* Overridden to return the position in the target encoding.
|
||||
*/
|
||||
public function tell() : int
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null, getSize isn't supported
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function getSize() : ?int
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @param int $offset
|
||||
* @param int $whence
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function seek($offset, $whence = SEEK_SET) : void
|
||||
{
|
||||
throw new RuntimeException('Cannot seek a QuotedPrintableStream');
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to return false
|
||||
*/
|
||||
public function isSeekable() : bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads $length chars from the underlying stream, prepending the past $pre
|
||||
* to it first.
|
||||
*
|
||||
* If the characters read (including the prepended $pre) contain invalid
|
||||
* quoted-printable characters, the underlying stream is rewound by the
|
||||
* total number of characters ($length + strlen($pre)).
|
||||
*
|
||||
* The quoted-printable encoded characters are returned. If the characters
|
||||
* read are invalid, '3D' is returned indicating an '=' character.
|
||||
*/
|
||||
private function readEncodedChars(int $length, string $pre = '') : string
|
||||
{
|
||||
$str = $pre . $this->stream->read($length);
|
||||
$len = \strlen($str);
|
||||
if ($len > 0 && !\preg_match('/^[0-9a-f]{2}$|^[\r\n]{1,2}.?$/is', $str) && $this->stream->isSeekable()) {
|
||||
$this->stream->seek(-$len, SEEK_CUR);
|
||||
return '3D'; // '=' character
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the passed $block of text.
|
||||
*
|
||||
* If the last or before last character is an '=' char, indicating the
|
||||
* beginning of a quoted-printable encoded char, 1 or 2 additional bytes are
|
||||
* read from the underlying stream respectively.
|
||||
*
|
||||
* @return string The decoded string
|
||||
*/
|
||||
private function decodeBlock(string $block) : string
|
||||
{
|
||||
if (\substr($block, -1) === '=') {
|
||||
$block .= $this->readEncodedChars(2);
|
||||
} elseif (\substr($block, -2, 1) === '=') {
|
||||
$first = \substr($block, -1);
|
||||
$block = \substr($block, 0, -1);
|
||||
$block .= $this->readEncodedChars(1, $first);
|
||||
}
|
||||
return \quoted_printable_decode($block);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads up to $length characters, appends them to the passed $str string,
|
||||
* and returns the total number of characters read.
|
||||
*
|
||||
* -1 is returned if there are no more bytes to read.
|
||||
*/
|
||||
private function readRawDecodeAndAppend(int $length, string &$str) : int
|
||||
{
|
||||
$block = $this->stream->read($length);
|
||||
if ($block === '') {
|
||||
return -1;
|
||||
}
|
||||
$decoded = $this->decodeBlock($block);
|
||||
$count = \strlen($decoded);
|
||||
$str .= $decoded;
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads up to $length decoded bytes from the underlying quoted-printable
|
||||
* encoded stream and returns them.
|
||||
*
|
||||
* @param int $length
|
||||
*/
|
||||
public function read($length) : string
|
||||
{
|
||||
// let Guzzle decide what to do.
|
||||
if ($length <= 0 || $this->eof()) {
|
||||
return $this->stream->read($length);
|
||||
}
|
||||
$count = 0;
|
||||
$bytes = '';
|
||||
while ($count < $length) {
|
||||
$nRead = $this->readRawDecodeAndAppend($length - $count, $bytes);
|
||||
if ($nRead === -1) {
|
||||
break;
|
||||
}
|
||||
$this->position += $nRead;
|
||||
$count += $nRead;
|
||||
}
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the passed string to the underlying stream after encoding it as
|
||||
* quoted-printable.
|
||||
*
|
||||
* Note that reading and writing to the same stream without rewinding is not
|
||||
* supported.
|
||||
*
|
||||
* @param string $string
|
||||
*
|
||||
* @return int the number of bytes written
|
||||
*/
|
||||
public function write($string) : int
|
||||
{
|
||||
$encodedLine = \quoted_printable_encode($this->lastLine);
|
||||
$lineAndString = \rtrim(\quoted_printable_encode($this->lastLine . $string), "\r\n");
|
||||
$write = \substr($lineAndString, \strlen($encodedLine));
|
||||
$this->stream->write($write);
|
||||
$written = \strlen($string);
|
||||
$this->position += $written;
|
||||
|
||||
$lpos = \strrpos($lineAndString, "\n");
|
||||
$lastLine = $lineAndString;
|
||||
if ($lpos !== false) {
|
||||
$lastLine = \substr($lineAndString, $lpos + 1);
|
||||
}
|
||||
$this->lastLine = \quoted_printable_decode($lastLine);
|
||||
return $written;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes out a final CRLF if the current line isn't empty.
|
||||
*/
|
||||
private function beforeClose() : void
|
||||
{
|
||||
if ($this->isWritable() && $this->lastLine !== '') {
|
||||
$this->stream->write("\r\n");
|
||||
$this->lastLine = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function close() : void
|
||||
{
|
||||
$this->beforeClose();
|
||||
$this->stream->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function detach()
|
||||
{
|
||||
$this->beforeClose();
|
||||
$this->stream->detach();
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
192
plugins/vendor/zbateson/stream-decorators/src/SeekingLimitStream.php
vendored
Normal file
192
plugins/vendor/zbateson/stream-decorators/src/SeekingLimitStream.php
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\StreamDecorators project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\StreamDecorators;
|
||||
|
||||
use GuzzleHttp\Psr7\StreamDecoratorTrait;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Maintains an internal 'read' position, and seeks to it before reading, then
|
||||
* seeks back to the original position of the underlying stream after reading if
|
||||
* the attached stream supports seeking.
|
||||
*
|
||||
* Although copied form LimitStream, it's not inherited from it since $offset
|
||||
* and $limit are set to private on LimitStream, and most other functions are
|
||||
* re-implemented anyway. This also decouples the implementation from upstream
|
||||
* changes.
|
||||
*/
|
||||
class SeekingLimitStream implements StreamInterface
|
||||
{
|
||||
use StreamDecoratorTrait;
|
||||
|
||||
/** @var int Offset to start reading from */
|
||||
private int $offset;
|
||||
|
||||
/** @var int Limit the number of bytes that can be read */
|
||||
private int $limit;
|
||||
|
||||
/**
|
||||
* @var int Number of bytes written, and importantly, if non-zero, writes a
|
||||
* final $lineEnding on close (and so maintained instead of using
|
||||
* tell() directly)
|
||||
*/
|
||||
private int $position = 0;
|
||||
|
||||
/**
|
||||
* @var StreamInterface $stream
|
||||
*/
|
||||
private StreamInterface $stream;
|
||||
|
||||
/**
|
||||
* @param StreamInterface $stream Stream to wrap
|
||||
* @param int $limit Total number of bytes to allow to be read
|
||||
* from the stream. Pass -1 for no limit.
|
||||
* @param int $offset Position to seek to before reading (only
|
||||
* works on seekable streams).
|
||||
*/
|
||||
public function __construct(StreamInterface $stream, int $limit = -1, int $offset = 0)
|
||||
{
|
||||
$this->stream = $stream;
|
||||
$this->setLimit($limit);
|
||||
$this->setOffset($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current relative read position of this stream subset.
|
||||
*/
|
||||
public function tell() : int
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the limited subset of data, or null if the wrapped
|
||||
* stream returns null for getSize.
|
||||
*/
|
||||
public function getSize() : ?int
|
||||
{
|
||||
$size = $this->stream->getSize();
|
||||
if ($size === null) {
|
||||
// this shouldn't happen on a seekable stream I don't think...
|
||||
$pos = $this->stream->tell();
|
||||
$this->stream->seek(0, SEEK_END);
|
||||
$size = $this->stream->tell();
|
||||
$this->stream->seek($pos);
|
||||
}
|
||||
if ($this->limit === -1) {
|
||||
return $size - $this->offset;
|
||||
}
|
||||
|
||||
return \min([$this->limit, $size - $this->offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current read position is at the end of the limited
|
||||
* stream
|
||||
*/
|
||||
public function eof() : bool
|
||||
{
|
||||
$size = $this->limit;
|
||||
if ($size === -1) {
|
||||
$size = $this->getSize();
|
||||
}
|
||||
return ($this->position >= $size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the seek position specified is within the stream's bounds, and
|
||||
* sets the internal position pointer (doesn't actually seek).
|
||||
*/
|
||||
private function doSeek(int $pos) : void
|
||||
{
|
||||
if ($this->limit !== -1) {
|
||||
$pos = \min([$pos, $this->limit]);
|
||||
}
|
||||
$this->position = \max([0, $pos]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Seeks to the passed position within the confines of the limited stream's
|
||||
* bounds.
|
||||
*
|
||||
* For SeekingLimitStream, no actual seek is performed on the underlying
|
||||
* wrapped stream. Instead, an internal pointer is set, and the stream is
|
||||
* 'seeked' on read operations
|
||||
*
|
||||
* @param int $offset
|
||||
* @param int $whence
|
||||
*/
|
||||
public function seek($offset, $whence = SEEK_SET) : void
|
||||
{
|
||||
$pos = $offset;
|
||||
switch ($whence) {
|
||||
case SEEK_CUR:
|
||||
$pos = $this->position + $offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
$pos = $this->limit + $offset;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
$this->doSeek($pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the offset to start reading from the wrapped stream.
|
||||
*/
|
||||
public function setOffset(int $offset) : void
|
||||
{
|
||||
$this->offset = $offset;
|
||||
$this->position = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the length of the stream to the passed $limit.
|
||||
*/
|
||||
public function setLimit(int $limit) : void
|
||||
{
|
||||
$this->limit = $limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Seeks to the current position and reads up to $length bytes, or less if
|
||||
* it would result in reading past $this->limit
|
||||
*/
|
||||
public function seekAndRead(int $length) : string
|
||||
{
|
||||
$this->stream->seek($this->offset + $this->position);
|
||||
if ($this->limit !== -1) {
|
||||
$length = \min($length, $this->limit - $this->position);
|
||||
if ($length <= 0) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
return $this->stream->read($length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads from the underlying stream after seeking to the position within the
|
||||
* bounds set for this limited stream. After reading, the wrapped stream is
|
||||
* 'seeked' back to its position prior to the call to read().
|
||||
*
|
||||
* @param int $length
|
||||
*/
|
||||
public function read($length) : string
|
||||
{
|
||||
$pos = $this->stream->tell();
|
||||
$ret = $this->seekAndRead($length);
|
||||
$this->position += \strlen($ret);
|
||||
$this->stream->seek($pos);
|
||||
if ($this->limit !== -1 && $this->position > $this->limit) {
|
||||
$ret = \substr($ret, 0, -($this->position - $this->limit));
|
||||
$this->position = $this->limit;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
31
plugins/vendor/zbateson/stream-decorators/src/TellZeroStream.php
vendored
Normal file
31
plugins/vendor/zbateson/stream-decorators/src/TellZeroStream.php
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\StreamDecorators project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\StreamDecorators;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use GuzzleHttp\Psr7\StreamDecoratorTrait;
|
||||
|
||||
/**
|
||||
* Calling tell() always returns 0. Used by DecoratedCachingStream so a
|
||||
* CachingStream can use a BufferedStream, because BufferedStream throws an
|
||||
* exception in tell().
|
||||
*/
|
||||
class TellZeroStream implements StreamInterface
|
||||
{
|
||||
use StreamDecoratorTrait;
|
||||
|
||||
/**
|
||||
* @var StreamInterface
|
||||
*/
|
||||
private StreamInterface $stream;
|
||||
|
||||
public function tell() : int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
315
plugins/vendor/zbateson/stream-decorators/src/UUStream.php
vendored
Normal file
315
plugins/vendor/zbateson/stream-decorators/src/UUStream.php
vendored
Normal file
@@ -0,0 +1,315 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of the ZBateson\StreamDecorators project.
|
||||
*
|
||||
* @license http://opensource.org/licenses/bsd-license.php BSD
|
||||
*/
|
||||
|
||||
namespace ZBateson\StreamDecorators;
|
||||
|
||||
use GuzzleHttp\Psr7\BufferStream;
|
||||
use GuzzleHttp\Psr7\StreamDecoratorTrait;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* GuzzleHttp\Psr7 stream decoder extension for UU-Encoded streams.
|
||||
*
|
||||
* The size of the underlying stream and the position of bytes can't be
|
||||
* determined because the number of encoded bytes is indeterminate without
|
||||
* reading the entire stream.
|
||||
*
|
||||
* @author Zaahid Bateson
|
||||
*/
|
||||
class UUStream implements StreamInterface
|
||||
{
|
||||
use StreamDecoratorTrait;
|
||||
|
||||
/**
|
||||
* @var string name of the UUEncoded file
|
||||
*/
|
||||
protected $filename = null;
|
||||
|
||||
/**
|
||||
* @var BufferStream of read and decoded bytes
|
||||
*/
|
||||
private $buffer;
|
||||
|
||||
/**
|
||||
* @var string remainder of write operation if the bytes didn't align to 3
|
||||
* bytes
|
||||
*/
|
||||
private $remainder = '';
|
||||
|
||||
/**
|
||||
* @var int read/write position
|
||||
*/
|
||||
private $position = 0;
|
||||
|
||||
/**
|
||||
* @var bool set to true when 'write' is called
|
||||
*/
|
||||
private $isWriting = false;
|
||||
|
||||
/**
|
||||
* @var StreamInterface $stream
|
||||
*/
|
||||
private $stream;
|
||||
|
||||
/**
|
||||
* @param StreamInterface $stream Stream to decorate
|
||||
* @param string $filename optional file name
|
||||
*/
|
||||
public function __construct(StreamInterface $stream, ?string $filename = null)
|
||||
{
|
||||
$this->stream = $stream;
|
||||
$this->filename = $filename;
|
||||
$this->buffer = new BufferStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to return the position in the target encoding.
|
||||
*/
|
||||
public function tell() : int
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null, getSize isn't supported
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function getSize() : ?int
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported.
|
||||
*
|
||||
* @param int $offset
|
||||
* @param int $whence
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function seek($offset, $whence = SEEK_SET) : void
|
||||
{
|
||||
throw new RuntimeException('Cannot seek a UUStream');
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to return false
|
||||
*/
|
||||
public function isSeekable() : bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the next end-of-line character to ensure a line isn't broken up
|
||||
* while buffering.
|
||||
*/
|
||||
private function readToEndOfLine(int $length) : string
|
||||
{
|
||||
$str = $this->stream->read($length);
|
||||
if ($str === '') {
|
||||
return $str;
|
||||
}
|
||||
while (\substr($str, -1) !== "\n") {
|
||||
$chr = $this->stream->read(1);
|
||||
if ($chr === '') {
|
||||
break;
|
||||
}
|
||||
$str .= $chr;
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes invalid characters from a uuencoded string, and 'BEGIN' and 'END'
|
||||
* line headers and footers from the passed string before returning it.
|
||||
*/
|
||||
private function filterAndDecode(string $str) : string
|
||||
{
|
||||
$ret = \str_replace("\r", '', $str);
|
||||
$ret = \preg_replace('/[^\x21-\xf5`\n]/', '`', $ret);
|
||||
if ($this->position === 0) {
|
||||
$matches = [];
|
||||
if (\preg_match('/^\s*begin\s+[^\s+]\s+([^\r\n]+)\s*$/im', $ret, $matches)) {
|
||||
$this->filename = $matches[1];
|
||||
}
|
||||
$ret = \preg_replace('/^\s*begin[^\r\n]+\s*$/im', '', $ret);
|
||||
} else {
|
||||
$ret = \preg_replace('/^\s*end\s*$/im', '', $ret);
|
||||
}
|
||||
return \convert_uudecode(\trim($ret));
|
||||
}
|
||||
|
||||
/**
|
||||
* Buffers bytes into $this->buffer, removing uuencoding headers and footers
|
||||
* and decoding them.
|
||||
*/
|
||||
private function fillBuffer(int $length) : void
|
||||
{
|
||||
// 5040 = 63 * 80, seems to be good balance for buffering in benchmarks
|
||||
// testing with a simple 'if ($length < x)' and calculating a better
|
||||
// size reduces speeds by up to 4x
|
||||
while ($this->buffer->getSize() < $length) {
|
||||
$read = $this->readToEndOfLine(5040);
|
||||
if ($read === '') {
|
||||
break;
|
||||
}
|
||||
$this->buffer->write($this->filterAndDecode($read));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the end of stream has been reached.
|
||||
*/
|
||||
public function eof() : bool
|
||||
{
|
||||
return ($this->buffer->eof() && $this->stream->eof());
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to read $length bytes after decoding them, and returns them.
|
||||
*
|
||||
* @param int $length
|
||||
*/
|
||||
public function read($length) : string
|
||||
{
|
||||
// let Guzzle decide what to do.
|
||||
if ($length <= 0 || $this->eof()) {
|
||||
return $this->stream->read($length);
|
||||
}
|
||||
$this->fillBuffer($length);
|
||||
$read = $this->buffer->read($length);
|
||||
$this->position += \strlen($read);
|
||||
return $read;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the 'begin' UU header line.
|
||||
*/
|
||||
private function writeUUHeader() : void
|
||||
{
|
||||
$filename = (empty($this->filename)) ? 'null' : $this->filename;
|
||||
$this->stream->write("begin 666 $filename");
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the '`' and 'end' UU footer lines.
|
||||
*/
|
||||
private function writeUUFooter() : void
|
||||
{
|
||||
$this->stream->write("\r\n`\r\nend\r\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the passed bytes to the underlying stream after encoding them.
|
||||
*/
|
||||
private function writeEncoded(string $bytes) : void
|
||||
{
|
||||
$encoded = \preg_replace('/\r\n|\r|\n/', "\r\n", \rtrim(\convert_uuencode($bytes)));
|
||||
// removes ending '`' line
|
||||
$this->stream->write("\r\n" . \rtrim(\substr($encoded, 0, -1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends any existing remainder to the passed string, then checks if the
|
||||
* string fits into a uuencoded line, and removes and keeps any remainder
|
||||
* from the string to write. Full lines ready for writing are returned.
|
||||
*/
|
||||
private function handleRemainder(string $string) : string
|
||||
{
|
||||
$write = $this->remainder . $string;
|
||||
$nRem = \strlen($write) % 45;
|
||||
$this->remainder = '';
|
||||
if ($nRem !== 0) {
|
||||
$this->remainder = \substr($write, -$nRem);
|
||||
$write = \substr($write, 0, -$nRem);
|
||||
}
|
||||
return $write;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the passed string to the underlying stream after encoding it.
|
||||
*
|
||||
* Note that reading and writing to the same stream without rewinding is not
|
||||
* supported.
|
||||
*
|
||||
* Also note that some bytes may not be written until close or detach are
|
||||
* called. This happens if written data doesn't align to a complete
|
||||
* uuencoded 'line' of 45 bytes. In addition, the UU footer is only written
|
||||
* when closing or detaching as well.
|
||||
*
|
||||
* @param string $string
|
||||
* @return int the number of bytes written
|
||||
*/
|
||||
public function write($string) : int
|
||||
{
|
||||
$this->isWriting = true;
|
||||
if ($this->position === 0) {
|
||||
$this->writeUUHeader();
|
||||
}
|
||||
$write = $this->handleRemainder($string);
|
||||
if ($write !== '') {
|
||||
$this->writeEncoded($write);
|
||||
}
|
||||
$written = \strlen($string);
|
||||
$this->position += $written;
|
||||
return $written;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filename set in the UUEncoded header (or null)
|
||||
*/
|
||||
public function getFilename() : string
|
||||
{
|
||||
return $this->filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the UUEncoded header file name written in the 'begin' header line.
|
||||
*/
|
||||
public function setFilename(string $filename) : void
|
||||
{
|
||||
$this->filename = $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes out any remaining bytes and the UU footer.
|
||||
*/
|
||||
private function beforeClose() : void
|
||||
{
|
||||
if (!$this->isWriting) {
|
||||
return;
|
||||
}
|
||||
if ($this->remainder !== '') {
|
||||
$this->writeEncoded($this->remainder);
|
||||
}
|
||||
$this->remainder = '';
|
||||
$this->isWriting = false;
|
||||
$this->writeUUFooter();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function close() : void
|
||||
{
|
||||
$this->beforeClose();
|
||||
$this->stream->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function detach()
|
||||
{
|
||||
$this->beforeClose();
|
||||
$this->stream->detach();
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user