Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
* text=auto eol=lf

/tests export-ignore
.editorconfig export-ignore
.gitattributes export-ignore
.gitignore export-ignore
.php_cs export-ignore
.travis.yml export-ignore
phpcs.xml.dist export-ignore
phpunit.xml.dist export-ignore
/tests export-ignore
.editorconfig export-ignore
.gitattributes export-ignore
.gitignore export-ignore
.php-cs-fixer.php export-ignore
phpcs.xml.dist export-ignore
phpunit.xml.dist export-ignore
.phpstan.neon export-ignore
47 changes: 22 additions & 25 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
name: "testing"

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
qa:
Expand All @@ -13,19 +13,19 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Validate composer.json and composer.lock
run: composer validate

- name: Cache Composer packages
id: composer-cache
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: vendor
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-php-
path: vendor
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-php-

- name: Install dependencies
if: steps.composer-cache.outputs.cache-hit != 'true'
Expand All @@ -40,37 +40,34 @@ jobs:

strategy:
matrix:
php:
- 7.2
- 7.3
- 7.4
composer-args: [ "" ]
include:
- php: 8.0
composer-args: --ignore-platform-reqs
fail-fast: false
php:
- 7.2
- 7.3
- 7.4
- 8.0
- 8.1
- 8.2
- 8.3
- 8.4

steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Install PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}

- name: Cache PHP dependencies
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: vendor
key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}
restore-keys: ${{ runner.os }}-php-${{ matrix.php }}-composer-

- name: Install dependencies
run: composer install --prefer-dist --no-progress ${{ matrix.composer-args }}
run: composer install --prefer-dist --no-progress

- name: Tests
run: composer test

- name: Tests coverage
run: composer coverage
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ vendor
composer.lock
coverage
*.cache
.idea
kit
File renamed without changes.
12 changes: 12 additions & 0 deletions .phpstan.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
parameters:
reportUnmatchedIgnoredErrors: false
inferPrivatePropertyTypeFromConstructor: true
level: 8
paths:
- src
- tests
ignoreErrors:
-
identifier: 'function.alreadyNarrowedType'
reportUnmatched: false
- "#^Unsafe usage of new static#"
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [3.0.0] - 2020-12-03
### Changed
- PHP 7.2 remains th minimum version.
- Updated `league/filesystem` to version 2 for php 7.2, 7.3 and 7.4, and to version 3 for >= php 8.0.
- With these changes, a breaking change is introduced by `league/filesystem`. Now you have to pass a FilesystemOperator interface compliant class to the middlewares. Check README's code examples.

## [2.0.1] - 2020-12-03
### Added
- Support for PHP 8.0
Expand Down Expand Up @@ -69,6 +75,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## 0.1.0 - 2016-10-02
First version

[3.0.0]: https://github.com/middlewares/filesystem/compare/v2.0.1...v3.0.0
[2.0.1]: https://github.com/middlewares/filesystem/compare/v2.0.0...v2.0.1
[2.0.0]: https://github.com/middlewares/filesystem/compare/v1.1.0...v2.0.0
[1.1.0]: https://github.com/middlewares/filesystem/compare/v1.0.0...v1.1.0
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2019
Copyright (c) 2019-2025

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
40 changes: 26 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,30 @@ Example using a ftp storage:

```php
use League\Flysystem\Filesystem;
use League\Flysystem\Adapter\Ftp;

$filesystem = new Filesystem(new Ftp([
'host' => 'ftp.example.com',
'username' => 'username',
'password' => 'password',
'port' => 21,
'root' => '/path/to/root',
'passive' => true,
'ssl' => true,
'timeout' => 30,
]));
use League\Flysystem\Ftp\FtpAdapter;
use League\Flysystem\Ftp\FtpConnectionOptions;

$adapter = new League\Flysystem\Ftp\FtpAdapter(
FtpConnectionOptions::fromArray([
'host' => 'hostname',
'root' => '/root/path/',
'username' => 'username',
'password' => 'password',
'port' => 21,
'ssl' => false,
'timeout' => 90,
'utf8' => false,
'passive' => true,
'transferMode' => FTP_BINARY,
'systemType' => null, // 'windows' or 'unix'
'ignorePassiveAddress' => null, // true or false
'timestampsOnUnixListingsEnabled' => false, // true or false
'recurseManually' => true // true
])
);

// The FilesystemOperator
$filesystem = new Filesystem($adapter);

Dispatcher::run([
new Middlewares\Reader($filesystem)
Expand All @@ -77,7 +89,7 @@ $reader = new Middlewares\Reader($filesystem, $responseFactory, $streamFactory);
Allows to continue to the next middleware on error (file not found, method not allowed, etc). This allows to create a simple caching system as the following:

```php
$cache = new Flysystem(new Local(__DIR__.'/path/to/files'));
$cache = new Filesystem(new LocalFilesystemAdapter(__DIR__.'/path/to/files'));

Dispatcher::run([
(new Middlewares\Reader($cache)) //read and returns the cached response...
Expand All @@ -103,7 +115,7 @@ To be compatible with `Reader` behaviour:
* If the response is gzipped (has the header `Content-Encoding: gzip`) the file is saved with the extension .gz. For example `/post/23/index.html.gz` (instead `/post/23/index.html`).

```php
$filesystem = new Flysystem(new Local(__DIR__.'/storage'));
$filesystem = new Filesystem(new LocalFilesystemAdapter(__DIR__.'/storage'));

Dispatcher::run([
new Middlewares\Writer($filesystem)
Expand Down
18 changes: 9 additions & 9 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@
},
"require": {
"php": "^7.2 || ^8.0",
"middlewares/utils": "^3.0",
"league/flysystem": "^1.0",
"psr/http-server-middleware": "^1.0"
"middlewares/utils": "^2 || ^3 || ^4",
"league/flysystem": "^2 || ^3",
"psr/http-server-middleware": "^1"
},
"require-dev": {
"phpunit/phpunit": "^8|^9",
"friendsofphp/php-cs-fixer": "^2.0",
"squizlabs/php_codesniffer": "^3.0",
"oscarotero/php-cs-fixer-config": "^1.0",
"phpstan/phpstan": "^0.12",
"laminas/laminas-diactoros": "^2.3"
"phpunit/phpunit": "^8 || ^9",
"friendsofphp/php-cs-fixer": "^3",
"squizlabs/php_codesniffer": "^3",
"oscarotero/php-cs-fixer-config": "^2",
"phpstan/phpstan": "^1 || ^2",
"laminas/laminas-diactoros": "^2 || ^3"
},
"autoload": {
"psr-4": {
Expand Down
File renamed without changes.
File renamed without changes.
14 changes: 7 additions & 7 deletions src/Filesystem.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@

namespace Middlewares;

use League\Flysystem\Adapter\Local;
use League\Flysystem\Filesystem as Flysystem;
use League\Flysystem\FilesystemInterface;
use League\Flysystem\FilesystemOperator;
use League\Flysystem\Local\LocalFilesystemAdapter;

abstract class Filesystem
{
/**
* @var FilesystemInterface
* @var FilesystemOperator
*/
protected $filesystem;

protected static function createLocalFlysystem(string $path): FilesystemInterface
protected static function createLocalFlysystem(string $path): FilesystemOperator
{
return new Flysystem(new Local($path));
return new Flysystem(new LocalFilesystemAdapter($path));
}

/**
Expand All @@ -25,8 +25,8 @@ protected static function createLocalFlysystem(string $path): FilesystemInterfac
protected static function getFilename(string $path): string
{
$parts = pathinfo(urldecode($path));
$path = isset($parts['dirname']) ? $parts['dirname'] : '';
$filename = isset($parts['basename']) ? $parts['basename'] : '';
$path = $parts['dirname'] ?? '';
$filename = $parts['basename'];

//if has not extension, assume it's a directory and append index.html
if (empty($parts['extension'])) {
Expand Down
22 changes: 13 additions & 9 deletions src/Reader.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace Middlewares;

use League\Flysystem\FilesystemInterface;
use League\Flysystem\FilesystemOperator;
use Middlewares\Utils\Factory;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
Expand Down Expand Up @@ -32,16 +32,17 @@ class Reader extends Filesystem implements MiddlewareInterface

public static function createFromDirectory(
string $path,
ResponseFactoryInterface $responseFactory = null,
StreamFactoryInterface $streamFactory = null
?ResponseFactoryInterface $responseFactory = null,
?StreamFactoryInterface $streamFactory = null
): self {
/* @note We use static so that other classes can extend it and get the expected behaviour */
return new static(static::createLocalFlysystem($path), $responseFactory, $streamFactory);
}

public function __construct(
FilesystemInterface $filesystem,
ResponseFactoryInterface $responseFactory = null,
StreamFactoryInterface $streamFactory = null
FilesystemOperator $filesystem,
?ResponseFactoryInterface $responseFactory = null,
?StreamFactoryInterface $streamFactory = null
) {
$this->filesystem = $filesystem;
$this->responseFactory = $responseFactory ?: Factory::getResponseFactory();
Expand Down Expand Up @@ -74,14 +75,16 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface

$file = static::getFilename($request->getUri()->getPath());

if ($this->filesystem->has($file)) {
if ($this->filesystem->fileExists($file)) {
return $this->read($request, $file);
}

//If the file does not exists, check if is gzipped
$file .= '.gz';

if (stripos($request->getHeaderLine('Accept-Encoding'), 'gzip') === false || !$this->filesystem->has($file)) {
if (stripos($request->getHeaderLine('Accept-Encoding'), 'gzip') === false
|| !$this->filesystem->fileExists($file)
) {
if ($this->continueOnError) {
return $handler->handle($request);
}
Expand All @@ -97,6 +100,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
*/
private function read(ServerRequestInterface $request, string $file): ResponseInterface
{
/** @var resource|false $resource */
$resource = $this->filesystem->readStream($file);

if ($resource === false) {
Expand Down Expand Up @@ -136,7 +140,7 @@ private static function range(ResponseInterface $response, string $range): Respo
/**
* Parses a range header, for example: bytes=500-999.
*
* @return false|array [first, last]
* @return array{0: int, 1: int|null}|false
*/
private static function parseRangeHeader(string $header)
{
Expand Down
9 changes: 5 additions & 4 deletions src/Writer.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace Middlewares;

use League\Flysystem\FilesystemInterface;
use League\Flysystem\FilesystemOperator;
use Middlewares\Utils\Factory;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
Expand All @@ -21,14 +21,15 @@ class Writer extends Filesystem implements MiddlewareInterface

public static function createFromDirectory(
string $path,
StreamFactoryInterface $streamFactory = null
?StreamFactoryInterface $streamFactory = null
): self {
/* @note We use static so that other classes can extend it and get the expected behaviour */
return new static(static::createLocalFlysystem($path), $streamFactory);
}

public function __construct(
FilesystemInterface $filesystem,
StreamFactoryInterface $streamFactory = null
FilesystemOperator $filesystem,
?StreamFactoryInterface $streamFactory = null
) {
$this->filesystem = $filesystem;
$this->streamFactory = $streamFactory ?: Factory::getStreamFactory();
Expand Down
Loading