Commit 67c063fa authored by 蔡闯's avatar 蔡闯

2021-6-22

parent bba9b773

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

*
!.gitignore
\ No newline at end of file
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit353c2d6a0a55b4821d5a3fd25f6dc248::getLoader();
#!/usr/bin/env sh
dir=$(cd "${0%[/\\]*}" > /dev/null; cd "../symfony/var-dumper/Resources/bin" && pwd)
if [ -d /proc/cygdrive ]; then
case $(which php) in
$(readlink -n /proc/cygdrive)/*)
# We are in Cygwin using Windows php, so the path must be translated
dir=$(cygpath -m "$dir");
;;
esac
fi
"${dir}/var-dump-server" "$@"
@ECHO OFF
setlocal DISABLEDELAYEDEXPANSION
SET BIN_TARGET=%~dp0/../symfony/var-dumper/Resources/bin/var-dump-server
php "%BIN_TARGET%" %*
This diff is collapsed.
Copyright (c) Nils Adermann, Jordi Boggiano
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.
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
);
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'9b552a3cc426e3287cc811caefa3cf53' => $vendorDir . '/topthink/think-helper/src/helper.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php',
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php',
);
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'PHPExcel' => array($vendorDir . '/phpoffice/phpexcel/Classes'),
'' => array($baseDir . '/extend'),
);
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'think\\trace\\' => array($vendorDir . '/topthink/think-trace/src'),
'think\\app\\' => array($vendorDir . '/topthink/think-multi-app/src'),
'think\\' => array($vendorDir . '/topthink/framework/src/think', $vendorDir . '/topthink/think-helper/src', $vendorDir . '/topthink/think-orm/src'),
'app\\' => array($baseDir . '/app'),
'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'),
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
'Symfony\\Component\\VarDumper\\' => array($vendorDir . '/symfony/var-dumper'),
'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'),
'League\\MimeTypeDetection\\' => array($vendorDir . '/league/mime-type-detection/src'),
'League\\Flysystem\\Cached\\' => array($vendorDir . '/league/flysystem-cached-adapter/src'),
'League\\Flysystem\\' => array($vendorDir . '/league/flysystem/src'),
'Firebase\\JWT\\' => array($vendorDir . '/firebase/php-jwt/src'),
);
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit353c2d6a0a55b4821d5a3fd25f6dc248
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit353c2d6a0a55b4821d5a3fd25f6dc248', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit353c2d6a0a55b4821d5a3fd25f6dc248', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit353c2d6a0a55b4821d5a3fd25f6dc248::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->register(true);
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInit353c2d6a0a55b4821d5a3fd25f6dc248::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire353c2d6a0a55b4821d5a3fd25f6dc248($fileIdentifier, $file);
}
return $loader;
}
}
function composerRequire353c2d6a0a55b4821d5a3fd25f6dc248($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInit353c2d6a0a55b4821d5a3fd25f6dc248
{
public static $files = array (
'9b552a3cc426e3287cc811caefa3cf53' => __DIR__ . '/..' . '/topthink/think-helper/src/helper.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php',
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php',
);
public static $prefixLengthsPsr4 = array (
't' =>
array (
'think\\trace\\' => 12,
'think\\app\\' => 10,
'think\\' => 6,
),
'a' =>
array (
'app\\' => 4,
),
'S' =>
array (
'Symfony\\Polyfill\\Php80\\' => 23,
'Symfony\\Polyfill\\Php72\\' => 23,
'Symfony\\Polyfill\\Mbstring\\' => 26,
'Symfony\\Component\\VarDumper\\' => 28,
),
'P' =>
array (
'Psr\\SimpleCache\\' => 16,
'Psr\\Log\\' => 8,
'Psr\\Container\\' => 14,
'Psr\\Cache\\' => 10,
),
'L' =>
array (
'League\\MimeTypeDetection\\' => 25,
'League\\Flysystem\\Cached\\' => 24,
'League\\Flysystem\\' => 17,
),
'F' =>
array (
'Firebase\\JWT\\' => 13,
),
);
public static $prefixDirsPsr4 = array (
'think\\trace\\' =>
array (
0 => __DIR__ . '/..' . '/topthink/think-trace/src',
),
'think\\app\\' =>
array (
0 => __DIR__ . '/..' . '/topthink/think-multi-app/src',
),
'think\\' =>
array (
0 => __DIR__ . '/..' . '/topthink/framework/src/think',
1 => __DIR__ . '/..' . '/topthink/think-helper/src',
2 => __DIR__ . '/..' . '/topthink/think-orm/src',
),
'app\\' =>
array (
0 => __DIR__ . '/../..' . '/app',
),
'Symfony\\Polyfill\\Php80\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php80',
),
'Symfony\\Polyfill\\Php72\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php72',
),
'Symfony\\Polyfill\\Mbstring\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
),
'Symfony\\Component\\VarDumper\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/var-dumper',
),
'Psr\\SimpleCache\\' =>
array (
0 => __DIR__ . '/..' . '/psr/simple-cache/src',
),
'Psr\\Log\\' =>
array (
0 => __DIR__ . '/..' . '/psr/log/Psr/Log',
),
'Psr\\Container\\' =>
array (
0 => __DIR__ . '/..' . '/psr/container/src',
),
'Psr\\Cache\\' =>
array (
0 => __DIR__ . '/..' . '/psr/cache/src',
),
'League\\MimeTypeDetection\\' =>
array (
0 => __DIR__ . '/..' . '/league/mime-type-detection/src',
),
'League\\Flysystem\\Cached\\' =>
array (
0 => __DIR__ . '/..' . '/league/flysystem-cached-adapter/src',
),
'League\\Flysystem\\' =>
array (
0 => __DIR__ . '/..' . '/league/flysystem/src',
),
'Firebase\\JWT\\' =>
array (
0 => __DIR__ . '/..' . '/firebase/php-jwt/src',
),
);
public static $prefixesPsr0 = array (
'P' =>
array (
'PHPExcel' =>
array (
0 => __DIR__ . '/..' . '/phpoffice/phpexcel/Classes',
),
),
);
public static $fallbackDirsPsr0 = array (
0 => __DIR__ . '/../..' . '/extend',
);
public static $classMap = array (
'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit353c2d6a0a55b4821d5a3fd25f6dc248::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit353c2d6a0a55b4821d5a3fd25f6dc248::$prefixDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticInit353c2d6a0a55b4821d5a3fd25f6dc248::$prefixesPsr0;
$loader->fallbackDirsPsr0 = ComposerStaticInit353c2d6a0a55b4821d5a3fd25f6dc248::$fallbackDirsPsr0;
$loader->classMap = ComposerStaticInit353c2d6a0a55b4821d5a3fd25f6dc248::$classMap;
}, null, ClassLoader::class);
}
}
This diff is collapsed.
Copyright (c) 2011, Neuman Vong
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.
* Neither the name of Neuman Vong nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
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
OWNER 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.
[![Build Status](https://travis-ci.org/firebase/php-jwt.png?branch=master)](https://travis-ci.org/firebase/php-jwt)
[![Latest Stable Version](https://poser.pugx.org/firebase/php-jwt/v/stable)](https://packagist.org/packages/firebase/php-jwt)
[![Total Downloads](https://poser.pugx.org/firebase/php-jwt/downloads)](https://packagist.org/packages/firebase/php-jwt)
[![License](https://poser.pugx.org/firebase/php-jwt/license)](https://packagist.org/packages/firebase/php-jwt)
PHP-JWT
=======
A simple library to encode and decode JSON Web Tokens (JWT) in PHP, conforming to [RFC 7519](https://tools.ietf.org/html/rfc7519).
Installation
------------
Use composer to manage your dependencies and download PHP-JWT:
```bash
composer require firebase/php-jwt
```
Example
-------
```php
<?php
use \Firebase\JWT\JWT;
$key = "example_key";
$payload = array(
"iss" => "http://example.org",
"aud" => "http://example.com",
"iat" => 1356999524,
"nbf" => 1357000000
);
/**
* IMPORTANT:
* You must specify supported algorithms for your application. See
* https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40
* for a list of spec-compliant algorithms.
*/
$jwt = JWT::encode($payload, $key);
$decoded = JWT::decode($jwt, $key, array('HS256'));
print_r($decoded);
/*
NOTE: This will now be an object instead of an associative array. To get
an associative array, you will need to cast it as such:
*/
$decoded_array = (array) $decoded;
/**
* You can add a leeway to account for when there is a clock skew times between
* the signing and verifying servers. It is recommended that this leeway should
* not be bigger than a few minutes.
*
* Source: http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#nbfDef
*/
JWT::$leeway = 60; // $leeway in seconds
$decoded = JWT::decode($jwt, $key, array('HS256'));
?>
```
Example with RS256 (openssl)
----------------------------
```php
<?php
use \Firebase\JWT\JWT;
$privateKey = <<<EOD
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQC8kGa1pSjbSYZVebtTRBLxBz5H4i2p/llLCrEeQhta5kaQu/Rn
vuER4W8oDH3+3iuIYW4VQAzyqFpwuzjkDI+17t5t0tyazyZ8JXw+KgXTxldMPEL9
5+qVhgXvwtihXC1c5oGbRlEDvDF6Sa53rcFVsYJ4ehde/zUxo6UvS7UrBQIDAQAB
AoGAb/MXV46XxCFRxNuB8LyAtmLDgi/xRnTAlMHjSACddwkyKem8//8eZtw9fzxz
bWZ/1/doQOuHBGYZU8aDzzj59FZ78dyzNFoF91hbvZKkg+6wGyd/LrGVEB+Xre0J
Nil0GReM2AHDNZUYRv+HYJPIOrB0CRczLQsgFJ8K6aAD6F0CQQDzbpjYdx10qgK1
cP59UHiHjPZYC0loEsk7s+hUmT3QHerAQJMZWC11Qrn2N+ybwwNblDKv+s5qgMQ5
5tNoQ9IfAkEAxkyffU6ythpg/H0Ixe1I2rd0GbF05biIzO/i77Det3n4YsJVlDck
ZkcvY3SK2iRIL4c9yY6hlIhs+K9wXTtGWwJBAO9Dskl48mO7woPR9uD22jDpNSwe
k90OMepTjzSvlhjbfuPN1IdhqvSJTDychRwn1kIJ7LQZgQ8fVz9OCFZ/6qMCQGOb
qaGwHmUK6xzpUbbacnYrIM6nLSkXgOAwv7XXCojvY614ILTK3iXiLBOxPu5Eu13k
eUz9sHyD6vkgZzjtxXECQAkp4Xerf5TGfQXGXhxIX52yH+N2LtujCdkQZjXAsGdm
B2zNzvrlgRmgBrklMTrMYgm1NPcW+bRLGcwgW2PTvNM=
-----END RSA PRIVATE KEY-----
EOD;
$publicKey = <<<EOD
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8kGa1pSjbSYZVebtTRBLxBz5H
4i2p/llLCrEeQhta5kaQu/RnvuER4W8oDH3+3iuIYW4VQAzyqFpwuzjkDI+17t5t
0tyazyZ8JXw+KgXTxldMPEL95+qVhgXvwtihXC1c5oGbRlEDvDF6Sa53rcFVsYJ4
ehde/zUxo6UvS7UrBQIDAQAB
-----END PUBLIC KEY-----
EOD;
$payload = array(
"iss" => "example.org",
"aud" => "example.com",
"iat" => 1356999524,
"nbf" => 1357000000
);
$jwt = JWT::encode($payload, $privateKey, 'RS256');
echo "Encode:\n" . print_r($jwt, true) . "\n";
$decoded = JWT::decode($jwt, $publicKey, array('RS256'));
/*
NOTE: This will now be an object instead of an associative array. To get
an associative array, you will need to cast it as such:
*/
$decoded_array = (array) $decoded;
echo "Decode:\n" . print_r($decoded_array, true) . "\n";
?>
```
Changelog
---------
#### 5.0.0 / 2017-06-26
- Support RS384 and RS512.
See [#117](https://github.com/firebase/php-jwt/pull/117). Thanks [@joostfaassen](https://github.com/joostfaassen)!
- Add an example for RS256 openssl.
See [#125](https://github.com/firebase/php-jwt/pull/125). Thanks [@akeeman](https://github.com/akeeman)!
- Detect invalid Base64 encoding in signature.
See [#162](https://github.com/firebase/php-jwt/pull/162). Thanks [@psignoret](https://github.com/psignoret)!
- Update `JWT::verify` to handle OpenSSL errors.
See [#159](https://github.com/firebase/php-jwt/pull/159). Thanks [@bshaffer](https://github.com/bshaffer)!
- Add `array` type hinting to `decode` method
See [#101](https://github.com/firebase/php-jwt/pull/101). Thanks [@hywak](https://github.com/hywak)!
- Add all JSON error types.
See [#110](https://github.com/firebase/php-jwt/pull/110). Thanks [@gbalduzzi](https://github.com/gbalduzzi)!
- Bugfix 'kid' not in given key list.
See [#129](https://github.com/firebase/php-jwt/pull/129). Thanks [@stampycode](https://github.com/stampycode)!
- Miscellaneous cleanup, documentation and test fixes.
See [#107](https://github.com/firebase/php-jwt/pull/107), [#115](https://github.com/firebase/php-jwt/pull/115),
[#160](https://github.com/firebase/php-jwt/pull/160), [#161](https://github.com/firebase/php-jwt/pull/161), and
[#165](https://github.com/firebase/php-jwt/pull/165). Thanks [@akeeman](https://github.com/akeeman),
[@chinedufn](https://github.com/chinedufn), and [@bshaffer](https://github.com/bshaffer)!
#### 4.0.0 / 2016-07-17
- Add support for late static binding. See [#88](https://github.com/firebase/php-jwt/pull/88) for details. Thanks to [@chappy84](https://github.com/chappy84)!
- Use static `$timestamp` instead of `time()` to improve unit testing. See [#93](https://github.com/firebase/php-jwt/pull/93) for details. Thanks to [@josephmcdermott](https://github.com/josephmcdermott)!
- Fixes to exceptions classes. See [#81](https://github.com/firebase/php-jwt/pull/81) for details. Thanks to [@Maks3w](https://github.com/Maks3w)!
- Fixes to PHPDoc. See [#76](https://github.com/firebase/php-jwt/pull/76) for details. Thanks to [@akeeman](https://github.com/akeeman)!
#### 3.0.0 / 2015-07-22
- Minimum PHP version updated from `5.2.0` to `5.3.0`.
- Add `\Firebase\JWT` namespace. See
[#59](https://github.com/firebase/php-jwt/pull/59) for details. Thanks to
[@Dashron](https://github.com/Dashron)!
- Require a non-empty key to decode and verify a JWT. See
[#60](https://github.com/firebase/php-jwt/pull/60) for details. Thanks to
[@sjones608](https://github.com/sjones608)!
- Cleaner documentation blocks in the code. See
[#62](https://github.com/firebase/php-jwt/pull/62) for details. Thanks to
[@johanderuijter](https://github.com/johanderuijter)!
#### 2.2.0 / 2015-06-22
- Add support for adding custom, optional JWT headers to `JWT::encode()`. See
[#53](https://github.com/firebase/php-jwt/pull/53/files) for details. Thanks to
[@mcocaro](https://github.com/mcocaro)!
#### 2.1.0 / 2015-05-20
- Add support for adding a leeway to `JWT:decode()` that accounts for clock skew
between signing and verifying entities. Thanks to [@lcabral](https://github.com/lcabral)!
- Add support for passing an object implementing the `ArrayAccess` interface for
`$keys` argument in `JWT::decode()`. Thanks to [@aztech-dev](https://github.com/aztech-dev)!
#### 2.0.0 / 2015-04-01
- **Note**: It is strongly recommended that you update to > v2.0.0 to address
known security vulnerabilities in prior versions when both symmetric and
asymmetric keys are used together.
- Update signature for `JWT::decode(...)` to require an array of supported
algorithms to use when verifying token signatures.
Tests
-----
Run the tests using phpunit:
```bash
$ pear install PHPUnit
$ phpunit --configuration phpunit.xml.dist
PHPUnit 3.7.10 by Sebastian Bergmann.
.....
Time: 0 seconds, Memory: 2.50Mb
OK (5 tests, 5 assertions)
```
New Lines in private keys
-----
If your private key contains `\n` characters, be sure to wrap it in double quotes `""`
and not single quotes `''` in order to properly interpret the escaped characters.
License
-------
[3-Clause BSD](http://opensource.org/licenses/BSD-3-Clause).
{
"name": "firebase/php-jwt",
"description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.",
"homepage": "https://github.com/firebase/php-jwt",
"keywords": [
"php",
"jwt"
],
"authors": [
{
"name": "Neuman Vong",
"email": "neuman+pear@twilio.com",
"role": "Developer"
},
{
"name": "Anant Narayanan",
"email": "anant@php.net",
"role": "Developer"
}
],
"license": "BSD-3-Clause",
"require": {
"php": ">=5.3.0"
},
"autoload": {
"psr-4": {
"Firebase\\JWT\\": "src"
}
},
"require-dev": {
"phpunit/phpunit": ">=4.8 <=9"
}
}
<?php
namespace Firebase\JWT;
class BeforeValidException extends \UnexpectedValueException
{
}
<?php
namespace Firebase\JWT;
class ExpiredException extends \UnexpectedValueException
{
}
<?php
namespace Firebase\JWT;
use DomainException;
use UnexpectedValueException;
/**
* JSON Web Key implementation, based on this spec:
* https://tools.ietf.org/html/draft-ietf-jose-json-web-key-41
*
* PHP version 5
*
* @category Authentication
* @package Authentication_JWT
* @author Bui Sy Nguyen <nguyenbs@gmail.com>
* @license http://opensource.org/licenses/BSD-3-Clause 3-clause BSD
* @link https://github.com/firebase/php-jwt
*/
class JWK
{
/**
* Parse a set of JWK keys
*
* @param array $jwks The JSON Web Key Set as an associative array
*
* @return array An associative array that represents the set of keys
*
* @throws InvalidArgumentException Provided JWK Set is empty
* @throws UnexpectedValueException Provided JWK Set was invalid
* @throws DomainException OpenSSL failure
*
* @uses parseKey
*/
public static function parseKeySet(array $jwks)
{
$keys = array();
if (!isset($jwks['keys'])) {
throw new UnexpectedValueException('"keys" member must exist in the JWK Set');
}
if (empty($jwks['keys'])) {
throw new InvalidArgumentException('JWK Set did not contain any keys');
}
foreach ($jwks['keys'] as $k => $v) {
$kid = isset($v['kid']) ? $v['kid'] : $k;
if ($key = self::parseKey($v)) {
$keys[$kid] = $key;
}
}
if (0 === \count($keys)) {
throw new UnexpectedValueException('No supported algorithms found in JWK Set');
}
return $keys;
}
/**
* Parse a JWK key
*
* @param array $jwk An individual JWK
*
* @return resource|array An associative array that represents the key
*
* @throws InvalidArgumentException Provided JWK is empty
* @throws UnexpectedValueException Provided JWK was invalid
* @throws DomainException OpenSSL failure
*
* @uses createPemFromModulusAndExponent
*/
private static function parseKey(array $jwk)
{
if (empty($jwk)) {
throw new InvalidArgumentException('JWK must not be empty');
}
if (!isset($jwk['kty'])) {
throw new UnexpectedValueException('JWK must contain a "kty" parameter');
}
switch ($jwk['kty']) {
case 'RSA':
if (\array_key_exists('d', $jwk)) {
throw new UnexpectedValueException('RSA private keys are not supported');
}
if (!isset($jwk['n']) || !isset($jwk['e'])) {
throw new UnexpectedValueException('RSA keys must contain values for both "n" and "e"');
}
$pem = self::createPemFromModulusAndExponent($jwk['n'], $jwk['e']);
$publicKey = \openssl_pkey_get_public($pem);
if (false === $publicKey) {
throw new DomainException(
'OpenSSL error: ' . \openssl_error_string()
);
}
return $publicKey;
default:
// Currently only RSA is supported
break;
}
}
/**
* Create a public key represented in PEM format from RSA modulus and exponent information
*
* @param string $n The RSA modulus encoded in Base64
* @param string $e The RSA exponent encoded in Base64
*
* @return string The RSA public key represented in PEM format
*
* @uses encodeLength
*/
private static function createPemFromModulusAndExponent($n, $e)
{
$modulus = JWT::urlsafeB64Decode($n);
$publicExponent = JWT::urlsafeB64Decode($e);
$components = array(
'modulus' => \pack('Ca*a*', 2, self::encodeLength(\strlen($modulus)), $modulus),
'publicExponent' => \pack('Ca*a*', 2, self::encodeLength(\strlen($publicExponent)), $publicExponent)
);
$rsaPublicKey = \pack(
'Ca*a*a*',
48,
self::encodeLength(\strlen($components['modulus']) + \strlen($components['publicExponent'])),
$components['modulus'],
$components['publicExponent']
);
// sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
$rsaOID = \pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
$rsaPublicKey = \chr(0) . $rsaPublicKey;
$rsaPublicKey = \chr(3) . self::encodeLength(\strlen($rsaPublicKey)) . $rsaPublicKey;
$rsaPublicKey = \pack(
'Ca*a*',
48,
self::encodeLength(\strlen($rsaOID . $rsaPublicKey)),
$rsaOID . $rsaPublicKey
);
$rsaPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
\chunk_split(\base64_encode($rsaPublicKey), 64) .
'-----END PUBLIC KEY-----';
return $rsaPublicKey;
}
/**
* DER-encode the length
*
* DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
* {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
*
* @param int $length
* @return string
*/
private static function encodeLength($length)
{
if ($length <= 0x7F) {
return \chr($length);
}
$temp = \ltrim(\pack('N', $length), \chr(0));
return \pack('Ca*', 0x80 | \strlen($temp), $temp);
}
}
This diff is collapsed.
<?php
namespace Firebase\JWT;
class SignatureInvalidException extends \UnexpectedValueException
{
}
; top-most EditorConfig file
root = true
; Unix-style newlines
[*]
end_of_line = LF
[*.php]
indent_style = space
indent_size = 4
coverage
coverage.xml
composer.lock
vendor
\ No newline at end of file
<?php
return Symfony\CS\Config\Config::create()
->level(Symfony\CS\FixerInterface::PSR2_LEVEL)
->fixers(['-yoda_conditions', 'ordered_use', 'short_array_syntax'])
->finder(Symfony\CS\Finder\DefaultFinder::create()
->in(__DIR__.'/src/'));
\ No newline at end of file
filter:
paths: [src/*]
checks:
php:
code_rating: true
remove_extra_empty_lines: true
remove_php_closing_tag: true
remove_trailing_whitespace: true
fix_use_statements:
remove_unused: true
preserve_multiple: false
preserve_blanklines: true
order_alphabetically: true
fix_php_opening_tag: true
fix_linefeed: true
fix_line_ending: true
fix_identation_4spaces: true
fix_doc_comments: true
tools:
external_code_coverage:
timeout: 900
runs: 6
php_code_coverage: false
php_code_sniffer:
config:
standard: PSR2
filter:
paths: ['src']
php_loc:
enabled: true
excluded_dirs: [vendor, spec, stubs]
php_cpd:
enabled: true
excluded_dirs: [vendor, spec, stubs]
\ No newline at end of file
language: php
php:
- 5.5
- 5.6
- 7.0
- 7.1
- 7.2
matrix:
allow_failures:
- php: 5.5
env:
- COMPOSER_OPTS=""
- COMPOSER_OPTS="--prefer-lowest"
install:
- if [[ "${TRAVIS_PHP_VERSION}" == "5.5" ]]; then composer require phpunit/phpunit:^4.8.36 phpspec/phpspec:^2 --prefer-dist --update-with-dependencies; fi
- if [[ "${TRAVIS_PHP_VERSION}" == "7.2" ]]; then composer require phpunit/phpunit:^6.0 --prefer-dist --update-with-dependencies; fi
- travis_retry composer update --prefer-dist $COMPOSER_OPTS
script:
- vendor/bin/phpspec run
- vendor/bin/phpunit
after_script:
- wget https://scrutinizer-ci.com/ocular.phar'
- php ocular.phar code-coverage:upload --format=php-clover ./clover/phpunit.xml'
Copyright (c) 2015 Frank de Jonge
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.
{
"name": "league/flysystem-cached-adapter",
"description": "An adapter decorator to enable meta-data caching.",
"autoload": {
"psr-4": {
"League\\Flysystem\\Cached\\": "src/"
}
},
"require": {
"league/flysystem": "~1.0",
"psr/cache": "^1.0.0"
},
"require-dev": {
"phpspec/phpspec": "^3.4",
"phpunit/phpunit": "^5.7",
"mockery/mockery": "~0.9",
"predis/predis": "~1.0",
"tedivm/stash": "~0.12"
},
"suggest": {
"ext-phpredis": "Pure C implemented extension for PHP"
},
"license": "MIT",
"authors": [
{
"name": "frankdejonge",
"email": "info@frenky.net"
}
]
}
---
suites:
cached_adapter_suite:
namespace: League\Flysystem\Cached
psr4_prefix: League\Flysystem\Cached
formatter.name: pretty
<?php
include __DIR__.'/vendor/autoload.php';
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="./phpunit.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="true"
verbose="true"
>
<testsuites>
<testsuite name="flysystem/tests">
<directory suffix=".php">./tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">./src/</directory>
</whitelist>
</filter>
<logging>
<log type="coverage-text" target="php://stdout" showUncoveredFiles="true"/>
<log type="coverage-html" target="coverage" showUncoveredFiles="true"/>
<log type="coverage-clover" target="clover/phpunit.xml" showUncoveredFiles="true"/>
</logging>
</phpunit>
# Flysystem Cached CachedAdapter
[![Author](http://img.shields.io/badge/author-@frankdejonge-blue.svg?style=flat-square)](https://twitter.com/frankdejonge)
[![Build Status](https://img.shields.io/travis/thephpleague/flysystem-cached-adapter/master.svg?style=flat-square)](https://travis-ci.org/thephpleague/flysystem-cached-adapter)
[![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/thephpleague/flysystem-cached-adapter.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/flysystem-cached-adapter/code-structure)
[![Quality Score](https://img.shields.io/scrutinizer/g/thephpleague/flysystem-cached-adapter.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/flysystem-cached-adapter)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)
[![Packagist Version](https://img.shields.io/packagist/v/league/flysystem-cached-adapter.svg?style=flat-square)](https://packagist.org/packages/league/flysystem-cached-adapter)
[![Total Downloads](https://img.shields.io/packagist/dt/league/flysystem-cached-adapter.svg?style=flat-square)](https://packagist.org/packages/league/flysystem-cached-adapter)
The adapter decorator caches metadata and directory listings.
```bash
composer require league/flysystem-cached-adapter
```
## Usage
[Check out the docs.](https://flysystem.thephpleague.com/docs/advanced/caching/)
<?php
namespace League\Flysystem\Cached;
use League\Flysystem\ReadInterface;
interface CacheInterface extends ReadInterface
{
/**
* Check whether the directory listing of a given directory is complete.
*
* @param string $dirname
* @param bool $recursive
*
* @return bool
*/
public function isComplete($dirname, $recursive);
/**
* Set a directory to completely listed.
*
* @param string $dirname
* @param bool $recursive
*/
public function setComplete($dirname, $recursive);
/**
* Store the contents of a directory.
*
* @param string $directory
* @param array $contents
* @param bool $recursive
*/
public function storeContents($directory, array $contents, $recursive);
/**
* Flush the cache.
*/
public function flush();
/**
* Autosave trigger.
*/
public function autosave();
/**
* Store the cache.
*/
public function save();
/**
* Load the cache.
*/
public function load();
/**
* Rename a file.
*
* @param string $path
* @param string $newpath
*/
public function rename($path, $newpath);
/**
* Copy a file.
*
* @param string $path
* @param string $newpath
*/
public function copy($path, $newpath);
/**
* Delete an object from cache.
*
* @param string $path object path
*/
public function delete($path);
/**
* Delete all objects from from a directory.
*
* @param string $dirname directory path
*/
public function deleteDir($dirname);
/**
* Update the metadata for an object.
*
* @param string $path object path
* @param array $object object metadata
* @param bool $autosave whether to trigger the autosave routine
*/
public function updateObject($path, array $object, $autosave = false);
/**
* Store object hit miss.
*
* @param string $path
*/
public function storeMiss($path);
}
<?php
namespace League\Flysystem\Cached;
use League\Flysystem\AdapterInterface;
use League\Flysystem\Config;
class CachedAdapter implements AdapterInterface
{
/**
* @var AdapterInterface
*/
private $adapter;
/**
* @var CacheInterface
*/
private $cache;
/**
* Constructor.
*
* @param AdapterInterface $adapter
* @param CacheInterface $cache
*/
public function __construct(AdapterInterface $adapter, CacheInterface $cache)
{
$this->adapter = $adapter;
$this->cache = $cache;
$this->cache->load();
}
/**
* Get the underlying Adapter implementation.
*
* @return AdapterInterface
*/
public function getAdapter()
{
return $this->adapter;
}
/**
* Get the used Cache implementation.
*
* @return CacheInterface
*/
public function getCache()
{
return $this->cache;
}
/**
* {@inheritdoc}
*/
public function write($path, $contents, Config $config)
{
$result = $this->adapter->write($path, $contents, $config);
if ($result !== false) {
$result['type'] = 'file';
$this->cache->updateObject($path, $result + compact('path', 'contents'), true);
}
return $result;
}
/**
* {@inheritdoc}
*/
public function writeStream($path, $resource, Config $config)
{
$result = $this->adapter->writeStream($path, $resource, $config);
if ($result !== false) {
$result['type'] = 'file';
$contents = false;
$this->cache->updateObject($path, $result + compact('path', 'contents'), true);
}
return $result;
}
/**
* {@inheritdoc}
*/
public function update($path, $contents, Config $config)
{
$result = $this->adapter->update($path, $contents, $config);
if ($result !== false) {
$result['type'] = 'file';
$this->cache->updateObject($path, $result + compact('path', 'contents'), true);
}
return $result;
}
/**
* {@inheritdoc}
*/
public function updateStream($path, $resource, Config $config)
{
$result = $this->adapter->updateStream($path, $resource, $config);
if ($result !== false) {
$result['type'] = 'file';
$contents = false;
$this->cache->updateObject($path, $result + compact('path', 'contents'), true);
}
return $result;
}
/**
* {@inheritdoc}
*/
public function rename($path, $newPath)
{
$result = $this->adapter->rename($path, $newPath);
if ($result !== false) {
$this->cache->rename($path, $newPath);
}
return $result;
}
/**
* {@inheritdoc}
*/
public function copy($path, $newpath)
{
$result = $this->adapter->copy($path, $newpath);
if ($result !== false) {
$this->cache->copy($path, $newpath);
}
return $result;
}
/**
* {@inheritdoc}
*/
public function delete($path)
{
$result = $this->adapter->delete($path);
if ($result !== false) {
$this->cache->delete($path);
}
return $result;
}
/**
* {@inheritdoc}
*/
public function deleteDir($dirname)
{
$result = $this->adapter->deleteDir($dirname);
if ($result !== false) {
$this->cache->deleteDir($dirname);
}
return $result;
}
/**
* {@inheritdoc}
*/
public function createDir($dirname, Config $config)
{
$result = $this->adapter->createDir($dirname, $config);
if ($result !== false) {
$type = 'dir';
$path = $dirname;
$this->cache->updateObject($dirname, compact('path', 'type'), true);
}
return $result;
}
/**
* {@inheritdoc}
*/
public function setVisibility($path, $visibility)
{
$result = $this->adapter->setVisibility($path, $visibility);
if ($result !== false) {
$this->cache->updateObject($path, compact('path', 'visibility'), true);
}
return $result;
}
/**
* {@inheritdoc}
*/
public function has($path)
{
$cacheHas = $this->cache->has($path);
if ($cacheHas !== null) {
return $cacheHas;
}
$adapterResponse = $this->adapter->has($path);
if (! $adapterResponse) {
$this->cache->storeMiss($path);
} else {
$cacheEntry = is_array($adapterResponse) ? $adapterResponse : compact('path');
$this->cache->updateObject($path, $cacheEntry, true);
}
return $adapterResponse;
}
/**
* {@inheritdoc}
*/
public function read($path)
{
return $this->callWithFallback('contents', $path, 'read');
}
/**
* {@inheritdoc}
*/
public function readStream($path)
{
return $this->adapter->readStream($path);
}
/**
* Get the path prefix.
*
* @return string|null path prefix or null if pathPrefix is empty
*/
public function getPathPrefix()
{
return $this->adapter->getPathPrefix();
}
/**
* Prefix a path.
*
* @param string $path
*
* @return string prefixed path
*/
public function applyPathPrefix($path)
{
return $this->adapter->applyPathPrefix($path);
}
/**
* {@inheritdoc}
*/
public function listContents($directory = '', $recursive = false)
{
if ($this->cache->isComplete($directory, $recursive)) {
return $this->cache->listContents($directory, $recursive);
}
$result = $this->adapter->listContents($directory, $recursive);
if ($result !== false) {
$this->cache->storeContents($directory, $result, $recursive);
}
return $result;
}
/**
* {@inheritdoc}
*/
public function getMetadata($path)
{
return $this->callWithFallback(null, $path, 'getMetadata');
}
/**
* {@inheritdoc}
*/
public function getSize($path)
{
return $this->callWithFallback('size', $path, 'getSize');
}
/**
* {@inheritdoc}
*/
public function getMimetype($path)
{
return $this->callWithFallback('mimetype', $path, 'getMimetype');
}
/**
* {@inheritdoc}
*/
public function getTimestamp($path)
{
return $this->callWithFallback('timestamp', $path, 'getTimestamp');
}
/**
* {@inheritdoc}
*/
public function getVisibility($path)
{
return $this->callWithFallback('visibility', $path, 'getVisibility');
}
/**
* Call a method and cache the response.
*
* @param string $property
* @param string $path
* @param string $method
*
* @return mixed
*/
protected function callWithFallback($property, $path, $method)
{
$result = $this->cache->{$method}($path);
if ($result !== false && ($property === null || array_key_exists($property, $result))) {
return $result;
}
$result = $this->adapter->{$method}($path);
if ($result) {
$object = $result + compact('path');
$this->cache->updateObject($path, $object, true);
}
return $result;
}
}
<?php
namespace League\Flysystem\Cached\Storage;
use League\Flysystem\Cached\CacheInterface;
use League\Flysystem\Util;
abstract class AbstractCache implements CacheInterface
{
/**
* @var bool
*/
protected $autosave = true;
/**
* @var array
*/
protected $cache = [];
/**
* @var array
*/
protected $complete = [];
/**
* Destructor.
*/
public function __destruct()
{
if (! $this->autosave) {
$this->save();
}
}
/**
* Get the autosave setting.
*
* @return bool autosave
*/
public function getAutosave()
{
return $this->autosave;
}
/**
* Get the autosave setting.
*
* @param bool $autosave
*/
public function setAutosave($autosave)
{
$this->autosave = $autosave;
}
/**
* Store the contents listing.
*
* @param string $directory
* @param array $contents
* @param bool $recursive
*
* @return array contents listing
*/
public function storeContents($directory, array $contents, $recursive = false)
{
$directories = [$directory];
foreach ($contents as $object) {
$this->updateObject($object['path'], $object);
$object = $this->cache[$object['path']];
if ($recursive && $this->pathIsInDirectory($directory, $object['path'])) {
$directories[] = $object['dirname'];
}
}
foreach (array_unique($directories) as $directory) {
$this->setComplete($directory, $recursive);
}
$this->autosave();
}
/**
* Update the metadata for an object.
*
* @param string $path object path
* @param array $object object metadata
* @param bool $autosave whether to trigger the autosave routine
*/
public function updateObject($path, array $object, $autosave = false)
{
if (! $this->has($path)) {
$this->cache[$path] = Util::pathinfo($path);
}
$this->cache[$path] = array_merge($this->cache[$path], $object);
if ($autosave) {
$this->autosave();
}
$this->ensureParentDirectories($path);
}
/**
* Store object hit miss.
*
* @param string $path
*/
public function storeMiss($path)
{
$this->cache[$path] = false;
$this->autosave();
}
/**
* Get the contents listing.
*
* @param string $dirname
* @param bool $recursive
*
* @return array contents listing
*/
public function listContents($dirname = '', $recursive = false)
{
$result = [];
foreach ($this->cache as $object) {
if ($object === false) {
continue;
}
if ($object['dirname'] === $dirname) {
$result[] = $object;
} elseif ($recursive && $this->pathIsInDirectory($dirname, $object['path'])) {
$result[] = $object;
}
}
return $result;
}
/**
* {@inheritdoc}
*/
public function has($path)
{
if ($path !== false && array_key_exists($path, $this->cache)) {
return $this->cache[$path] !== false;
}
if ($this->isComplete(Util::dirname($path), false)) {
return false;
}
}
/**
* {@inheritdoc}
*/
public function read($path)
{
if (isset($this->cache[$path]['contents']) && $this->cache[$path]['contents'] !== false) {
return $this->cache[$path];
}
return false;
}
/**
* {@inheritdoc}
*/
public function readStream($path)
{
return false;
}
/**
* {@inheritdoc}
*/
public function rename($path, $newpath)
{
if ($this->has($path)) {
$object = $this->cache[$path];
unset($this->cache[$path]);
$object['path'] = $newpath;
$object = array_merge($object, Util::pathinfo($newpath));
$this->cache[$newpath] = $object;
$this->autosave();
}
}
/**
* {@inheritdoc}
*/
public function copy($path, $newpath)
{
if ($this->has($path)) {
$object = $this->cache[$path];
$object = array_merge($object, Util::pathinfo($newpath));
$this->updateObject($newpath, $object, true);
}
}
/**
* {@inheritdoc}
*/
public function delete($path)
{
$this->storeMiss($path);
}
/**
* {@inheritdoc}
*/
public function deleteDir($dirname)
{
foreach ($this->cache as $path => $object) {
if ($this->pathIsInDirectory($dirname, $path) || $path === $dirname) {
unset($this->cache[$path]);
}
}
unset($this->complete[$dirname]);
$this->autosave();
}
/**
* {@inheritdoc}
*/
public function getMimetype($path)
{
if (isset($this->cache[$path]['mimetype'])) {
return $this->cache[$path];
}
if (! $result = $this->read($path)) {
return false;
}
$mimetype = Util::guessMimeType($path, $result['contents']);
$this->cache[$path]['mimetype'] = $mimetype;
return $this->cache[$path];
}
/**
* {@inheritdoc}
*/
public function getSize($path)
{
if (isset($this->cache[$path]['size'])) {
return $this->cache[$path];
}
return false;
}
/**
* {@inheritdoc}
*/
public function getTimestamp($path)
{
if (isset($this->cache[$path]['timestamp'])) {
return $this->cache[$path];
}
return false;
}
/**
* {@inheritdoc}
*/
public function getVisibility($path)
{
if (isset($this->cache[$path]['visibility'])) {
return $this->cache[$path];
}
return false;
}
/**
* {@inheritdoc}
*/
public function getMetadata($path)
{
if (isset($this->cache[$path]['type'])) {
return $this->cache[$path];
}
return false;
}
/**
* {@inheritdoc}
*/
public function isComplete($dirname, $recursive)
{
if (! array_key_exists($dirname, $this->complete)) {
return false;
}
if ($recursive && $this->complete[$dirname] !== 'recursive') {
return false;
}
return true;
}
/**
* {@inheritdoc}
*/
public function setComplete($dirname, $recursive)
{
$this->complete[$dirname] = $recursive ? 'recursive' : true;
}
/**
* Filter the contents from a listing.
*
* @param array $contents object listing
*
* @return array filtered contents
*/
public function cleanContents(array $contents)
{
$cachedProperties = array_flip([
'path', 'dirname', 'basename', 'extension', 'filename',
'size', 'mimetype', 'visibility', 'timestamp', 'type',
'md5',
]);
foreach ($contents as $path => $object) {
if (is_array($object)) {
$contents[$path] = array_intersect_key($object, $cachedProperties);
}
}
return $contents;
}
/**
* {@inheritdoc}
*/
public function flush()
{
$this->cache = [];
$this->complete = [];
$this->autosave();
}
/**
* {@inheritdoc}
*/
public function autosave()
{
if ($this->autosave) {
$this->save();
}
}
/**
* Retrieve serialized cache data.
*
* @return string serialized data
*/
public function getForStorage()
{
$cleaned = $this->cleanContents($this->cache);
return json_encode([$cleaned, $this->complete]);
}
/**
* Load from serialized cache data.
*
* @param string $json
*/
public function setFromStorage($json)
{
list($cache, $complete) = json_decode($json, true);
if (json_last_error() === JSON_ERROR_NONE && is_array($cache) && is_array($complete)) {
$this->cache = $cache;
$this->complete = $complete;
}
}
/**
* Ensure parent directories of an object.
*
* @param string $path object path
*/
public function ensureParentDirectories($path)
{
$object = $this->cache[$path];
while ($object['dirname'] !== '' && ! isset($this->cache[$object['dirname']])) {
$object = Util::pathinfo($object['dirname']);
$object['type'] = 'dir';
$this->cache[$object['path']] = $object;
}
}
/**
* Determines if the path is inside the directory.
*
* @param string $directory
* @param string $path
*
* @return bool
*/
protected function pathIsInDirectory($directory, $path)
{
return $directory === '' || strpos($path, $directory . '/') === 0;
}
}
<?php
namespace League\Flysystem\Cached\Storage;
use League\Flysystem\AdapterInterface;
use League\Flysystem\Config;
class Adapter extends AbstractCache
{
/**
* @var AdapterInterface An adapter
*/
protected $adapter;
/**
* @var string the file to cache to
*/
protected $file;
/**
* @var int|null seconds until cache expiration
*/
protected $expire = null;
/**
* Constructor.
*
* @param AdapterInterface $adapter adapter
* @param string $file the file to cache to
* @param int|null $expire seconds until cache expiration
*/
public function __construct(AdapterInterface $adapter, $file, $expire = null)
{
$this->adapter = $adapter;
$this->file = $file;
$this->setExpire($expire);
}
/**
* Set the expiration time in seconds.
*
* @param int $expire relative expiration time
*/
protected function setExpire($expire)
{
if ($expire) {
$this->expire = $this->getTime($expire);
}
}
/**
* Get expiration time in seconds.
*
* @param int $time relative expiration time
*
* @return int actual expiration time
*/
protected function getTime($time = 0)
{
return intval(microtime(true)) + $time;
}
/**
* {@inheritdoc}
*/
public function setFromStorage($json)
{
list($cache, $complete, $expire) = json_decode($json, true);
if (! $expire || $expire > $this->getTime()) {
$this->cache = is_array($cache) ? $cache : [];
$this->complete = is_array($complete) ? $complete : [];
} else {
$this->adapter->delete($this->file);
}
}
/**
* {@inheritdoc}
*/
public function load()
{
if ($this->adapter->has($this->file)) {
$file = $this->adapter->read($this->file);
if ($file && !empty($file['contents'])) {
$this->setFromStorage($file['contents']);
}
}
}
/**
* {@inheritdoc}
*/
public function getForStorage()
{
$cleaned = $this->cleanContents($this->cache);
return json_encode([$cleaned, $this->complete, $this->expire]);
}
/**
* {@inheritdoc}
*/
public function save()
{
$config = new Config();
$contents = $this->getForStorage();
if ($this->adapter->has($this->file)) {
$this->adapter->update($this->file, $contents, $config);
} else {
$this->adapter->write($this->file, $contents, $config);
}
}
}
<?php
namespace League\Flysystem\Cached\Storage;
use Memcached as NativeMemcached;
class Memcached extends AbstractCache
{
/**
* @var string storage key
*/
protected $key;
/**
* @var int|null seconds until cache expiration
*/
protected $expire;
/**
* @var \Memcached Memcached instance
*/
protected $memcached;
/**
* Constructor.
*
* @param \Memcached $memcached
* @param string $key storage key
* @param int|null $expire seconds until cache expiration
*/
public function __construct(NativeMemcached $memcached, $key = 'flysystem', $expire = null)
{
$this->key = $key;
$this->expire = $expire;
$this->memcached = $memcached;
}
/**
* {@inheritdoc}
*/
public function load()
{
$contents = $this->memcached->get($this->key);
if ($contents !== false) {
$this->setFromStorage($contents);
}
}
/**
* {@inheritdoc}
*/
public function save()
{
$contents = $this->getForStorage();
$expiration = $this->expire === null ? 0 : time() + $this->expire;
$this->memcached->set($this->key, $contents, $expiration);
}
}
<?php
namespace League\Flysystem\Cached\Storage;
class Memory extends AbstractCache
{
/**
* {@inheritdoc}
*/
public function save()
{
// There is nothing to save
}
/**
* {@inheritdoc}
*/
public function load()
{
// There is nothing to load
}
}
<?php
namespace League\Flysystem\Cached\Storage;
class Noop extends AbstractCache
{
/**
* {@inheritdoc}
*/
protected $autosave = false;
/**
* {@inheritdoc}
*/
public function updateObject($path, array $object, $autosave = false)
{
return $object;
}
/**
* {@inheritdoc}
*/
public function isComplete($dirname, $recursive)
{
return false;
}
/**
* {@inheritdoc}
*/
public function setComplete($dirname, $recursive)
{
//
}
/**
* {@inheritdoc}
*/
public function copy($path, $newpath)
{
return false;
}
/**
* {@inheritdoc}
*/
public function rename($path, $newpath)
{
return false;
}
/**
* {@inheritdoc}
*/
public function storeContents($directory, array $contents, $recursive = false)
{
return $contents;
}
/**
* {@inheritdoc}
*/
public function storeMiss($path)
{
return $this;
}
/**
* {@inheritdoc}
*/
public function flush()
{
//
}
/**
* {@inheritdoc}
*/
public function autosave()
{
//
}
/**
* {@inheritdoc}
*/
public function save()
{
//
}
/**
* {@inheritdoc}
*/
public function load()
{
//
}
/**
* {@inheritdoc}
*/
public function has($path)
{
return;
}
/**
* {@inheritdoc}
*/
public function read($path)
{
return false;
}
/**
* {@inheritdoc}
*/
public function readStream($path)
{
return false;
}
/**
* {@inheritdoc}
*/
public function listContents($directory = '', $recursive = false)
{
return [];
}
/**
* {@inheritdoc}
*/
public function getMetadata($path)
{
return false;
}
/**
* {@inheritdoc}
*/
public function getSize($path)
{
return false;
}
/**
* {@inheritdoc}
*/
public function getMimetype($path)
{
return false;
}
/**
* {@inheritdoc}
*/
public function getTimestamp($path)
{
return false;
}
/**
* {@inheritdoc}
*/
public function getVisibility($path)
{
return false;
}
}
<?php
namespace League\Flysystem\Cached\Storage;
use Redis;
class PhpRedis extends AbstractCache
{
/**
* @var Redis PhpRedis Client
*/
protected $client;
/**
* @var string storage key
*/
protected $key;
/**
* @var int|null seconds until cache expiration
*/
protected $expire;
/**
* Constructor.
*
* @param Redis|null $client phpredis client
* @param string $key storage key
* @param int|null $expire seconds until cache expiration
*/
public function __construct(Redis $client = null, $key = 'flysystem', $expire = null)
{
$this->client = $client ?: new Redis();
$this->key = $key;
$this->expire = $expire;
}
/**
* {@inheritdoc}
*/
public function load()
{
$contents = $this->client->get($this->key);
if ($contents !== false) {
$this->setFromStorage($contents);
}
}
/**
* {@inheritdoc}
*/
public function save()
{
$contents = $this->getForStorage();
$this->client->set($this->key, $contents);
if ($this->expire !== null) {
$this->client->expire($this->key, $this->expire);
}
}
}
<?php
namespace League\Flysystem\Cached\Storage;
use Predis\Client;
class Predis extends AbstractCache
{
/**
* @var \Predis\Client Predis Client
*/
protected $client;
/**
* @var string storage key
*/
protected $key;
/**
* @var int|null seconds until cache expiration
*/
protected $expire;
/**
* Constructor.
*
* @param \Predis\Client $client predis client
* @param string $key storage key
* @param int|null $expire seconds until cache expiration
*/
public function __construct(Client $client = null, $key = 'flysystem', $expire = null)
{
$this->client = $client ?: new Client();
$this->key = $key;
$this->expire = $expire;
}
/**
* {@inheritdoc}
*/
public function load()
{
if (($contents = $this->executeCommand('get', [$this->key])) !== null) {
$this->setFromStorage($contents);
}
}
/**
* {@inheritdoc}
*/
public function save()
{
$contents = $this->getForStorage();
$this->executeCommand('set', [$this->key, $contents]);
if ($this->expire !== null) {
$this->executeCommand('expire', [$this->key, $this->expire]);
}
}
/**
* Execute a Predis command.
*
* @param string $name
* @param array $arguments
*
* @return string
*/
protected function executeCommand($name, array $arguments)
{
$command = $this->client->createCommand($name, $arguments);
return $this->client->executeCommand($command);
}
}
This diff is collapsed.
<?php
use League\Flysystem\Cached\CachedAdapter;
use PHPUnit\Framework\TestCase;
class InspectionTests extends TestCase {
public function testGetAdapter()
{
$adapter = Mockery::mock('League\Flysystem\AdapterInterface');
$cache = Mockery::mock('League\Flysystem\Cached\CacheInterface');
$cache->shouldReceive('load')->once();
$cached_adapter = new CachedAdapter($adapter, $cache);
$this->assertInstanceOf('League\Flysystem\AdapterInterface', $cached_adapter->getAdapter());
}
}
<?php
use League\Flysystem\Cached\Storage\Memcached;
use PHPUnit\Framework\TestCase;
class MemcachedTests extends TestCase
{
public function testLoadFail()
{
$client = Mockery::mock('Memcached');
$client->shouldReceive('get')->once()->andReturn(false);
$cache = new Memcached($client);
$cache->load();
$this->assertFalse($cache->isComplete('', false));
}
public function testLoadSuccess()
{
$response = json_encode([[], ['' => true]]);
$client = Mockery::mock('Memcached');
$client->shouldReceive('get')->once()->andReturn($response);
$cache = new Memcached($client);
$cache->load();
$this->assertTrue($cache->isComplete('', false));
}
public function testSave()
{
$response = json_encode([[], []]);
$client = Mockery::mock('Memcached');
$client->shouldReceive('set')->once()->andReturn($response);
$cache = new Memcached($client);
$cache->save();
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<?php
namespace League\Flysystem\Adapter;
class SynologyFtp extends Ftpd
{
// This class merely exists because of BC.
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment