first commit

This commit is contained in:
Sampanna Rimal
2024-08-27 17:48:06 +05:45
commit 53c0140f58
10839 changed files with 1125847 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) Taylor Otwell
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,73 @@
# Serializable Closure
<a href="https://github.com/laravel/serializable-closure/actions">
<img src="https://github.com/laravel/serializable-closure/workflows/tests/badge.svg" alt="Build Status">
</a>
<a href="https://packagist.org/packages/laravel/serializable-closure">
<img src="https://img.shields.io/packagist/dt/laravel/serializable-closure" alt="Total Downloads">
</a>
<a href="https://packagist.org/packages/laravel/serializable-closure">
<img src="https://img.shields.io/packagist/v/laravel/serializable-closure" alt="Latest Stable Version">
</a>
<a href="https://packagist.org/packages/laravel/serializable-closure">
<img src="https://img.shields.io/packagist/l/laravel/serializable-closure" alt="License">
</a>
## Introduction
> This project is a fork of the excellent [opis/closure: 3.x](https://github.com/opis/closure) package. At Laravel, we decided to fork this package as the upcoming version [4.x](https://github.com/opis/closure) is a complete rewrite on top of the [FFI extension](https://www.php.net/manual/en/book.ffi.php). As Laravel is a web framework, and FFI is not enabled by default in web requests, this fork allows us to keep using the `3.x` series while adding support for new PHP versions.
Laravel Serializable Closure provides an easy and secure way to **serialize closures in PHP**.
## Official Documentation
### Installation
> **Requires [PHP 7.4+](https://php.net/releases/)**
First, install Laravel Serializable Closure via the [Composer](https://getcomposer.org/) package manager:
```bash
composer require laravel/serializable-closure
```
### Usage
You may serialize a closure this way:
```php
use Laravel\SerializableClosure\SerializableClosure;
$closure = fn () => 'james';
// Recommended
SerializableClosure::setSecretKey('secret');
$serialized = serialize(new SerializableClosure($closure));
$closure = unserialize($serialized)->getClosure();
echo $closure(); // james;
```
### Caveats
* Anonymous classes cannot be created within closures.
* Attributes cannot be used within closures.
* Serializing closures on REPL environments like Laravel Tinker is not supported.
* Serializing closures that reference objects with readonly properties is not supported.
## Contributing
Thank you for considering contributing to Serializable Closure! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
## Code of Conduct
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
## Security Vulnerabilities
Please review [our security policy](https://github.com/laravel/serializable-closure/security/policy) on how to report security vulnerabilities.
## License
Serializable Closure is open-sourced software licensed under the [MIT license](LICENSE.md).

View File

@@ -0,0 +1,52 @@
{
"name": "laravel/serializable-closure",
"description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.",
"keywords": ["laravel", "Serializable", "closure"],
"license": "MIT",
"support": {
"issues": "https://github.com/laravel/serializable-closure/issues",
"source": "https://github.com/laravel/serializable-closure"
},
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
},
{
"name": "Nuno Maduro",
"email": "nuno@laravel.com"
}
],
"require": {
"php": "^7.3|^8.0"
},
"require-dev": {
"nesbot/carbon": "^2.61",
"pestphp/pest": "^1.21.3",
"phpstan/phpstan": "^1.8.2",
"symfony/var-dumper": "^5.4.11"
},
"autoload": {
"psr-4": {
"Laravel\\SerializableClosure\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"config": {
"sort-packages": true,
"allow-plugins": {
"pestphp/pest-plugin": true
}
},
"minimum-stability": "dev",
"prefer-stable": true
}

View File

@@ -0,0 +1,20 @@
<?php
namespace Laravel\SerializableClosure\Contracts;
interface Serializable
{
/**
* Resolve the closure with the given arguments.
*
* @return mixed
*/
public function __invoke();
/**
* Gets the closure that got serialized/unserialized.
*
* @return \Closure
*/
public function getClosure();
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Laravel\SerializableClosure\Contracts;
interface Signer
{
/**
* Sign the given serializable.
*
* @param string $serializable
* @return array
*/
public function sign($serializable);
/**
* Verify the given signature.
*
* @param array $signature
* @return bool
*/
public function verify($signature);
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Laravel\SerializableClosure\Exceptions;
use Exception;
class InvalidSignatureException extends Exception
{
/**
* Create a new exception instance.
*
* @param string $message
* @return void
*/
public function __construct($message = 'Your serialized closure might have been modified or it\'s unsafe to be unserialized.')
{
parent::__construct($message);
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Laravel\SerializableClosure\Exceptions;
use Exception;
class MissingSecretKeyException extends Exception
{
/**
* Create a new exception instance.
*
* @param string $message
* @return void
*/
public function __construct($message = 'No serializable closure secret key has been specified.')
{
parent::__construct($message);
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Laravel\SerializableClosure\Exceptions;
use Exception;
class PhpVersionNotSupportedException extends Exception
{
/**
* Create a new exception instance.
*
* @param string $message
* @return void
*/
public function __construct($message = 'PHP 7.3 is not supported.')
{
parent::__construct($message);
}
}

View File

@@ -0,0 +1,139 @@
<?php
namespace Laravel\SerializableClosure;
use Closure;
use Laravel\SerializableClosure\Exceptions\InvalidSignatureException;
use Laravel\SerializableClosure\Exceptions\PhpVersionNotSupportedException;
use Laravel\SerializableClosure\Serializers\Signed;
use Laravel\SerializableClosure\Signers\Hmac;
class SerializableClosure
{
/**
* The closure's serializable.
*
* @var \Laravel\SerializableClosure\Contracts\Serializable
*/
protected $serializable;
/**
* Creates a new serializable closure instance.
*
* @param \Closure $closure
* @return void
*/
public function __construct(Closure $closure)
{
if (\PHP_VERSION_ID < 70400) {
throw new PhpVersionNotSupportedException();
}
$this->serializable = Serializers\Signed::$signer
? new Serializers\Signed($closure)
: new Serializers\Native($closure);
}
/**
* Resolve the closure with the given arguments.
*
* @return mixed
*/
public function __invoke()
{
if (\PHP_VERSION_ID < 70400) {
throw new PhpVersionNotSupportedException();
}
return call_user_func_array($this->serializable, func_get_args());
}
/**
* Gets the closure.
*
* @return \Closure
*/
public function getClosure()
{
if (\PHP_VERSION_ID < 70400) {
throw new PhpVersionNotSupportedException();
}
return $this->serializable->getClosure();
}
/**
* Create a new unsigned serializable closure instance.
*
* @param Closure $closure
* @return \Laravel\SerializableClosure\UnsignedSerializableClosure
*/
public static function unsigned(Closure $closure)
{
return new UnsignedSerializableClosure($closure);
}
/**
* Sets the serializable closure secret key.
*
* @param string|null $secret
* @return void
*/
public static function setSecretKey($secret)
{
Serializers\Signed::$signer = $secret
? new Hmac($secret)
: null;
}
/**
* Sets the serializable closure secret key.
*
* @param \Closure|null $transformer
* @return void
*/
public static function transformUseVariablesUsing($transformer)
{
Serializers\Native::$transformUseVariables = $transformer;
}
/**
* Sets the serializable closure secret key.
*
* @param \Closure|null $resolver
* @return void
*/
public static function resolveUseVariablesUsing($resolver)
{
Serializers\Native::$resolveUseVariables = $resolver;
}
/**
* Get the serializable representation of the closure.
*
* @return array
*/
public function __serialize()
{
return [
'serializable' => $this->serializable,
];
}
/**
* Restore the closure after serialization.
*
* @param array $data
* @return void
*
* @throws \Laravel\SerializableClosure\Exceptions\InvalidSignatureException
*/
public function __unserialize($data)
{
if (Signed::$signer && ! $data['serializable'] instanceof Signed) {
throw new InvalidSignatureException();
}
$this->serializable = $data['serializable'];
}
}

View File

@@ -0,0 +1,514 @@
<?php
namespace Laravel\SerializableClosure\Serializers;
use Closure;
use DateTimeInterface;
use Laravel\SerializableClosure\Contracts\Serializable;
use Laravel\SerializableClosure\SerializableClosure;
use Laravel\SerializableClosure\Support\ClosureScope;
use Laravel\SerializableClosure\Support\ClosureStream;
use Laravel\SerializableClosure\Support\ReflectionClosure;
use Laravel\SerializableClosure\Support\SelfReference;
use Laravel\SerializableClosure\UnsignedSerializableClosure;
use ReflectionObject;
use UnitEnum;
class Native implements Serializable
{
/**
* Transform the use variables before serialization.
*
* @var \Closure|null
*/
public static $transformUseVariables;
/**
* Resolve the use variables after unserialization.
*
* @var \Closure|null
*/
public static $resolveUseVariables;
/**
* The closure to be serialized/unserialized.
*
* @var \Closure
*/
protected $closure;
/**
* The closure's reflection.
*
* @var \Laravel\SerializableClosure\Support\ReflectionClosure|null
*/
protected $reflector;
/**
* The closure's code.
*
* @var array|null
*/
protected $code;
/**
* The closure's reference.
*
* @var string
*/
protected $reference;
/**
* The closure's scope.
*
* @var \Laravel\SerializableClosure\Support\ClosureScope|null
*/
protected $scope;
/**
* The "key" that marks an array as recursive.
*/
const ARRAY_RECURSIVE_KEY = 'LARAVEL_SERIALIZABLE_RECURSIVE_KEY';
/**
* Creates a new serializable closure instance.
*
* @param \Closure $closure
* @return void
*/
public function __construct(Closure $closure)
{
$this->closure = $closure;
}
/**
* Resolve the closure with the given arguments.
*
* @return mixed
*/
public function __invoke()
{
return call_user_func_array($this->closure, func_get_args());
}
/**
* Gets the closure.
*
* @return \Closure
*/
public function getClosure()
{
return $this->closure;
}
/**
* Get the serializable representation of the closure.
*
* @return array
*/
public function __serialize()
{
if ($this->scope === null) {
$this->scope = new ClosureScope();
$this->scope->toSerialize++;
}
$this->scope->serializations++;
$scope = $object = null;
$reflector = $this->getReflector();
if ($reflector->isBindingRequired()) {
$object = $reflector->getClosureThis();
static::wrapClosures($object, $this->scope);
}
if ($scope = $reflector->getClosureScopeClass()) {
$scope = $scope->name;
}
$this->reference = spl_object_hash($this->closure);
$this->scope[$this->closure] = $this;
$use = $reflector->getUseVariables();
if (static::$transformUseVariables) {
$use = call_user_func(static::$transformUseVariables, $reflector->getUseVariables());
}
$code = $reflector->getCode();
$this->mapByReference($use);
$data = [
'use' => $use,
'function' => $code,
'scope' => $scope,
'this' => $object,
'self' => $this->reference,
];
if (! --$this->scope->serializations && ! --$this->scope->toSerialize) {
$this->scope = null;
}
return $data;
}
/**
* Restore the closure after serialization.
*
* @param array $data
* @return void
*/
public function __unserialize($data)
{
ClosureStream::register();
$this->code = $data;
unset($data);
$this->code['objects'] = [];
if ($this->code['use']) {
$this->scope = new ClosureScope();
if (static::$resolveUseVariables) {
$this->code['use'] = call_user_func(static::$resolveUseVariables, $this->code['use']);
}
$this->mapPointers($this->code['use']);
extract($this->code['use'], EXTR_OVERWRITE | EXTR_REFS);
$this->scope = null;
}
$this->closure = include ClosureStream::STREAM_PROTO.'://'.$this->code['function'];
if ($this->code['this'] === $this) {
$this->code['this'] = null;
}
$this->closure = $this->closure->bindTo($this->code['this'], $this->code['scope']);
if (! empty($this->code['objects'])) {
foreach ($this->code['objects'] as $item) {
$item['property']->setValue($item['instance'], $item['object']->getClosure());
}
}
$this->code = $this->code['function'];
}
/**
* Ensures the given closures are serializable.
*
* @param mixed $data
* @param \Laravel\SerializableClosure\Support\ClosureScope $storage
* @return void
*/
public static function wrapClosures(&$data, $storage)
{
if ($data instanceof Closure) {
$data = new static($data);
} elseif (is_array($data)) {
if (isset($data[self::ARRAY_RECURSIVE_KEY])) {
return;
}
$data[self::ARRAY_RECURSIVE_KEY] = true;
foreach ($data as $key => &$value) {
if ($key === self::ARRAY_RECURSIVE_KEY) {
continue;
}
static::wrapClosures($value, $storage);
}
unset($value);
unset($data[self::ARRAY_RECURSIVE_KEY]);
} elseif ($data instanceof \stdClass) {
if (isset($storage[$data])) {
$data = $storage[$data];
return;
}
$data = $storage[$data] = clone $data;
foreach ($data as &$value) {
static::wrapClosures($value, $storage);
}
unset($value);
} elseif (is_object($data) && ! $data instanceof static && ! $data instanceof UnitEnum) {
if (isset($storage[$data])) {
$data = $storage[$data];
return;
}
$instance = $data;
$reflection = new ReflectionObject($instance);
if (! $reflection->isUserDefined()) {
$storage[$instance] = $data;
return;
}
$storage[$instance] = $data = $reflection->newInstanceWithoutConstructor();
do {
if (! $reflection->isUserDefined()) {
break;
}
foreach ($reflection->getProperties() as $property) {
if ($property->isStatic() || ! $property->getDeclaringClass()->isUserDefined()) {
continue;
}
$property->setAccessible(true);
if (PHP_VERSION >= 7.4 && ! $property->isInitialized($instance)) {
continue;
}
$value = $property->getValue($instance);
if (is_array($value) || is_object($value)) {
static::wrapClosures($value, $storage);
}
$property->setValue($data, $value);
}
} while ($reflection = $reflection->getParentClass());
}
}
/**
* Gets the closure's reflector.
*
* @return \Laravel\SerializableClosure\Support\ReflectionClosure
*/
public function getReflector()
{
if ($this->reflector === null) {
$this->code = null;
$this->reflector = new ReflectionClosure($this->closure);
}
return $this->reflector;
}
/**
* Internal method used to map closure pointers.
*
* @param mixed $data
* @return void
*/
protected function mapPointers(&$data)
{
$scope = $this->scope;
if ($data instanceof static) {
$data = &$data->closure;
} elseif (is_array($data)) {
if (isset($data[self::ARRAY_RECURSIVE_KEY])) {
return;
}
$data[self::ARRAY_RECURSIVE_KEY] = true;
foreach ($data as $key => &$value) {
if ($key === self::ARRAY_RECURSIVE_KEY) {
continue;
} elseif ($value instanceof static) {
$data[$key] = &$value->closure;
} elseif ($value instanceof SelfReference && $value->hash === $this->code['self']) {
$data[$key] = &$this->closure;
} else {
$this->mapPointers($value);
}
}
unset($value);
unset($data[self::ARRAY_RECURSIVE_KEY]);
} elseif ($data instanceof \stdClass) {
if (isset($scope[$data])) {
return;
}
$scope[$data] = true;
foreach ($data as $key => &$value) {
if ($value instanceof SelfReference && $value->hash === $this->code['self']) {
$data->{$key} = &$this->closure;
} elseif (is_array($value) || is_object($value)) {
$this->mapPointers($value);
}
}
unset($value);
} elseif (is_object($data) && ! ($data instanceof Closure)) {
if (isset($scope[$data])) {
return;
}
$scope[$data] = true;
$reflection = new ReflectionObject($data);
do {
if (! $reflection->isUserDefined()) {
break;
}
foreach ($reflection->getProperties() as $property) {
if ($property->isStatic() || ! $property->getDeclaringClass()->isUserDefined()) {
continue;
}
$property->setAccessible(true);
if (PHP_VERSION >= 7.4 && ! $property->isInitialized($data)) {
continue;
}
$item = $property->getValue($data);
if ($item instanceof SerializableClosure || $item instanceof UnsignedSerializableClosure || ($item instanceof SelfReference && $item->hash === $this->code['self'])) {
$this->code['objects'][] = [
'instance' => $data,
'property' => $property,
'object' => $item instanceof SelfReference ? $this : $item,
];
} elseif (is_array($item) || is_object($item)) {
$this->mapPointers($item);
$property->setValue($data, $item);
}
}
} while ($reflection = $reflection->getParentClass());
}
}
/**
* Internal method used to map closures by reference.
*
* @param mixed $data
* @return void
*/
protected function mapByReference(&$data)
{
if ($data instanceof Closure) {
if ($data === $this->closure) {
$data = new SelfReference($this->reference);
return;
}
if (isset($this->scope[$data])) {
$data = $this->scope[$data];
return;
}
$instance = new static($data);
$instance->scope = $this->scope;
$data = $this->scope[$data] = $instance;
} elseif (is_array($data)) {
if (isset($data[self::ARRAY_RECURSIVE_KEY])) {
return;
}
$data[self::ARRAY_RECURSIVE_KEY] = true;
foreach ($data as $key => &$value) {
if ($key === self::ARRAY_RECURSIVE_KEY) {
continue;
}
$this->mapByReference($value);
}
unset($value);
unset($data[self::ARRAY_RECURSIVE_KEY]);
} elseif ($data instanceof \stdClass) {
if (isset($this->scope[$data])) {
$data = $this->scope[$data];
return;
}
$instance = $data;
$this->scope[$instance] = $data = clone $data;
foreach ($data as &$value) {
$this->mapByReference($value);
}
unset($value);
} elseif (is_object($data) && ! $data instanceof SerializableClosure && ! $data instanceof UnsignedSerializableClosure) {
if (isset($this->scope[$data])) {
$data = $this->scope[$data];
return;
}
$instance = $data;
if ($data instanceof DateTimeInterface) {
$this->scope[$instance] = $data;
return;
}
if ($data instanceof UnitEnum) {
$this->scope[$instance] = $data;
return;
}
$reflection = new ReflectionObject($data);
if (! $reflection->isUserDefined()) {
$this->scope[$instance] = $data;
return;
}
$this->scope[$instance] = $data = $reflection->newInstanceWithoutConstructor();
do {
if (! $reflection->isUserDefined()) {
break;
}
foreach ($reflection->getProperties() as $property) {
if ($property->isStatic() || ! $property->getDeclaringClass()->isUserDefined()) {
continue;
}
$property->setAccessible(true);
if (PHP_VERSION >= 7.4 && ! $property->isInitialized($instance)) {
continue;
}
$value = $property->getValue($instance);
if (is_array($value) || is_object($value)) {
$this->mapByReference($value);
}
$property->setValue($data, $value);
}
} while ($reflection = $reflection->getParentClass());
}
}
}

View File

@@ -0,0 +1,91 @@
<?php
namespace Laravel\SerializableClosure\Serializers;
use Laravel\SerializableClosure\Contracts\Serializable;
use Laravel\SerializableClosure\Exceptions\InvalidSignatureException;
use Laravel\SerializableClosure\Exceptions\MissingSecretKeyException;
class Signed implements Serializable
{
/**
* The signer that will sign and verify the closure's signature.
*
* @var \Laravel\SerializableClosure\Contracts\Signer|null
*/
public static $signer;
/**
* The closure to be serialized/unserialized.
*
* @var \Closure
*/
protected $closure;
/**
* Creates a new serializable closure instance.
*
* @param \Closure $closure
* @return void
*/
public function __construct($closure)
{
$this->closure = $closure;
}
/**
* Resolve the closure with the given arguments.
*
* @return mixed
*/
public function __invoke()
{
return call_user_func_array($this->closure, func_get_args());
}
/**
* Gets the closure.
*
* @return \Closure
*/
public function getClosure()
{
return $this->closure;
}
/**
* Get the serializable representation of the closure.
*
* @return array
*/
public function __serialize()
{
if (! static::$signer) {
throw new MissingSecretKeyException();
}
return static::$signer->sign(
serialize(new Native($this->closure))
);
}
/**
* Restore the closure after serialization.
*
* @param array $signature
* @return void
*
* @throws \Laravel\SerializableClosure\Exceptions\InvalidSignatureException
*/
public function __unserialize($signature)
{
if (static::$signer && ! static::$signer->verify($signature)) {
throw new InvalidSignatureException();
}
/** @var \Laravel\SerializableClosure\Contracts\Serializable $serializable */
$serializable = unserialize($signature['serializable']);
$this->closure = $serializable->getClosure();
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace Laravel\SerializableClosure\Signers;
use Laravel\SerializableClosure\Contracts\Signer;
class Hmac implements Signer
{
/**
* The secret key.
*
* @var string
*/
protected $secret;
/**
* Creates a new signer instance.
*
* @param string $secret
* @return void
*/
public function __construct($secret)
{
$this->secret = $secret;
}
/**
* Sign the given serializable.
*
* @param string $serialized
* @return array
*/
public function sign($serialized)
{
return [
'serializable' => $serialized,
'hash' => base64_encode(hash_hmac('sha256', $serialized, $this->secret, true)),
];
}
/**
* Verify the given signature.
*
* @param array $signature
* @return bool
*/
public function verify($signature)
{
return hash_equals(base64_encode(
hash_hmac('sha256', $signature['serializable'], $this->secret, true)
), $signature['hash']);
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Laravel\SerializableClosure\Support;
use SplObjectStorage;
class ClosureScope extends SplObjectStorage
{
/**
* The number of serializations in current scope.
*
* @var int
*/
public $serializations = 0;
/**
* The number of closures that have to be serialized.
*
* @var int
*/
public $toSerialize = 0;
}

View File

@@ -0,0 +1,179 @@
<?php
namespace Laravel\SerializableClosure\Support;
#[\AllowDynamicProperties]
class ClosureStream
{
/**
* The stream protocol.
*/
const STREAM_PROTO = 'laravel-serializable-closure';
/**
* Checks if this stream is registered.
*
* @var bool
*/
protected static $isRegistered = false;
/**
* The stream content.
*
* @var string
*/
protected $content;
/**
* The stream content.
*
* @var int
*/
protected $length;
/**
* The stream pointer.
*
* @var int
*/
protected $pointer = 0;
/**
* Opens file or URL.
*
* @param string $path
* @param string $mode
* @param string $options
* @param string|null $opened_path
* @return bool
*/
public function stream_open($path, $mode, $options, &$opened_path)
{
$this->content = "<?php\nreturn ".substr($path, strlen(static::STREAM_PROTO.'://')).';';
$this->length = strlen($this->content);
return true;
}
/**
* Read from stream.
*
* @param int $count
* @return string
*/
public function stream_read($count)
{
$value = substr($this->content, $this->pointer, $count);
$this->pointer += $count;
return $value;
}
/**
* Tests for end-of-file on a file pointer.
*
* @return bool
*/
public function stream_eof()
{
return $this->pointer >= $this->length;
}
/**
* Change stream options.
*
* @param int $option
* @param int $arg1
* @param int $arg2
* @return bool
*/
public function stream_set_option($option, $arg1, $arg2)
{
return false;
}
/**
* Retrieve information about a file resource.
*
* @return array|bool
*/
public function stream_stat()
{
$stat = stat(__FILE__);
// @phpstan-ignore-next-line
$stat[7] = $stat['size'] = $this->length;
return $stat;
}
/**
* Retrieve information about a file.
*
* @param string $path
* @param int $flags
* @return array|bool
*/
public function url_stat($path, $flags)
{
$stat = stat(__FILE__);
// @phpstan-ignore-next-line
$stat[7] = $stat['size'] = $this->length;
return $stat;
}
/**
* Seeks to specific location in a stream.
*
* @param int $offset
* @param int $whence
* @return bool
*/
public function stream_seek($offset, $whence = SEEK_SET)
{
$crt = $this->pointer;
switch ($whence) {
case SEEK_SET:
$this->pointer = $offset;
break;
case SEEK_CUR:
$this->pointer += $offset;
break;
case SEEK_END:
$this->pointer = $this->length + $offset;
break;
}
if ($this->pointer < 0 || $this->pointer >= $this->length) {
$this->pointer = $crt;
return false;
}
return true;
}
/**
* Retrieve the current position of a stream.
*
* @return int
*/
public function stream_tell()
{
return $this->pointer;
}
/**
* Registers the stream.
*
* @return void
*/
public static function register()
{
if (! static::$isRegistered) {
static::$isRegistered = stream_wrapper_register(static::STREAM_PROTO, __CLASS__);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,24 @@
<?php
namespace Laravel\SerializableClosure\Support;
class SelfReference
{
/**
* The unique hash representing the object.
*
* @var string
*/
public $hash;
/**
* Creates a new self reference instance.
*
* @param string $hash
* @return void
*/
public function __construct($hash)
{
$this->hash = $hash;
}
}

View File

@@ -0,0 +1,82 @@
<?php
namespace Laravel\SerializableClosure;
use Closure;
use Laravel\SerializableClosure\Exceptions\PhpVersionNotSupportedException;
class UnsignedSerializableClosure
{
/**
* The closure's serializable.
*
* @var \Laravel\SerializableClosure\Contracts\Serializable
*/
protected $serializable;
/**
* Creates a new serializable closure instance.
*
* @param \Closure $closure
* @return void
*/
public function __construct(Closure $closure)
{
if (\PHP_VERSION_ID < 70400) {
throw new PhpVersionNotSupportedException();
}
$this->serializable = new Serializers\Native($closure);
}
/**
* Resolve the closure with the given arguments.
*
* @return mixed
*/
public function __invoke()
{
if (\PHP_VERSION_ID < 70400) {
throw new PhpVersionNotSupportedException();
}
return call_user_func_array($this->serializable, func_get_args());
}
/**
* Gets the closure.
*
* @return \Closure
*/
public function getClosure()
{
if (\PHP_VERSION_ID < 70400) {
throw new PhpVersionNotSupportedException();
}
return $this->serializable->getClosure();
}
/**
* Get the serializable representation of the closure.
*
* @return array
*/
public function __serialize()
{
return [
'serializable' => $this->serializable,
];
}
/**
* Restore the closure after serialization.
*
* @param array $data
* @return void
*/
public function __unserialize($data)
{
$this->serializable = $data['serializable'];
}
}