Full Code of thephpleague/flysystem for AI

3.x 254b1595b16b cached
293 files
720.5 KB
184.8k tokens
1627 symbols
1 requests
Download .txt
Showing preview only (790K chars total). Download the full file or copy to clipboard to get everything.
Repository: thephpleague/flysystem
Branch: 3.x
Commit: 254b1595b16b
Files: 293
Total size: 720.5 KB

Directory structure:
gitextract_99z1k6qe/

├── .dockerignore
├── .editorconfig
├── .gitattributes
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── Bug.md
│   │   ├── Feature_Request.md
│   │   └── Question.md
│   ├── release.yml
│   ├── stale.yml
│   └── workflows/
│       ├── publish-subsplits.yml
│       ├── quality-assurance.yml
│       └── set-subsplit-default-branch.yml
├── .gitignore
├── .php-cs-fixer.dist.php
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── INFO.md
├── LICENSE
├── bin/
│   ├── .gitignore
│   ├── check-versions.php
│   ├── close-subsplit-prs.yml
│   ├── set-flysystem-version.php
│   ├── tools.php
│   └── update-subsplit-closers.php
├── composer.json
├── config.subsplit-publish.json
├── docker-compose.yml
├── mocked-functions.php
├── phpstan-baseline.neon
├── phpstan.neon
├── phpunit.php
├── phpunit.xml.dist
├── readme.md
├── src/
│   ├── AdapterTestUtilities/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── ExceptionThrowingFilesystemAdapter.php
│   │   ├── FilesystemAdapterTestCase.php
│   │   ├── README.md
│   │   ├── RetryOnTestException.php
│   │   ├── ToxiproxyManagement.php
│   │   ├── composer.json
│   │   ├── test-functions.php
│   │   └── test_files/
│   │       └── unknown-mime-type.md5
│   ├── AsyncAwsS3/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── AsyncAwsS3Adapter.php
│   │   ├── AsyncAwsS3AdapterTest.php
│   │   ├── LICENSE
│   │   ├── PortableVisibilityConverter.php
│   │   ├── README.md
│   │   ├── S3ClientStub.php
│   │   ├── VisibilityConverter.php
│   │   └── composer.json
│   ├── AwsS3V3/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── AwsS3V3Adapter.php
│   │   ├── AwsS3V3AdapterTest.php
│   │   ├── LICENSE
│   │   ├── PortableVisibilityConverter.php
│   │   ├── README.md
│   │   ├── S3ClientStub.php
│   │   ├── VisibilityConverter.php
│   │   └── composer.json
│   ├── AzureBlobStorage/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── AzureBlobStorageAdapter.php
│   │   ├── AzureBlobStorageAdapterTest.php
│   │   ├── LICENSE
│   │   ├── README.md
│   │   └── composer.json
│   ├── CalculateChecksumFromStream.php
│   ├── ChecksumAlgoIsNotSupported.php
│   ├── ChecksumProvider.php
│   ├── Config.php
│   ├── ConfigTest.php
│   ├── CorruptedPathDetected.php
│   ├── DecoratedAdapter.php
│   ├── DirectoryAttributes.php
│   ├── DirectoryAttributesTest.php
│   ├── DirectoryListing.php
│   ├── DirectoryListingTest.php
│   ├── ExceptionInformationTest.php
│   ├── FileAttributes.php
│   ├── FileAttributesTest.php
│   ├── Filesystem.php
│   ├── FilesystemAdapter.php
│   ├── FilesystemException.php
│   ├── FilesystemOperationFailed.php
│   ├── FilesystemOperator.php
│   ├── FilesystemReader.php
│   ├── FilesystemTest.php
│   ├── FilesystemWriter.php
│   ├── Ftp/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── ConnectionProvider.php
│   │   ├── ConnectivityChecker.php
│   │   ├── ConnectivityCheckerThatCanFail.php
│   │   ├── FtpAdapter.php
│   │   ├── FtpAdapterTest.php
│   │   ├── FtpAdapterTestCase.php
│   │   ├── FtpConnectionException.php
│   │   ├── FtpConnectionOptions.php
│   │   ├── FtpConnectionProvider.php
│   │   ├── FtpConnectionProviderTest.php
│   │   ├── FtpdAdapterTest.php
│   │   ├── InvalidListResponseReceived.php
│   │   ├── LICENSE
│   │   ├── NoopCommandConnectivityChecker.php
│   │   ├── NoopCommandConnectivityCheckerTest.php
│   │   ├── README.md
│   │   ├── RawListFtpConnectivityChecker.php
│   │   ├── RawListFtpConnectivityCheckerTest.php
│   │   ├── StubConnectionProvider.php
│   │   ├── UnableToAuthenticate.php
│   │   ├── UnableToConnectToFtpHost.php
│   │   ├── UnableToEnableUtf8Mode.php
│   │   ├── UnableToMakeConnectionPassive.php
│   │   ├── UnableToResolveConnectionRoot.php
│   │   ├── UnableToSetFtpOption.php
│   │   └── composer.json
│   ├── GoogleCloudStorage/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── GoogleCloudStorageAdapter.php
│   │   ├── GoogleCloudStorageAdapterTest.php
│   │   ├── GoogleCloudStorageAdapterWithoutAclTest.php
│   │   ├── LICENSE
│   │   ├── PortableVisibilityHandler.php
│   │   ├── README.md
│   │   ├── StubRiggedBucket.php
│   │   ├── StubStorageClient.php
│   │   ├── UniformBucketLevelAccessVisibility.php
│   │   ├── VisibilityHandler.php
│   │   └── composer.json
│   ├── GridFS/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── GridFSAdapter.php
│   │   ├── GridFSAdapterTest.php
│   │   ├── LICENSE
│   │   ├── README.md
│   │   └── composer.json
│   ├── InMemory/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── InMemoryFile.php
│   │   ├── InMemoryFilesystemAdapter.php
│   │   ├── InMemoryFilesystemAdapterTest.php
│   │   ├── LICENSE
│   │   ├── README.md
│   │   ├── StaticInMemoryAdapterRegistry.php
│   │   ├── StaticInMemoryAdapterRegistryTest.php
│   │   └── composer.json
│   ├── InvalidStreamProvided.php
│   ├── InvalidVisibilityProvided.php
│   ├── Local/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── FallbackMimeTypeDetector.php
│   │   ├── LICENSE
│   │   ├── LocalFilesystemAdapter.php
│   │   ├── LocalFilesystemAdapterTest.php
│   │   ├── README.md
│   │   └── composer.json
│   ├── MountManager.php
│   ├── MountManagerTest.php
│   ├── PathNormalizer.php
│   ├── PathPrefixer.php
│   ├── PathPrefixerTest.php
│   ├── PathPrefixing/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── LICENSE
│   │   ├── PathPrefixedAdapter.php
│   │   ├── PathPrefixedAdapterTest.php
│   │   ├── README.md
│   │   └── composer.json
│   ├── PathTraversalDetected.php
│   ├── PhpseclibV2/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── ConnectionProvider.php
│   │   ├── ConnectivityChecker.php
│   │   ├── FixatedConnectivityChecker.php
│   │   ├── README.md
│   │   ├── SftpAdapter.php
│   │   ├── SftpAdapterTest.php
│   │   ├── SftpConnectionProvider.php
│   │   ├── SftpConnectionProviderTest.php
│   │   ├── SftpStub.php
│   │   ├── SimpleConnectivityChecker.php
│   │   ├── StubSftpConnectionProvider.php
│   │   ├── UnableToAuthenticate.php
│   │   ├── UnableToConnectToSftpHost.php
│   │   ├── UnableToEstablishAuthenticityOfHost.php
│   │   ├── UnableToLoadPrivateKey.php
│   │   └── composer.json
│   ├── PhpseclibV3/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── ConnectionProvider.php
│   │   ├── ConnectivityChecker.php
│   │   ├── FixatedConnectivityChecker.php
│   │   ├── LICENSE
│   │   ├── README.md
│   │   ├── SftpAdapter.php
│   │   ├── SftpAdapterTest.php
│   │   ├── SftpConnectionProvider.php
│   │   ├── SftpConnectionProviderTest.php
│   │   ├── SftpStub.php
│   │   ├── SimpleConnectivityChecker.php
│   │   ├── StubSftpConnectionProvider.php
│   │   ├── UnableToAuthenticate.php
│   │   ├── UnableToConnectToSftpHost.php
│   │   ├── UnableToEstablishAuthenticityOfHost.php
│   │   ├── UnableToLoadPrivateKey.php
│   │   └── composer.json
│   ├── PortableVisibilityGuard.php
│   ├── ProxyArrayAccessToProperties.php
│   ├── ReadOnly/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── LICENSE
│   │   ├── README.md
│   │   ├── ReadOnlyFilesystemAdapter.php
│   │   ├── ReadOnlyFilesystemAdapterTest.php
│   │   └── composer.json
│   ├── ResolveIdenticalPathConflict.php
│   ├── StorageAttributes.php
│   ├── SymbolicLinkEncountered.php
│   ├── UnableToCheckDirectoryExistence.php
│   ├── UnableToCheckExistence.php
│   ├── UnableToCheckFileExistence.php
│   ├── UnableToCopyFile.php
│   ├── UnableToCreateDirectory.php
│   ├── UnableToDeleteDirectory.php
│   ├── UnableToDeleteFile.php
│   ├── UnableToGeneratePublicUrl.php
│   ├── UnableToGenerateTemporaryUrl.php
│   ├── UnableToListContents.php
│   ├── UnableToMountFilesystem.php
│   ├── UnableToMoveFile.php
│   ├── UnableToProvideChecksum.php
│   ├── UnableToReadFile.php
│   ├── UnableToResolveFilesystemMount.php
│   ├── UnableToRetrieveMetadata.php
│   ├── UnableToSetVisibility.php
│   ├── UnableToWriteFile.php
│   ├── UnixVisibility/
│   │   ├── PortableVisibilityConverter.php
│   │   ├── PortableVisibilityConverterTest.php
│   │   └── VisibilityConverter.php
│   ├── UnreadableFileEncountered.php
│   ├── UrlGeneration/
│   │   ├── ChainedPublicUrlGenerator.php
│   │   ├── ChainedPublicUrlGeneratorTest.php
│   │   ├── PrefixPublicUrlGenerator.php
│   │   ├── PublicUrlGenerator.php
│   │   ├── ShardedPrefixPublicUrlGenerator.php
│   │   └── TemporaryUrlGenerator.php
│   ├── Visibility.php
│   ├── WebDAV/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── ByteMarkWebDAVServerTest.php
│   │   ├── LICENSE
│   │   ├── README.md
│   │   ├── SabreServerTest.php
│   │   ├── UrlPrefixingClientStub.php
│   │   ├── WebDAVAdapter.php
│   │   ├── WebDAVAdapterTestCase.php
│   │   ├── composer.json
│   │   └── resources/
│   │       ├── .gitignore
│   │       └── server.php
│   ├── WhitespacePathNormalizer.php
│   ├── WhitespacePathNormalizerTest.php
│   └── ZipArchive/
│       ├── .gitattributes
│       ├── .github/
│       │   └── workflows/
│       │       └── close-subsplit-prs.yaml
│       ├── FilesystemZipArchiveProvider.php
│       ├── LICENSE
│       ├── NoRootPrefixZipArchiveAdapterTest.php
│       ├── PrefixedRootZipArchiveAdapterTest.php
│       ├── README.md
│       ├── StubZipArchive.php
│       ├── StubZipArchiveProvider.php
│       ├── UnableToCreateParentDirectory.php
│       ├── UnableToOpenZipArchive.php
│       ├── ZipArchiveAdapter.php
│       ├── ZipArchiveAdapterTestCase.php
│       ├── ZipArchiveException.php
│       ├── ZipArchiveProvider.php
│       └── composer.json
└── test_files/
    ├── .gitignore
    ├── sftp/
    │   ├── id_rsa
    │   ├── id_rsa.pub
    │   ├── ssh_host_ed25519_key
    │   ├── ssh_host_ed25519_key.pub
    │   ├── ssh_host_rsa_key
    │   ├── ssh_host_rsa_key.pub
    │   ├── sshd_custom_configs.sh
    │   ├── unknown.key
    │   └── users.conf
    ├── toxiproxy/
    │   └── toxiproxy.json
    ├── wait_for_ftp.php
    └── wait_for_sftp.php

================================================
FILE CONTENTS
================================================

================================================
FILE: .dockerignore
================================================
.git


================================================
FILE: .editorconfig
================================================
[*]
indent_style = space

[*.yml]
indent_size = 2

[composer.json]
indent_size = 4

[*.php]
end_of_line = lf
insert_final_newline = true


================================================
FILE: .gitattributes
================================================
* text=auto

/.docker export-ignore
/.dockerignore export-ignore
/docker-compose.yml export-ignore
/config.subsplit-publish.json export-ignore
/.editorconfig export-ignore
/.php-cs-fixer.dist.php export-ignore
/phpstan.neon export-ignore
/phpstan-baseline.neon export-ignore
/phpunit.php export-ignore
/phpunit.xml.dist export-ignore
/.travis.yml export-ignore
/.scrutinizer.yml export-ignore
/CHANGELOG.md export-ignore
/CODE_OF_CONDUCT.md export-ignore
/deprecations.md export-ignore
/docker-composer.yml export-ignore
/README.md export-ignore
/CODE_OF_CONDUCT.md export-ignore
/.github export-ignore
/src/AsyncAwsS3 export-ignore
/src/AwsS3V3 export-ignore
/src/GoogleCloudStorage export-ignore
/src/Ftp export-ignore
/src/InMemory export-ignore
/src/PhpseclibV2 export-ignore
/src/PhpseclibV3 export-ignore
/src/AdapterTestUtilities export-ignore
/src/AzureBlobStorage export-ignore
/src/ZipArchive export-ignore
/src/WebDAV export-ignore
/src/PathPrefixing export-ignore
/src/Local export-ignore
/src/ReadOnly export-ignore
/src/GridFS export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/bin/ export-ignore
/mocked-functions.php export-ignore
/test_files/ export-ignore
/**/*Test.php export-ignore
/**/*Stub.php export-ignore
/**/Stub*.php export-ignore


================================================
FILE: .github/ISSUE_TEMPLATE/Bug.md
================================================
---
name: 🐛 Bug
about: Did you encounter a bug?
---

### Bug Report

<!-- Fill in the relevant information below to help triage your issue. -->

| Q                 | A       |
|-------------------|---------|
| Flysystem Version | x.y.z   |
| Adapter Name      | example |
| Adapter version   | x.y.z   |

#### Summary

<!-- Provide a summary describing the problem you are experiencing. -->

#### How to reproduce

<!--
Provide steps to reproduce the issue.
If possible, also add a code snippet.
-->


================================================
FILE: .github/ISSUE_TEMPLATE/Feature_Request.md
================================================
---
name: 🎉 Feature Request
about: Do you have a new feature in mind?
---

### Feature Request

<!-- Fill in the relevant information below to help triage your issue. -->

| Q                 | A       |
|-------------------|---------|
| Flysystem Version | x.y.z   |
| Adapter Name      | example |
| Adapter version   | x.y.z   |

#### Scenario / Use-case

<!-- Provide an explain in which scenario the feature would be helpful. --> 

#### Summary

<!-- Provide a summary of the feature you would like to see implemented. -->


================================================
FILE: .github/ISSUE_TEMPLATE/Question.md
================================================
---
name: ❓ Question
about: Are you unsure about something?
---

### Question

<!-- Fill in the relevant information below to help triage your issue. -->

| Q                 | A       |
|-------------------|---------|
| Flysystem Version | x.y.z   |
| Adapter Name      | example |
| Adapter version   | x.y.z   |


================================================
FILE: .github/release.yml
================================================
changelog:
  categories:
    - title: Breaking Changes 🛠
      labels:
        - Semver-Major
        - breaking-change
    - title: Exciting New Features 🎉
      labels:
        - Semver-Minor
        - enhancement
    - title: Other Changes
      labels:
        - "*"

================================================
FILE: .github/stale.yml
================================================
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
    - keep open
    - 2.0 ideas
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
    This issue has been automatically marked as stale because it has not had
    recent activity. It will be closed if no further activity occurs. Thank you
    for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false


================================================
FILE: .github/workflows/publish-subsplits.yml
================================================
---
name: Sub-Split Publishing
on:
  push:
    branches:
      - 3.x
  create:
    tags:
      - '3.*'
  delete:
    tags:
      - '3.*'

jobs:
  publish_subsplits:
    runs-on: ubuntu-latest
    name: Publish package sub-splits
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: '0'
          persist-credentials: 'false'
      - uses: frankdejonge/use-github-token@1.1.0
        with:
          authentication: 'frankdejonge:${{ secrets.PERSONAL_ACCESS_TOKEN }}'
          user_name: 'Frank de Jonge'
          user_email: 'info@frenky.net'
      - name: Cache splitsh-lite
        id: splitsh-cache
        uses: actions/cache@v4
        with:
          path: './.splitsh'
          key: '${{ runner.os }}-splitsh'
      - uses: frankdejonge/use-subsplit-publish@1.1.0
        with:
          source-branch: '3.x'
          config-path: './config.subsplit-publish.json'
          splitsh-path: './.splitsh/splitsh-lite'
          splitsh-version: 'v1.0.1'


================================================
FILE: .github/workflows/quality-assurance.yml
================================================
---
name: Quality Assurance
concurrency:
  group: ${{ github.ref }}
  cancel-in-progress: true
on:
  push:
    paths:
      - src/**/*.php
      - .github/workflows/quality-assurance.yml
    branches:
      - 3.x
      - 4.x
  pull_request:
    paths:
      - src/**/*.php
      - .github/workflows/quality-assurance.yml
    branches:
      - 3.x
      - 4.x
  schedule:
    - cron: "5 1 * * *"

env:
  FLYSYSTEM_AWS_S3_KEY: '${{ secrets.FLYSYSTEM_AWS_S3_KEY }}'
  FLYSYSTEM_AWS_S3_SECRET: '${{ secrets.FLYSYSTEM_AWS_S3_SECRET }}'
  FLYSYSTEM_AWS_S3_BUCKET: '${{ secrets.FLYSYSTEM_AWS_S3_BUCKET }}'
  MONGODB_URI: 'mongodb://127.0.0.1:27017/'
  FLYSYSTEM_TEST_DANGEROUS_THINGS: "yes"
  FLYSYSTEM_TEST_SFTP: "yes"

jobs:
  phpunit:
    name: PHPUnit tests on ${{ matrix.php }} ${{ matrix.composer-flags }}
    runs-on: ubuntu-latest
    continue-on-error: ${{ matrix.experimental }}
    strategy:
      fail-fast: false
      matrix:
        php: [ '8.2', '8.3', '8.4', '8.5' ]
        composer-flags: [ '' ]
        experimental: [false]
        phpstan: [true]
        phpunit-flags: [ '--coverage-text' ]
#        include:
#          - php: '8.2'
#            experimental: false
#            phpstan: false
#            phpunit-flags: '--no-coverage'
#          - php: '8.3'
#            experimental: false
#            phpstan: false
#            phpunit-flags: '--no-coverage'
#          - php: '8.4'
#            experimental: false
#            phpstan: false
#            phpunit-flags: '--no-coverage'
    steps:
      - uses: actions/checkout@v4
      - run: docker compose -f docker-compose.yml up -d
      - name: Start an SSH Agent
        uses: frankdejonge/use-ssh-agent@1.1.0
      - run: chmod 0400 ./test_files/sftp/id_*
      - id: ssh_agent
        run: ssh-add ./test_files/sftp/id_rsa
      - uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php }}
          extensions: mongodb
          coverage: pcov
          tools: composer:v2
      - run: composer update --no-progress ${{ matrix.composer-flags }}
      - run: php test_files/wait_for_sftp.php
      - run: php test_files/wait_for_ftp.php 2121
      - run: php test_files/wait_for_ftp.php 2122
      - run: COMPOSER_OPTS='${{ matrix.composer-flags }}' vendor/bin/phpunit ${{ matrix.phpunit-flags }}
      - run: vendor/bin/phpstan analyse
        if: ${{ matrix.phpstan }}
      - run: vendor/bin/php-cs-fixer fix --diff --dry-run
        continue-on-error: true
        if: ${{ matrix.php == '8.0' }}



================================================
FILE: .github/workflows/set-subsplit-default-branch.yml
================================================
---
name: Update default sub-split branch

on: workflow_dispatch

jobs:
  set-default-branch:
    name: Set default git branch
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: '0'
          persist-credentials: 'false'
      - uses: actions/github-script@v7
        with:
          github-token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
          script: |
            const fs = require('fs');
            let splits = JSON.parse(fs.readFileSync('config.subsplit-publish.json'))['sub-splits'];

            for (let split of splits) {
              const { groups: { repo } } = /git@github\.com:thephpleague\/(?<repo>.*)\.git/.exec(split.target);
              console.log(`Found repo ${repo}`);
              await github.rest.repos.update({
                owner: 'thephpleague',
                repo,
                default_branch: '3.x',
              });
            }


================================================
FILE: .gitignore
================================================
/vendor/
/coverage/
/.phpunit.result.cache
/phpunit.xml
/composer.lock
/index_*.php
/.php-cs-fixer.php
/.php-cs-fixer.cache
/google-cloud-service-account.json
.idea

================================================
FILE: .php-cs-fixer.dist.php
================================================
<?php

$finder = PhpCsFixer\Finder::create()
    ->in([__DIR__ . '/'])
    ->exclude(__DIR__ . '/vendor');

return (new PhpCsFixer\Config())
    ->setRules([
        '@PSR2' => true,
        'array_syntax' => ['syntax' => 'short'],
        'binary_operator_spaces' => true,
        'single_line_after_imports' => true,
        'blank_line_before_statement' => ['statements' => ['return']],
        'cast_spaces' => true,
        'concat_space' => ['spacing' => 'one'],
        'no_singleline_whitespace_before_semicolons' => true,
        'not_operator_with_space' => true,
        'no_unused_imports' => true,
        'phpdoc_align' => false,
        'phpdoc_indent' => true,
        'phpdoc_no_access' => true,
        'phpdoc_no_alias_tag' => true,
        'phpdoc_no_package' => true,
        'phpdoc_scalar' => true,
        'phpdoc_separation' => true,
        'phpdoc_summary' => true,
        'phpdoc_to_comment' => true,
        'phpdoc_trim' => true,
        'single_blank_line_at_eof' => true,
        'ternary_operator_spaces' => true,
        'ordered_imports' => [
            'sort_algorithm' => 'alpha',
            'imports_order' => ['const', 'class', 'function'],
        ],
        'no_extra_blank_lines' => true,
        'no_whitespace_in_blank_line' => true,
        'nullable_type_declaration_for_default_null_value' => true,
    ])
    ->setFinder($finder);


================================================
FILE: CHANGELOG.md
================================================
# Changelog

## 3.32.0 - 2026-02-25

### Changes

- [AwsS3V3] Allow SSE-C options when fetching file metadata

## 3.31.0 - 2026-01-23

### Changes

- [AsyncAwsS3] Allow V3

## 3.30.2 - 2025-11-10

### Fixes

- [Local] Clear last error for rename and copy operations (#1883) 

## 3.30.1 - 2025-10-20

### Fixes

- Ensure listing directories called "0" do not produce unfiltered listings.

## 3.30.0 - 2025-06-25

### Changes

- [MongoDB] Allow v2
- [AsyncAWS] Encode/decode object identifiers
- [GoogleCloudStorage] Add option to stream responses
- [Local] Clear stat cache consistently
- [SFTP] Add option to disconnect connections on destruction
- [WebDAV] Deal with 405 case when trying to create a directory that already exists.

## 3.29.1 - 2024-10-08

### Fixes

- Normalise path for checksum call

## 3.29.0 - 2024-09-29

### Changes

- [FTP] Add error context from error messages
- [SFTP] overwrite on move
- [AWS S3] same path copy/move no-op
- [Async S3] transform error to flysystem errors

## 3.28.0 - 2024-05-22

### Added

- MongoDB GridFS adapter (by @GromNaN)

### Fixed

- PHP 8.3 directory listing issue for the FTP adapter (by @lanz1)

## 3.27.0 - 2024-04-07

### Fixed

- Corrected AWS SSE-C Options
- Handle MetadataDirective gracefully.

## 3.26.0 - 2024-03-25

### Fixed

- Make SFTP connectivity pinging an opt-in feature.

### Added 

- Add `add_content_md5` option to AWS S3 (#1774)
- Added AWS SSE-C options (#1773)

## 3.25.1 - 2024-03-16

### Fixed

- Cleanup connection instance after disconnecting SFTP connection.
- Fix upcoming PHP 8.4 deprecations (#1772) 

## 3.25.0 - 2024-03-09

### Added

- [MountManager] added ability to (dangerously) mount additional filesystems
- [FTP] added `disconnect` method to proactively close connections
- [SFTP V3] added `disconnect` method to proactively close connections

## 3.24.0 - 2024-02-04

### Fixes

- Updated method signatures to match upgraded dependency signatures for overrides (#1748, #1746)
- Added missing path prefixing in FTP implementation (#1747)

### Changes

- Updated string assertions to use PHP 8 functions (#1750, #1749))

## 3.23.1 - 2024-01-26

### Changes

- Updated license year

## 3.23.0 - 2023-12-04

### Fixed

- Fixed upstream regression caused by resolving inconclusive mime-type.

### Added

- Made inconclusive mime-type resolving configurable on the local adapter.

## 3.22.0 - 2023-12-03

### Changes

- Prevent double directory creation with lazy root creation for Local filesystem.

### Fixes

- Resolve to "inconclusive" mimetype instead of causing a type error by @GuySartorelli
- Corrected spelling of a configuration key for the Azure adapter by @shineability

### Additions

- MountManager::extend allows for immutable dynamic extension of the mount manager.
- Added a new abstract DecoratedAdapter for easier decoration of adapters by @jnoordsij

## 3.21.0 - 2023-11-18

### Changes

- Retain visibility on local copy for local FS, in line with other adapter (#1730) by @jnoordsij

## 3.20.0 - 2023-11-14

### Changed

- Normalise paths for public and temporary URLs (#1727)

## 3.19.0 - 2023-11-07

### Added

- Configuration option to specify if visibility should be retained during copy/move operations
- InMemoryFilesystemAdapter now supports visibility changes on move and copy.
- Default visibility options are ignored when moving/copying while respecting visibility retention settings.
- Local filesystem implementation now allows setting visibility on move and copy.

## 3.18.0 - 2023-10-05

### Added

- Configuration option to specify how to handle same path copy/move operations (#1715)

## 3.17.0 - 2023-10-05

### Added

- [AsyncAWS] Added support for version 2.0 of async-aws/{s3,simple-s3}

## 3.16.0 - 2023-09-07

### Added

- [AsyncAws] Allow specifying `get_object_options` for temporary URL generation

### Fixed

- [ZipArchive] override on move
- [WebDAV] encode path for propfind actions
- [PathPrefixing]  [#1686](https://github.com/thephpleague/flysystem/issues/1686)

## 3.15.1 - 2023-05-04

### Fixed

- Remove duplicate class caused by package extractin and inclusion

## 3.15.0 - 2023-05-04

### Added

- Extracted the local adapter as a standalone package

### Changed

- Removed readme's from shipped artefacts.

## 3.14.0 - 2023-04-11

### Added

- Made disabling stat cache configurable for SFTP adapters.

## 3.13.0 - 2023-04-11

### Fixed

- AsyncAwsS3 object deletion now chunks per 100 objects to prevent memory exhaustion
- AsyncAwsS3 now disregards top-level directories from listings
- LocalAdapter now deals with file deletions during directory listings gracefully.

### Added

- DirectoryListing now supports correct phpstan for map and filter methods. 
- FTP/SFTP added config option to detect the mime-type using the path alone (prevents a read)
- SFTP now supports PuTTY style private keys
- 

## 3.12.3 - 2023-02-18

### Fixed

- [Google Cloud Storage] Fixed ACL error for uniform bucker ACL copy operations.
- 
- ## 3.12.2 - 2023-01-19

### Fixed

- [AWS S3] Corrected param order for doesObjectExistV2 call

## 3.12.1 - 2023-01-06

### Fixed

- [AWS S3] Use doesObjectExistV2 to prevent false positive respomnses.

## 3.12.0 - 2022-12-20

### Added

- [Core] Chained public URL generation strategy

### Fixed

- [WebDAV] Handle cases where the content listing returns entries with URL prefixes.
- [Local] Ensure correct implicit root creations happens on windows.
- [ZipArchive] Fix incorrect zip contents listing for top-level directory.

## 3.11.0 - 2022-12-02

### Added

- [Google Cloud Storage] Added `UniformBucketLevelAccessVisibility` to allow buckets with uniform bucket-level access policies.

## 3.10.4 - 2022-11-26

### Changed

- [I became a dad, meet Tim](https://twitter.com/frankdejonge/status/1594966175108177921)

### Fixed

- [PathPrefixing] ensure `checksum` and `temporaryUrl` are prefixed
- [WebDAV] ensure directory creation uses trailing slashes for paths

## 3.10.3 - 2022-11-14

### Fixed

- [Local] Handle checksum errors without message (#1590)

## 3.10.2 - 2022-10-25

### Fixed

- [Filesystem] Ensure adapter is used for exposing temporary URLs.

## 3.10.1 - 2022-10-21

### Fixed

- [Filesystem] Added missing constructor argument to allow temporary URL generator injection.

## 3.10.0 - 2022-10-21

### Added

- [Filesystem] added `temporaryUrl` method
- [AsyncAWS] added `temporaryUrl` method
- [AWS S3] added `temporaryUrl` method
- [Azure Blob Storage] added `temporaryUrl` method
- [MountManager] added `temporaryUrl` method
- [Google Cloud Storage] added `temporaryUrl` method
- [ReadOnly] added `temporaryUrl` method
- [PathPrefixing] added `temporaryUrl` method

## 3.9.0 - 2022-10-18

### Added

- [Filesystem] Added ability to inject custom public URL generator into a filesystem.
- [MountManager] added `checksum` and `publicUrl` methods
- [ZipArchive] Do not prefix directories when creating/reading an archive
- [ShardedPrefixPublicUrlGenerator] added url generator strategy that distributes over a list of prefixes

## 3.8.0 - 2022-10-18

### Added

- [ChecksumAlgoIsNotSupported] Exception to indicate a checksum is not supported by the checksum provider, filesystem will fall back to ad-hoc generation.

## 3.7.0 - 2022-10-17

### Added

- [Filesystem] added `checksum` method
- [AWS S3] added `checksum` method
- [Async S3] added `checksum` method
- [Google Cloud Storage] added `checksum` method
- [Azure Blob Storage] added `checksum` method

## 3.6.0 - 2022-10-13

### Added

- [Filesystem] Added public url method
- [Azure Blob Storage] Added public url method
- [AWS S3] Added public url method
- [Async S3] Added public url method
- [GCS] Added public url method
- [WebDAV] Added public url method
- [ReadOnly] Added public url method
- [PathPrefixing] Added public url method

## 3.5.3 - 2022-09-23

### Fixed

- [SFTP] Account for missing "type" field in metadata result.

## 3.5.2 - 2022-09-23

### Fixed

- [SFTP v2/v3] Fixed possible race-condition during directory creation leading to false failures.

## 3.5.1 - 2022-09-18

### Fixed

- [WebDAV] Strip directory prefix in `createDirectory` to prevent double prefixing in `directoryExists`.

## 3.5.0 - 2022-09-17

### Added

- [AWS S3] Allow specifying visibility on move and copy

## 3.4.0 - 2022-09-15

### Added

- Added FTP configuration option useRawListOptions (null|false|true).
- UnableToListContents exception was added to uniformly represent content listing exceptions.

### Fixed

- [FTP] Don't use raw list options for FileZilla FTP servers ([#1553](https://github.com/thephpleague/flysystem/pull/1553))
- [WebDAV] Correct path formatting for move and copy operations ([#1552](https://github.com/thephpleague/flysystem/pull/1552))

## 3.3.0 - 2022-09-09

### Added

- StaticInMemoryAdapterRegistry contributed by @kbond
- ReadonlyFilesystemAdapter contributed by @kbond
- PathPrefixedAdapter contributed by @shyim

### Fixed

- WebDAV prefix is now encoded and the dir is not required to be pre-created ([#1533](https://github.com/thephpleague/flysystem/pull/1533))

## 3.2.1 - 2022-08-14

### Fixed

- [ZipArchive] reverted regression introduced in [#1525](https://github.com/thephpleague/flysystem/pull/1525)

## 3.2.0 - 2022-07-26

### Added

- [AwsS3V3] Added configuration options for forwarded options, multipart upload configuration, and metadata fields.

### Fixes

- [ZipArchive] delete top-level directory when deleting directories.
- [AwsS3V3] add `ChecksumAlgorithm` to forwarded options.
- [AwsS3V3] add `ContentMD5` to forwarded options.
- [AwsS3V3] made forwarded options and metadata fields configurable.
- [SftpV3] upgrade minimum version, PHP 8 and the lowest version fails to authenticate.

## 3.1.1 - 2022-07-18

- [AwsS3V3] Corrected exception type (#1524)

## 3.1.0 - 2022-06-29

- Added option for the Local adapter to create the root directory only on the first mutating (write/copy/move) action.

## 3.0.23 - 2022-06-29

- Added reasons for exceptions for all adapters that were missing previous exception messages.

## 3.0.22 - 2022-06-29

- [AwsS3V3] Added reasons for exceptions
- [AwsS3V3] Use ListObjectsV2 instead of ListObjects

## 3.0.21 - 2022-06-12

- [AwsS3V3] Use ListObjectsV2 instead of ListObjects

## 3.0.20 - 2022-05-25

### Fixed

- [Core] Fix deprecated ${var} string interpolation patterns (#1470)

## 3.0.19 - 2022-05-03

### Fixed

- [FTP] Turn errors into proper exceptions when resolving the connection root (#1460)

## 3.0.18 - 2022-04-25

### Fixed

- [SFTP v3] Fix retries (#1451)

## 3.0.17 - 2022-04-14

### Fixed

- [SFTP v2] Avoid type errors when public key is not retrieved (#1446)
- [SFTP v3] Avoid type errors when public key is not retrieved (#1446)

## 3.0.16 - 2022-04-11

### Fixed

- [Local] fall back to extension lookups when the mime-type comes up as inconclusive.

## 3.0.15 - 2022-04-08

### Fixed

- [GCS] Allow setting upload metadata
- [GCS] Allow setting contentType, or resolve it
- [SFTP v2+v3] Delete top-level directory too.

## 3.0.14 - 2022-04-06

### Added

- [InMemory] allow to set a last-updated time (#1438)
- [SFTP V3] allow configuring preferred algo's (#1440)

## 3.0.13 - 2022-04-02

### Fixed

- [AWS S3 V3] Do not return top-level directory when listing that same directory

## 3.0.12 - 2022-03-12

### Fixed

- [SFTP V3] Fix issue where listing is false.
- [Async AWS S3] Cosmetic fix for directory prefixing.

## 3.0.11 - 2022-03-04

### Fixed

- [AWS S3] Use globally configured options.

## 3.0.10 - 2022-02-26

### Fixed

- [AWS S3] fix detecting directories that only contain other directories but no files.
- [AWS S3] when checking for directory existence, limit the result set (perf)
- [AWS S3] throw interface exception when failing to delete directory
- [Async AWS S3] when checking for directory existence, limit the result set (perf)

## 3.0.9 - 2022-02-22

### Fixed

- [AWS S3] support setting an ACL as a direct option instead of using visibility.

## 3.0.8 - 2022-02-16

### Fixed

- [AWS S3] Set ContentType when mime-type config option is set during writes, like in v1.

## 3.0.7 - 2022-02-14

### Fixed

- [WebDAV] added missing composer.json for sub-split

## 3.0.6 - 2022-02-14

### Added

- [WebDAV] new adapter added

### Fixed

- [Core] Trim slashed uniformly in the attribute classes.
- [Core] Uniformly use directory_visibility over visibility for directory usage.
- [FTP] export-ignore the test case.

## 3.0.5 - 2022-02-12

### Added

- [AzureBlobStorage] New adapter added

### Fixed

- [AsyncAwsS3] Make EXTRA_METADATA_FIELDS protected to prevent error when extending the class

## 3.0.4 - 2022-02-10

### Fixed

- [FTP] Do not require setting of the root directory, use '' by default.

## 3.0.3 - 2022-01-31

### Fixed

- [FTP] Made connection resolving lazy again (#1414)

## 3.0.2 - 2022-01-30

### Fixes

* [FTP] Support relative or empty connection root directories (#1410)

## 3.0.1 - 2022-01-15

### Fixes

* [ZipArchive] delete top-level directory too when deleting a directory
* [GoogleCloudStorage] Use listing to check for directory existence (consistency)
* [GoogleCloudStorage] Fixed bug where exceptions were not thrown 
* [AwsS3V3] Allow passing options for controlling multi-upload options (#1396)
* [Local] Convert windows-style directory separator to unix-style (#1398)

## 3.0.0 - 2022-01-13

### Added

* FilesystemReader::has to check for directory or file existence
* FilesystemReader::directoryExists to check for directory existence
* FilesystemReader::fileExists to check for file existence
* FilesystemAdapter::directoryExists to check for directory existence
* FilesystemAdapter::fileExists to check for file existence

## 2.5.0 - 2022-09-17

### Added

- [AWS S3] Allow specifying visibility on move and copy

## 2.4.5 - 2022-04-25

- [SFTP v3] Fix retries (#1451)

## 2.4.4 - 2022-04-14

### Fixed

- [SFTP v2] Avoid type errors when public key is not retrieved (#1446)
- [SFTP v3] Avoid type errors when public key is not retrieved (#1446)

## 2.4.3 - 2022-02-16

### Fixed

- [AWS S3] Set ContentType when mime-type config option is set during writes, like in v1.

## 2.4.2 - 2022-01-31

### Fixed

- [FTP] Made connection resolving lazy again (#1414)

## 2.4.1 - 2022-01-30

### Fixed

- [FTP] Fix relative connection root handling

## 2.4.0 - 2022-01-04

### Added

- [SFTP V3] New adapter officially published

## 2.3.2 - 2021-11-28

### Fixed

- [FTP] Check for FTP\Connection object in addition to a `resource` for connectivity checks and connection handling.
- [Local] Simplify writeStream, as a bonus, have an EXT_LOCK on it now by default.

## 2.3.1 - 2021-09-22

### Fixed

- [ZipArchive] copy stream, the ziparchive is closed after getting the stream
- [Core] PHP 8.1 compatibility updates
- [LocalFilesystem] parse permissions during listing
- [LocalFilesystem] clear realstatcache
- [FTP] PHP 8.1 compatibility updates
- [Core] Upgraded PHP-CS-Fixer

## 2.3.0 - 2021-09-22

### Added

- [GoogleCloudStorage] Make it possible to set an empty prefix (#1358)
- [GoogleCloudStorage] Added possibility not to set visibility (#1356)

## 2.2.3 - 2021-08-18

### Fixed

- [Core] Corrected exception message for UnableToCopyFile.

## 2.2.2 - 2021-08-18

### Fixed

- [Core] Ensure the sorted directory listing can be iterated over (#1342).

## 2.2.1 - 2021-08-17

### Fixed

- [FTP] use original path when ensuring the parent directory exists during `move` operation.
- [FTP] do not fail setting UTF-8 when the server is already on UTF-8.
 
## 2.2.0 - 2021-07-20

### Added

* [Core] Added sortByPath on the directory listing to allows content listings to be sorted. 

## 2.1.1 - 2021-06-24

### Fixed

* [Core] Whitespace normalization now no longer strips funky whitespace but throws an exception.

## 2.1.0 - 2021-05-25

### Added

* [Core] the DirectoryAttributes now have an `extraMetadata` like files do.

### Fixed

* [AwsS3V3] Allow the ACL config option to take precedence over the visibility key.

## 2.0.8 - 2021-05-15

### Fixed

* [SFTP] Don't fail listing contents when a directory does not exist (#1301)

## 2.0.7 - 2021-05-13

### Fixed

* [LocalFilesystem] convert windows style paths to unix style paths on listing

## 2.0.6 - 2021-05-13

### Fixed

* [AsyncAwsS3] do not urlencode CopySource arguments (#1302)

## 2.0.5 - 2021-04-11

### Fixed

* [AwsS3] ensure write errors are turned into exceptions. 

## 2.0.4 - 2021-02-13

### Fixed

* [InMemory] Corrected how the file size is determined.

## 2.0.3 - 2021-02-09

### Fixed

* [AwsS3V3] Use the $config array during the copy operation.
* [Ftp] Close FTP connections when the object is destructed.
* [Core] Allow for an absolute root path of `/`.

## 2.0.2 - 2020-12-28

### Fixed

* Corrected the ignored exports for Ftp

## 2.0.1 - 2020-12-28

### Fixed

* Corrected the ignored exports for Phpseclib

## 2.0.0 - 2020-11-24

### Changed

- string type added to all visibility input

### Added

- Google Cloud Storage adapter.

## 2.0.0-beta.3 - 2020-08-23

### Added

- UnableToCheckFileExistence error introduced
- Mount manager is re-introduced

### Fixes

- Allow FTP filenames to contain special characters.
- Prevent resources of incorrect types to be passed.

### Improved

- [AWS] By default, make sure readStream resources are streamed over HTTP.

### Added

- DirectoryAttributes now have a `lastModified` accessor.

## 2.0.0-beta.2 - 2020-08-08

### Fixes

- Allow listing of top-level directory for AWS S3
- Ensure the adapters can use the correct beta release.

## 2.0.0-beta.1 - 2020-08-04

### Changes

- Small code optimizations
- Add global options array to AwsS3V3Adapter like in V1

## 2.0.0-alpha.4 - 2020-07-26

### Changes

* Renamed AwsS3V3Filesystem to AwsS3V3Adapter (in line with other adapter names).
* Renamed the PHPSecLibV2 package to PhpseclibV2, Renamed the FTP package to Ftp.
* Public key and ss-agent authentication support for Sftp

### Fixes

* Allow creation of files with empty streams.

## 2.0.0-alpha.3 - 2020-03-21

### Fixes

* Corrected the required version for the sub-split packages.

## 2.0.0-alpha.2 - 2020-03-17

### Changes

* The `League\Flysystem\FilesystemAdapter::listContents` method returns an `iterable` instead of a `Generator`.
* The `League\Flysystem\DirectoryListing` class accepts an `iterable` instead of a `Generator`.

## 2.0.0-alpha.1 - 2020-03-09

* Initial 2.0.0 alpha release


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.

We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.

## Our Standards

Examples of behavior that contributes to a positive environment for our
community include:

* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
  and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
  overall community

Examples of unacceptable behavior include:

* The use of sexualized language or imagery, and sexual attention or
  advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
  address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Enforcement Responsibilities

Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.

Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.

## Scope

This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
conduct@flysystem.io.
All complaints will be reviewed and investigated promptly and fairly.

All community leaders are obligated to respect the privacy and security of the
reporter of any incident.

## Enforcement Guidelines

Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:

### 1. Correction

**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.

**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.

### 2. Warning

**Community Impact**: A violation through a single incident or series
of actions.

**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.

### 3. Temporary Ban

**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.

**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.

### 4. Permanent Ban

**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior,  harassment of an
individual, or aggression toward or disparagement of classes of individuals.

**Consequence**: A permanent ban from any sort of public interaction within
the community.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.

Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.


================================================
FILE: INFO.md
================================================
View the docs at: https://flysystem.thephpleague.com/docs/  
Changelog at: https://github.com/thephpleague/flysystem/blob/3.x/CHANGELOG.md


================================================
FILE: LICENSE
================================================
Copyright (c) 2013-2026 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.


================================================
FILE: bin/.gitignore
================================================
renamespace.php


================================================
FILE: bin/check-versions.php
================================================
<?php

declare(strict_types=1);

/**
 * This script check for composer dependency incompatibilities:.
 *
 *  - All required dependencies of the extracted packages MUST be
 *    present in the main composer.json's require(-dev) section.
 *  - Dependency constraints of extracted packages may not exclude
 *    the constraints of the main package and vice versa.
 *  - The provided target release argument must be satisfiable by
 *    all the extracted packages' core dependency constraint.
 */

use Composer\Semver\Comparator;
use Composer\Semver\Semver;
use Composer\Semver\VersionParser;
use League\Flysystem\FileAttributes;
use League\Flysystem\Filesystem;
use League\Flysystem\Local\LocalFilesystemAdapter;
use League\Flysystem\StorageAttributes;

include_once __DIR__ . '/tools.php';

function constraint_has_conflict(string $mainConstraint, string $packageConstraint): bool
{
    $parser = new VersionParser();
    $mainConstraint = $parser->parseConstraints($mainConstraint);
    $mainLowerBound = $mainConstraint->getLowerBound()->getVersion();
    $mainUpperBound = $mainConstraint->getUpperBound()->getVersion();
    $packageConstraint = $parser->parseConstraints($packageConstraint);
    $packageLowerBound = $packageConstraint->getLowerBound()->getVersion();
    $packageUpperBound = $packageConstraint->getUpperBound()->getVersion();

    if (Comparator::compare($mainUpperBound, '<=', $packageLowerBound)) {
        return true;
    }

    if (Comparator::compare($packageUpperBound, '<=', $mainLowerBound)) {
        return true;
    }

    return false;
}

if ( ! isset($argv[1])) {
    panic('No base version provided');
}

write_line("🔎 Inspecting composer dependency incompatibilities.");

$mainVersion = $argv[1];
$filesystem = new Filesystem(new LocalFilesystemAdapter(__DIR__ . '/../'));

$mainComposer = $filesystem->read('composer.json');
/** @var string[] $otherComposers */
$otherComposers = $filesystem->listContents('src', true)
    ->filter(function (StorageAttributes $item) {
        return $item->isFile();
    })
    ->filter(function (FileAttributes $item) {
        return substr($item->path(), -5) === '.json';
    })
    ->map(function (FileAttributes $item) {
        return $item->path();
    })
    ->toArray();

$mainInformation = json_decode($mainComposer, true);

foreach ($otherComposers as $composerFile) {
    $information = json_decode($filesystem->read($composerFile), true);

    foreach ($information['require'] as $dependency => $constraint) {
        if (str_starts_with($dependency, 'ext-') || $dependency === 'phpseclib/phpseclib') {
            continue;
        }

        if ($dependency === 'league/flysystem') {
            if ( ! Semver::satisfies($mainVersion, $constraint)) {
                panic("Composer file {$composerFile} does not allow league/flysystem:{$mainVersion}");
            } else {
                write_line("Composer file {$composerFile} allows league/flysystem:{$mainVersion} with {$constraint}");
            }

            continue;
        }

        $mainDependencyConstraint = $mainInformation['require'][$dependency]
            ?? $mainInformation['require-dev'][$dependency]
            ?? null;

        if ( ! is_string($mainDependencyConstraint)) {
            panic(
                "The main composer file does not depend on an adapter dependency.\n" .
                "Depedency {$dependency} from {$composerFile} is missing."
            );
        }

        if (constraint_has_conflict($mainDependencyConstraint, $constraint)) {
            panic(
                "Package constraints are conflicting:\n\n" .
                "Package composer file: {$composerFile}\n" .
                "Dependency name: {$dependency}\n" .
                "Main constraint: {$mainDependencyConstraint}\n" .
                "Package constraint: {$constraint}"
            );
        }
    }
}

write_line("✅ Composer dependencies are looking fine.");


================================================
FILE: bin/close-subsplit-prs.yml
================================================
---
name: Close sub-split PRs

on:
  push:
    branches:
      - 2.x
      - 3.x
  pull_request:
    branches:
      - 2.x
      - 3.x
  schedule:
    - cron: '30 7 * * *'

jobs:
  close_subsplit_prs:
    runs-on: ubuntu-latest
    name: Close sub-split PRs
    steps:
      - uses: frankdejonge/action-close-subsplit-pr@0.1.0
        with:
          close_pr: 'yes'
          target_branch_match: '^(?!master).+$'
          message: |
            Hi :wave:,
            
            Thank you for contributing to Flysystem. Unfortunately, you've sent a PR to a read-only sub-split repository. 

            All pull requests should be directed towards: https://github.com/thephpleague/flysystem


================================================
FILE: bin/set-flysystem-version.php
================================================
<?php

use League\Flysystem\FileAttributes;
use League\Flysystem\Filesystem;
use League\Flysystem\Local\LocalFilesystemAdapter;
use League\Flysystem\StorageAttributes;

include_once __DIR__ . '/tools.php';

if ( ! isset($argv[1])) {
    panic('No base version provided');
}

$mainVersion = $argv[1];

write_line("☝️ Setting all flysystem constraints to {$mainVersion}.");

$filesystem = new Filesystem(new LocalFilesystemAdapter(__DIR__ . '/../'));

/** @var string[] $otherComposers */
$composerFiles = $filesystem->listContents('src', true)
    ->filter(function (StorageAttributes $item) {
        return $item->isFile();
    })
    ->filter(function (FileAttributes $item) {
        return substr($item->path(), -5) === '.json';
    })
    ->map(function (FileAttributes $item) {
        return $item->path();
    })
    ->toArray();

foreach ($composerFiles as $composerFile) {
    $contents = $filesystem->read($composerFile);
    $mainVersionRegex = preg_quote($mainVersion, '~');
    $updated = preg_replace('~("league/flysystem": "\\^[a-zA-Z0-9\\.-]+")~ms', '"league/flysystem": "^' . $mainVersion . '"', $contents);
    $filesystem->write($composerFile, $updated);
}


================================================
FILE: bin/tools.php
================================================
<?php

include_once __DIR__ . '/../vendor/autoload.php';

function write_line(string $line)
{
    fwrite(STDOUT, "{$line}\n");
}

function panic(string $reason)
{
    write_line('🚨 ' . $reason);
    exit(1);
}


================================================
FILE: bin/update-subsplit-closers.php
================================================
<?php

use League\Flysystem\Filesystem;
use League\Flysystem\Local\LocalFilesystemAdapter;

include __DIR__ . '/../vendor/autoload.php';

$filesystem = new Filesystem(new LocalFilesystemAdapter(realpath(__DIR__ . '/../')));
$subsplits = json_decode($filesystem->read('config.subsplit-publish.json'), true);
$workflowContents = $filesystem->read('bin/close-subsplit-prs.yml');

foreach ($subsplits['sub-splits'] as ['directory' => $subsplit]) {
    $workflowPath = $subsplit . '/.github/workflows/close-subsplit-prs.yaml';
    $filesystem->write($workflowPath, $workflowContents);
}


================================================
FILE: composer.json
================================================
{
    "name": "league/flysystem",
    "description": "File storage abstraction for PHP",
    "keywords": [
        "filesystem", "filesystems", "files", "storage", "aws",
        "s3", "ftp", "sftp", "webdav", "file", "cloud"
    ],
    "scripts": {
        "phpstan": "vendor/bin/phpstan analyse -l 6 src"
    },
    "type": "library",
    "minimum-stability": "dev",
    "prefer-stable": true,
    "autoload": {
        "psr-4": {
            "League\\Flysystem\\": "src"
        }
    },
    "require": {
        "php": "^8.0.2",
        "league/flysystem-local":  "^3.0.0",
        "league/mime-type-detection": "^1.0.0"
    },
    "require-dev": {
        "ext-zip": "*",
        "ext-fileinfo": "*",
        "ext-ftp": "*",
        "ext-mongodb": "^1.3|^2",
        "microsoft/azure-storage-blob": "^1.1",
        "phpunit/phpunit": "^9.5.11|^10.0",
        "phpstan/phpstan": "^1.10",
        "phpseclib/phpseclib": "^3.0.36",
        "aws/aws-sdk-php": "^3.295.10",
        "composer/semver": "^3.0",
        "friendsofphp/php-cs-fixer": "^3.5",
        "google/cloud-storage": "^1.23",
        "async-aws/s3": "^1.5 || ^2.0",
        "async-aws/simple-s3": "^1.1 || ^2.0",
        "mongodb/mongodb": "^1.2|^2",
        "sabre/dav": "^4.6.0",
        "guzzlehttp/psr7": "^2.6"
    },
    "conflict": {
        "async-aws/core": "<1.19.0",
        "async-aws/s3": "<1.14.0",
        "symfony/http-client": "<5.2",
        "guzzlehttp/ringphp": "<1.1.1",
        "guzzlehttp/guzzle": "<7.0",
        "aws/aws-sdk-php": "3.209.31 || 3.210.0",
        "phpseclib/phpseclib": "3.0.15"
    },
    "license": "MIT",
    "authors": [
        {
            "name": "Frank de Jonge",
            "email": "info@frankdejonge.nl"
        }
    ],
    "repositories": [
        {
            "type": "package",
            "package": {
                "name": "league/flysystem-local",
                "version": "3.0.0",
                "dist": {
                    "type": "path",
                    "url": "src/Local"
                }
            }
        }
    ]
}


================================================
FILE: config.subsplit-publish.json
================================================
{
    "sub-splits": [
        {
            "name": "ftp",
            "directory": "src/Ftp",
            "target": "git@github.com:thephpleague/flysystem-ftp.git"
        },
        {
            "name": "sftp",
            "directory": "src/PhpseclibV2",
            "target": "git@github.com:thephpleague/flysystem-sftp.git"
        },
        {
            "name": "sftp-v3",
            "directory": "src/PhpseclibV3",
            "target": "git@github.com:thephpleague/flysystem-sftp-v3.git"
        },
        {
            "name": "memory",
            "directory": "src/InMemory",
            "target": "git@github.com:thephpleague/flysystem-memory.git"
        },
        {
            "name": "local",
            "directory": "src/Local",
            "target": "git@github.com:thephpleague/flysystem-local.git"
        },
        {
            "name": "ziparchive",
            "directory": "src/ZipArchive",
            "target": "git@github.com:thephpleague/flysystem-ziparchive.git"
        },
        {
            "name": "aws-s3-v3",
            "directory": "src/AwsS3V3",
            "target": "git@github.com:thephpleague/flysystem-aws-s3-v3.git"
        },
        {
            "name": "async-aws-s3",
            "directory": "src/AsyncAwsS3",
            "target": "git@github.com:thephpleague/flysystem-async-aws-s3.git"
        },
        {
            "name": "azure-blob-storage",
            "directory": "src/AzureBlobStorage",
            "target": "git@github.com:thephpleague/flysystem-azure-blob-storage.git"
        },
        {
            "name": "google-cloud-storage",
            "directory": "src/GoogleCloudStorage",
            "target": "git@github.com:thephpleague/flysystem-google-cloud-storage.git"
        },
        {
            "name": "readonly",
            "directory": "src/ReadOnly",
            "target": "git@github.com:thephpleague/flysystem-read-only.git"
        },
        {
            "name": "pathprefixing",
            "directory": "src/PathPrefixing",
            "target": "git@github.com:thephpleague/flysystem-path-prefixing.git"
        },
        {
            "name": "webdav",
            "directory": "src/WebDAV",
            "target": "git@github.com:thephpleague/flysystem-webdav.git"
        },
        {
            "name": "adapter-test-utilities",
            "directory": "src/AdapterTestUtilities",
            "target": "git@github.com:thephpleague/flysystem-adapter-test-utilities.git"
        },
        {
            "name": "gridfs",
            "directory": "src/GridFS",
            "target": "git@github.com:thephpleague/flysystem-gridfs.git"
        }
    ]
}


================================================
FILE: docker-compose.yml
================================================
---
version: "3"
services:
  mongodb:
    image: mongo:7
    ports:
      - "27017:27017"
  sabredav:
    image: php:8.1-alpine3.15
    restart: always
    volumes:
      - ./:/var/www/html/
    ports:
      - "4040:4040"
    command: php -S 0.0.0.0:4040 /var/www/html/src/WebDAV/resources/server.php
  webdav:
    image: bytemark/webdav
    restart: always
    ports:
      - "4080:80"
    environment:
      AUTH_TYPE: Digest
      USERNAME: alice
      PASSWORD: secret1234
      ANONYMOUS_METHODS: 'GET,OPTIONS'
  sftp:
    container_name: sftp
    restart: always
    image: atmoz/sftp
    volumes:
      - ./test_files/sftp/users.conf:/etc/sftp/users.conf
      - ./test_files/sftp/ssh_host_ed25519_key:/etc/ssh/ssh_host_ed25519_key
      - ./test_files/sftp/ssh_host_rsa_key:/etc/ssh/ssh_host_rsa_key
      - ./test_files/sftp/id_rsa.pub:/home/bar/.ssh/keys/id_rsa.pub
    ports:
      - "2222:22"
  sftp_eddsa_only:
    container_name: sftp_eddsa_only
    restart: always
    image: atmoz/sftp
    volumes:
      - ./test_files/sftp/users.conf:/etc/sftp/users.conf
      - ./test_files/sftp/sshd_custom_configs.sh:/etc/sftp.d/sshd_custom_configs.sh
      - ./test_files/sftp/ssh_host_ed25519_key:/etc/ssh/ssh_host_ed25519_key
    ports:
      - "2223:22"
  ftp:
    container_name: ftp
    restart: always
    image: delfer/alpine-ftp-server
    environment:
      USERS: 'foo|pass|/home/foo/upload'
      ADDRESS: 'localhost'
    ports:
      - "2121:21"
      - "21000-21010:21000-21010"
  ftpd:
    container_name: ftpd
    restart: always
    environment:
      PUBLICHOST: localhost
      FTP_USER_NAME: foo
      FTP_USER_PASS: pass
      FTP_USER_HOME: /home/foo
    image: stilliard/pure-ftpd
    ports:
      - "2122:21"
      - "30000-30009:30000-30009"
    command: "/run.sh -l puredb:/etc/pure-ftpd/pureftpd.pdb -E -j -P localhost"
  toxiproxy:
    container_name: toxiproxy
    restart: unless-stopped
    image: ghcr.io/shopify/toxiproxy
    command: "-host 0.0.0.0 -config /opt/toxiproxy/config.json"
    volumes:
      - ./test_files/toxiproxy/toxiproxy.json:/opt/toxiproxy/config.json:ro
    ports:
      - "8474:8474" # HTTP API
      - "8222:8222" # SFTP
      - "8121:8121" # FTP
      - "8122:8122" # FTPD


================================================
FILE: mocked-functions.php
================================================
<?php

namespace League\Flysystem\Local {
    function rmdir(...$arguments)
    {
        if ( ! is_mocked('rmdir')) {
            return \rmdir(...$arguments);
        }

        return return_mocked_value('rmdir');
    }

    function unlink(...$arguments)
    {
        if ( ! is_mocked('unlink')) {
            return \unlink(...$arguments);
        }

        return return_mocked_value('unlink');
    }

    function filemtime(...$arguments)
    {
        if ( ! is_mocked('filemtime')) {
            return \filemtime(...$arguments);
        }

        return return_mocked_value('filemtime');
    }

    function filesize(...$arguments)
    {
        if ( ! is_mocked('filesize')) {
            return \filesize(...$arguments);
        }

        return return_mocked_value('filesize');
    }
}

namespace League\Flysystem\InMemory {
    function time()
    {
        if ( ! is_mocked('time')) {
            return \time();
        }

        return return_mocked_value('time');
    }
}

namespace League\Flysystem\Ftp {
    function ftp_raw(...$arguments)
    {
        if ( ! is_mocked('ftp_raw')) {
            return \ftp_raw(...$arguments);
        }

        return return_mocked_value('ftp_raw');
    }

    function ftp_set_option(...$arguments)
    {
        if ( ! is_mocked('ftp_set_option')) {
            return \ftp_set_option(...$arguments);
        }

        return return_mocked_value('ftp_set_option');
    }

    function ftp_pasv(...$arguments)
    {
        if ( ! is_mocked('ftp_pasv')) {
            return \ftp_pasv(...$arguments);
        }

        return return_mocked_value('ftp_pasv');
    }

    function ftp_pwd(...$arguments)
    {
        if ( ! is_mocked('ftp_pwd')) {
            return \ftp_pwd(...$arguments);
        }

        return return_mocked_value('ftp_pwd');
    }

    function ftp_fput(...$arguments)
    {
        if ( ! is_mocked('ftp_fput')) {
            return \ftp_fput(...$arguments);
        }

        return return_mocked_value('ftp_fput');
    }

    function ftp_chmod(...$arguments)
    {
        if ( ! is_mocked('ftp_chmod')) {
            return \ftp_chmod(...$arguments);
        }

        return return_mocked_value('ftp_chmod');
    }

    function ftp_mkdir(...$arguments)
    {
        if ( ! is_mocked('ftp_mkdir')) {
            return \ftp_mkdir(...$arguments);
        }

        return return_mocked_value('ftp_mkdir');
    }

    function ftp_delete(...$arguments)
    {
        if ( ! is_mocked('ftp_delete')) {
            return \ftp_delete(...$arguments);
        }

        return return_mocked_value('ftp_delete');
    }

    function ftp_rmdir(...$arguments)
    {
        if ( ! is_mocked('ftp_rmdir')) {
            return \ftp_rmdir(...$arguments);
        }

        return return_mocked_value('ftp_rmdir');
    }

    function ftp_fget(...$arguments)
    {
        if ( ! is_mocked('ftp_fget')) {
            return \ftp_fget(...$arguments);
        }

        return return_mocked_value('ftp_fget');
    }

    function ftp_rawlist(...$arguments)
    {
        if ( ! is_mocked('ftp_rawlist')) {
            return \ftp_rawlist(...$arguments);
        }

        return return_mocked_value('ftp_rawlist');
    }
}

namespace League\Flysystem\ZipArchive {
    function stream_get_contents(...$arguments)
    {
        if ( ! is_mocked('stream_get_contents')) {
            return \stream_get_contents(...$arguments);
        }

        return return_mocked_value('stream_get_contents');
    }
}


================================================
FILE: phpstan-baseline.neon
================================================
parameters:
	ignoreErrors:
		-
			message: "#^Parameter \\$connection of method League\\\\Flysystem\\\\Ftp\\\\FtpAdapter\\:\\:resolveConnectionRoot\\(\\) has invalid type FTP\\\\Connection\\.$#"
			count: 1
			path: src/Ftp/FtpAdapter.php

		-
			message: "#^Unsafe access to private property League\\\\Flysystem\\\\GoogleCloudStorage\\\\GoogleCloudStorageAdapter\\:\\:\\$algoToInfoMap through static\\:\\:\\.$#"
			count: 1
			path: src/GoogleCloudStorage/GoogleCloudStorageAdapter.php

		-
			message: "#^Unsafe access to private property League\\\\Flysystem\\\\GoogleCloudStorage\\\\GoogleCloudStorageAdapterTest\\:\\:\\$adapterPrefix through static\\:\\:\\.$#"
			count: 3
			path: src/GoogleCloudStorage/GoogleCloudStorageAdapterTest.php

		-
			message: "#^Unsafe access to private property League\\\\Flysystem\\\\GoogleCloudStorage\\\\GoogleCloudStorageAdapterTest\\:\\:\\$bucket through static\\:\\:\\.$#"
			count: 5
			path: src/GoogleCloudStorage/GoogleCloudStorageAdapterTest.php

		-
			message: "#^Unsafe access to private property League\\\\Flysystem\\\\GoogleCloudStorage\\\\GoogleCloudStorageAdapterTest\\:\\:\\$prefixer through static\\:\\:\\.$#"
			count: 3
			path: src/GoogleCloudStorage/GoogleCloudStorageAdapterTest.php

		-
			message: "#^Offset 2 does not exist on array\\{League\\\\Flysystem\\\\FilesystemOperator, string\\}\\.$#"
			count: 1
			path: src/MountManager.php

		-
			message: "#^Unsafe access to private property League\\\\Flysystem\\\\ZipArchive\\\\ZipArchiveAdapterTestCase\\:\\:\\$archiveProvider through static\\:\\:\\.$#"
			count: 10
			path: src/ZipArchive/ZipArchiveAdapterTestCase.php
		-
			message: "#^Parameter \\#1 \\$ftp of function ftp_chdir expects FTP\\\\Connection, resource given\\.$#"
			count: 2
			path: src/Ftp/FtpAdapter.php

		-
			message: "#^Parameter \\#1 \\$ftp of function ftp_chmod expects FTP\\\\Connection, resource given\\.$#"
			count: 2
			path: src/Ftp/FtpAdapter.php

		-
			message: "#^Parameter \\#1 \\$ftp of function ftp_delete expects FTP\\\\Connection, resource given\\.$#"
			count: 1
			path: src/Ftp/FtpAdapter.php

		-
			message: "#^Parameter \\#1 \\$ftp of function ftp_fget expects FTP\\\\Connection, resource given\\.$#"
			count: 1
			path: src/Ftp/FtpAdapter.php

		-
			message: "#^Parameter \\#1 \\$ftp of function ftp_fput expects FTP\\\\Connection, resource given\\.$#"
			count: 1
			path: src/Ftp/FtpAdapter.php

		-
			message: "#^Parameter \\#1 \\$ftp of function ftp_mdtm expects FTP\\\\Connection, resource given\\.$#"
			count: 1
			path: src/Ftp/FtpAdapter.php

		-
			message: "#^Parameter \\#1 \\$ftp of function ftp_mkdir expects FTP\\\\Connection, resource given\\.$#"
			count: 1
			path: src/Ftp/FtpAdapter.php

		-
			message: "#^Parameter \\#1 \\$ftp of function ftp_raw expects FTP\\\\Connection, resource given\\.$#"
			count: 1
			path: src/Ftp/FtpAdapter.php

		-
			message: "#^Parameter \\#1 \\$ftp of function ftp_rawlist expects FTP\\\\Connection, resource given\\.$#"
			count: 1
			path: src/Ftp/FtpAdapter.php

		-
			message: "#^Parameter \\#1 \\$ftp of function ftp_rename expects FTP\\\\Connection, resource given\\.$#"
			count: 1
			path: src/Ftp/FtpAdapter.php

		-
			message: "#^Parameter \\#1 \\$ftp of function ftp_rmdir expects FTP\\\\Connection, resource given\\.$#"
			count: 1
			path: src/Ftp/FtpAdapter.php

		-
			message: "#^Parameter \\#1 \\$ftp of function ftp_size expects FTP\\\\Connection, resource given\\.$#"
			count: 2
			path: src/Ftp/FtpAdapter.php

		-
			message: "#^Method League\\\\Flysystem\\\\Ftp\\\\FtpConnectionProvider\\:\\:createConnectionResource\\(\\) should return resource but returns FTP\\\\Connection\\.$#"
			count: 1
			path: src/Ftp/FtpConnectionProvider.php

		-
			message: "#^Parameter \\#1 \\$ftp of function ftp_close expects FTP\\\\Connection, resource given\\.$#"
			count: 1
			path: src/Ftp/FtpConnectionProvider.php

		-
			message: "#^Parameter \\#1 \\$ftp of function ftp_login expects FTP\\\\Connection, resource given\\.$#"
			count: 1
			path: src/Ftp/FtpConnectionProvider.php

		-
			message: "#^Parameter \\#1 \\$ftp of function ftp_pasv expects FTP\\\\Connection, resource given\\.$#"
			count: 1
			path: src/Ftp/FtpConnectionProvider.php

		-
			message: "#^Parameter \\#1 \\$ftp of function ftp_raw expects FTP\\\\Connection, resource given\\.$#"
			count: 1
			path: src/Ftp/FtpConnectionProvider.php

		-
			message: "#^Parameter \\#1 \\$ftp of function ftp_set_option expects FTP\\\\Connection, resource given\\.$#"
			count: 1
			path: src/Ftp/FtpConnectionProvider.php

		-
			message: "#^Parameter \\#1 \\$ftp of function ftp_close expects FTP\\\\Connection, resource given\\.$#"
			count: 1
			path: src/Ftp/FtpConnectionProviderTest.php

		-
			message: "#^Parameter \\#1 \\$ftp of function ftp_raw expects FTP\\\\Connection, resource given\\.$#"
			count: 1
			path: src/Ftp/NoopCommandConnectivityChecker.php

		-
			message: "#^Parameter \\#1 \\$ftp of function ftp_close expects FTP\\\\Connection, resource given\\.$#"
			count: 1
			path: src/Ftp/NoopCommandConnectivityCheckerTest.php

		-
			message: "#^Parameter \\#1 \\$ftp of function ftp_rawlist expects FTP\\\\Connection, resource given\\.$#"
			count: 1
			path: src/Ftp/RawListFtpConnectivityChecker.php

		-
			message: "#^Parameter \\#1 \\$ftp of function ftp_close expects FTP\\\\Connection, resource given\\.$#"
			count: 1
			path: src/Ftp/RawListFtpConnectivityCheckerTest.php


================================================
FILE: phpstan.neon
================================================
includes:
    - phpstan-baseline.neon
parameters:
    level: 6
    paths:
        - src
    checkMissingIterableValueType: false
    reportUnmatchedIgnoredErrors: false
    checkGenericClassInNonGenericObjectType: false
    scanFiles:
        - src/AdapterTestUtilities/test-functions.php
    excludePaths:
        - src/AdapterTestUtilities/
        - src/AsyncAwsS3
        - src/AwsS3V3
        - src/FTP
        - src/InMemory
        - src/PhpseclibV2
        - src/PhpseclibV3
    ignoreErrors:
        - '#invalid typehint type FTP\\Connection#'
        - '#FTP\\Connection not found#'
        - '#unknown class FTP\\Connection#'
        - '#Call to function iterator_to_array\(\) on a separate line has no effect\.#'
        - '#Comparison operation "<" between 0|1 and 4 is always true.#'
        - '#Method League\\Flysystem\\AwsS3V3\\S3ClientStub.*#'
        - '#Constant NET_SFTP_TYPE_DIRECTORY not found\.#'
        - '#\$local_file of method phpseclib\\Net\\SFTP::get\(\) expects string, resource given#'


================================================
FILE: phpunit.php
================================================
<?php

include __DIR__ . '/vendor/autoload.php';
include __DIR__ . '/src/AdapterTestUtilities/test-functions.php';
include __DIR__ . '/mocked-functions.php';


================================================
FILE: phpunit.xml.dist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true" bootstrap="phpunit.php">
    <testsuites>
        <testsuite name="Flysystem">
            <directory suffix="Test.php">src/</directory>
        </testsuite>
    </testsuites>
    <php>
        <env name="FLYSYSTEM_TEST_SFTP" value="yes" />
    </php>
    <groups>
        <exclude>
            <group>legacy</group>
        </exclude>
    </groups>
    <coverage>
        <include>
            <directory suffix=".php">src</directory>
        </include>
    </coverage>
</phpunit>


================================================
FILE: readme.md
================================================
# League\Flysystem

[![Author](https://img.shields.io/badge/author-@frankdejonge-blue.svg)](https://twitter.com/frankdejonge)
[![Source Code](https://img.shields.io/badge/source-thephpleague/flysystem-blue.svg)](https://github.com/thephpleague/flysystem)
[![Latest Version](https://img.shields.io/github/tag/thephpleague/flysystem.svg)](https://github.com/thephpleague/flysystem/releases)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://github.com/thephpleague/flysystem/blob/master/LICENSE)
[![Quality Assurance](https://github.com/thephpleague/flysystem/workflows/Quality%20Assurance/badge.svg?branch=2.x)](https://github.com/thephpleague/flysystem/actions?query=workflow%3A%22Quality+Assurance%22)
[![Total Downloads](https://img.shields.io/packagist/dt/league/flysystem.svg)](https://packagist.org/packages/league/flysystem)
![php 7.2+](https://img.shields.io/badge/php-min%208.0.2-red.svg)

## About Flysystem

Flysystem is a file storage library for PHP. It provides one interface to
interact with many types of filesystems. When you use Flysystem, you're
not only protected from vendor lock-in, you'll also have a consistent experience
for which ever storage is right for you. 

## Getting Started

* **[New in V3](https://flysystem.thephpleague.com/docs/what-is-new/)**: What is new in Flysystem V2/V3?
* **[Architecture](https://flysystem.thephpleague.com/docs/architecture/)**: Flysystem's internal architecture
* **[Flysystem API](https://flysystem.thephpleague.com/docs/usage/filesystem-api/)**: How to interact with your Flysystem instance
* **[Upgrade from 1x](https://flysystem.thephpleague.com/docs/upgrade-from-1.x/)**: How to upgrade from 1.x/2.x

### Officially supported adapters

* **[Local](https://flysystem.thephpleague.com/docs/adapter/local/)**
* **[FTP](https://flysystem.thephpleague.com/docs/adapter/ftp/)**
* **[SFTP](https://flysystem.thephpleague.com/docs/adapter/sftp-v3/)**
* **[Memory](https://flysystem.thephpleague.com/docs/adapter/in-memory/)**
* **[AWS S3](https://flysystem.thephpleague.com/docs/adapter/aws-s3-v3/)**
* **[AsyncAws S3](https://flysystem.thephpleague.com/docs/adapter/async-aws-s3/)**
* **[Google Cloud Storage](https://flysystem.thephpleague.com/docs/adapter/google-cloud-storage/)**
* **[MongoDB GridFS](https://flysystem.thephpleague.com/docs/adapter/gridfs/)**
* **[WebDAV](https://flysystem.thephpleague.com/docs/adapter/webdav/)**
* **[ZipArchive](https://flysystem.thephpleague.com/docs/adapter/zip-archive/)**

### Third party Adapters

* **[Azure Blob Storage](https://github.com/Azure-OSS/azure-storage-php-adapter-flysystem)**
* **[Gitlab](https://github.com/RoyVoetman/flysystem-gitlab-storage)**
* **[Google Drive (using regular paths)](https://github.com/masbug/flysystem-google-drive-ext)**
* **[bunny.net / BunnyCDN](https://github.com/PlatformCommunity/flysystem-bunnycdn/tree/v3)**
* **[Sharepoint 365 / One Drive (Using MS Graph)](https://github.com/shitware-ltd/flysystem-msgraph)**
* **[OneDrive](https://github.com/doerffler/flysystem-onedrive)**
* **[Dropbox](https://github.com/spatie/flysystem-dropbox)**
* **[ReplicateAdapter](https://github.com/ajgarlag/flysystem-replicate)**
* **[Uploadcare](https://github.com/vormkracht10/flysystem-uploadcare)**
* **[Useful adapters (FallbackAdapter, LogAdapter, ReadWriteAdapter, RetryAdapter)](https://github.com/ElGigi/FlysystemUsefulAdapters)**
* **[Metadata Cache](https://github.com/jgivoni/flysystem-cache-adapter)**
* **[Migration adapter (lazy)](https://github.com/antonsacred/flysystem-lazy-migration-adapter)**

You can always [create an adapter](https://flysystem.thephpleague.com/docs/advanced/creating-an-adapter/) yourself.

## Security

If you discover any security related issues, please email info@frankdejonge.nl instead of using the issue tracker.

## Enjoy

Oh, and if you've come down this far, you might as well follow me on [twitter](https://twitter.com/frankdejonge).


================================================
FILE: src/AdapterTestUtilities/.gitattributes
================================================
* text=auto

.github export-ignore
.gitattributes export-ignore
README.md export-ignore


================================================
FILE: src/AdapterTestUtilities/.github/workflows/close-subsplit-prs.yaml
================================================
---
name: Close sub-split PRs

on:
  push:
    branches:
      - 2.x
      - 3.x
  pull_request:
    branches:
      - 2.x
      - 3.x
  schedule:
    - cron: '30 7 * * *'

jobs:
  close_subsplit_prs:
    runs-on: ubuntu-latest
    name: Close sub-split PRs
    steps:
      - uses: frankdejonge/action-close-subsplit-pr@0.1.0
        with:
          close_pr: 'yes'
          target_branch_match: '^(?!master).+$'
          message: |
            Hi :wave:,
            
            Thank you for contributing to Flysystem. Unfortunately, you've sent a PR to a read-only sub-split repository. 

            All pull requests should be directed towards: https://github.com/thephpleague/flysystem


================================================
FILE: src/AdapterTestUtilities/ExceptionThrowingFilesystemAdapter.php
================================================
<?php

declare(strict_types=1);

namespace League\Flysystem\AdapterTestUtilities;

use League\Flysystem\Config;
use League\Flysystem\FileAttributes;
use League\Flysystem\FilesystemAdapter;
use League\Flysystem\FilesystemOperationFailed;

class ExceptionThrowingFilesystemAdapter implements FilesystemAdapter
{
    /**
     * @var FilesystemAdapter
     */
    private $adapter;

    /**
     * @var array<string, FilesystemOperationFailed>
     */
    private $stagedExceptions = [];

    public function __construct(FilesystemAdapter $adapter)
    {
        $this->adapter = $adapter;
    }

    public function stageException(string $method, string $path, FilesystemOperationFailed $exception): void
    {
        $this->stagedExceptions[join('@', [$method, $path])] = $exception;
    }

    private function throwStagedException(string $method, $path): void
    {
        $method = preg_replace('~.+::~', '', $method);
        $key = join('@', [$method, $path]);

        if ( ! array_key_exists($key, $this->stagedExceptions)) {
            return;
        }

        $exception = $this->stagedExceptions[$key];
        unset($this->stagedExceptions[$key]);
        throw $exception;
    }

    public function fileExists(string $path): bool
    {
        $this->throwStagedException(__METHOD__, $path);

        return $this->adapter->fileExists($path);
    }

    public function write(string $path, string $contents, Config $config): void
    {
        $this->throwStagedException(__METHOD__, $path);

        $this->adapter->write($path, $contents, $config);
    }

    public function writeStream(string $path, $contents, Config $config): void
    {
        $this->throwStagedException(__METHOD__, $path);

        $this->adapter->writeStream($path, $contents, $config);
    }

    public function read(string $path): string
    {
        $this->throwStagedException(__METHOD__, $path);

        return $this->adapter->read($path);
    }

    public function readStream(string $path)
    {
        $this->throwStagedException(__METHOD__, $path);

        return $this->adapter->readStream($path);
    }

    public function delete(string $path): void
    {
        $this->throwStagedException(__METHOD__, $path);

        $this->adapter->delete($path);
    }

    public function deleteDirectory(string $path): void
    {
        $this->throwStagedException(__METHOD__, $path);

        $this->adapter->deleteDirectory($path);
    }

    public function createDirectory(string $path, Config $config): void
    {
        $this->throwStagedException(__METHOD__, $path);

        $this->adapter->createDirectory($path, $config);
    }

    public function setVisibility(string $path, string $visibility): void
    {
        $this->throwStagedException(__METHOD__, $path);

        $this->adapter->setVisibility($path, $visibility);
    }

    public function visibility(string $path): FileAttributes
    {
        $this->throwStagedException(__METHOD__, $path);

        return $this->adapter->visibility($path);
    }

    public function mimeType(string $path): FileAttributes
    {
        $this->throwStagedException(__METHOD__, $path);

        return $this->adapter->mimeType($path);
    }

    public function lastModified(string $path): FileAttributes
    {
        $this->throwStagedException(__METHOD__, $path);

        return $this->adapter->lastModified($path);
    }

    public function fileSize(string $path): FileAttributes
    {
        $this->throwStagedException(__METHOD__, $path);

        return $this->adapter->fileSize($path);
    }

    public function listContents(string $path, bool $deep): iterable
    {
        $this->throwStagedException(__METHOD__, $path);

        return $this->adapter->listContents($path, $deep);
    }

    public function move(string $source, string $destination, Config $config): void
    {
        $this->throwStagedException(__METHOD__, $source);

        $this->adapter->move($source, $destination, $config);
    }

    public function copy(string $source, string $destination, Config $config): void
    {
        $this->throwStagedException(__METHOD__, $source);

        $this->adapter->copy($source, $destination, $config);
    }

    public function directoryExists(string $path): bool
    {
        $this->throwStagedException(__METHOD__, $path);

        return $this->adapter->directoryExists($path);
    }
}


================================================
FILE: src/AdapterTestUtilities/FilesystemAdapterTestCase.php
================================================
<?php

declare(strict_types=1);

namespace League\Flysystem\AdapterTestUtilities;

use const PHP_EOL;
use DateInterval;
use DateTimeImmutable;
use Generator;
use League\Flysystem\ChecksumProvider;
use League\Flysystem\Config;
use League\Flysystem\DirectoryAttributes;
use League\Flysystem\FileAttributes;
use League\Flysystem\FilesystemAdapter;
use League\Flysystem\StorageAttributes;
use League\Flysystem\UnableToCopyFile;
use League\Flysystem\UnableToMoveFile;
use League\Flysystem\UnableToProvideChecksum;
use League\Flysystem\UnableToReadFile;
use League\Flysystem\UnableToRetrieveMetadata;
use League\Flysystem\UnableToSetVisibility;
use League\Flysystem\UrlGeneration\PublicUrlGenerator;
use League\Flysystem\UrlGeneration\TemporaryUrlGenerator;
use League\Flysystem\Visibility;
use PHPUnit\Framework\TestCase;
use Throwable;
use function file_get_contents;
use function is_resource;
use function iterator_to_array;

/**
 * @codeCoverageIgnore
 */
abstract class FilesystemAdapterTestCase extends TestCase
{
    use RetryOnTestException;

    /**
     * @var FilesystemAdapter
     */
    protected static $adapter;

    /**
     * @var bool
     */
    protected $isUsingCustomAdapter = false;

    public static function clearFilesystemAdapterCache(): void
    {
        static::$adapter = null;
    }

    abstract protected static function createFilesystemAdapter(): FilesystemAdapter;

    public function adapter(): FilesystemAdapter
    {
        if ( ! static::$adapter instanceof FilesystemAdapter) {
            static::$adapter = static::createFilesystemAdapter();
        }

        return static::$adapter;
    }

    public static function tearDownAfterClass(): void
    {
        self::clearFilesystemAdapterCache();
    }

    protected function setUp(): void
    {
        parent::setUp();
        $this->adapter();
    }

    protected function useAdapter(FilesystemAdapter $adapter): FilesystemAdapter
    {
        static::$adapter = $adapter;
        $this->isUsingCustomAdapter = true;

        return $adapter;
    }

    /**
     * @after
     */
    public function cleanupAdapter(): void
    {
        $this->clearCustomAdapter();
        $this->clearStorage();
    }

    public function clearStorage(): void
    {
        reset_function_mocks();

        try {
            $adapter = $this->adapter();
        } catch (Throwable $exception) {
            /*
             * Setting up the filesystem adapter failed. This is OK at this stage.
             * The exception will have been shown to the user when trying to run
             * a test. We expect an exception to be thrown when tests are marked as
             * skipped when a filesystem adapter cannot be constructed.
             */
            return;
        }

        $this->runSetup(function () use ($adapter) {
            /** @var StorageAttributes $item */
            foreach ($adapter->listContents('', false) as $item) {
                if ($item->isDir()) {
                    $adapter->deleteDirectory($item->path());
                } else {
                    $adapter->delete($item->path());
                }
            }
        });
    }

    public function clearCustomAdapter(): void
    {
        if ($this->isUsingCustomAdapter) {
            $this->isUsingCustomAdapter = false;
            self::clearFilesystemAdapterCache();
        }
    }

    /**
     * @test
     */
    public function writing_and_reading_with_string(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();

            $adapter->write('path.txt', 'contents', new Config());
            $fileExists = $adapter->fileExists('path.txt');
            $contents = $adapter->read('path.txt');

            $this->assertTrue($fileExists);
            $this->assertEquals('contents', $contents);
        });
    }

    /**
     * @test
     */
    public function writing_a_file_with_a_stream(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();
            $writeStream = stream_with_contents('contents');

            $adapter->writeStream('path.txt', $writeStream, new Config([
                Config::OPTION_VISIBILITY => Visibility::PUBLIC,
            ]));

            if (is_resource($writeStream)) {
                fclose($writeStream);
            }

            $fileExists = $adapter->fileExists('path.txt');

            $this->assertTrue($fileExists);
        });
    }

    /**
     * @test
     *
     * @dataProvider filenameProvider
     */
    public function writing_and_reading_files_with_special_path(string $path): void
    {
        $this->runScenario(function () use ($path) {
            $adapter = $this->adapter();

            $adapter->write($path, 'contents', new Config());
            $contents = $adapter->read($path);

            $this->assertEquals('contents', $contents);
        });
    }

    public static function filenameProvider(): Generator
    {
        yield "a path with square brackets in filename 1" => ["some/file[name].txt"];
        yield "a path with square brackets in filename 2" => ["some/file[0].txt"];
        yield "a path with square brackets in filename 3" => ["some/file[10].txt"];
        yield "a path with square brackets in dirname 1" => ["some[name]/file.txt"];
        yield "a path with square brackets in dirname 2" => ["some[0]/file.txt"];
        yield "a path with square brackets in dirname 3" => ["some[10]/file.txt"];
        yield "a path with curly brackets in filename 1" => ["some/file{name}.txt"];
        yield "a path with curly brackets in filename 2" => ["some/file{0}.txt"];
        yield "a path with curly brackets in filename 3" => ["some/file{10}.txt"];
        yield "a path with curly brackets in dirname 1" => ["some{name}/filename.txt"];
        yield "a path with curly brackets in dirname 2" => ["some{0}/filename.txt"];
        yield "a path with curly brackets in dirname 3" => ["some{10}/filename.txt"];
        yield "a path with space in dirname" => ["some dir/filename.txt"];
        yield "a path with space in filename" => ["somedir/file name.txt"];
    }

    /**
     * @test
     */
    public function writing_a_file_with_an_empty_stream(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();
            $writeStream = stream_with_contents('');

            $adapter->writeStream('path.txt', $writeStream, new Config());

            if (is_resource($writeStream)) {
                fclose($writeStream);
            }

            $fileExists = $adapter->fileExists('path.txt');

            $this->assertTrue($fileExists);

            $contents = $adapter->read('path.txt');
            $this->assertEquals('', $contents);
        });
    }

    /**
     * @test
     */
    public function listing_a_directory_named_0(): void
    {
        $this->givenWeHaveAnExistingFile('0/path.txt');
        $this->givenWeHaveAnExistingFile('1/path.txt');

        $this->runScenario(function () {
            $listing = iterator_to_array($this->adapter()->listContents('0', false));

            $this->assertCount(1, $listing);
        });
    }

    /**
     * @test
     */
    public function reading_a_file(): void
    {
        $this->givenWeHaveAnExistingFile('path.txt', 'contents');

        $this->runScenario(function () {
            $contents = $this->adapter()->read('path.txt');

            $this->assertEquals('contents', $contents);
        });
    }

    /**
     * @test
     */
    public function reading_a_file_with_a_stream(): void
    {
        $this->givenWeHaveAnExistingFile('path.txt', 'contents');

        $this->runScenario(function () {
            $readStream = $this->adapter()->readStream('path.txt');
            $contents = stream_get_contents($readStream);

            $this->assertIsResource($readStream);
            $this->assertEquals('contents', $contents);
            fclose($readStream);
        });
    }

    /**
     * @test
     */
    public function overwriting_a_file(): void
    {
        $this->runScenario(function () {
            $this->givenWeHaveAnExistingFile('path.txt', 'contents', ['visibility' => Visibility::PUBLIC]);
            $adapter = $this->adapter();

            $adapter->write('path.txt', 'new contents', new Config(['visibility' => Visibility::PRIVATE]));

            $contents = $adapter->read('path.txt');
            $this->assertEquals('new contents', $contents);
            $visibility = $adapter->visibility('path.txt')->visibility();
            $this->assertEquals(Visibility::PRIVATE, $visibility);
        });
    }

    /**
     * @test
     */
    public function a_file_exists_only_when_it_is_written_and_not_deleted(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();

            // does not exist before creation
            self::assertFalse($adapter->fileExists('path.txt'));

            // a file exists after creation
            $this->givenWeHaveAnExistingFile('path.txt');
            self::assertTrue($adapter->fileExists('path.txt'));

            // a file no longer exists after creation
            $adapter->delete('path.txt');
            self::assertFalse($adapter->fileExists('path.txt'));
        });
    }

    /**
     * @test
     */
    public function listing_contents_shallow(): void
    {
        $this->runScenario(function () {
            $this->givenWeHaveAnExistingFile('some/0-path.txt', 'contents');
            $this->givenWeHaveAnExistingFile('some/1-nested/path.txt', 'contents');

            $listing = $this->adapter()->listContents('some', false);
            /** @var StorageAttributes[] $items */
            $items = iterator_to_array($listing);

            $this->assertInstanceOf(Generator::class, $listing);
            $this->assertContainsOnlyInstancesOf(StorageAttributes::class, $items);

            $this->assertCount(2, $items, $this->formatIncorrectListingCount($items));

            // Order of entries is not guaranteed
            [$fileIndex, $directoryIndex] = $items[0]->isFile() ? [0, 1] : [1, 0];

            $this->assertEquals('some/0-path.txt', $items[$fileIndex]->path());
            $this->assertEquals('some/1-nested', $items[$directoryIndex]->path());
            $this->assertTrue($items[$fileIndex]->isFile());
            $this->assertTrue($items[$directoryIndex]->isDir());
        });
    }

    /**
     * @test
     */
    public function checking_if_a_non_existing_directory_exists(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();
            self::assertFalse($adapter->directoryExists('this-does-not-exist.php'));
        });
    }

    /**
     * @test
     */
    public function checking_if_a_directory_exists_after_writing_a_file(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();
            $this->givenWeHaveAnExistingFile('existing-directory/file.txt');
            self::assertTrue($adapter->directoryExists('existing-directory'));
        });
    }

    /**
     * @test
     */
    public function checking_if_a_directory_exists_after_creating_it(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();
            $adapter->createDirectory('explicitly-created-directory', new Config());
            self::assertTrue($adapter->directoryExists('explicitly-created-directory'));
            $adapter->deleteDirectory('explicitly-created-directory');
            $l = iterator_to_array($adapter->listContents('/', false), false);
            self::assertEquals([], $l);
            self::assertFalse($adapter->directoryExists('explicitly-created-directory'));
        });
    }

    /**
     * @test
     */
    public function listing_contents_recursive(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();
            $adapter->createDirectory('path', new Config());
            $adapter->write('path/file.txt', 'string', new Config());

            $listing = $adapter->listContents('', true);
            /** @var StorageAttributes[] $items */
            $items = iterator_to_array($listing);
            $this->assertCount(2, $items, $this->formatIncorrectListingCount($items));
        });
    }

    protected function formatIncorrectListingCount(array $items): string
    {
        $message = "Incorrect number of items returned.\nThe listing contains:\n\n";

        /** @var StorageAttributes $item */
        foreach ($items as $item) {
            $message .= "- {$item->path()}\n";
        }

        return $message . PHP_EOL;
    }

    protected function givenWeHaveAnExistingFile(string $path, string $contents = 'contents', array $config = []): void
    {
        $this->runSetup(function () use ($path, $contents, $config) {
            $this->adapter()->write($path, $contents, new Config($config));
        });
    }

    /**
     * @test
     */
    public function fetching_file_size(): void
    {
        $adapter = $this->adapter();
        $this->givenWeHaveAnExistingFile('path.txt', 'contents');

        $this->runScenario(function () use ($adapter) {
            $attributes = $adapter->fileSize('path.txt');
            $this->assertInstanceOf(FileAttributes::class, $attributes);
            $this->assertEquals(8, $attributes->fileSize());
        });
    }

    /**
     * @test
     */
    public function setting_visibility(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();
            $this->givenWeHaveAnExistingFile('path.txt', 'contents', [Config::OPTION_VISIBILITY => Visibility::PUBLIC]);

            $this->assertEquals(Visibility::PUBLIC, $adapter->visibility('path.txt')->visibility());

            $adapter->setVisibility('path.txt', Visibility::PRIVATE);

            $this->assertEquals(Visibility::PRIVATE, $adapter->visibility('path.txt')->visibility());

            $adapter->setVisibility('path.txt', Visibility::PUBLIC);

            $this->assertEquals(Visibility::PUBLIC, $adapter->visibility('path.txt')->visibility());
        });
    }

    /**
     * @test
     */
    public function fetching_file_size_of_a_directory(): void
    {
        $this->expectException(UnableToRetrieveMetadata::class);

        $adapter = $this->adapter();

        $this->runScenario(function () use ($adapter) {
            $adapter->createDirectory('path', new Config());
            $adapter->fileSize('path/');
        });
    }

    /**
     * @test
     */
    public function fetching_file_size_of_non_existing_file(): void
    {
        $this->expectException(UnableToRetrieveMetadata::class);

        $this->runScenario(function () {
            $this->adapter()->fileSize('non-existing-file.txt');
        });
    }

    /**
     * @test
     */
    public function fetching_last_modified_of_non_existing_file(): void
    {
        $this->expectException(UnableToRetrieveMetadata::class);

        $this->runScenario(function () {
            $this->adapter()->lastModified('non-existing-file.txt');
        });
    }

    /**
     * @test
     */
    public function fetching_visibility_of_non_existing_file(): void
    {
        $this->expectException(UnableToRetrieveMetadata::class);

        $this->runScenario(function () {
            $this->adapter()->visibility('non-existing-file.txt');
        });
    }

    /**
     * @test
     */
    public function fetching_the_mime_type_of_an_svg_file(): void
    {
        $this->runScenario(function () {
            $this->givenWeHaveAnExistingFile('file.svg', file_get_contents(__DIR__ . '/test_files/flysystem.svg'));

            $mimetype = $this->adapter()->mimeType('file.svg')->mimeType();

            $this->assertStringStartsWith('image/svg+xml', $mimetype);
        });
    }

    /**
     * @test
     */
    public function fetching_mime_type_of_non_existing_file(): void
    {
        $this->expectException(UnableToRetrieveMetadata::class);

        $this->runScenario(function () {
            $this->adapter()->mimeType('non-existing-file.txt');
        });
    }

    /**
     * @test
     */
    public function fetching_unknown_mime_type_of_a_file(): void
    {
        $this->givenWeHaveAnExistingFile(
            'unknown-mime-type.md5',
            file_get_contents(__DIR__ . '/test_files/unknown-mime-type.md5')
        );

        $this->expectException(UnableToRetrieveMetadata::class);

        $this->runScenario(function () {
            $this->adapter()->mimeType('unknown-mime-type.md5');
        });
    }

    /**
     * @test
     */
    public function listing_a_toplevel_directory(): void
    {
        $this->givenWeHaveAnExistingFile('path1.txt');
        $this->givenWeHaveAnExistingFile('path2.txt');

        $this->runScenario(function () {
            $contents = iterator_to_array($this->adapter()->listContents('', true));

            $this->assertCount(2, $contents);
        });
    }

    /**
     * @test
     */
    public function writing_and_reading_with_streams(): void
    {
        $this->runScenario(function () {
            $writeStream = stream_with_contents('contents');
            $adapter = $this->adapter();

            $adapter->writeStream('path.txt', $writeStream, new Config());
            if (is_resource($writeStream)) {
                fclose($writeStream);
            };
            $readStream = $adapter->readStream('path.txt');

            $this->assertIsResource($readStream);
            $contents = stream_get_contents($readStream);
            fclose($readStream);
            $this->assertEquals('contents', $contents);
        });
    }

    /**
     * @test
     */
    public function setting_visibility_on_a_file_that_does_not_exist(): void
    {
        $this->expectException(UnableToSetVisibility::class);

        $this->runScenario(function () {
            $this->adapter()->setVisibility('this-path-does-not-exists.txt', Visibility::PRIVATE);
        });
    }

    /**
     * @test
     */
    public function copying_a_file(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();
            $adapter->write(
                'source.txt',
                'contents to be copied',
                new Config([Config::OPTION_VISIBILITY => Visibility::PUBLIC])
            );

            $adapter->copy('source.txt', 'destination.txt', new Config());

            $this->assertTrue($adapter->fileExists('source.txt'));
            $this->assertTrue($adapter->fileExists('destination.txt'));
            $this->assertEquals(Visibility::PUBLIC, $adapter->visibility('destination.txt')->visibility());
            $this->assertEquals('text/plain', $adapter->mimeType('destination.txt')->mimeType());
            $this->assertEquals('contents to be copied', $adapter->read('destination.txt'));
        });
    }

    /**
     * @test
     */
    public function copying_a_file_that_does_not_exist(): void
    {
        $this->expectException(UnableToCopyFile::class);

        $this->runScenario(function () {
            $this->adapter()->copy('source.txt', 'destination.txt', new Config());
        });
    }

    /**
     * @test
     */
    public function copying_a_file_again(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();
            $adapter->write(
                'source.txt',
                'contents to be copied',
                new Config([Config::OPTION_VISIBILITY => Visibility::PUBLIC])
            );

            $adapter->copy('source.txt', 'destination.txt', new Config());

            $this->assertTrue($adapter->fileExists('source.txt'));
            $this->assertTrue($adapter->fileExists('destination.txt'));
            $this->assertEquals(Visibility::PUBLIC, $adapter->visibility('destination.txt')->visibility());
            $this->assertEquals('contents to be copied', $adapter->read('destination.txt'));
        });
    }

    /**
     * @test
     */
    public function moving_a_file(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();
            $adapter->write(
                'source.txt',
                'contents to be copied',
                new Config([Config::OPTION_VISIBILITY => Visibility::PUBLIC])
            );
            $adapter->move('source.txt', 'destination.txt', new Config());
            $this->assertFalse(
                $adapter->fileExists('source.txt'),
                'After moving a file should no longer exist in the original location.'
            );
            $this->assertTrue(
                $adapter->fileExists('destination.txt'),
                'After moving, a file should be present at the new location.'
            );
            $this->assertEquals(Visibility::PUBLIC, $adapter->visibility('destination.txt')->visibility());
            $this->assertEquals('text/plain', $adapter->mimeType('destination.txt')->mimeType());
            $this->assertEquals('contents to be copied', $adapter->read('destination.txt'));
        });
    }

    /**
     * @test
     */
    public function file_exists_on_directory_is_false(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();

            $this->assertFalse($adapter->directoryExists('test'));
            $adapter->createDirectory('test', new Config());

            $this->assertTrue($adapter->directoryExists('test'));
            $this->assertFalse($adapter->fileExists('test'));
        });
    }

    /**
     * @test
     */
    public function directory_exists_on_file_is_false(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();

            $this->assertFalse($adapter->fileExists('test.txt'));
            $adapter->write('test.txt', 'content', new Config());

            $this->assertTrue($adapter->fileExists('test.txt'));
            $this->assertFalse($adapter->directoryExists('test.txt'));
        });
    }

    /**
     * @test
     */
    public function reading_a_file_that_does_not_exist(): void
    {
        $this->expectException(UnableToReadFile::class);

        $this->runScenario(function () {
            $this->adapter()->read('path.txt');
        });
    }

    /**
     * @test
     */
    public function moving_a_file_that_does_not_exist(): void
    {
        $this->expectException(UnableToMoveFile::class);

        $this->runScenario(function () {
            $this->adapter()->move('source.txt', 'destination.txt', new Config());
        });
    }

    /**
     * @test
     */
    public function trying_to_delete_a_non_existing_file(): void
    {
        $adapter = $this->adapter();

        $adapter->delete('path.txt');
        $fileExists = $adapter->fileExists('path.txt');

        $this->assertFalse($fileExists);
    }

    /**
     * @test
     */
    public function checking_if_files_exist(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();
            $fileExistsBefore = $adapter->fileExists('some/path.txt');
            $adapter->write('some/path.txt', 'contents', new Config());
            $fileExistsAfter = $adapter->fileExists('some/path.txt');

            $this->assertFalse($fileExistsBefore);
            $this->assertTrue($fileExistsAfter);
        });
    }

    /**
     * @test
     */
    public function fetching_last_modified(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();
            $adapter->write('path.txt', 'contents', new Config());

            $attributes = $adapter->lastModified('path.txt');

            $this->assertInstanceOf(FileAttributes::class, $attributes);
            $this->assertIsInt($attributes->lastModified());
            $this->assertTrue($attributes->lastModified() > time() - 30);
            $this->assertTrue($attributes->lastModified() < time() + 30);
        });
    }

    /**
     * @test
     */
    public function failing_to_read_a_non_existing_file_into_a_stream(): void
    {
        $this->expectException(UnableToReadFile::class);

        $this->adapter()->readStream('something.txt');
    }

    /**
     * @test
     */
    public function failing_to_read_a_non_existing_file(): void
    {
        $this->expectException(UnableToReadFile::class);

        $this->adapter()->read('something.txt');
    }

    /**
     * @test
     */
    public function creating_a_directory(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();

            $adapter->createDirectory('creating_a_directory/path', new Config());

            // Creating a directory should be idempotent.
            $adapter->createDirectory('creating_a_directory/path', new Config());

            $contents = iterator_to_array($adapter->listContents('creating_a_directory', false));
            $this->assertCount(1, $contents, $this->formatIncorrectListingCount($contents));
            /** @var DirectoryAttributes $directory */
            $directory = $contents[0];
            $this->assertInstanceOf(DirectoryAttributes::class, $directory);
            $this->assertEquals('creating_a_directory/path', $directory->path());
            $adapter->deleteDirectory('creating_a_directory/path');
        });
    }

    /**
     * @test
     */
    public function copying_a_file_with_collision(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();
            $adapter->write('path.txt', 'new contents', new Config());
            $adapter->write('new-path.txt', 'contents', new Config());

            $adapter->copy('path.txt', 'new-path.txt', new Config());
            $contents = $adapter->read('new-path.txt');

            $this->assertEquals('new contents', $contents);
        });
    }

    /**
     * @test
     */
    public function moving_a_file_with_collision(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();
            $adapter->write('path.txt', 'new contents', new Config());
            $adapter->write('new-path.txt', 'contents', new Config());

            $adapter->move('path.txt', 'new-path.txt', new Config());

            $oldFileExists = $adapter->fileExists('path.txt');
            $this->assertFalse($oldFileExists);

            $contents = $adapter->read('new-path.txt');
            $this->assertEquals('new contents', $contents);
        });
    }

    /**
     * @test
     */
    public function copying_a_file_with_same_destination(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();
            $adapter->write('path.txt', 'new contents', new Config());

            $adapter->copy('path.txt', 'path.txt', new Config());
            $contents = $adapter->read('path.txt');

            $this->assertEquals('new contents', $contents);
        });
    }

    /**
     * @test
     */
    public function moving_a_file_with_same_destination(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();
            $adapter->write('path.txt', 'new contents', new Config());

            $adapter->move('path.txt', 'path.txt', new Config());

            $contents = $adapter->read('path.txt');
            $this->assertEquals('new contents', $contents);
        });
    }

    protected function assertFileExistsAtPath(string $path): void
    {
        $this->runScenario(function () use ($path) {
            $fileExists = $this->adapter()->fileExists($path);
            $this->assertTrue($fileExists);
        });
    }

    /**
     * @test
     */
    public function generating_a_public_url(): void
    {
        $adapter = $this->adapter();

        if ( ! $adapter instanceof PublicUrlGenerator) {
            $this->markTestSkipped('Adapter does not supply public URls');
        }

        $adapter->write('some/path.txt', 'public contents', new Config(['visibility' => 'public']));

        $url = $adapter->publicUrl('some/path.txt', new Config());
        $contents = file_get_contents($url);

        self::assertEquals('public contents', $contents);
    }

    /**
     * @test
     */
    public function generating_a_temporary_url(): void
    {
        $adapter = $this->adapter();

        if ( ! $adapter instanceof TemporaryUrlGenerator) {
            $this->markTestSkipped('Adapter does not supply temporary URls');
        }

        $adapter->write('some/private.txt', 'public contents', new Config(['visibility' => 'private']));

        $expiresAt = (new DateTimeImmutable())->add(DateInterval::createFromDateString('1 minute'));
        $url = $adapter->temporaryUrl('some/private.txt', $expiresAt, new Config());
        $contents = file_get_contents($url);

        self::assertEquals('public contents', $contents);
    }

    /**
     * @test
     */
    public function get_checksum(): void
    {
        $adapter = $this->adapter();

        if ( ! $adapter instanceof ChecksumProvider) {
            $this->markTestSkipped('Adapter does not supply providing checksums');
        }

        $adapter->write('path.txt', 'foobar', new Config());

        $this->assertSame('3858f62230ac3c915f300c664312c63f', $adapter->checksum('path.txt', new Config()));
    }

    /**
     * @test
     */
    public function cannot_get_checksum_for_non_existent_file(): void
    {
        $adapter = $this->adapter();

        if ( ! $adapter instanceof ChecksumProvider) {
            $this->markTestSkipped('Adapter does not supply providing checksums');
        }

        $this->expectException(UnableToProvideChecksum::class);

        $adapter->checksum('path.txt', new Config());
    }

    /**
     * @test
     */
    public function cannot_get_checksum_for_directory(): void
    {
        $adapter = $this->adapter();

        if ( ! $adapter instanceof ChecksumProvider) {
            $this->markTestSkipped('Adapter does not supply providing checksums');
        }

        $adapter->createDirectory('dir', new Config());

        $this->expectException(UnableToProvideChecksum::class);

        $adapter->checksum('dir', new Config());
    }
}


================================================
FILE: src/AdapterTestUtilities/README.md
================================================
## Flysystem Adapter Test Utilities

> ⚠️ this is a sub-split, for pull requests and issues, visit: https://github.com/thephpleague/flysystem

Require this package to make use of some adapter test utilities.

```bash
composer require --dev league/flysystem-adapter-test-utilities
```

View the [documentation of Flysystem](https://flysystem.thephpleague.com/docs/).


================================================
FILE: src/AdapterTestUtilities/RetryOnTestException.php
================================================
<?php

declare(strict_types=1);

namespace League\Flysystem\AdapterTestUtilities;

use const PHP_EOL;
use const STDOUT;
use League\Flysystem\FilesystemException;
use Throwable;

/**
 * @codeCoverageIgnore
 */
trait RetryOnTestException
{
    /**
     * @var string
     */
    protected $exceptionTypeToRetryOn;

    /**
     * @var int
     */
    protected $timeoutForExceptionRetry = 2;

    protected function retryOnException(string $className, int $timout = 2): void
    {
        $this->exceptionTypeToRetryOn = $className;
        $this->timeoutForExceptionRetry = $timout;
    }

    protected function retryScenarioOnException(string $className, callable $scenario, int $timeout = 2): void
    {
        $this->retryOnException($className, $timeout);
        $this->runScenario($scenario);
    }

    protected function dontRetryOnException(): void
    {
        $this->exceptionTypeToRetryOn = null;
    }

    /**
     * @internal
     *
     * @throws Throwable
     */
    protected function runSetup(callable $scenario): void
    {
        $previousException = $this->exceptionTypeToRetryOn;
        $previousTimeout = $this->timeoutForExceptionRetry;
        $this->retryOnException(FilesystemException::class);

        try {
            $this->runScenario($scenario);
        } finally {
            $this->exceptionTypeToRetryOn = $previousException;
            $this->timeoutForExceptionRetry = $previousTimeout;
        }
    }

    protected function runScenario(callable $scenario): void
    {
        if ($this->exceptionTypeToRetryOn === null) {
            $scenario();

            return;
        }

        $firstTryAt = \time();
        $lastTryAt = $firstTryAt + 60;

        while (time() <= $lastTryAt) {
            try {
                $scenario();

                return;
            } catch (Throwable $exception) {
                if ( ! $exception instanceof $this->exceptionTypeToRetryOn) {
                    throw $exception;
                }
                fwrite(STDOUT, 'Retrying ...' . PHP_EOL);
                sleep($this->timeoutForExceptionRetry);
            }
        }

        $this->exceptionTypeToRetryOn = null;

        if (isset($exception) && $exception instanceof Throwable) {
            throw $exception;
        }
    }
}


================================================
FILE: src/AdapterTestUtilities/ToxiproxyManagement.php
================================================
<?php

declare(strict_types=1);

namespace League\Flysystem\AdapterTestUtilities;

use GuzzleHttp\Client;

/**
 * This class provides a client for the HTTP API provided by the proxy that simulates network issues.
 *
 * @see https://github.com/shopify/toxiproxy#http-api
 *
 * @phpstan-type RegisteredProxies 'ftp'|'sftp'|'ftpd'
 * @phpstan-type StreamDirection 'upstream'|'downstream'
 * @phpstan-type Type 'latency'|'bandwidth'|'slow_close'|'timeout'|'reset_peer'|'slicer'|'limit_data'
 * @phpstan-type Attributes array{latency?: int, jitter?: int, rate?: int, delay?: int}
 * @phpstan-type Toxic array{name?: string, type: Type, stream?: StreamDirection, toxicity?: float, attributes: Attributes}
 */
final class ToxiproxyManagement
{
    /** @var Client */
    private $apiClient;

    public function __construct(Client $apiClient)
    {
        $this->apiClient = $apiClient;
    }

    public static function forServer(string $apiUri = 'http://localhost:8474'): self
    {
        return new self(
            new Client(
                [
                    'base_uri' => $apiUri,
                    'base_url' => $apiUri, // Compatibility with older versions of Guzzle
                ]
            )
        );
    }

    public function removeAllToxics(): void
    {
        $this->apiClient->post('/reset');
    }

    /**
     * Simulates a peer reset on the client->server direction.
     *
     * @param RegisteredProxies $proxyName
     */
    public function resetPeerOnRequest(
        string $proxyName,
        int $timeoutInMilliseconds
    ): void {
        $configuration = [
            'type' => 'reset_peer',
            'stream' => 'upstream',
            'attributes' => ['timeout' => $timeoutInMilliseconds],
        ];

        $this->addToxic($proxyName, $configuration);
    }

    /**
     * Registers a network toxic for the given proxy.
     *
     * @param RegisteredProxies $proxyName
     * @param Toxic $configuration
     */
    private function addToxic(string $proxyName, array $configuration): void
    {
        $this->apiClient->post('/proxies/' . $proxyName . '/toxics', ['json' => $configuration]);
    }
}


================================================
FILE: src/AdapterTestUtilities/composer.json
================================================
{
    "name": "league/flysystem-adapter-test-utilities",
    "description": "Flysystem utilities for testing adapters.",
    "keywords": ["filesystem", "flysystem", "adapter", "test", "utilities"],
    "minimum-stability": "dev",
    "prefer-stable": true,
    "autoload": {
        "psr-4": {
            "League\\Flysystem\\AdapterTestUtilities\\": ""
        },
        "files": [
            "test-functions.php"
        ]
    },
    "require": {
        "php": "^8.0.2",
        "league/flysystem": "^3.0.0"
    },
    "license": "MIT",
    "authors": [
        {
            "name": "Frank de Jonge",
            "email": "info@frankdejonge.nl"
        }
    ]
}


================================================
FILE: src/AdapterTestUtilities/test-functions.php
================================================
<?php

declare(strict_types=1);

function return_mocked_value(string $name)
{
    return array_shift($_ENV['__FM:RETURNS:' . $name]);
}

function reset_function_mocks()
{
    foreach (array_keys($_ENV) as $name) {
        if (is_string($name) && substr($name, 0, 5) === '__FM:') {
            unset($_ENV[$name]);
        }
    }
}

function mock_function(string $name, ...$returns)
{
    $_ENV['__FM:FUNC_IS_MOCKED:' . $name] = 'yes';
    $_ENV['__FM:RETURNS:' . $name] = $returns;
}

function is_mocked(string $name)
{
    return ($_ENV['__FM:FUNC_IS_MOCKED:' . $name] ?? 'no') === 'yes';
}

function stream_with_contents(string $contents)
{
    $stream = fopen('php://temp', 'w+b');
    fwrite($stream, $contents);
    rewind($stream);

    return $stream;
}

function delete_directory(string $dir): void
{
    if ( ! is_dir($dir)) {
        return;
    }

    foreach ((array) scandir($dir) as $file) {
        if ('.' === $file || '..' === $file) {
            continue;
        }
        if (is_dir("$dir/$file")) {
            delete_directory("$dir/$file");
        } else {
            unlink("$dir/$file");
        }
    }
    rmdir($dir);
}


================================================
FILE: src/AdapterTestUtilities/test_files/unknown-mime-type.md5
================================================
141d15ed35fc57dcc3c72bba881742b1

================================================
FILE: src/AsyncAwsS3/.gitattributes
================================================
* text=auto

.github export-ignore
.gitattributes export-ignore
.gitignore export-ignore
**/*Test.php export-ignore
**/*Stub.php export-ignore
README.md export-ignore


================================================
FILE: src/AsyncAwsS3/.github/workflows/close-subsplit-prs.yaml
================================================
---
name: Close sub-split PRs

on:
  push:
    branches:
      - 2.x
      - 3.x
  pull_request:
    branches:
      - 2.x
      - 3.x
  schedule:
    - cron: '30 7 * * *'

jobs:
  close_subsplit_prs:
    runs-on: ubuntu-latest
    name: Close sub-split PRs
    steps:
      - uses: frankdejonge/action-close-subsplit-pr@0.1.0
        with:
          close_pr: 'yes'
          target_branch_match: '^(?!master).+$'
          message: |
            Hi :wave:,
            
            Thank you for contributing to Flysystem. Unfortunately, you've sent a PR to a read-only sub-split repository. 

            All pull requests should be directed towards: https://github.com/thephpleague/flysystem


================================================
FILE: src/AsyncAwsS3/AsyncAwsS3Adapter.php
================================================
<?php

declare(strict_types=1);

namespace League\Flysystem\AsyncAwsS3;

use AsyncAws\Core\Exception\Http\ClientException;
use AsyncAws\Core\Stream\ResultStream;
use AsyncAws\S3\Input\GetObjectRequest;
use AsyncAws\S3\Result\HeadObjectOutput;
use AsyncAws\S3\S3Client;
use AsyncAws\S3\ValueObject\AwsObject;
use AsyncAws\S3\ValueObject\CommonPrefix;
use AsyncAws\S3\ValueObject\ObjectIdentifier;
use AsyncAws\SimpleS3\SimpleS3Client;
use DateTimeImmutable;
use DateTimeInterface;
use Generator;
use League\Flysystem\ChecksumAlgoIsNotSupported;
use League\Flysystem\ChecksumProvider;
use League\Flysystem\Config;
use League\Flysystem\DirectoryAttributes;
use League\Flysystem\FileAttributes;
use League\Flysystem\FilesystemAdapter;
use League\Flysystem\PathPrefixer;
use League\Flysystem\StorageAttributes;
use League\Flysystem\UnableToCheckDirectoryExistence;
use League\Flysystem\UnableToCheckFileExistence;
use League\Flysystem\UnableToCopyFile;
use League\Flysystem\UnableToCreateDirectory;
use League\Flysystem\UnableToDeleteDirectory;
use League\Flysystem\UnableToDeleteFile;
use League\Flysystem\UnableToGeneratePublicUrl;
use League\Flysystem\UnableToGenerateTemporaryUrl;
use League\Flysystem\UnableToListContents;
use League\Flysystem\UnableToMoveFile;
use League\Flysystem\UnableToProvideChecksum;
use League\Flysystem\UnableToReadFile;
use League\Flysystem\UnableToRetrieveMetadata;
use League\Flysystem\UnableToSetVisibility;
use League\Flysystem\UnableToWriteFile;
use League\Flysystem\UrlGeneration\PublicUrlGenerator;
use League\Flysystem\UrlGeneration\TemporaryUrlGenerator;
use League\Flysystem\Visibility;
use League\MimeTypeDetection\FinfoMimeTypeDetector;
use League\MimeTypeDetection\MimeTypeDetector;
use Throwable;
use function trim;

class AsyncAwsS3Adapter implements FilesystemAdapter, PublicUrlGenerator, ChecksumProvider, TemporaryUrlGenerator
{
    /**
     * @var string[]
     */
    public const AVAILABLE_OPTIONS = [
        'ACL',
        'CacheControl',
        'ContentDisposition',
        'ContentEncoding',
        'ContentLength',
        'ContentType',
        'ContentMD5',
        'Expires',
        'GrantFullControl',
        'GrantRead',
        'GrantReadACP',
        'GrantWriteACP',
        'Metadata',
        'MetadataDirective',
        'RequestPayer',
        'SSECustomerAlgorithm',
        'SSECustomerKey',
        'SSECustomerKeyMD5',
        'SSEKMSKeyId',
        'ServerSideEncryption',
        'StorageClass',
        'Tagging',
        'WebsiteRedirectLocation',
        'ChecksumAlgorithm',
        'CopySourceSSECustomerAlgorithm',
        'CopySourceSSECustomerKey',
        'CopySourceSSECustomerKeyMD5',
    ];

    /**
     * @var string[]
     */
    protected const EXTRA_METADATA_FIELDS = [
        'Metadata',
        'StorageClass',
        'ETag',
        'VersionId',
    ];

    private PathPrefixer $prefixer;
    private VisibilityConverter $visibility;
    private MimeTypeDetector $mimeTypeDetector;

    /**
     * @var array|string[]
     */
    private array $forwardedOptions;

    /**
     * @var array|string[]
     */
    private array $metadataFields;

    /**
     * @param S3Client|SimpleS3Client $client Uploading of files larger than 5GB is only supported with SimpleS3Client
     */
    public function __construct(
        private S3Client $client,
        private string $bucket,
        string $prefix = '',
        ?VisibilityConverter $visibility = null,
        ?MimeTypeDetector $mimeTypeDetector = null,
        array $forwardedOptions = self::AVAILABLE_OPTIONS,
        array $metadataFields = self::EXTRA_METADATA_FIELDS,
    ) {
        $this->prefixer = new PathPrefixer($prefix);
        $this->visibility = $visibility ?? new PortableVisibilityConverter();
        $this->mimeTypeDetector = $mimeTypeDetector ?? new FinfoMimeTypeDetector();
        $this->forwardedOptions = $forwardedOptions;
        $this->metadataFields = $metadataFields;
    }

    public function fileExists(string $path): bool
    {
        try {
            return $this->client->objectExists(
                [
                    'Bucket' => $this->bucket,
                    'Key' => $this->prefixer->prefixPath($path),
                ]
            )->isSuccess();
        } catch (ClientException $e) {
            throw UnableToCheckFileExistence::forLocation($path, $e);
        }
    }

    public function write(string $path, string $contents, Config $config): void
    {
        $this->upload($path, $contents, $config);
    }

    public function writeStream(string $path, $contents, Config $config): void
    {
        $this->upload($path, $contents, $config);
    }

    public function read(string $path): string
    {
        $body = $this->readObject($path);

        return $body->getContentAsString();
    }

    public function readStream(string $path)
    {
        $body = $this->readObject($path);

        return $body->getContentAsResource();
    }

    public function delete(string $path): void
    {
        $arguments = ['Bucket' => $this->bucket, 'Key' => $this->prefixer->prefixPath($path)];

        try {
            $this->client->deleteObject($arguments);
        } catch (Throwable $exception) {
            throw UnableToDeleteFile::atLocation($path, '', $exception);
        }
    }

    public function deleteDirectory(string $path): void
    {
        $prefix = $this->prefixer->prefixDirectoryPath($path);
        $prefix = ltrim($prefix, '/');

        $objects = [];
        $params = ['Bucket' => $this->bucket, 'Prefix' => $prefix];

        try {
            $result = $this->client->listObjectsV2($params);
            /** @var AwsObject $item */
            foreach ($result->getContents() as $item) {
                $key = $item->getKey();
                if (null !== $key) {
                    $objects[] = $this->createObjectIdentifierForXmlRequest($key);
                }
            }

            if (empty($objects)) {
                return;
            }

            foreach (array_chunk($objects, 1000) as $chunk) {
                $this->client->deleteObjects([
                    'Bucket' => $this->bucket,
                    'Delete' => ['Objects' => $chunk],
                ]);
            }
        } catch (\Throwable $e) {
            throw UnableToDeleteDirectory::atLocation($path, $e->getMessage(), $e);
        }
    }

    public function createDirectory(string $path, Config $config): void
    {
        $defaultVisibility = $config->get(Config::OPTION_DIRECTORY_VISIBILITY, $this->visibility->defaultForDirectories());
        $config = $config->withDefaults([Config::OPTION_VISIBILITY => $defaultVisibility]);

        try {
            $this->upload(rtrim($path, '/') . '/', '', $config);
        } catch (Throwable $e) {
            throw UnableToCreateDirectory::dueToFailure($path, $e);
        }
    }

    public function setVisibility(string $path, string $visibility): void
    {
        $arguments = [
            'Bucket' => $this->bucket,
            'Key' => $this->prefixer->prefixPath($path),
            'ACL' => $this->visibility->visibilityToAcl($visibility),
        ];

        try {
            $this->client->putObjectAcl($arguments);
        } catch (Throwable $exception) {
            throw UnableToSetVisibility::atLocation($path, $exception->getMessage(), $exception);
        }
    }

    public function visibility(string $path): FileAttributes
    {
        $arguments = ['Bucket' => $this->bucket, 'Key' => $this->prefixer->prefixPath($path)];

        try {
            $result = $this->client->getObjectAcl($arguments);
            $grants = $result->getGrants();
        } catch (Throwable $exception) {
            throw UnableToRetrieveMetadata::visibility($path, $exception->getMessage(), $exception);
        }

        $visibility = $this->visibility->aclToVisibility($grants);

        return new FileAttributes($path, null, $visibility);
    }

    public function mimeType(string $path): FileAttributes
    {
        $attributes = $this->fetchFileMetadata($path, FileAttributes::ATTRIBUTE_MIME_TYPE);

        if (null === $attributes->mimeType()) {
            throw UnableToRetrieveMetadata::mimeType($path);
        }

        return $attributes;
    }

    public function lastModified(string $path): FileAttributes
    {
        $attributes = $this->fetchFileMetadata($path, FileAttributes::ATTRIBUTE_LAST_MODIFIED);

        if (null === $attributes->lastModified()) {
            throw UnableToRetrieveMetadata::lastModified($path);
        }

        return $attributes;
    }

    public function fileSize(string $path): FileAttributes
    {
        $attributes = $this->fetchFileMetadata($path, FileAttributes::ATTRIBUTE_FILE_SIZE);

        if (null === $attributes->fileSize()) {
            throw UnableToRetrieveMetadata::fileSize($path);
        }

        return $attributes;
    }

    public function directoryExists(string $path): bool
    {
        try {
            $prefix = $this->prefixer->prefixDirectoryPath($path);
            $options = ['Bucket' => $this->bucket, 'Prefix' => $prefix, 'MaxKeys' => 1, 'Delimiter' => '/'];

            return $this->client->listObjectsV2($options)->getKeyCount() > 0;
        } catch (Throwable $exception) {
            throw UnableToCheckDirectoryExistence::forLocation($path, $exception);
        }
    }

    public function listContents(string $path, bool $deep): iterable
    {
        $path = trim($path, '/');
        $prefix = trim($this->prefixer->prefixPath($path), '/');
        $prefix = $prefix === '' ? '' : $prefix . '/';
        $options = ['Bucket' => $this->bucket, 'Prefix' => $prefix];

        if (false === $deep) {
            $options['Delimiter'] = '/';
        }

        try {
            $listing = $this->retrievePaginatedListing($options);

            foreach ($listing as $item) {
                $item = $this->mapS3ObjectMetadata($item);

                if ($item->path() === $path) {
                    continue;
                }

                yield $item;
            }
        } catch (\Throwable $e) {
            throw UnableToListContents::atLocation($path, $deep, $e);
        }
    }

    public function move(string $source, string $destination, Config $config): void
    {
        if ($source === $destination) {
            return;
        }

        try {
            $this->copy($source, $destination, $config);
            $this->delete($source);
        } catch (Throwable $exception) {
            throw UnableToMoveFile::fromLocationTo($source, $destination, $exception);
        }
    }

    public function copy(string $source, string $destination, Config $config): void
    {
        if ($source === $destination) {
            return;
        }

        try {
            $visibility = $config->get(Config::OPTION_VISIBILITY);

            if ($visibility === null && $config->get(Config::OPTION_RETAIN_VISIBILITY, true)) {
                $visibility = $this->visibility($source)->visibility();
            }
        } catch (Throwable $exception) {
            throw UnableToCopyFile::fromLocationTo($source, $destination, $exception);
        }

        $arguments = [
            'ACL' => $this->visibility->visibilityToAcl($visibility ?: 'private'),
            'Bucket' => $this->bucket,
            'Key' => $this->prefixer->prefixPath($destination),
            'CopySource' => rawurlencode($this->bucket . '/' . $this->prefixer->prefixPath($source)),
        ];

        try {
            $this->client->copyObject($arguments);
        } catch (Throwable $exception) {
            throw UnableToCopyFile::fromLocationTo($source, $destination, $exception);
        }
    }

    /**
     * @param string|resource $body
     */
    private function upload(string $path, $body, Config $config): void
    {
        $key = $this->prefixer->prefixPath($path);
        $acl = $this->determineAcl($config);
        $options = $this->createOptionsFromConfig($config);
        $shouldDetermineMimetype = '' !== $body && ! \array_key_exists('ContentType', $options);

        if ($shouldDetermineMimetype && $mimeType = $this->mimeTypeDetector->detectMimeType($key, $body)) {
            $options['ContentType'] = $mimeType;
        }

        try {
            if ($this->client instanceof SimpleS3Client) {
                // Supports upload of files larger than 5GB
                $this->client->upload($this->bucket, $key, $body, array_merge($options, ['ACL' => $acl]));
            } else {
                $this->client->putObject(array_merge($options, [
                    'Bucket' => $this->bucket,
                    'Key' => $key,
                    'Body' => $body,
                    'ACL' => $acl,
                ]));
            }
        } catch (Throwable $exception) {
            throw UnableToWriteFile::atLocation($path, $exception->getMessage(), $exception);
        }
    }

    private function determineAcl(Config $config): string
    {
        $visibility = (string) $config->get(Config::OPTION_VISIBILITY, Visibility::PRIVATE);

        return $this->visibility->visibilityToAcl($visibility);
    }

    private function createOptionsFromConfig(Config $config): array
    {
        $options = [];

        foreach ($this->forwardedOptions as $option) {
            $value = $config->get($option, '__NOT_SET__');

            if ('__NOT_SET__' !== $value) {
                $options[$option] = $value;
            }
        }

        return $options;
    }

    private function fetchFileMetadata(string $path, string $type): FileAttributes
    {
        $arguments = ['Bucket' => $this->bucket, 'Key' => $this->prefixer->prefixPath($path)];

        try {
            $result = $this->client->headObject($arguments);
            $result->resolve();
        } catch (Throwable $exception) {
            throw UnableToRetrieveMetadata::create($path, $type, $exception->getMessage(), $exception);
        }

        $attributes = $this->mapS3ObjectMetadata($result, $path);

        if ( ! $attributes instanceof FileAttributes) {
            throw UnableToRetrieveMetadata::create($path, $type, 'Unable to retrieve file attributes, directory attributes received.');
        }

        return $attributes;
    }

    /**
     * @param HeadObjectOutput|AwsObject|CommonPrefix $item
     */
    private function mapS3ObjectMetadata($item, ?string $path = null): StorageAttributes
    {
        if (null === $path) {
            if ($item instanceof AwsObject) {
                $path = $this->prefixer->stripPrefix($item->getKey() ?? '');
            } elseif ($item instanceof CommonPrefix) {
                $path = $this->prefixer->stripPrefix($item->getPrefix() ?? '');
            } else {
                throw new \RuntimeException(sprintf('Argument 2 of "%s" cannot be null when $item is not instance of "%s" or %s', __METHOD__, AwsObject::class, CommonPrefix::class));
            }
        }

        if ('/' === substr($path, -1)) {
            return new DirectoryAttributes(rtrim($path, '/'));
        }

        $mimeType = null;
        $fileSize = null;
        $lastModified = null;
        $dateTime = null;
        $metadata = [];

        if ($item instanceof AwsObject) {
            $dateTime = $item->getLastModified();
            $fileSize = $item->getSize();
        } elseif ($item instanceof CommonPrefix) {
            // No data available
        } elseif ($item instanceof HeadObjectOutput) {
            $mimeType = $item->getContentType();
            $fileSize = $item->getContentLength();
            $dateTime = $item->getLastModified();
            $metadata = $this->extractExtraMetadata($item);
        } else {
            throw new \RuntimeException(sprintf('Object of class "%s" is not supported in %s()', \get_class($item), __METHOD__));
        }

        if ($dateTime instanceof \DateTimeInterface) {
            $lastModified = $dateTime->getTimestamp();
        }

        return new FileAttributes($path, $fileSize !== null ? (int) $fileSize : null, null, $lastModified, $mimeType, $metadata);
    }

    /**
     * @param HeadObjectOutput $metadata
     */
    private function extractExtraMetadata($metadata): array
    {
        $extracted = [];

        foreach ($this->metadataFields as $field) {
            $method = 'get' . $field;
            if ( ! method_exists($metadata, $method)) {
                continue;
            }
            $value = $metadata->$method();
            if (null !== $value) {
                $extracted[$field] = $value;
            }
        }

        return $extracted;
    }

    private function retrievePaginatedListing(array $options): Generator
    {
        $result = $this->client->listObjectsV2($options);

        foreach ($result as $item) {
            yield $item;
        }
    }

    private function readObject(string $path): ResultStream
    {
        $options = ['Bucket' => $this->bucket, 'Key' => $this->prefixer->prefixPath($path)];

        try {
            return $this->client->getObject($options)->getBody();
        } catch (Throwable $exception) {
            throw UnableToReadFile::fromLocation($path, $exception->getMessage(), $exception);
        }
    }

    private function createObjectIdentifierForXmlRequest(string $key): ObjectIdentifier
    {
        $escapedKey = htmlentities($key, ENT_XML1 | ENT_QUOTES, 'UTF-8');

        if ($escapedKey === '') {
            throw new \RuntimeException(sprintf('Cannot escape key "%s" for XML request, htmlentities() returned an empty string.', $key));
        }

        return new ObjectIdentifier(['Key' => $escapedKey]);
    }

    public function publicUrl(string $path, Config $config): string
    {
        if ( ! $this->client instanceof SimpleS3Client) {
            throw UnableToGeneratePublicUrl::noGeneratorConfigured($path, 'Client needs to be instance of SimpleS3Client');
        }

        try {
            return $this->client->getUrl($this->bucket, $this->prefixer->prefixPath($path));
        } catch (Throwable $exception) {
            throw UnableToGeneratePublicUrl::dueToError($path, $exception);
        }
    }

    public function checksum(string $path, Config $config): string
    {
        $algo = $config->get('checksum_algo', 'etag');

        if ($algo !== 'etag') {
            throw new ChecksumAlgoIsNotSupported();
        }

        try {
            $metadata = $this->fetchFileMetadata($path, 'checksum')->extraMetadata();
        } catch (UnableToRetrieveMetadata $exception) {
            throw new UnableToProvideChecksum($exception->reason(), $path, $exception);
        }

        if ( ! isset($metadata['ETag'])) {
            throw new UnableToProvideChecksum('ETag header not available.', $path);
        }

        return trim($metadata['ETag'], '"');
    }

    public function temporaryUrl(string $path, DateTimeInterface $expiresAt, Config $config): string
    {
        try {
            $request = new GetObjectRequest([
                'Bucket' => $this->bucket,
                'Key' => $this->prefixer->prefixPath($path),
            ] + $config->get('get_object_options', []));

            return $this->client->presign($request, DateTimeImmutable::createFromInterface($expiresAt));
        } catch (Throwable $exception) {
            throw UnableToGenerateTemporaryUrl::dueToError($path, $exception);
        }
    }
}


================================================
FILE: src/AsyncAwsS3/AsyncAwsS3AdapterTest.php
================================================
<?php

declare(strict_types=1);

namespace League\Flysystem\AsyncAwsS3;

use AsyncAws\Core\Exception\Http\ClientException;
use AsyncAws\Core\Exception\Http\NetworkException;
use AsyncAws\Core\Test\Http\SimpleMockedResponse;
use AsyncAws\Core\Test\ResultMockFactory;
use AsyncAws\S3\Result\HeadObjectOutput;
use AsyncAws\S3\Result\ListObjectsV2Output;
use AsyncAws\S3\Result\PutObjectOutput;
use AsyncAws\S3\S3Client;
use AsyncAws\S3\ValueObject\AwsObject;
use AsyncAws\SimpleS3\SimpleS3Client;
use Exception;
use League\Flysystem\AdapterTestUtilities\FilesystemAdapterTestCase;
use League\Flysystem\AwsS3V3\AwsS3V3Adapter;
use League\Flysystem\ChecksumAlgoIsNotSupported;
use League\Flysystem\Config;
use League\Flysystem\FileAttributes;
use League\Flysystem\FilesystemAdapter;
use League\Flysystem\StorageAttributes;
use League\Flysystem\UnableToCheckFileExistence;
use League\Flysystem\UnableToDeleteDirectory;
use League\Flysystem\UnableToDeleteFile;
use League\Flysystem\UnableToListContents;
use League\Flysystem\UnableToMoveFile;
use League\Flysystem\UnableToRetrieveMetadata;
use League\Flysystem\UnableToWriteFile;
use League\Flysystem\Visibility;
use function getenv;
use function iterator_to_array;

/**
 * @group aws
 */
class AsyncAwsS3AdapterTest extends FilesystemAdapterTestCase
{
    /**
     * @var bool
     */
    private $shouldCleanUp = false;

    /**
     * @var string
     */
    private static $adapterPrefix = 'test-prefix';

    /**
     * @var S3Client|null
     */
    private static $s3Client;

    /**
     * @var S3ClientStub
     */
    private static $stubS3Client;

    private static function awsConfig(): array
    {
        $key = getenv('FLYSYSTEM_AWS_S3_KEY');
        $secret = getenv('FLYSYSTEM_AWS_S3_SECRET');
        $region = getenv('FLYSYSTEM_AWS_S3_REGION') ?: 'eu-central-1';

        if ( ! $key || ! $secret) {
            self::markTestSkipped('No AWS credentials present for testing.');
        }

        return [
            'accessKeyId' => $key,
            'accessKeySecret' => $secret,
            'region' => $region,
        ];
    }

    protected function setUp(): void
    {
        parent::setUp();
        $this->retryOnException(NetworkException::class);
    }

    public static function setUpBeforeClass(): void
    {
        static::$adapterPrefix = 'ci/' . bin2hex(random_bytes(10));
    }

    protected function tearDown(): void
    {
        if ( ! $this->shouldCleanUp) {
            return;
        }

        $adapter = $this->adapter();
        $adapter->deleteDirectory('/');
        /** @var StorageAttributes[] $listing */
        $listing = $adapter->listContents('', false);

        foreach ($listing as $item) {
            if ($item->isFile()) {
                $adapter->delete($item->path());
            } else {
                $adapter->deleteDirectory($item->path());
            }
        }
    }

    private static function s3Client(): S3Client
    {
        if (static::$s3Client instanceof S3Client) {
            return static::$s3Client;
        }

        $bucket = getenv('FLYSYSTEM_AWS_S3_BUCKET');

        if ( ! $bucket) {
            self::markTestSkipped('No AWS credentials present for testing.');
        }

        static::$s3Client = new SimpleS3Client(self::awsConfig());

        return static::$s3Client;
    }

    /**
     * @test
     */
    public function specifying_a_custom_checksum_algo_is_not_supported(): void
    {
        /** @var AwsS3V3Adapter $adapter */
        $adapter = $this->adapter();

        $this->expectException(ChecksumAlgoIsNotSupported::class);

        $adapter->checksum('something', new Config(['checksum_algo' => 'md5']));
    }

    /**
     * @test
     *
     * @see https://github.com/thephpleague/flysystem-aws-s3-v3/issues/287
     */
    public function issue_287(): void
    {
        $adapter = $this->adapter();
        $adapter->write('KmFVvKqo/QLMExy2U/620ff60c8a154.pdf', 'pdf content', new Config());

        self::assertTrue($adapter->directoryExists('KmFVvKqo'));
    }

    /**
     * @test
     */
    public function writing_with_a_specific_mime_type(): void
    {
        $adapter = $this->adapter();
        $adapter->write('some/path.txt', 'contents', new Config(['ContentType' => 'text/plain+special']));
        $mimeType = $adapter->mimeType('some/path.txt')->mimeType();
        $this->assertEquals('text/plain+special', $mimeType);
    }

    /**
     * @test
     */
    public function listing_contents_recursive(): void
    {
        $adapter = $this->adapter();
        $adapter->write('something/0/here.txt', 'contents', new Config());
        $adapter->write('something/1/also/here.txt', 'contents', new Config());

        $contents = iterator_to_array($adapter->listContents('', true));

        $this->assertCount(2, $contents);
        $this->assertContainsOnlyInstancesOf(FileAttributes::class, $contents);
        /** @var FileAttributes $file */
        $file = $contents[0];
        $this->assertEquals('something/0/here.txt', $file->path());
        /** @var FileAttributes $file */
        $file = $contents[1];
        $this->assertEquals('something/1/also/here.txt', $file->path());
    }

    /**
     * @test
     */
    public function failing_to_delete_while_moving(): void
    {
        $adapter = $this->adapter();
        $adapter->write('source.txt', 'contents to be copied', new Config());
        static::$stubS3Client->throwExceptionWhenExecutingCommand('CopyObject');

        $this->expectException(UnableToMoveFile::class);

        $adapter->move('source.txt', 'destination.txt', new Config());
    }

    /**
     * @test
     */
    public function failing_to_delete_a_file(): void
    {
        $adapter = $this->adapter();
        static::$stubS3Client->throwExceptionWhenExecutingCommand('DeleteObject');

        $this->expectException(UnableToDeleteFile::class);

        $adapter->delete('path.txt');
    }

    /**
     * @test
     */
    public function delete_directory_replaces_special_characters_by_xml_entity_codes(): void
    {
        $this->runScenario(function () {
            $directory = 'to-delete';
            $object = sprintf('/%s/\'\"&<>.txt', $directory);

            $adapter = $this->adapter();
            $adapter->write(
                $object,
                '',
                new Config()
            );

            $adapter->deleteDirectory($directory);

            $this->assertFalse($adapter->fileExists($object));
            $this->assertFalse($adapter->directoryExists($directory));
        });
    }

    /**
     * @test
     */
    public function delete_directory_throws_exception_if_object_key_can_not_be_escaped_correctly(): void
    {
        $listObjectsMock = $this->getMockBuilder(ListObjectsV2Output::class)
            ->disableOriginalConstructor()
            ->onlyMethods(['getContents'])
            ->getMock();

        $listObjectsMock->expects(self::once())
            ->method('getContents')
            ->willReturn([new AwsObject(['Key' => "\x8F.txt"])]);

        $s3Client = $this->getMockBuilder(S3Client::class)
            ->disableOriginalConstructor()
            ->onlyMethods(['ListObjectsV2'])
            ->getMock();

        $s3Client->expects(self::once())
            ->method('ListObjectsV2')
            ->willReturn($listObjectsMock);

        $filesystem = new AsyncAwsS3Adapter($s3Client, 'my-bucket');

        $this->expectException(UnableToDeleteDirectory::class);
        $this->expectExceptionMessageMatches('/htmlentities\(\) returned an empty string/');

        $filesystem->deleteDirectory('directory/containing/objects/with/un-escapable/key');
    }

    /**
     * @test
     */
    public function fetching_unknown_mime_type_of_a_file(): void
    {
        $this->adapter();
        $result = ResultMockFactory::create(HeadObjectOutput::class, []);
        static::$stubS3Client->stageResultForCommand('HeadObject', $result);

        parent::fetching_unknown_mime_type_of_a_file();
    }

    /**
     * @test
     *
     * @dataProvider dpFailingMetadataGetters
     */
    public function failing_to_retrieve_metadata(Exception $exception, string $getterName): void
    {
        $adapter = $this->adapter();
        $result = ResultMockFactory::create(HeadObjectOutput::class, []);
        static::$stubS3Client->stageResultForCommand('HeadObject', $result);

        $this->expectExceptionObject($exception);

        $adapter->{$getterName}('filename.txt');
    }

    public static function dpFailingMetadataGetters(): iterable
    {
        yield "mimeType" => [UnableToRetrieveMetadata::mimeType('filename.txt'), 'mimeType'];
        yield "lastModified" => [UnableToRetrieveMetadata::lastModified('filename.txt'), 'lastModified'];
        yield "fileSize" => [UnableToRetrieveMetadata::fileSize('filename.txt'), 'fileSize'];
    }

    /**
     * @test
     */
    public function failing_to_check_for_file_existence(): void
    {
        $adapter = $this->adapter();
        $exception = new ClientException(new SimpleMockedResponse());
        static::$stubS3Client->throwExceptionWhenExecutingCommand('ObjectExists', $exception);

        $this->expectException(UnableToCheckFileExistence::class);

        $adapter->fileExists('something-that-does-exist.txt');
    }

    /**
     * @test
     */
    public function configuring_http_streaming_via_options(): void
    {
        $adapter = $this->useAdapter($this->createFilesystemAdapter());
        $this->givenWeHaveAnExistingFile('path.txt');

        $resource = $adapter->readStream('path.txt');
        $metadata = stream_get_meta_data($resource);
        fclose($resource);

        $this->assertTrue($metadata['seekable']);
    }

    /**
     * @test
     */
    public function write_with_s3_client(): void
    {
        $file = 'foo/bar.txt';
        $prefix = 'all-files';
        $bucket = 'foobar';
        $contents = 'contents';

        $s3Client = $this->getMockBuilder(S3Client::class)
            ->disableOriginalConstructor()
            ->onlyMethods(['putObject'])
            ->getMock();
        $s3Client->expects(self::once())
            ->method('putObject')
            ->with(self::callback(function (array $input) use ($file, $prefix, $bucket, $contents) {
                if ($input['Key'] !== $prefix . '/' . $file) {
                    return false;
                }
                if ($contents !== $input['Body']) {
                    return false;
                }
                if ($input['Bucket'] !== $bucket) {
                    return false;
                }

                return true;
            }))->willReturn(ResultMockFactory::create(PutObjectOutput::class));

        $filesystem = new AsyncAwsS3Adapter($s3Client, $bucket, $prefix);
        $filesystem->write($file, $contents, new Config());
    }

    /**
     * @test
     */
    public function write_with_simple_s3_client(): void
    {
        $file = 'foo/bar.txt';
        $prefix = 'all-files';
        $bucket = 'foobar';
        $contents = 'contents';

        $s3Client = $this->getMockBuilder(SimpleS3Client::class)
            ->disableOriginalConstructor()
            ->onlyMethods(['upload', 'putObject'])
            ->getMock();
        $s3Client->expects(self::never())->method('putObject');
        $s3Client->expects(self::once())
            ->method('upload')
            ->with($bucket, $prefix . '/' . $file, $contents);

        $filesystem = new AsyncAwsS3Adapter($s3Client, $bucket, $prefix);
        $filesystem->write($file, $contents, new Config());
    }

    /**
     * @test
     */
    public function failing_to_write_a_file(): void
    {
        $adapter = $this->adapter();
        static::$stubS3Client->throwExceptionWhenExecutingCommand('PutObject');
        $this->expectException(UnableToWriteFile::class);

        $adapter->write('foo/bar.txt', 'contents', new Config());
    }

    /**
     * @test
     */
    public function moving_a_file_with_visibility(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();
            $adapter->write(
                'source.txt',
                'contents to be copied',
                new Config([Config::OPTION_VISIBILITY => Visibility::PUBLIC])
            );
            $adapter->move('source.txt', 'destination.txt', new Config([Config::OPTION_VISIBILITY => Visibility::PRIVATE]));
            $this->assertFalse(
                $adapter->fileExists('source.txt'),
                'After moving a file should no longer exist in the original location.'
            );
            $this->assertTrue(
                $adapter->fileExists('destination.txt'),
                'After moving, a file should be present at the new location.'
            );
            $this->assertEquals(Visibility::PRIVATE, $adapter->visibility('destination.txt')->visibility());
            $this->assertEquals('contents to be copied', $adapter->read('destination.txt'));
        });
    }

    /**
     * @test
     */
    public function copying_a_file_with_visibility(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();
            $adapter->write(
                'source.txt',
                'contents to be copied',
                new Config([Config::OPTION_VISIBILITY => Visibility::PUBLIC])
            );

            $adapter->copy('source.txt', 'destination.txt', new Config([Config::OPTION_VISIBILITY => Visibility::PRIVATE]));

            $this->assertTrue($adapter->fileExists('source.txt'));
            $this->assertTrue($adapter->fileExists('destination.txt'));
            $this->assertEquals(Visibility::PRIVATE, $adapter->visibility('destination.txt')->visibility());
            $this->assertEquals('contents to be copied', $adapter->read('destination.txt'));
        });
    }

    /**
     * @test
     */
    public function copying_a_file_with_non_ascii_characters(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();
            $adapter->write(
                'ıÇöü🤔.txt',
                'contents to be copied',
                new Config()
            );

            $adapter->copy('ıÇöü🤔.txt', 'ıÇöü🤔_copy.txt', new Config());

            $this->assertTrue($adapter->fileExists('ıÇöü🤔.txt'));
            $this->assertTrue($adapter->fileExists('ıÇöü🤔_copy.txt'));
            $this->assertEquals('contents to be copied', $adapter->read('ıÇöü🤔_copy.txt'));
        });
    }

    /**
     * @test
     */
    public function top_level_directory_excluded_from_listing(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();
            $adapter->write('directory/file.txt', '', new Config());
            $adapter->createDirectory('empty', new Config());
            $adapter->createDirectory('nested/nested', new Config());
            $listing1 = iterator_to_array($adapter->listContents('directory', true));
            $listing2 = iterator_to_array($adapter->listContents('empty', true));
            $listing3 = iterator_to_array($adapter->listContents('nested', true));

            self::assertCount(1, $listing1);
            self::assertCount(0, $listing2);
            self::assertCount(1, $listing3);
        });
    }

    /**
     * @test
     */
    public function failing_to_list_contents(): void
    {
        $adapter = $this->adapter();
        static::$stubS3Client->throwExceptionWhenExecutingCommand('ListObjectsV2');

        $this->expectException(UnableToListContents::class);

        iterator_to_array($adapter->listContents('/path', false));
    }

    protected static function createFilesystemAdapter(): FilesystemAdapter
    {
        static::$stubS3Client = new S3ClientStub(static::s3Client(), self::awsConfig());
        /** @var string $bucket */
        $bucket = getenv('FLYSYSTEM_AWS_S3_BUCKET');
        $prefix = getenv('FLYSYSTEM_AWS_S3_PREFIX') ?: static::$adapterPrefix;

        return new AsyncAwsS3Adapter(static::$stubS3Client, $bucket, $prefix, null, null);
    }
}


================================================
FILE: src/AsyncAwsS3/LICENSE
================================================
Copyright (c) 2013-2026 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.


================================================
FILE: src/AsyncAwsS3/PortableVisibilityConverter.php
================================================
<?php

declare(strict_types=1);

namespace League\Flysystem\AsyncAwsS3;

use AsyncAws\S3\ValueObject\Grant;
use League\Flysystem\Visibility;

class PortableVisibilityConverter implements VisibilityConverter
{
    private const PUBLIC_GRANTEE_URI = 'http://acs.amazonaws.com/groups/global/AllUsers';
    private const PUBLIC_GRANTS_PERMISSION = 'READ';
    private const PUBLIC_ACL = 'public-read';
    private const PRIVATE_ACL = 'private';

    /**
     * @var string
     */
    private $defaultForDirectories;

    public function __construct(string $defaultForDirectories = Visibility::PUBLIC)
    {
        $this->defaultForDirectories = $defaultForDirectories;
    }

    public function visibilityToAcl(string $visibility): string
    {
        if (Visibility::PUBLIC === $visibility) {
            return self::PUBLIC_ACL;
        }

        return self::PRIVATE_ACL;
    }

    /**
     * @param Grant[] $grants
     */
    public function aclToVisibility(array $grants): string
    {
        foreach ($grants as $grant) {
            if (null === $grantee = $grant->getGrantee()) {
                continue;
            }
            $granteeUri = $grantee->getURI();
            $permission = $grant->getPermission();

            if (self::PUBLIC_GRANTEE_URI === $granteeUri && self::PUBLIC_GRANTS_PERMISSION === $permission) {
                return Visibility::PUBLIC;
            }
        }

        return Visibility::PRIVATE;
    }

    public function defaultForDirectories(): string
    {
        return $this->defaultForDirectories;
    }
}


================================================
FILE: src/AsyncAwsS3/README.md
================================================
## Sub-split of Flysystem for AsyncAws S3.

> ⚠️ this is a sub-split, for pull requests and issues, visit: https://github.com/thephpleague/flysystem

```bash
composer require league/flysystem-async-aws-s3
```

View the [documentation](https://flysystem.thephpleague.com/docs/adapter/async-aws-s3/)


================================================
FILE: src/AsyncAwsS3/S3ClientStub.php
================================================
<?php

declare(strict_types=1);

namespace League\Flysystem\AsyncAwsS3;

use AsyncAws\Core\Exception\Exception;
use AsyncAws\Core\Exception\Http\NetworkException;
use AsyncAws\Core\Result;
use AsyncAws\S3\Input\CopyObjectRequest;
use AsyncAws\S3\Input\DeleteObjectRequest;
use AsyncAws\S3\Input\DeleteObjectsRequest;
use AsyncAws\S3\Input\GetObjectAclRequest;
use AsyncAws\S3\Input\GetObjectRequest;
use AsyncAws\S3\Input\HeadObjectRequest;
use AsyncAws\S3\Input\ListObjectsV2Request;
use AsyncAws\S3\Input\PutObjectAclRequest;
use AsyncAws\S3\Input\PutObjectRequest;
use AsyncAws\S3\Result\CopyObjectOutput;
use AsyncAws\S3\Result\DeleteObjectOutput;
use AsyncAws\S3\Result\DeleteObjectsOutput;
use AsyncAws\S3\Result\GetObjectAclOutput;
use AsyncAws\S3\Result\GetObjectOutput;
use AsyncAws\S3\Result\HeadObjectOutput;
use AsyncAws\S3\Result\ListObjectsV2Output;
use AsyncAws\S3\Result\ObjectExistsWaiter;
use AsyncAws\S3\Result\PutObjectAclOutput;
use AsyncAws\S3\Result\PutObjectOutput;
use AsyncAws\S3\S3Client;
use AsyncAws\SimpleS3\SimpleS3Client;
use DateTimeImmutable;
use Symfony\Component\HttpClient\MockHttpClient;

/**
 * @codeCoverageIgnore
 */
class S3ClientStub extends SimpleS3Client
{
    /**
     * @var S3Client
     */
    private $actualClient;

    /**
     * @var Exception[]
     */
    private $stagedExceptions = [];

    /**
     * @var Result[]
     */
    private $stagedResult = [];

    public function __construct(SimpleS3Client $client, $configuration = [])
    {
        $this->actualClient = $client;
        parent::__construct($configuration, null, new MockHttpClient());
    }

    public function throwExceptionWhenExecutingCommand(string $commandName, ?Exception $exception = null): void
    {
        $this->stagedExceptions[$commandName] = $exception ?? new NetworkException();
    }

    public function stageResultForCommand(string $commandName, Result $result): void
    {
        $this->stagedResult[$commandName] = $result;
    }

    private function getStagedResult(string $name): ?Result
    {
        if (array_key_exists($name, $this->stagedExceptions)) {
            $exception = $this->stagedExceptions[$name];
            unset($this->stagedExceptions[$name]);

            throw $exception;
        }

        if (array_key_exists($name, $this->stagedResult)) {
            $result = $this->stagedResult[$name];
            unset($this->stagedResult[$name]);

            return $result;
        }

        return null;
    }

    /**
     * @param array|CopyObjectRequest $input
     */
    public function copyObject($input): CopyObjectOutput
    {
        // @phpstan-ignore-next-line
        return $this->getStagedResult('CopyObject') ?? $this->actualClient->copyObject($input);
    }

    /**
     * @param array|DeleteObjectRequest $input
     */
    public function deleteObject($input): DeleteObjectOutput
    {
        // @phpstan-ignore-next-line
        return $this->getStagedResult('DeleteObject') ?? $this->actualClient->deleteObject($input);
    }

    /**
     * @param array|HeadObjectRequest $input
     */
    public function headObject($input): HeadObjectOutput
    {
        // @phpstan-ignore-next-line
        return $this->getStagedResult('HeadObject') ?? $this->actualClient->headObject($input);
    }

    /**
     * @param array|HeadObjectRequest $input
     */
    public function objectExists($input): ObjectExistsWaiter
    {
        // @phpstan-ignore-next-line
        return $this->getStagedResult('ObjectExists') ?? $this->actualClient->objectExists($input);
    }

    /**
     * @param array|ListObjectsV2Request $input
     */
    public function listObjectsV2($input): ListObjectsV2Output
    {
        // @phpstan-ignore-next-line
        return $this->getStagedResult('ListObjectsV2') ?? $this->actualClient->listObjectsV2($input);
    }

    /**
     * @param array|DeleteObjectsRequest $input
     */
    public function deleteObjects($input): DeleteObjectsOutput
    {
        // @phpstan-ignore-next-line
        return $this->getStagedResult('DeleteObjects') ?? $this->actualClient->deleteObjects($input);
    }

    /**
     * @param array|GetObjectAclRequest $input
     */
    public function getObjectAcl($input): GetObjectAclOutput
    {
        // @phpstan-ignore-next-line
        return $this->getStagedResult('GetObjectAcl') ?? $this->actualClient->getObjectAcl($input);
    }

    /**
     * @param array|PutObjectAclRequest $input
     */
    public function putObjectAcl($input): PutObjectAclOutput
    {
        // @phpstan-ignore-next-line
        return $this->getStagedResult('PutObjectAcl') ?? $this->actualClient->putObjectAcl($input);
    }

    /**
     * @param array|PutObjectRequest $input
     */
    public function putObject($input): PutObjectOutput
    {
        // @phpstan-ignore-next-line
        return $this->getStagedResult('PutObject') ?? $this->actualClient->putObject($input);
    }

    /**
     * @param array|GetObjectRequest $input
     */
    public function getObject($input): GetObjectOutput
    {
        // @phpstan-ignore-next-line
        return $this->getStagedResult('GetObject') ?? $this->actualClient->getObject($input);
    }

    public function getUrl(string $bucket, string $key): string
    {
        return $this->actualClient->getUrl($bucket, $key);
    }

    public function getPresignedUrl(string $bucket, string $key, ?DateTimeImmutable $expires = null, ?string $versionId = null): string
    {
        return $this->actualClient->getPresignedUrl($bucket, $key, $expires);
    }
}


================================================
FILE: src/AsyncAwsS3/VisibilityConverter.php
================================================
<?php

declare(strict_types=1);

namespace League\Flysystem\AsyncAwsS3;

use AsyncAws\S3\ValueObject\Grant;

interface VisibilityConverter
{
    public function visibilityToAcl(string $visibility): string;

    /**
     * @param Grant[] $grants
     */
    public function aclToVisibility(array $grants): string;

    public function defaultForDirectories(): string;
}


================================================
FILE: src/AsyncAwsS3/composer.json
================================================
{
    "name": "league/flysystem-async-aws-s3",
    "description": "AsyncAws S3 filesystem adapter for Flysystem.",
    "keywords": ["async-aws","aws", "s3", "flysystem", "filesystem", "storage", "file", "files"],
    "type": "library",
    "autoload": {
        "psr-4": {
            "League\\Flysystem\\AsyncAwsS3\\": ""
        }
    },
    "require": {
        "php": "^8.0.2",
        "league/flysystem": "^3.10.0",
        "league/mime-type-detection": "^1.0.0",
        "async-aws/s3": "^1.5 || ^2.0 || ^3.0"
    },
    "require-dev": {
        "async-aws/simple-s3": "^2.1"
    },
    "conflict": {
        "symfony/http-client": "<5.2"
    },
    "license": "MIT",
    "authors": [
        {
            "name": "Frank de Jonge",
            "email": "info@frankdejonge.nl"
        }
    ]
}


================================================
FILE: src/AwsS3V3/.gitattributes
================================================
* text=auto

.github export-ignore
.gitattributes export-ignore
.gitignore export-ignore
**/*Test.php export-ignore
**/*Stub.php export-ignore
README.md export-ignore


================================================
FILE: src/AwsS3V3/.github/workflows/close-subsplit-prs.yaml
================================================
---
name: Close sub-split PRs

on:
  push:
    branches:
      - 2.x
      - 3.x
  pull_request:
    branches:
      - 2.x
      - 3.x
  schedule:
    - cron: '30 7 * * *'

jobs:
  close_subsplit_prs:
    runs-on: ubuntu-latest
    name: Close sub-split PRs
    steps:
      - uses: frankdejonge/action-close-subsplit-pr@0.1.0
        with:
          close_pr: 'yes'
          target_branch_match: '^(?!master).+$'
          message: |
            Hi :wave:,
            
            Thank you for contributing to Flysystem. Unfortunately, you've sent a PR to a read-only sub-split repository. 

            All pull requests should be directed towards: https://github.com/thephpleague/flysystem


================================================
FILE: src/AwsS3V3/AwsS3V3Adapter.php
================================================
<?php

declare(strict_types=1);

namespace League\Flysystem\AwsS3V3;

use Aws\Api\DateTimeResult;
use Aws\S3\S3ClientInterface;
use DateTimeInterface;
use Generator;
use League\Flysystem\ChecksumAlgoIsNotSupported;
use League\Flysystem\ChecksumProvider;
use League\Flysystem\Config;
use League\Flysystem\DirectoryAttributes;
use League\Flysystem\FileAttributes;
use League\Flysystem\FilesystemAdapter;
use League\Flysystem\FilesystemOperationFailed;
use League\Flysystem\PathPrefixer;
use League\Flysystem\StorageAttributes;
use League\Flysystem\UnableToCheckDirectoryExistence;
use League\Flysystem\UnableToCheckFileExistence;
use League\Flysystem\UnableToCopyFile;
use League\Flysystem\UnableToDeleteDirectory;
use League\Flysystem\UnableToDeleteFile;
use League\Flysystem\UnableToGeneratePublicUrl;
use League\Flysystem\UnableToGenerateTemporaryUrl;
use League\Flysystem\UnableToMoveFile;
use League\Flysystem\UnableToProvideChecksum;
use League\Flysystem\UnableToReadFile;
use League\Flysystem\UnableToRetrieveMetadata;
use League\Flysystem\UnableToSetVisibility;
use League\Flysystem\UnableToWriteFile;
use League\Flysystem\UrlGeneration\PublicUrlGenerator;
use League\Flysystem\UrlGeneration\TemporaryUrlGenerator;
use League\Flysystem\Visibility;
use League\MimeTypeDetection\FinfoMimeTypeDetector;
use League\MimeTypeDetection\MimeTypeDetector;
use Psr\Http\Message\StreamInterface;
use Throwable;
use function trim;

class AwsS3V3Adapter implements FilesystemAdapter, PublicUrlGenerator, ChecksumProvider, TemporaryUrlGenerator
{
    /**
     * @var string[]
     */
    public const AVAILABLE_OPTIONS = [
        'ACL',
        'CacheControl',
        'ContentDisposition',
        'ContentEncoding',
        'ContentLength',
        'ContentType',
        'Expires',
        'GrantFullControl',
        'GrantRead',
        'GrantReadACP',
        'GrantWriteACP',
        'Metadata',
        'MetadataDirective',
        'RequestPayer',
        'SSECustomerAlgorithm',
        'SSECustomerKey',
        'SSECustomerKeyMD5',
        'SSEKMSKeyId',
        'ServerSideEncryption',
        'StorageClass',
        'Tagging',
        'WebsiteRedirectLocation',
        'ChecksumAlgorithm',
        'CopySourceSSECustomerAlgorithm',
        'CopySourceSSECustomerKey',
        'CopySourceSSECustomerKeyMD5',
    ];
    /**
     * @var string[]
     */
    public const MUP_AVAILABLE_OPTIONS = [
        'add_content_md5',
        'before_upload',
        'concurrency',
        'mup_threshold',
        'params',
        'part_size',
    ];

    /**
     * @var string[]
     */
    private const EXTRA_METADATA_FIELDS = [
        'Metadata',
        'StorageClass',
        'ETag',
        'VersionId',
    ];

    private PathPrefixer $prefixer;
    private VisibilityConverter $visibility;
    private MimeTypeDetector $mimeTypeDetector;

    public function __construct(
        private S3ClientInterface $client,
        private string $bucket,
        string $prefix = '',
        ?VisibilityConverter $visibility = null,
        ?MimeTypeDetector $mimeTypeDetector = null,
        private array $options = [],
        private bool $streamReads = true,
        private array $forwardedOptions = self::AVAILABLE_OPTIONS,
        private array $metadataFields = self::EXTRA_METADATA_FIELDS,
        private array $multipartUploadOptions = self::MUP_AVAILABLE_OPTIONS,
    ) {
        $this->prefixer = new PathPrefixer($prefix);
        $this->visibility = $visibility ?? new PortableVisibilityConverter();
        $this->mimeTypeDetector = $mimeTypeDetector ?? new FinfoMimeTypeDetector();
    }

    public function fileExists(string $path): bool
    {
        try {
            return $this->client->doesObjectExistV2($this->bucket, $this->prefixer->prefixPath($path), false, $this->options);
        } catch (Throwable $exception) {
            throw UnableToCheckFileExistence::forLocation($path, $exception);
        }
    }

    public function directoryExists(string $path): bool
    {
        try {
            $prefix = $this->prefixer->prefixDirectoryPath($path);
            $options = ['Bucket' => $this->bucket, 'Prefix' => $prefix, 'MaxKeys' => 1, 'Delimiter' => '/'];
            $command = $this->client->getCommand('ListObjectsV2', $options);
            $result = $this->client->execute($command);

            return $result->hasKey('Contents') || $result->hasKey('CommonPrefixes');
        } catch (Throwable $exception) {
            throw UnableToCheckDirectoryExistence::forLocation($path, $exception);
        }
    }

    public function write(string $path, string $contents, Config $config): void
    {
        $this->upload($path, $contents, $config);
    }

    /**
     * @param string          $path
     * @param string|resource $body
     * @param Config          $config
     */
    private function upload(string $path, $body, Config $config): void
    {
        $key = $this->prefixer->prefixPath($path);
        $options = $this->createOptionsFromConfig($config);
        $acl = $options['params']['ACL'] ?? $this->determineAcl($config);
        $shouldDetermineMimetype = ! array_key_exists('ContentType', $options['params']);

        if ($shouldDetermineMimetype && $mimeType = $this->mimeTypeDetector->detectMimeType($key, $body)) {
            $options['params']['ContentType'] = $mimeType;
        }

        try {
            $this->client->upload($this->bucket, $key, $body, $acl, $options);
        } catch (Throwable $exception) {
            throw UnableToWriteFile::atLocation($path, $exception->getMessage(), $exception);
        }
    }

    private function determineAcl(Config $config): string
    {
        $visibility = (string) $config->get(Config::OPTION_VISIBILITY, Visibility::PRIVATE);

        return $this->visibility->visibilityToAcl($visibility);
    }

    private function createOptionsFromConfig(Config $config): array
    {
        $config = $config->withDefaults($this->options);
        $options = ['params' => []];

        if ($mimetype = $config->get('mimetype')) {
            $options['params']['ContentType'] = $mimetype;
        }

        foreach ($this->forwardedOptions as $option) {
            $value = $config->get($option, '__NOT_SET__');

            if ($value !== '__NOT_SET__') {
                $options['params'][$option] = $value;
            }
        }

        foreach ($this->multipartUploadOptions as $option) {
            $value = $config->get($option, '__NOT_SET__');

            if ($value !== '__NOT_SET__') {
                $options[$option] = $value;
            }
        }

        return $options;
    }

    public function writeStream(string $path, $contents, Config $config): void
    {
        $this->upload($path, $contents, $config);
    }

    public function read(string $path): string
    {
        $body = $this->readObject($path, false);

        return (string) $body->getContents();
    }

    public function readStream(string $path)
    {
        /** @var resource $resource */
        $resource = $this->readObject($path, true)->detach();

        return $resource;
    }

    public function delete(string $path): void
    {
        $arguments = ['Bucket' => $this->bucket, 'Key' => $this->prefixer->prefixPath($path)];
        $command = $this->client->getCommand('DeleteObject', $arguments);

        try {
            $this->client->execute($command);
        } catch (Throwable $exception) {
            throw UnableToDeleteFile::atLocation($path, '', $exception);
        }
    }

    public function deleteDirectory(string $path): void
    {
        $prefix = $this->prefixer->prefixPath($path);
        $prefix = ltrim(rtrim($prefix, '/') . '/', '/');

        try {
            $this->client->deleteMatchingObjects($this->bucket, $prefix);
        } catch (Throwable $exception) {
            throw UnableToDeleteDirectory::atLocation($path, '', $exception);
        }
    }

    public function createDirectory(string $path, Config $config): void
    {
        $defaultVisibility = $config->get(Config::OPTION_DIRECTORY_VISIBILITY, $this->visibility->defaultForDirectories());
        $config = $config->withDefaults([Config::OPTION_VISIBILITY => $defaultVisibility]);
        $this->upload(rtrim($path, '/') . '/', '', $config);
    }

    public function setVisibility(string $path, string $visibility): void
    {
        $arguments = [
            'Bucket' => $this->bucket,
            'Key' => $this->prefixer->prefixPath($path),
            'ACL' => $this->visibility->visibilityToAcl($visibility),
        ];
        $command = $this->client->getCommand('PutObjectAcl', $arguments);

        try {
            $this->client->execute($command);
        } catch (Throwable $exception) {
            throw UnableToSetVisibility::atLocation($path, '', $exception);
        }
    }

    public function visibility(string $path): FileAttributes
    {
        $arguments = ['Bucket' => $this->bucket, 'Key' => $this->prefixer->prefixPath($path)];
        $command = $this->client->getCommand('GetObjectAcl', $arguments);

        try {
            $result = $this->client->execute($command);
        } catch (Throwable $exception) {
            throw UnableToRetrieveMetadata::visibility($path, '', $exception);
        }

        $visibility = $this->visibility->aclToVisibility((array) $result->get('Grants'));

        return new FileAttributes($path, null, $visibility);
    }

    private function fetchFileMetadata(string $path, string $type): FileAttributes
    {
        $options = ['Bucket' => $this->bucket, 'Key' => $this->prefixer->prefixPath($path)];
        $command = $this->client->getCommand('HeadObject', $options + $this->options);

        try {
            $result = $this->client->execute($command);
        } catch (Throwable $exception) {
            throw UnableToRetrieveMetadata::create($path, $type, '', $exception);
        }

        $attributes = $this->mapS3ObjectMetadata($result->toArray(), $path);

        if ( ! $attributes instanceof FileAttributes) {
            throw UnableToRetrieveMetadata::create($path, $type, '');
        }

        return $attributes;
    }

    private function mapS3ObjectMetadata(array $metadata, string $path): StorageAttributes
    {
        if (substr($path, -1) === '/') {
            return new DirectoryAttributes(rtrim($path, '/'));
        }

        $mimetype = $metadata['ContentType'] ?? null;
        $fileSize = $metadata['ContentLength'] ?? $metadata['Size'] ?? null;
        $fileSize = $fileSize === null ? null : (int) $fileSize;
        $dateTime = $metadata['LastModified'] ?? null;
        $lastModified = $dateTime instanceof DateTimeResult ? $dateTime->getTimeStamp() : null;

        return new FileAttributes(
            $path,
            $fileSize,
            null,
            $lastModified,
            $mimetype,
            $this->extractExtraMetadata($metadata)
        );
    }

    private function extractExtraMetadata(array $metadata): array
    {
        $extracted = [];

        foreach ($this->metadataFields as $field) {
            if (isset($metadata[$field]) && $metadata[$field] !== '') {
                $extracted[$field] = $metadata[$field];
            }
        }

        return $extracted;
    }

    public function mimeType(string $path): FileAttributes
    {
        $attributes = $this->fetchFileMetadata($path, FileAttributes::ATTRIBUTE_MIME_TYPE);

        if ($attributes->mimeType() === null) {
            throw UnableToRetrieveMetadata::mimeType($path);
        }

        return $attributes;
    }

    public function lastModified(string $path): FileAttributes
    {
        $attributes = $this->fetchFileMetadata($path, FileAttributes::ATTRIBUTE_LAST_MODIFIED);

        if ($attributes->lastModified() === null) {
            throw UnableToRetrieveMetadata::lastModified($path);
        }

        return $attributes;
    }

    public function fileSize(string $path): FileAttributes
    {
        $attributes = $this->fetchFileMetadata($path, FileAttributes::ATTRIBUTE_FILE_SIZE);

        if ($attributes->fileSize() === null) {
            throw UnableToRetrieveMetadata::fileSize($path);
        }

        return $attributes;
    }

    public function listContents(string $path, bool $deep): iterable
    {
        $prefix = trim($this->prefixer->prefixPath($path), '/');
        $prefix = $prefix === '' ? '' : $prefix . '/';
        $options = ['Bucket' => $this->bucket, 'Prefix' => $prefix];

        if ($deep === false) {
            $options['Delimiter'] = '/';
        }

        $listing = $this->retrievePaginatedListing($options);

        foreach ($listing as $item) {
            $key = $item['Key'] ?? $item['Prefix'];

            if ($key === $prefix) {
                continue;
            }

            yield $this->mapS3ObjectMetadata($item, $this->prefixer->stripPrefix($key));
        }
    }

    private function retrievePaginatedListing(array $options): Generator
    {
        $resultPaginator = $this->client->getPaginator('ListObjectsV2', $options + $this->options);

        foreach ($resultPaginator as $result) {
            yield from ($result->get('CommonPrefixes') ?? []);
            yield from ($result->get('Contents') ?? []);
        }
    }

    public function move(string $source, string $destination, Config $config): void
    {
        if ($source === $destination) {
            return;
        }

        try {
            $this->copy($source, $destination, $config);
            $this->delete($source);
        } catch (FilesystemOperationFailed $exception) {
            throw UnableToMoveFile::fromLocationTo($source, $destination, $exception);
        }
    }

    public function copy(string $source, string $destination, Config $config): void
    {
        if ($source === $destination) {
            return;
        }

        try {
            $visibility = $config->get(Config::OPTION_VISIBILITY);

            if ($visibility === null && $config->get(Config::OPTION_RETAIN_VISIBILITY, true)) {
                $visibility = $this->visibility($source)->visibility();
            }
        } catch (Throwable $exception) {
            throw UnableToCopyFile::fromLocationTo(
                $source,
                $destination,
                $exception
            );
        }

        $options = $this->createOptionsFromConfig($config);
        $options['MetadataDirective'] = $config->get('MetadataDirective', 'COPY');

        try {
            $this->client->copy(
                $this->bucket,
                $this->prefixer->prefixPath($source),
                $this->bucket,
                $this->prefixer->prefixPath($destination),
                $this->visibility->visibilityToAcl($visibility ?: 'private'),
                $options,
            );
        } catch (Throwable $exception) {
            throw UnableToCopyFile::fromLocationTo($source, $destination, $exception);
        }
    }

    private function readObject(string $path, bool $wantsStream): StreamInterface
    {
        $options = ['Bucket' => $this->bucket, 'Key' => $this->prefixer->prefixPath($path)];

        if ($wantsStream && $this->streamReads && ! isset($this->options['@http']['stream'])) {
            $options['@http']['stream'] = true;
        }

        $command = $this->client->getCommand('GetObject', $options + $this->options);

        try {
            return $this->client->execute($command)->get('Body');
        } catch (Throwable $exception) {
            throw UnableToReadFile::fromLocation($path, '', $exception);
        }
    }

    public function publicUrl(string $path, Config $config): string
    {
        $location = $this->prefixer->prefixPath($path);

        try {
            return $this->client->getObjectUrl($this->bucket, $location);
        } catch (Throwable $exception) {
            throw UnableToGeneratePublicUrl::dueToError($path, $exception);
        }
    }

    public function checksum(string $path, Config $config): string
    {
        $algo = $config->get('checksum_algo', 'etag');

        if ($algo !== 'etag') {
            throw new ChecksumAlgoIsNotSupported();
        }

        try {
            $metadata = $this->fetchFileMetadata($path, 'checksum')->extraMetadata();
        } catch (UnableToRetrieveMetadata $exception) {
            throw new UnableToProvideChecksum($exception->reason(), $path, $exception);
        }

        if ( ! isset($metadata['ETag'])) {
            throw new UnableToProvideChecksum('ETag header not available.', $path);
        }

        return trim($metadata['ETag'], '"');
    }

    public function temporaryUrl(string $path, DateTimeInterface $expiresAt, Config $config): string
    {
        try {
            $options = $config->get('get_object_options', []);
            $command = $this->client->getCommand('GetObject', [
                    'Bucket' => $this->bucket,
                    'Key' => $this->prefixer->prefixPath($path),
                ] + $options);

            $presignedRequestOptions = $config->get('presigned_request_options', []);
            $request = $this->client->createPresignedRequest($command, $expiresAt, $presignedRequestOptions);

            return (string) $request->getUri();
        } catch (Throwable $exception) {
            throw UnableToGenerateTemporaryUrl::dueToError($path, $exception);
        }
    }
}


================================================
FILE: src/AwsS3V3/AwsS3V3AdapterTest.php
================================================
<?php

declare(strict_types=1);

namespace League\Flysystem\AwsS3V3;

use Aws\Result;
use Aws\S3\S3Client;
use Aws\S3\S3ClientInterface;
use Exception;
use Generator;
use League\Flysystem\AdapterTestUtilities\FilesystemAdapterTestCase;
use League\Flysystem\ChecksumAlgoIsNotSupported;
use League\Flysystem\Config;
use League\Flysystem\FileAttributes;
use League\Flysystem\FilesystemAdapter;
use League\Flysystem\PathPrefixer;
use League\Flysystem\StorageAttributes;
use League\Flysystem\UnableToCheckFileExistence;
use League\Flysystem\UnableToDeleteFile;
use League\Flysystem\UnableToMoveFile;
use League\Flysystem\UnableToRetrieveMetadata;
use League\Flysystem\UnableToWriteFile;
use League\Flysystem\Visibility;
use RuntimeException;

use function getenv;
use function iterator_to_array;

/**
 * @group aws
 */
class AwsS3V3AdapterTest extends FilesystemAdapterTestCase
{
    /**
     * @var bool
     */
    private $shouldCleanUp = false;

    /**
     * @var string
     */
    private static $adapterPrefix = 'test-prefix';

    /**
     * @var S3ClientInterface|null
     */
    private static $s3Client;

    /**
     * @var S3ClientStub
     */
    private static $stubS3Client;

    public static function setUpBeforeClass(): void
    {
        static::$adapterPrefix = getenv('FLYSYSTEM_AWS_S3_PREFIX') ?: 'ci/' . bin2hex(random_bytes(10));
    }

    protected function tearDown(): void
    {
        if ( ! $this->shouldCleanUp) {
            return;
        }

        $adapter = $this->adapter();
        $adapter->deleteDirectory('/');
        /** @var StorageAttributes[] $listing */
        $listing = $adapter->listContents('', false);

        foreach ($listing as $item) {
            if ($item->isFile()) {
                $adapter->delete($item->path());
            } else {
                $adapter->deleteDirectory($item->path());
            }
        }

        self::$adapter = null;
    }

    protected function setUp(): void
    {
        if (PHP_VERSION_ID < 80100) {
            $this->markTestSkipped('AWS does not support this anymore.');
        }

        parent::setUp();
    }

    private static function s3Client(): S3ClientInterface
    {
        if (static::$s3Client instanceof S3ClientInterface) {
            return static::$s3Client;
        }

        $key = getenv('FLYSYSTEM_AWS_S3_KEY');
        $secret = getenv('FLYSYSTEM_AWS_S3_SECRET');
        $bucket = getenv('FLYSYSTEM_AWS_S3_BUCKET');
        $region = getenv('FLYSYSTEM_AWS_S3_REGION') ?: 'eu-central-1';

        if ( ! $key || ! $secret || ! $bucket) {
            self::markTestSkipped('No AWS credentials present for testing.');
        }

        $options = ['version' => 'latest', 'credentials' => compact('key', 'secret'), 'region' => $region];

        return static::$s3Client = new S3Client($options);
    }

    /**
     * @test
     */
    public function writing_with_a_specific_mime_type(): void
    {
        $adapter = $this->adapter();
        $adapter->write('some/path.txt', 'contents', new Config(['ContentType' => 'text/plain+special']));
        $mimeType = $adapter->mimeType('some/path.txt')->mimeType();
        $this->assertEquals('text/plain+special', $mimeType);
    }

    /**
     * @test
     */
    public function writing_a_file_with_explicit_mime_type(): void
    {
        $adapter = $this->adapter();
        $adapter->write('some/path.txt', 'contents', new Config(['mimetype' => 'text/plain+special']));
        $mimeType = $adapter->mimeType('some/path.txt')->mimeType();
        $this->assertEquals('text/plain+special', $mimeType);
    }

    /**
     * @test
     *
     * @see https://github.com/thephpleague/flysystem-aws-s3-v3/issues/291
     */
    public function issue_291(): void
    {
        $adapter = $this->adapter();
        $adapter->createDirectory('directory', new Config());
        $listing = iterator_to_array($adapter->listContents('directory', true));

        self::assertCount(0, $listing);
    }

    /**
     * @test
     */
    public function listing_contents_recursive(): void
    {
        $adapter = $this->adapter();
        $adapter->write('something/0/here.txt', 'contents', new Config());
        $adapter->write('something/1/also/here.txt', 'contents', new Config());

        $contents = iterator_to_array($adapter->listContents('', true));

        $this->assertCount(2, $contents);
        $this->assertContainsOnlyInstancesOf(FileAttributes::class, $contents);
        /** @var FileAttributes $file */
        $file = $contents[0];
        $this->assertEquals('something/0/here.txt', $file->path());
        /** @var FileAttributes $file */
        $file = $contents[1];
        $this->assertEquals('something/1/also/here.txt', $file->path());
    }

    /**
     * @test
     */
    public function failing_to_delete_while_moving(): void
    {
        $adapter = $this->adapter();
        $adapter->write('source.txt', 'contents to be copied', new Config());
        static::$stubS3Client->failOnNextCopy();

        $this->expectException(UnableToMoveFile::class);

        $adapter->move('source.txt', 'destination.txt', new Config());
    }

    /**
     * @test
     *
     * @see https://github.com/thephpleague/flysystem-aws-s3-v3/issues/287
     */
    public function issue_287(): void
    {
        $adapter = $this->adapter();
        $adapter->write('KmFVvKqo/QLMExy2U/620ff60c8a154.pdf', 'pdf content', new Config());

        self::assertTrue($adapter->directoryExists('KmFVvKqo'));
    }

    /**
     * @test
     */
    public function failing_to_write_a_file(): void
    {
        $adapter = $this->adapter();
        static::$stubS3Client->throwDuringUpload(new RuntimeException('Oh no'));

        $this->expectException(UnableToWriteFile::class);

        $adapter->write('path.txt', 'contents', new Config());
    }

    /**
     * @test
     */
    public function failing_to_delete_a_file(): void
    {
        $adapter = $this->adapter();
        static::$stubS3Client->throwExceptionWhenExecutingCommand('DeleteObject');

        $this->expectException(UnableToDeleteFile::class);

        $adapter->delete('path.txt');
    }

    /**
     * @test
     */
    public function fetching_unknown_mime_type_of_a_file(): void
    {
        $this->adapter();
        $result = new Result([
            'Key' => static::$adapterPrefix . '/unknown-mime-type.md5',
        ]);
        static::$stubS3Client->stageResultForCommand('HeadObject', $result);

        parent::fetching_unknown_mime_type_of_a_file();
    }

    /**
     * @test
     *
     * @dataProvider dpFailingMetadataGetters
     */
    public function failing_to_retrieve_metadata(Exception $exception, string $getterName): void
    {
        $adapter = $this->adapter();
        $result = new Result([
             'Key' => static::$adapterPrefix . '/filename.txt',
        ]);
        static::$stubS3Client->stageResultForCommand('HeadObject', $result);

        $this->expectExceptionObject($exception);

        $adapter->{$getterName}('filename.txt');
    }

    public static function dpFailingMetadataGetters(): iterable
    {
        yield "mimeType" => [UnableToRetrieveMetadata::mimeType('filename.txt'), 'mimeType'];
        yield "lastModified" => [UnableToRetrieveMetadata::lastModified('filename.txt'), 'lastModified'];
        yield "fileSize" => [UnableToRetrieveMetadata::fileSize('filename.txt'), 'fileSize'];
    }

    /**
     * @test
     */
    public function failing_to_check_for_file_existence(): void
    {
        $adapter = $this->adapter();

        static::$stubS3Client->throw500ExceptionWhenExecutingCommand('HeadObject');

        $this->expectException(UnableToCheckFileExistence::class);

        $adapter->fileExists('something-that-does-exist.txt');
    }

    /**
     * @test
     *
     * @dataProvider casesWhereHttpStreamingInfluencesSeekability
     */
    public function streaming_reads_are_not_seekable_and_non_streaming_are(bool $streaming, bool $seekable): void
    {
        if (getenv('COMPOSER_OPTS') === '--prefer-lowest') {
            $this->markTestSkipped('The SDK does not support streaming in low versions.');
        }

        $adapter = $this->useAdapter($this->createFilesystemAdapter($streaming));
        $this->givenWeHaveAnExistingFile('path.txt');

        $resource = $adapter->readStream('path.txt');
        $metadata = stream_get_meta_data($resource);
        fclose($resource);

        $this->assertEquals($seekable, $metadata['seekable']);
    }

    public static function casesWhereHttpStreamingInfluencesSeekability(): Generator
    {
        yield "not streaming reads have seekable stream" => [false, true];
        yield "streaming reads have non-seekable stream" => [true, false];
    }

    /**
     * @test
     *
     * @dataProvider casesWhereHttpStreamingInfluencesSeekability
     */
    public function configuring_http_streaming_via_options(bool $streaming): void
    {
        $adapter = $this->useAdapter($this->createFilesystemAdapter($streaming, ['@http' => ['stream' => false]]));
        $this->givenWeHaveAnExistingFile('path.txt');

        $resource = $adapter->readStream('path.txt');
        $metadata = stream_get_meta_data($resource);
        fclose($resource);

        $this->assertTrue($metadata['seekable']);
    }

    /**
     * @test
     *
     * @dataProvider casesWhereHttpStreamingInfluencesSeekability
     */
    public function use_globally_configured_options(bool $streaming): void
    {
        $adapter = $this->useAdapter($this->createFilesystemAdapter($streaming, ['ContentType' => 'text/plain+special']));
        $this->givenWeHaveAnExistingFile('path.txt');

        $mimeType = $adapter->mimeType('path.txt')->mimeType();
        $this->assertSame('text/plain+special', $mimeType);
    }

    /**
     * @test
     */
    public function moving_with_updated_metadata(): void
    {
        $adapter = $this->adapter();
        $adapter->write('source.txt', 'contents to be moved', new Config(['ContentType' => 'text/plain']));
        $mimeTypeSource = $adapter->mimeType('source.txt')->mimeType();
        $this->assertSame('text/plain', $mimeTypeSource);

        $adapter->move('source.txt', 'destination.txt', new Config(
            ['ContentType' => 'text/plain+special', 'MetadataDirective' => 'REPLACE']
        ));
        $mimeTypeDestination = $adapter->mimeType('destination.txt')->mimeType();
        $this->assertSame('text/plain+special', $mimeTypeDestination);
    }

    /**
     * @test
     */
    public function moving_without_updated_metadata(): void
    {
        $adapter = $this->adapter();
        $adapter->write('source.txt', 'contents to be moved', new Config(['ContentType' => 'text/plain']));
        $mimeTypeSource = $adapter->mimeType('source.txt')->mimeType();
        $this->assertSame('text/plain', $mimeTypeSource);

        $adapter->move('source.txt', 'destination.txt', new Config(
            ['ContentType' => 'text/plain+special']
        ));
        $mimeTypeDestination = $adapter->mimeType('destination.txt')->mimeType();
        $this->assertSame('text/plain', $mimeTypeDestination);
    }

    /**
     * @test
     */
    public function copying_with_updated_metadata(): void
    {
        $adapter = $this->adapter();
        $adapter->write('source.txt', 'contents to be moved', new Config(['ContentType' => 'text/plain']));
        $mimeTypeSource = $adapter->mimeType('source.txt')->mimeType();
        $this->assertSame('text/plain', $mimeTypeSource);

        $adapter->copy('source.txt', 'destination.txt', new Config(
            ['ContentType' => 'text/plain+special', 'MetadataDirective' => 'REPLACE']
        ));
        $mimeTypeDestination = $adapter->mimeType('destination.txt')->mimeType();
        $this->assertSame('text/plain+special', $mimeTypeDestination);
    }

    /**
     * @test
     */
    public function setting_acl_via_options(): void
    {
        $adapter = $this->adapter();
        $prefixer = new PathPrefixer(static::$adapterPrefix);
        $prefixedPath = $prefixer->prefixPath('path.txt');

        $adapter->write('path.txt', 'contents', new Config(['ACL' => 'bucket-owner-full-control']));
        $arguments = ['Bucket' => getenv('FLYSYSTEM_AWS_S3_BUCKET'), 'Key' => $prefixedPath];
        $command = static::$s3Client->getCommand('GetObjectAcl', $arguments);
        $response = static::$s3Client->execute($command)->toArray();
        $permission = $response['Grants'][0]['Permission'];

        self::assertEquals('FULL_CONTROL', $permission);
    }

    /**
     * @test
     */
    public function moving_a_file_with_visibility(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();
            $adapter->write(
                'source.txt',
                'contents to be copied',
                new Config([Config::OPTION_VISIBILITY => Visibility::PUBLIC])
            );
            $adapter->move('source.txt', 'destination.txt', new Config([Config::OPTION_VISIBILITY => Visibility::PRIVATE]));
            $this->assertFalse(
                $adapter->fileExists('source.txt'),
                'After moving a file should no longer exist in the original location.'
            );
            $this->assertTrue(
                $adapter->fileExists('destination.txt'),
                'After moving, a file should be present at the new location.'
            );
            $this->assertEquals(Visibility::PRIVATE, $adapter->visibility('destination.txt')->visibility());
            $this->assertEquals('contents to be copied', $adapter->read('destination.txt'));
        });
    }

    /**
     * @test
     */
    public function specifying_a_custom_checksum_algo_is_not_supported(): void
    {
        /** @var AwsS3V3Adapter $adapter */
        $adapter = $this->adapter();

        $this->expectException(ChecksumAlgoIsNotSupported::class);

        $adapter->checksum('something', new Config(['checksum_algo' => 'md5']));
    }

    /**
     * @test
     */
    public function copying_a_file_with_visibility(): void
    {
        $this->runScenario(function () {
            $adapter = $this->adapter();
            $adapter->write(
                'source.txt',
                'contents to be copied',
                new Config([Config::OPTION_VISIBILITY => Visibility::PUBLIC])
            );

            $adapter->copy('source.txt', 'destination.txt', new Config([Config::OPTION_VISIBILITY => Visibility::PRIVATE]));

            $this->assertTrue($adapter->fileExists('source.txt'));
            $this->assertTrue($adapter->fileExists('destination.txt'));
            $this->assertEquals(Visibility::PRIVATE, $adapter->visibility('destination.txt')->visibility());
            $this->assertEquals('contents to be copied', $adapter->read('destination.txt'));
        });
    }

    protected static function createFilesystemAdapter(bool $streaming = true, array $options = []): FilesystemAdapter
    {
        static::$stubS3Client = new S3ClientStub(static::s3Client());
        /** @var string $bucket */
        $bucket = getenv('FLYSYSTEM_AWS_S3_BUCKET');
        $prefix = static::$adapterPrefix;

        return new AwsS3V3Adapter(static::$stubS3Client, $bucket, $prefix, null, null, $options, $streaming);
    }
}


================================================
FILE: src/AwsS3V3/LICENSE
================================================
Copyright (c) 2013-2026 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.


================================================
FILE: src/AwsS3V3/PortableVisibilityConverter.php
================================================
<?php

declare(strict_types=1);

namespace League\Flysystem\AwsS3V3;

use League\Flysystem\Visibility;

class PortableVisibilityConverter implements VisibilityConverter
{
    private const PUBLIC_GRANTEE_URI = 'http://acs.amazonaws.com/groups/global/AllUsers';
    private const PUBLIC_GRANTS_PERMISSION = 'READ';
    private const PUBLIC_ACL = 'public-read';
    private const PRIVATE_ACL = 'private';

    public function __construct(private string $defaultForDirectories = Visibility::PUBLIC)
    {
    }

    public function visibilityToAcl(string $visibility): string
    {
        if ($visibility === Visibility::PUBLIC) {
            return self::PUBLIC_ACL;
        }

        return self::PRIVATE_ACL;
    }

    public function aclToVisibility(array $grants): string
    {
        foreach ($grants as $grant) {
            $granteeUri = $grant['Grantee']['URI'] ?? null;
            $permission = $grant['Permission'] ?? null;

            if ($granteeUri === self::PUBLIC_GRANTEE_URI && $permission === self::PUBLIC_GRANTS_PERMISSION) {
                return Visibility::PUBLIC;
            }
        }

        return Visibility::PRIVATE;
    }

    public function defaultForDirectories(): string
    {
        return $this->defaultForDirectories;
    }
}


================================================
FILE: src/AwsS3V3/README.md
================================================
## Sub-split of Flysystem for AWS S3.

> ⚠️ this is a sub-split, for pull requests and issues, visit: https://github.com/thephpleague/flysystem

```bash
composer require league/flysystem-aws-s3-v3
```

View the [documentation](https://flysystem.thephpleague.com/docs/adapter/aws-s3-v3/).


================================================
FILE: src/AwsS3V3/S3ClientStub.php
================================================
<?php

declare(strict_types=1);

namespace League\Flysystem\AwsS3V3;

use Aws\Command;
use Aws\CommandInterface;
use Aws\ResultInterface;
use Aws\S3\Exception\S3Exception;
use Aws\S3\S3ClientInterface;
use Aws\S3\S3ClientTrait;
use GuzzleHttp\Psr7\Response;

use Throwable;

use function GuzzleHttp\Promise\promise_for;

/**
 * @codeCoverageIgnore
 */
class S3ClientStub implements S3ClientInterface
{
    use S3ClientTrait;

    /**
     * @var S3ClientInterface
     */
    private $actualClient;

    /**
     * @var S3Exception[]
     */
    private $stagedExceptions = [];

    /**
     * @var ResultInterface[]
     */
    private $stagedResult = [];

    /**
     * @var Throwable|null
     */
    private $exceptionForUpload = null;

    public function __construct(S3ClientInterface $client)
    {
        return $this->actualClient = $client;
    }

    public function throwDuringUpload(Throwable $throwable): void
    {
        $this->exceptionForUpload = $throwable;
    }

    public function upload($bucket, $key, $body, $acl = 'private', array $options = [])
    {
        if ($this->exceptionForUpload instanceof Throwable) {
            $throwable = $this->exceptionForUpload;
            $this->exceptionForUpload = null;
            throw $throwable;
        }

        return $this->actualClient->upload($bucket, $key, $body, $acl, $options);
    }

    public function failOnNextCopy(): void
    {
        $this->throwExceptionWhenExecutingCommand('CopyObject');
    }

    public function throwExceptionWhenExecutingCommand(string $commandName, ?S3Exception $exception = null): void
    {
        $this->stagedExceptions[$commandName] = $exception ?? new S3Exception($commandName, new Command($commandName));
    }

    public function throw500ExceptionWhenExecutingCommand(string $commandName): void
    {
        $response = new Response(500);
        $exception = new S3Exception($commandName, new Command($commandName), compact('response'));

        $this->throwExceptionWhenExecutingCommand($commandName, $exception);
    }

    public function stageResultForCommand(string $commandName, ResultInterface $result): void
    {
        $this->stagedResult[$commandName] = $result;
    }

    public function execute(CommandInterface $command)
    {
        return $this->executeAsync($command)->wait();
    }

    public function getCommand($name, array $args = [])
    {
        return $this->actualClient->getCommand($name, $args);
    }

    public function getHandlerList()
    {
        return $this->actualClient->getHandlerList();
    }

    public function getIterator($name, array $args = [])
    {
        return $this->actualClient->getIterator($name, $args);
    }

    public function __call($name, array $arguments)
    {
        return $this->actualClient->__call($name, $arguments);
    }

    public function executeAsync(CommandInterface $command)
    {
        $name = $command->getName();

        if (array_key_exists($name, $this->stagedExceptions)) {
            $exception = $this->stagedExceptions[$name];
            unset($this->stagedExceptions[$name]);
            throw $exception;
        }

        if (array_key_exists($name, $this->stagedResult)) {
            $result = $this->stagedResult[$name];
            unset($this->stagedResult[$name]);

            return promise_for($result);
        }

        return $this->actualClient->executeAsync($command);
    }

    public function getCredentials()
    {
        return $this->actualClient->getCredentials();
    }

    public function getRegion()
    {
        return $this->actualClient->getRegion();
    }

    public function getEndpoint()
    {
        return $this->actualClient->getEndpoint();
    }

    public function getApi()
    {
        return $this->actualClient->getApi();
    }

    public function getConfig($option = null)
    {
        return $this->actualClient->getConfig($option);
    }

    public function getPaginator($name, array $args = [])
    {
        return $this->actualClient->getPaginator($name, $args);
    }

    public function waitUntil($name, array $args = [])
    {
        $this->actualClient->waitUntil($name, $args);
    }

    public function getWaiter($name, array $args = [])
    {
        return $this->actualClient->getWaiter($name, $args);
    }

    public function createPresignedRequest(CommandInterface $command, $expires, array $options = [])
    {
        return $this->actualClient->createPresignedRequest($command, $expires, $options);
    }

    public function getObjectUrl($bucket, $key)
    {
        return $this->actualClient->getObjectUrl($bucket, $key);
    }
}


================================================
FILE: src/AwsS3V3/VisibilityConverter.php
================================================
<?php

declare(strict_types=1);

namespace League\Flysystem\AwsS3V3;

interface VisibilityConverter
{
    public function visibilityToAcl(string $visib
Download .txt
gitextract_99z1k6qe/

├── .dockerignore
├── .editorconfig
├── .gitattributes
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── Bug.md
│   │   ├── Feature_Request.md
│   │   └── Question.md
│   ├── release.yml
│   ├── stale.yml
│   └── workflows/
│       ├── publish-subsplits.yml
│       ├── quality-assurance.yml
│       └── set-subsplit-default-branch.yml
├── .gitignore
├── .php-cs-fixer.dist.php
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── INFO.md
├── LICENSE
├── bin/
│   ├── .gitignore
│   ├── check-versions.php
│   ├── close-subsplit-prs.yml
│   ├── set-flysystem-version.php
│   ├── tools.php
│   └── update-subsplit-closers.php
├── composer.json
├── config.subsplit-publish.json
├── docker-compose.yml
├── mocked-functions.php
├── phpstan-baseline.neon
├── phpstan.neon
├── phpunit.php
├── phpunit.xml.dist
├── readme.md
├── src/
│   ├── AdapterTestUtilities/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── ExceptionThrowingFilesystemAdapter.php
│   │   ├── FilesystemAdapterTestCase.php
│   │   ├── README.md
│   │   ├── RetryOnTestException.php
│   │   ├── ToxiproxyManagement.php
│   │   ├── composer.json
│   │   ├── test-functions.php
│   │   └── test_files/
│   │       └── unknown-mime-type.md5
│   ├── AsyncAwsS3/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── AsyncAwsS3Adapter.php
│   │   ├── AsyncAwsS3AdapterTest.php
│   │   ├── LICENSE
│   │   ├── PortableVisibilityConverter.php
│   │   ├── README.md
│   │   ├── S3ClientStub.php
│   │   ├── VisibilityConverter.php
│   │   └── composer.json
│   ├── AwsS3V3/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── AwsS3V3Adapter.php
│   │   ├── AwsS3V3AdapterTest.php
│   │   ├── LICENSE
│   │   ├── PortableVisibilityConverter.php
│   │   ├── README.md
│   │   ├── S3ClientStub.php
│   │   ├── VisibilityConverter.php
│   │   └── composer.json
│   ├── AzureBlobStorage/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── AzureBlobStorageAdapter.php
│   │   ├── AzureBlobStorageAdapterTest.php
│   │   ├── LICENSE
│   │   ├── README.md
│   │   └── composer.json
│   ├── CalculateChecksumFromStream.php
│   ├── ChecksumAlgoIsNotSupported.php
│   ├── ChecksumProvider.php
│   ├── Config.php
│   ├── ConfigTest.php
│   ├── CorruptedPathDetected.php
│   ├── DecoratedAdapter.php
│   ├── DirectoryAttributes.php
│   ├── DirectoryAttributesTest.php
│   ├── DirectoryListing.php
│   ├── DirectoryListingTest.php
│   ├── ExceptionInformationTest.php
│   ├── FileAttributes.php
│   ├── FileAttributesTest.php
│   ├── Filesystem.php
│   ├── FilesystemAdapter.php
│   ├── FilesystemException.php
│   ├── FilesystemOperationFailed.php
│   ├── FilesystemOperator.php
│   ├── FilesystemReader.php
│   ├── FilesystemTest.php
│   ├── FilesystemWriter.php
│   ├── Ftp/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── ConnectionProvider.php
│   │   ├── ConnectivityChecker.php
│   │   ├── ConnectivityCheckerThatCanFail.php
│   │   ├── FtpAdapter.php
│   │   ├── FtpAdapterTest.php
│   │   ├── FtpAdapterTestCase.php
│   │   ├── FtpConnectionException.php
│   │   ├── FtpConnectionOptions.php
│   │   ├── FtpConnectionProvider.php
│   │   ├── FtpConnectionProviderTest.php
│   │   ├── FtpdAdapterTest.php
│   │   ├── InvalidListResponseReceived.php
│   │   ├── LICENSE
│   │   ├── NoopCommandConnectivityChecker.php
│   │   ├── NoopCommandConnectivityCheckerTest.php
│   │   ├── README.md
│   │   ├── RawListFtpConnectivityChecker.php
│   │   ├── RawListFtpConnectivityCheckerTest.php
│   │   ├── StubConnectionProvider.php
│   │   ├── UnableToAuthenticate.php
│   │   ├── UnableToConnectToFtpHost.php
│   │   ├── UnableToEnableUtf8Mode.php
│   │   ├── UnableToMakeConnectionPassive.php
│   │   ├── UnableToResolveConnectionRoot.php
│   │   ├── UnableToSetFtpOption.php
│   │   └── composer.json
│   ├── GoogleCloudStorage/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── GoogleCloudStorageAdapter.php
│   │   ├── GoogleCloudStorageAdapterTest.php
│   │   ├── GoogleCloudStorageAdapterWithoutAclTest.php
│   │   ├── LICENSE
│   │   ├── PortableVisibilityHandler.php
│   │   ├── README.md
│   │   ├── StubRiggedBucket.php
│   │   ├── StubStorageClient.php
│   │   ├── UniformBucketLevelAccessVisibility.php
│   │   ├── VisibilityHandler.php
│   │   └── composer.json
│   ├── GridFS/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── GridFSAdapter.php
│   │   ├── GridFSAdapterTest.php
│   │   ├── LICENSE
│   │   ├── README.md
│   │   └── composer.json
│   ├── InMemory/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── InMemoryFile.php
│   │   ├── InMemoryFilesystemAdapter.php
│   │   ├── InMemoryFilesystemAdapterTest.php
│   │   ├── LICENSE
│   │   ├── README.md
│   │   ├── StaticInMemoryAdapterRegistry.php
│   │   ├── StaticInMemoryAdapterRegistryTest.php
│   │   └── composer.json
│   ├── InvalidStreamProvided.php
│   ├── InvalidVisibilityProvided.php
│   ├── Local/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── FallbackMimeTypeDetector.php
│   │   ├── LICENSE
│   │   ├── LocalFilesystemAdapter.php
│   │   ├── LocalFilesystemAdapterTest.php
│   │   ├── README.md
│   │   └── composer.json
│   ├── MountManager.php
│   ├── MountManagerTest.php
│   ├── PathNormalizer.php
│   ├── PathPrefixer.php
│   ├── PathPrefixerTest.php
│   ├── PathPrefixing/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── LICENSE
│   │   ├── PathPrefixedAdapter.php
│   │   ├── PathPrefixedAdapterTest.php
│   │   ├── README.md
│   │   └── composer.json
│   ├── PathTraversalDetected.php
│   ├── PhpseclibV2/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── ConnectionProvider.php
│   │   ├── ConnectivityChecker.php
│   │   ├── FixatedConnectivityChecker.php
│   │   ├── README.md
│   │   ├── SftpAdapter.php
│   │   ├── SftpAdapterTest.php
│   │   ├── SftpConnectionProvider.php
│   │   ├── SftpConnectionProviderTest.php
│   │   ├── SftpStub.php
│   │   ├── SimpleConnectivityChecker.php
│   │   ├── StubSftpConnectionProvider.php
│   │   ├── UnableToAuthenticate.php
│   │   ├── UnableToConnectToSftpHost.php
│   │   ├── UnableToEstablishAuthenticityOfHost.php
│   │   ├── UnableToLoadPrivateKey.php
│   │   └── composer.json
│   ├── PhpseclibV3/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── ConnectionProvider.php
│   │   ├── ConnectivityChecker.php
│   │   ├── FixatedConnectivityChecker.php
│   │   ├── LICENSE
│   │   ├── README.md
│   │   ├── SftpAdapter.php
│   │   ├── SftpAdapterTest.php
│   │   ├── SftpConnectionProvider.php
│   │   ├── SftpConnectionProviderTest.php
│   │   ├── SftpStub.php
│   │   ├── SimpleConnectivityChecker.php
│   │   ├── StubSftpConnectionProvider.php
│   │   ├── UnableToAuthenticate.php
│   │   ├── UnableToConnectToSftpHost.php
│   │   ├── UnableToEstablishAuthenticityOfHost.php
│   │   ├── UnableToLoadPrivateKey.php
│   │   └── composer.json
│   ├── PortableVisibilityGuard.php
│   ├── ProxyArrayAccessToProperties.php
│   ├── ReadOnly/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── LICENSE
│   │   ├── README.md
│   │   ├── ReadOnlyFilesystemAdapter.php
│   │   ├── ReadOnlyFilesystemAdapterTest.php
│   │   └── composer.json
│   ├── ResolveIdenticalPathConflict.php
│   ├── StorageAttributes.php
│   ├── SymbolicLinkEncountered.php
│   ├── UnableToCheckDirectoryExistence.php
│   ├── UnableToCheckExistence.php
│   ├── UnableToCheckFileExistence.php
│   ├── UnableToCopyFile.php
│   ├── UnableToCreateDirectory.php
│   ├── UnableToDeleteDirectory.php
│   ├── UnableToDeleteFile.php
│   ├── UnableToGeneratePublicUrl.php
│   ├── UnableToGenerateTemporaryUrl.php
│   ├── UnableToListContents.php
│   ├── UnableToMountFilesystem.php
│   ├── UnableToMoveFile.php
│   ├── UnableToProvideChecksum.php
│   ├── UnableToReadFile.php
│   ├── UnableToResolveFilesystemMount.php
│   ├── UnableToRetrieveMetadata.php
│   ├── UnableToSetVisibility.php
│   ├── UnableToWriteFile.php
│   ├── UnixVisibility/
│   │   ├── PortableVisibilityConverter.php
│   │   ├── PortableVisibilityConverterTest.php
│   │   └── VisibilityConverter.php
│   ├── UnreadableFileEncountered.php
│   ├── UrlGeneration/
│   │   ├── ChainedPublicUrlGenerator.php
│   │   ├── ChainedPublicUrlGeneratorTest.php
│   │   ├── PrefixPublicUrlGenerator.php
│   │   ├── PublicUrlGenerator.php
│   │   ├── ShardedPrefixPublicUrlGenerator.php
│   │   └── TemporaryUrlGenerator.php
│   ├── Visibility.php
│   ├── WebDAV/
│   │   ├── .gitattributes
│   │   ├── .github/
│   │   │   └── workflows/
│   │   │       └── close-subsplit-prs.yaml
│   │   ├── ByteMarkWebDAVServerTest.php
│   │   ├── LICENSE
│   │   ├── README.md
│   │   ├── SabreServerTest.php
│   │   ├── UrlPrefixingClientStub.php
│   │   ├── WebDAVAdapter.php
│   │   ├── WebDAVAdapterTestCase.php
│   │   ├── composer.json
│   │   └── resources/
│   │       ├── .gitignore
│   │       └── server.php
│   ├── WhitespacePathNormalizer.php
│   ├── WhitespacePathNormalizerTest.php
│   └── ZipArchive/
│       ├── .gitattributes
│       ├── .github/
│       │   └── workflows/
│       │       └── close-subsplit-prs.yaml
│       ├── FilesystemZipArchiveProvider.php
│       ├── LICENSE
│       ├── NoRootPrefixZipArchiveAdapterTest.php
│       ├── PrefixedRootZipArchiveAdapterTest.php
│       ├── README.md
│       ├── StubZipArchive.php
│       ├── StubZipArchiveProvider.php
│       ├── UnableToCreateParentDirectory.php
│       ├── UnableToOpenZipArchive.php
│       ├── ZipArchiveAdapter.php
│       ├── ZipArchiveAdapterTestCase.php
│       ├── ZipArchiveException.php
│       ├── ZipArchiveProvider.php
│       └── composer.json
└── test_files/
    ├── .gitignore
    ├── sftp/
    │   ├── id_rsa
    │   ├── id_rsa.pub
    │   ├── ssh_host_ed25519_key
    │   ├── ssh_host_ed25519_key.pub
    │   ├── ssh_host_rsa_key
    │   ├── ssh_host_rsa_key.pub
    │   ├── sshd_custom_configs.sh
    │   ├── unknown.key
    │   └── users.conf
    ├── toxiproxy/
    │   └── toxiproxy.json
    ├── wait_for_ftp.php
    └── wait_for_sftp.php
Download .txt
SYMBOL INDEX (1627 symbols across 175 files)

FILE: bin/check-versions.php
  function constraint_has_conflict (line 26) | function constraint_has_conflict(string $mainConstraint, string $package...

FILE: bin/tools.php
  function write_line (line 5) | function write_line(string $line)
  function panic (line 10) | function panic(string $reason)

FILE: mocked-functions.php
  function rmdir (line 4) | function rmdir(...$arguments)
  function unlink (line 13) | function unlink(...$arguments)
  function filemtime (line 22) | function filemtime(...$arguments)
  function filesize (line 31) | function filesize(...$arguments)
  function time (line 42) | function time()
  function ftp_raw (line 53) | function ftp_raw(...$arguments)
  function ftp_set_option (line 62) | function ftp_set_option(...$arguments)
  function ftp_pasv (line 71) | function ftp_pasv(...$arguments)
  function ftp_pwd (line 80) | function ftp_pwd(...$arguments)
  function ftp_fput (line 89) | function ftp_fput(...$arguments)
  function ftp_chmod (line 98) | function ftp_chmod(...$arguments)
  function ftp_mkdir (line 107) | function ftp_mkdir(...$arguments)
  function ftp_delete (line 116) | function ftp_delete(...$arguments)
  function ftp_rmdir (line 125) | function ftp_rmdir(...$arguments)
  function ftp_fget (line 134) | function ftp_fget(...$arguments)
  function ftp_rawlist (line 143) | function ftp_rawlist(...$arguments)
  function stream_get_contents (line 154) | function stream_get_contents(...$arguments)

FILE: src/AdapterTestUtilities/ExceptionThrowingFilesystemAdapter.php
  class ExceptionThrowingFilesystemAdapter (line 12) | class ExceptionThrowingFilesystemAdapter implements FilesystemAdapter
    method __construct (line 24) | public function __construct(FilesystemAdapter $adapter)
    method stageException (line 29) | public function stageException(string $method, string $path, Filesyste...
    method throwStagedException (line 34) | private function throwStagedException(string $method, $path): void
    method fileExists (line 48) | public function fileExists(string $path): bool
    method write (line 55) | public function write(string $path, string $contents, Config $config):...
    method writeStream (line 62) | public function writeStream(string $path, $contents, Config $config): ...
    method read (line 69) | public function read(string $path): string
    method readStream (line 76) | public function readStream(string $path)
    method delete (line 83) | public function delete(string $path): void
    method deleteDirectory (line 90) | public function deleteDirectory(string $path): void
    method createDirectory (line 97) | public function createDirectory(string $path, Config $config): void
    method setVisibility (line 104) | public function setVisibility(string $path, string $visibility): void
    method visibility (line 111) | public function visibility(string $path): FileAttributes
    method mimeType (line 118) | public function mimeType(string $path): FileAttributes
    method lastModified (line 125) | public function lastModified(string $path): FileAttributes
    method fileSize (line 132) | public function fileSize(string $path): FileAttributes
    method listContents (line 139) | public function listContents(string $path, bool $deep): iterable
    method move (line 146) | public function move(string $source, string $destination, Config $conf...
    method copy (line 153) | public function copy(string $source, string $destination, Config $conf...
    method directoryExists (line 160) | public function directoryExists(string $path): bool

FILE: src/AdapterTestUtilities/FilesystemAdapterTestCase.php
  class FilesystemAdapterTestCase (line 35) | abstract class FilesystemAdapterTestCase extends TestCase
    method clearFilesystemAdapterCache (line 49) | public static function clearFilesystemAdapterCache(): void
    method createFilesystemAdapter (line 54) | abstract protected static function createFilesystemAdapter(): Filesyst...
    method adapter (line 56) | public function adapter(): FilesystemAdapter
    method tearDownAfterClass (line 65) | public static function tearDownAfterClass(): void
    method setUp (line 70) | protected function setUp(): void
    method useAdapter (line 76) | protected function useAdapter(FilesystemAdapter $adapter): FilesystemA...
    method cleanupAdapter (line 87) | public function cleanupAdapter(): void
    method clearStorage (line 93) | public function clearStorage(): void
    method clearCustomAdapter (line 121) | public function clearCustomAdapter(): void
    method writing_and_reading_with_string (line 132) | public function writing_and_reading_with_string(): void
    method writing_a_file_with_a_stream (line 149) | public function writing_a_file_with_a_stream(): void
    method writing_and_reading_files_with_special_path (line 174) | public function writing_and_reading_files_with_special_path(string $pa...
    method filenameProvider (line 186) | public static function filenameProvider(): Generator
    method writing_a_file_with_an_empty_stream (line 207) | public function writing_a_file_with_an_empty_stream(): void
    method listing_a_directory_named_0 (line 231) | public function listing_a_directory_named_0(): void
    method reading_a_file (line 246) | public function reading_a_file(): void
    method reading_a_file_with_a_stream (line 260) | public function reading_a_file_with_a_stream(): void
    method overwriting_a_file (line 277) | public function overwriting_a_file(): void
    method a_file_exists_only_when_it_is_written_and_not_deleted (line 295) | public function a_file_exists_only_when_it_is_written_and_not_deleted(...
    method listing_contents_shallow (line 316) | public function listing_contents_shallow(): void
    method checking_if_a_non_existing_directory_exists (line 344) | public function checking_if_a_non_existing_directory_exists(): void
    method checking_if_a_directory_exists_after_writing_a_file (line 355) | public function checking_if_a_directory_exists_after_writing_a_file():...
    method checking_if_a_directory_exists_after_creating_it (line 367) | public function checking_if_a_directory_exists_after_creating_it(): void
    method listing_contents_recursive (line 383) | public function listing_contents_recursive(): void
    method formatIncorrectListingCount (line 397) | protected function formatIncorrectListingCount(array $items): string
    method givenWeHaveAnExistingFile (line 409) | protected function givenWeHaveAnExistingFile(string $path, string $con...
    method fetching_file_size (line 419) | public function fetching_file_size(): void
    method setting_visibility (line 434) | public function setting_visibility(): void
    method fetching_file_size_of_a_directory (line 455) | public function fetching_file_size_of_a_directory(): void
    method fetching_file_size_of_non_existing_file (line 470) | public function fetching_file_size_of_non_existing_file(): void
    method fetching_last_modified_of_non_existing_file (line 482) | public function fetching_last_modified_of_non_existing_file(): void
    method fetching_visibility_of_non_existing_file (line 494) | public function fetching_visibility_of_non_existing_file(): void
    method fetching_the_mime_type_of_an_svg_file (line 506) | public function fetching_the_mime_type_of_an_svg_file(): void
    method fetching_mime_type_of_non_existing_file (line 520) | public function fetching_mime_type_of_non_existing_file(): void
    method fetching_unknown_mime_type_of_a_file (line 532) | public function fetching_unknown_mime_type_of_a_file(): void
    method listing_a_toplevel_directory (line 549) | public function listing_a_toplevel_directory(): void
    method writing_and_reading_with_streams (line 564) | public function writing_and_reading_with_streams(): void
    method setting_visibility_on_a_file_that_does_not_exist (line 586) | public function setting_visibility_on_a_file_that_does_not_exist(): void
    method copying_a_file (line 598) | public function copying_a_file(): void
    method copying_a_file_that_does_not_exist (line 621) | public function copying_a_file_that_does_not_exist(): void
    method copying_a_file_again (line 633) | public function copying_a_file_again(): void
    method moving_a_file (line 655) | public function moving_a_file(): void
    method file_exists_on_directory_is_false (line 682) | public function file_exists_on_directory_is_false(): void
    method directory_exists_on_file_is_false (line 698) | public function directory_exists_on_file_is_false(): void
    method reading_a_file_that_does_not_exist (line 714) | public function reading_a_file_that_does_not_exist(): void
    method moving_a_file_that_does_not_exist (line 726) | public function moving_a_file_that_does_not_exist(): void
    method trying_to_delete_a_non_existing_file (line 738) | public function trying_to_delete_a_non_existing_file(): void
    method checking_if_files_exist (line 751) | public function checking_if_files_exist(): void
    method fetching_last_modified (line 767) | public function fetching_last_modified(): void
    method failing_to_read_a_non_existing_file_into_a_stream (line 785) | public function failing_to_read_a_non_existing_file_into_a_stream(): void
    method failing_to_read_a_non_existing_file (line 795) | public function failing_to_read_a_non_existing_file(): void
    method creating_a_directory (line 805) | public function creating_a_directory(): void
    method copying_a_file_with_collision (line 828) | public function copying_a_file_with_collision(): void
    method moving_a_file_with_collision (line 845) | public function moving_a_file_with_collision(): void
    method copying_a_file_with_same_destination (line 865) | public function copying_a_file_with_same_destination(): void
    method moving_a_file_with_same_destination (line 881) | public function moving_a_file_with_same_destination(): void
    method assertFileExistsAtPath (line 894) | protected function assertFileExistsAtPath(string $path): void
    method generating_a_public_url (line 905) | public function generating_a_public_url(): void
    method generating_a_temporary_url (line 924) | public function generating_a_temporary_url(): void
    method get_checksum (line 944) | public function get_checksum(): void
    method cannot_get_checksum_for_non_existent_file (line 960) | public function cannot_get_checksum_for_non_existent_file(): void
    method cannot_get_checksum_for_directory (line 976) | public function cannot_get_checksum_for_directory(): void

FILE: src/AdapterTestUtilities/RetryOnTestException.php
  type RetryOnTestException (line 15) | trait RetryOnTestException
    method retryOnException (line 27) | protected function retryOnException(string $className, int $timout = 2...
    method retryScenarioOnException (line 33) | protected function retryScenarioOnException(string $className, callabl...
    method dontRetryOnException (line 39) | protected function dontRetryOnException(): void
    method runSetup (line 49) | protected function runSetup(callable $scenario): void
    method runScenario (line 63) | protected function runScenario(callable $scenario): void

FILE: src/AdapterTestUtilities/ToxiproxyManagement.php
  class ToxiproxyManagement (line 20) | final class ToxiproxyManagement
    method __construct (line 25) | public function __construct(Client $apiClient)
    method forServer (line 30) | public static function forServer(string $apiUri = 'http://localhost:84...
    method removeAllToxics (line 42) | public function removeAllToxics(): void
    method resetPeerOnRequest (line 52) | public function resetPeerOnRequest(
    method addToxic (line 71) | private function addToxic(string $proxyName, array $configuration): void

FILE: src/AdapterTestUtilities/test-functions.php
  function return_mocked_value (line 5) | function return_mocked_value(string $name)
  function reset_function_mocks (line 10) | function reset_function_mocks()
  function mock_function (line 19) | function mock_function(string $name, ...$returns)
  function is_mocked (line 25) | function is_mocked(string $name)
  function stream_with_contents (line 30) | function stream_with_contents(string $contents)
  function delete_directory (line 39) | function delete_directory(string $dir): void

FILE: src/AsyncAwsS3/AsyncAwsS3Adapter.php
  class AsyncAwsS3Adapter (line 50) | class AsyncAwsS3Adapter implements FilesystemAdapter, PublicUrlGenerator...
    method __construct (line 112) | public function __construct(
    method fileExists (line 128) | public function fileExists(string $path): bool
    method write (line 142) | public function write(string $path, string $contents, Config $config):...
    method writeStream (line 147) | public function writeStream(string $path, $contents, Config $config): ...
    method read (line 152) | public function read(string $path): string
    method readStream (line 159) | public function readStream(string $path)
    method delete (line 166) | public function delete(string $path): void
    method deleteDirectory (line 177) | public function deleteDirectory(string $path): void
    method createDirectory (line 210) | public function createDirectory(string $path, Config $config): void
    method setVisibility (line 222) | public function setVisibility(string $path, string $visibility): void
    method visibility (line 237) | public function visibility(string $path): FileAttributes
    method mimeType (line 253) | public function mimeType(string $path): FileAttributes
    method lastModified (line 264) | public function lastModified(string $path): FileAttributes
    method fileSize (line 275) | public function fileSize(string $path): FileAttributes
    method directoryExists (line 286) | public function directoryExists(string $path): bool
    method listContents (line 298) | public function listContents(string $path, bool $deep): iterable
    method move (line 326) | public function move(string $source, string $destination, Config $conf...
    method copy (line 340) | public function copy(string $source, string $destination, Config $conf...
    method upload (line 373) | private function upload(string $path, $body, Config $config): void
    method determineAcl (line 401) | private function determineAcl(Config $config): string
    method createOptionsFromConfig (line 408) | private function createOptionsFromConfig(Config $config): array
    method fetchFileMetadata (line 423) | private function fetchFileMetadata(string $path, string $type): FileAt...
    method mapS3ObjectMetadata (line 446) | private function mapS3ObjectMetadata($item, ?string $path = null): Sto...
    method extractExtraMetadata (line 492) | private function extractExtraMetadata($metadata): array
    method retrievePaginatedListing (line 510) | private function retrievePaginatedListing(array $options): Generator
    method readObject (line 519) | private function readObject(string $path): ResultStream
    method createObjectIdentifierForXmlRequest (line 530) | private function createObjectIdentifierForXmlRequest(string $key): Obj...
    method publicUrl (line 541) | public function publicUrl(string $path, Config $config): string
    method checksum (line 554) | public function checksum(string $path, Config $config): string
    method temporaryUrl (line 575) | public function temporaryUrl(string $path, DateTimeInterface $expiresA...

FILE: src/AsyncAwsS3/AsyncAwsS3AdapterTest.php
  class AsyncAwsS3AdapterTest (line 39) | class AsyncAwsS3AdapterTest extends FilesystemAdapterTestCase
    method awsConfig (line 61) | private static function awsConfig(): array
    method setUp (line 78) | protected function setUp(): void
    method setUpBeforeClass (line 84) | public static function setUpBeforeClass(): void
    method tearDown (line 89) | protected function tearDown(): void
    method s3Client (line 109) | private static function s3Client(): S3Client
    method specifying_a_custom_checksum_algo_is_not_supported (line 129) | public function specifying_a_custom_checksum_algo_is_not_supported(): ...
    method issue_287 (line 144) | public function issue_287(): void
    method writing_with_a_specific_mime_type (line 155) | public function writing_with_a_specific_mime_type(): void
    method listing_contents_recursive (line 166) | public function listing_contents_recursive(): void
    method failing_to_delete_while_moving (line 187) | public function failing_to_delete_while_moving(): void
    method failing_to_delete_a_file (line 201) | public function failing_to_delete_a_file(): void
    method delete_directory_replaces_special_characters_by_xml_entity_codes (line 214) | public function delete_directory_replaces_special_characters_by_xml_en...
    method delete_directory_throws_exception_if_object_key_can_not_be_escaped_correctly (line 237) | public function delete_directory_throws_exception_if_object_key_can_no...
    method fetching_unknown_mime_type_of_a_file (line 268) | public function fetching_unknown_mime_type_of_a_file(): void
    method failing_to_retrieve_metadata (line 282) | public function failing_to_retrieve_metadata(Exception $exception, str...
    method dpFailingMetadataGetters (line 293) | public static function dpFailingMetadataGetters(): iterable
    method failing_to_check_for_file_existence (line 303) | public function failing_to_check_for_file_existence(): void
    method configuring_http_streaming_via_options (line 317) | public function configuring_http_streaming_via_options(): void
    method write_with_s3_client (line 332) | public function write_with_s3_client(): void
    method write_with_simple_s3_client (line 366) | public function write_with_simple_s3_client(): void
    method failing_to_write_a_file (line 389) | public function failing_to_write_a_file(): void
    method moving_a_file_with_visibility (line 401) | public function moving_a_file_with_visibility(): void
    method copying_a_file_with_visibility (line 427) | public function copying_a_file_with_visibility(): void
    method copying_a_file_with_non_ascii_characters (line 449) | public function copying_a_file_with_non_ascii_characters(): void
    method top_level_directory_excluded_from_listing (line 470) | public function top_level_directory_excluded_from_listing(): void
    method failing_to_list_contents (line 490) | public function failing_to_list_contents(): void
    method createFilesystemAdapter (line 500) | protected static function createFilesystemAdapter(): FilesystemAdapter

FILE: src/AsyncAwsS3/PortableVisibilityConverter.php
  class PortableVisibilityConverter (line 10) | class PortableVisibilityConverter implements VisibilityConverter
    method __construct (line 22) | public function __construct(string $defaultForDirectories = Visibility...
    method visibilityToAcl (line 27) | public function visibilityToAcl(string $visibility): string
    method aclToVisibility (line 39) | public function aclToVisibility(array $grants): string
    method defaultForDirectories (line 56) | public function defaultForDirectories(): string

FILE: src/AsyncAwsS3/S3ClientStub.php
  class S3ClientStub (line 37) | class S3ClientStub extends SimpleS3Client
    method __construct (line 54) | public function __construct(SimpleS3Client $client, $configuration = [])
    method throwExceptionWhenExecutingCommand (line 60) | public function throwExceptionWhenExecutingCommand(string $commandName...
    method stageResultForCommand (line 65) | public function stageResultForCommand(string $commandName, Result $res...
    method getStagedResult (line 70) | private function getStagedResult(string $name): ?Result
    method copyObject (line 92) | public function copyObject($input): CopyObjectOutput
    method deleteObject (line 101) | public function deleteObject($input): DeleteObjectOutput
    method headObject (line 110) | public function headObject($input): HeadObjectOutput
    method objectExists (line 119) | public function objectExists($input): ObjectExistsWaiter
    method listObjectsV2 (line 128) | public function listObjectsV2($input): ListObjectsV2Output
    method deleteObjects (line 137) | public function deleteObjects($input): DeleteObjectsOutput
    method getObjectAcl (line 146) | public function getObjectAcl($input): GetObjectAclOutput
    method putObjectAcl (line 155) | public function putObjectAcl($input): PutObjectAclOutput
    method putObject (line 164) | public function putObject($input): PutObjectOutput
    method getObject (line 173) | public function getObject($input): GetObjectOutput
    method getUrl (line 179) | public function getUrl(string $bucket, string $key): string
    method getPresignedUrl (line 184) | public function getPresignedUrl(string $bucket, string $key, ?DateTime...

FILE: src/AsyncAwsS3/VisibilityConverter.php
  type VisibilityConverter (line 9) | interface VisibilityConverter
    method visibilityToAcl (line 11) | public function visibilityToAcl(string $visibility): string;
    method aclToVisibility (line 16) | public function aclToVisibility(array $grants): string;
    method defaultForDirectories (line 18) | public function defaultForDirectories(): string;

FILE: src/AwsS3V3/AwsS3V3Adapter.php
  class AwsS3V3Adapter (line 42) | class AwsS3V3Adapter implements FilesystemAdapter, PublicUrlGenerator, C...
    method __construct (line 101) | public function __construct(
    method fileExists (line 118) | public function fileExists(string $path): bool
    method directoryExists (line 127) | public function directoryExists(string $path): bool
    method write (line 141) | public function write(string $path, string $contents, Config $config):...
    method upload (line 151) | private function upload(string $path, $body, Config $config): void
    method determineAcl (line 169) | private function determineAcl(Config $config): string
    method createOptionsFromConfig (line 176) | private function createOptionsFromConfig(Config $config): array
    method writeStream (line 204) | public function writeStream(string $path, $contents, Config $config): ...
    method read (line 209) | public function read(string $path): string
    method readStream (line 216) | public function readStream(string $path)
    method delete (line 224) | public function delete(string $path): void
    method deleteDirectory (line 236) | public function deleteDirectory(string $path): void
    method createDirectory (line 248) | public function createDirectory(string $path, Config $config): void
    method setVisibility (line 255) | public function setVisibility(string $path, string $visibility): void
    method visibility (line 271) | public function visibility(string $path): FileAttributes
    method fetchFileMetadata (line 287) | private function fetchFileMetadata(string $path, string $type): FileAt...
    method mapS3ObjectMetadata (line 307) | private function mapS3ObjectMetadata(array $metadata, string $path): S...
    method extractExtraMetadata (line 329) | private function extractExtraMetadata(array $metadata): array
    method mimeType (line 342) | public function mimeType(string $path): FileAttributes
    method lastModified (line 353) | public function lastModified(string $path): FileAttributes
    method fileSize (line 364) | public function fileSize(string $path): FileAttributes
    method listContents (line 375) | public function listContents(string $path, bool $deep): iterable
    method retrievePaginatedListing (line 398) | private function retrievePaginatedListing(array $options): Generator
    method move (line 408) | public function move(string $source, string $destination, Config $conf...
    method copy (line 422) | public function copy(string $source, string $destination, Config $conf...
    method readObject (line 459) | private function readObject(string $path, bool $wantsStream): StreamIn...
    method publicUrl (line 476) | public function publicUrl(string $path, Config $config): string
    method checksum (line 487) | public function checksum(string $path, Config $config): string
    method temporaryUrl (line 508) | public function temporaryUrl(string $path, DateTimeInterface $expiresA...

FILE: src/AwsS3V3/AwsS3V3AdapterTest.php
  class AwsS3V3AdapterTest (line 33) | class AwsS3V3AdapterTest extends FilesystemAdapterTestCase
    method setUpBeforeClass (line 55) | public static function setUpBeforeClass(): void
    method tearDown (line 60) | protected function tearDown(): void
    method setUp (line 82) | protected function setUp(): void
    method s3Client (line 91) | private static function s3Client(): S3ClientInterface
    method writing_with_a_specific_mime_type (line 114) | public function writing_with_a_specific_mime_type(): void
    method writing_a_file_with_explicit_mime_type (line 125) | public function writing_a_file_with_explicit_mime_type(): void
    method issue_291 (line 138) | public function issue_291(): void
    method listing_contents_recursive (line 150) | public function listing_contents_recursive(): void
    method failing_to_delete_while_moving (line 171) | public function failing_to_delete_while_moving(): void
    method issue_287 (line 187) | public function issue_287(): void
    method failing_to_write_a_file (line 198) | public function failing_to_write_a_file(): void
    method failing_to_delete_a_file (line 211) | public function failing_to_delete_a_file(): void
    method fetching_unknown_mime_type_of_a_file (line 224) | public function fetching_unknown_mime_type_of_a_file(): void
    method failing_to_retrieve_metadata (line 240) | public function failing_to_retrieve_metadata(Exception $exception, str...
    method dpFailingMetadataGetters (line 253) | public static function dpFailingMetadataGetters(): iterable
    method failing_to_check_for_file_existence (line 263) | public function failing_to_check_for_file_existence(): void
    method streaming_reads_are_not_seekable_and_non_streaming_are (line 279) | public function streaming_reads_are_not_seekable_and_non_streaming_are...
    method casesWhereHttpStreamingInfluencesSeekability (line 295) | public static function casesWhereHttpStreamingInfluencesSeekability():...
    method configuring_http_streaming_via_options (line 306) | public function configuring_http_streaming_via_options(bool $streaming...
    method use_globally_configured_options (line 323) | public function use_globally_configured_options(bool $streaming): void
    method moving_with_updated_metadata (line 335) | public function moving_with_updated_metadata(): void
    method moving_without_updated_metadata (line 352) | public function moving_without_updated_metadata(): void
    method copying_with_updated_metadata (line 369) | public function copying_with_updated_metadata(): void
    method setting_acl_via_options (line 386) | public function setting_acl_via_options(): void
    method moving_a_file_with_visibility (line 404) | public function moving_a_file_with_visibility(): void
    method specifying_a_custom_checksum_algo_is_not_supported (line 430) | public function specifying_a_custom_checksum_algo_is_not_supported(): ...
    method copying_a_file_with_visibility (line 443) | public function copying_a_file_with_visibility(): void
    method createFilesystemAdapter (line 462) | protected static function createFilesystemAdapter(bool $streaming = tr...

FILE: src/AwsS3V3/PortableVisibilityConverter.php
  class PortableVisibilityConverter (line 9) | class PortableVisibilityConverter implements VisibilityConverter
    method __construct (line 16) | public function __construct(private string $defaultForDirectories = Vi...
    method visibilityToAcl (line 20) | public function visibilityToAcl(string $visibility): string
    method aclToVisibility (line 29) | public function aclToVisibility(array $grants): string
    method defaultForDirectories (line 43) | public function defaultForDirectories(): string

FILE: src/AwsS3V3/S3ClientStub.php
  class S3ClientStub (line 22) | class S3ClientStub implements S3ClientInterface
    method __construct (line 46) | public function __construct(S3ClientInterface $client)
    method throwDuringUpload (line 51) | public function throwDuringUpload(Throwable $throwable): void
    method upload (line 56) | public function upload($bucket, $key, $body, $acl = 'private', array $...
    method failOnNextCopy (line 67) | public function failOnNextCopy(): void
    method throwExceptionWhenExecutingCommand (line 72) | public function throwExceptionWhenExecutingCommand(string $commandName...
    method throw500ExceptionWhenExecutingCommand (line 77) | public function throw500ExceptionWhenExecutingCommand(string $commandN...
    method stageResultForCommand (line 85) | public function stageResultForCommand(string $commandName, ResultInter...
    method execute (line 90) | public function execute(CommandInterface $command)
    method getCommand (line 95) | public function getCommand($name, array $args = [])
    method getHandlerList (line 100) | public function getHandlerList()
    method getIterator (line 105) | public function getIterator($name, array $args = [])
    method __call (line 110) | public function __call($name, array $arguments)
    method executeAsync (line 115) | public function executeAsync(CommandInterface $command)
    method getCredentials (line 135) | public function getCredentials()
    method getRegion (line 140) | public function getRegion()
    method getEndpoint (line 145) | public function getEndpoint()
    method getApi (line 150) | public function getApi()
    method getConfig (line 155) | public function getConfig($option = null)
    method getPaginator (line 160) | public function getPaginator($name, array $args = [])
    method waitUntil (line 165) | public function waitUntil($name, array $args = [])
    method getWaiter (line 170) | public function getWaiter($name, array $args = [])
    method createPresignedRequest (line 175) | public function createPresignedRequest(CommandInterface $command, $exp...
    method getObjectUrl (line 180) | public function getObjectUrl($bucket, $key)

FILE: src/AwsS3V3/VisibilityConverter.php
  type VisibilityConverter (line 7) | interface VisibilityConverter
    method visibilityToAcl (line 9) | public function visibilityToAcl(string $visibility): string;
    method aclToVisibility (line 10) | public function aclToVisibility(array $grants): string;
    method defaultForDirectories (line 11) | public function defaultForDirectories(): string;

FILE: src/AzureBlobStorage/AzureBlobStorageAdapter.php
  class AzureBlobStorageAdapter (line 46) | class AzureBlobStorageAdapter implements FilesystemAdapter, PublicUrlGen...
    method __construct (line 62) | public function __construct(
    method copy (line 75) | public function copy(string $source, string $destination, Config $conf...
    method delete (line 92) | public function delete(string $path): void
    method read (line 107) | public function read(string $path): string
    method readStream (line 114) | public function readStream(string $path)
    method listContents (line 127) | public function listContents(string $path, bool $deep = false): iterable
    method fileExists (line 158) | public function fileExists(string $path): bool
    method directoryExists (line 171) | public function directoryExists(string $path): bool
    method deleteDirectory (line 187) | public function deleteDirectory(string $path): void
    method createDirectory (line 212) | public function createDirectory(string $path, Config $config): void
    method setVisibility (line 217) | public function setVisibility(string $path, string $visibility): void
    method visibility (line 224) | public function visibility(string $path): FileAttributes
    method mimeType (line 229) | public function mimeType(string $path): FileAttributes
    method lastModified (line 238) | public function lastModified(string $path): FileAttributes
    method fileSize (line 247) | public function fileSize(string $path): FileAttributes
    method move (line 256) | public function move(string $source, string $destination, Config $conf...
    method write (line 266) | public function write(string $path, string $contents, Config $config):...
    method writeStream (line 271) | public function writeStream(string $path, $contents, Config $config): ...
    method upload (line 279) | private function upload(string $destination, $contents, Config $config...
    method fetchMetadata (line 300) | private function fetchMetadata(string $path): FileAttributes
    method getOptionsFromConfig (line 308) | private function getOptionsFromConfig(Config $config): CreateBlockBlob...
    method normalizeBlobProperties (line 331) | private function normalizeBlobProperties(string $path, BlobProperties ...
    method publicUrl (line 343) | public function publicUrl(string $path, Config $config): string
    method checksum (line 350) | public function checksum(string $path, Config $config): string
    method temporaryUrl (line 372) | public function temporaryUrl(string $path, DateTimeInterface $expiresA...

FILE: src/AzureBlobStorage/AzureBlobStorageAdapterTest.php
  class AzureBlobStorageAdapterTest (line 19) | class AzureBlobStorageAdapterTest extends TestCase
    method createFilesystemAdapter (line 23) | protected static function createFilesystemAdapter(): FilesystemAdapter
    method overwriting_a_file (line 45) | public function overwriting_a_file(): void
    method setting_visibility (line 63) | public function setting_visibility(): void
    method failing_to_set_visibility (line 71) | public function failing_to_set_visibility(): void
    method failing_to_check_visibility (line 79) | public function failing_to_check_visibility(): void
    method fetching_unknown_mime_type_of_a_file (line 84) | public function fetching_unknown_mime_type_of_a_file(): void
    method listing_contents_recursive (line 89) | public function listing_contents_recursive(): void
    method copying_a_file (line 97) | public function copying_a_file(): void
    method moving_a_file (line 118) | public function moving_a_file(): void
    method copying_a_file_again (line 143) | public function copying_a_file_again(): void
    method setting_visibility_can_be_ignored_not_supported (line 164) | public function setting_visibility_can_be_ignored_not_supported(): void
    method setting_visibility_causes_errors (line 178) | public function setting_visibility_causes_errors(): void
    method checking_if_a_directory_exists_after_creating_it (line 191) | public function checking_if_a_directory_exists_after_creating_it(): void
    method setting_visibility_on_a_file_that_does_not_exist (line 199) | public function setting_visibility_on_a_file_that_does_not_exist(): void
    method creating_a_directory (line 207) | public function creating_a_directory(): void

FILE: src/CalculateChecksumFromStream.php
  type CalculateChecksumFromStream (line 10) | trait CalculateChecksumFromStream
    method calculateChecksumFromStream (line 12) | private function calculateChecksumFromStream(string $path, Config $con...
    method readStream (line 29) | abstract public function readStream(string $path);

FILE: src/ChecksumAlgoIsNotSupported.php
  class ChecksumAlgoIsNotSupported (line 8) | final class ChecksumAlgoIsNotSupported extends InvalidArgumentException

FILE: src/ChecksumProvider.php
  type ChecksumProvider (line 5) | interface ChecksumProvider
    method checksum (line 13) | public function checksum(string $path, Config $config): string;

FILE: src/Config.php
  class Config (line 11) | class Config
    method __construct (line 19) | public function __construct(private array $options = [])
    method get (line 28) | public function get(string $property, $default = null)
    method extend (line 33) | public function extend(array $options): Config
    method withDefaults (line 38) | public function withDefaults(array $defaults): Config
    method toArray (line 43) | public function toArray(): array
    method withSetting (line 48) | public function withSetting(string $property, mixed $setting): Config
    method withoutSettings (line 53) | public function withoutSettings(string ...$settings): Config

FILE: src/ConfigTest.php
  class ConfigTest (line 9) | class ConfigTest extends TestCase
    method a_config_object_exposes_passed_options (line 14) | public function a_config_object_exposes_passed_options(): void
    method a_config_object_returns_a_default_value (line 23) | public function a_config_object_returns_a_default_value(): void
    method extending_a_config_with_options (line 34) | public function extending_a_config_with_options(): void
    method extending_with_defaults (line 47) | public function extending_with_defaults(): void
    method extending_without_settings (line 60) | public function extending_without_settings(): void

FILE: src/CorruptedPathDetected.php
  class CorruptedPathDetected (line 7) | final class CorruptedPathDetected extends RuntimeException implements Fi...
    method forPath (line 9) | public static function forPath(string $path): CorruptedPathDetected

FILE: src/DecoratedAdapter.php
  class DecoratedAdapter (line 7) | abstract class DecoratedAdapter implements FilesystemAdapter
    method __construct (line 9) | public function __construct(protected FilesystemAdapter $adapter)
    method fileExists (line 13) | public function fileExists(string $path): bool
    method directoryExists (line 18) | public function directoryExists(string $path): bool
    method write (line 23) | public function write(string $path, string $contents, Config $config):...
    method writeStream (line 28) | public function writeStream(string $path, $contents, Config $config): ...
    method read (line 33) | public function read(string $path): string
    method readStream (line 38) | public function readStream(string $path)
    method delete (line 43) | public function delete(string $path): void
    method deleteDirectory (line 48) | public function deleteDirectory(string $path): void
    method createDirectory (line 53) | public function createDirectory(string $path, Config $config): void
    method setVisibility (line 58) | public function setVisibility(string $path, string $visibility): void
    method visibility (line 63) | public function visibility(string $path): FileAttributes
    method mimeType (line 68) | public function mimeType(string $path): FileAttributes
    method lastModified (line 73) | public function lastModified(string $path): FileAttributes
    method fileSize (line 78) | public function fileSize(string $path): FileAttributes
    method listContents (line 83) | public function listContents(string $path, bool $deep): iterable
    method move (line 88) | public function move(string $source, string $destination, Config $conf...
    method copy (line 93) | public function copy(string $source, string $destination, Config $conf...

FILE: src/DirectoryAttributes.php
  class DirectoryAttributes (line 7) | class DirectoryAttributes implements StorageAttributes
    method __construct (line 12) | public function __construct(
    method path (line 21) | public function path(): string
    method type (line 26) | public function type(): string
    method visibility (line 31) | public function visibility(): ?string
    method lastModified (line 36) | public function lastModified(): ?int
    method extraMetadata (line 41) | public function extraMetadata(): array
    method isFile (line 46) | public function isFile(): bool
    method isDir (line 51) | public function isDir(): bool
    method withPath (line 56) | public function withPath(string $path): self
    method fromArray (line 64) | public static function fromArray(array $attributes): self
    method jsonSerialize (line 77) | public function jsonSerialize(): array

FILE: src/DirectoryAttributesTest.php
  class DirectoryAttributesTest (line 12) | class DirectoryAttributesTest extends TestCase
    method exposing_some_values (line 17) | public function exposing_some_values(): void
    method exposing_visibility (line 30) | public function exposing_visibility(): void
    method exposing_last_modified (line 39) | public function exposing_last_modified(): void
    method exposing_extra_meta_data (line 48) | public function exposing_extra_meta_data(): void
    method serialization_capabilities (line 57) | public function serialization_capabilities(): void

FILE: src/DirectoryListing.php
  class DirectoryListing (line 15) | class DirectoryListing implements IteratorAggregate
    method __construct (line 20) | public function __construct(private iterable $listing)
    method filter (line 29) | public function filter(callable $filter): DirectoryListing
    method map (line 49) | public function map(callable $mapper): DirectoryListing
    method sortByPath (line 63) | public function sortByPath(): DirectoryListing
    method getIterator (line 77) | public function getIterator(): Traversable
    method toArray (line 87) | public function toArray(): array

FILE: src/DirectoryListingTest.php
  class DirectoryListingTest (line 15) | class DirectoryListingTest extends TestCase
    method mapping_a_listing (line 20) | public function mapping_a_listing(): void
    method mapping_a_listing_twice (line 37) | public function mapping_a_listing_twice(): void
    method filter_a_listing (line 57) | public function filter_a_listing(): void
    method filter_a_listing_twice (line 74) | public function filter_a_listing_twice(): void
    method sorting_a_directory_listing (line 94) | public function sorting_a_directory_listing(): void
    method iterating_over_storted_output (line 120) | public function iterating_over_storted_output(): void
    method generateIntegers (line 137) | private function generateIntegers(int $min, int $max): Generator

FILE: src/ExceptionInformationTest.php
  class ExceptionInformationTest (line 12) | class ExceptionInformationTest extends TestCase
    method copy_exception_information (line 17) | public function copy_exception_information(): void
    method create_directory_exception_information (line 28) | public function create_directory_exception_information(): void
    method delete_directory_exception_information (line 39) | public function delete_directory_exception_information(): void
    method delete_file_exception_information (line 51) | public function delete_file_exception_information(): void
    method unable_to_check_for_file_existence (line 63) | public function unable_to_check_for_file_existence(): void
    method unable_to_check_for_existence (line 72) | public function unable_to_check_for_existence(): void
    method unable_to_check_for_directory_existence (line 81) | public function unable_to_check_for_directory_existence(): void
    method move_file_exception_information (line 90) | public function move_file_exception_information(): void
    method read_file_exception_information (line 101) | public function read_file_exception_information(): void
    method retrieve_visibility_exception_information (line 113) | public function retrieve_visibility_exception_information(): void
    method set_visibility_exception_information (line 125) | public function set_visibility_exception_information(): void
    method write_file_exception_information (line 137) | public function write_file_exception_information(): void
    method unreadable_file_exception_information (line 149) | public function unreadable_file_exception_information(): void
    method symbolic_link_exception_information (line 159) | public function symbolic_link_exception_information(): void
    method path_traversal_exception_information (line 169) | public function path_traversal_exception_information(): void

FILE: src/FileAttributes.php
  class FileAttributes (line 7) | class FileAttributes implements StorageAttributes
    method __construct (line 12) | public function __construct(
    method type (line 23) | public function type(): string
    method path (line 28) | public function path(): string
    method fileSize (line 33) | public function fileSize(): ?int
    method visibility (line 38) | public function visibility(): ?string
    method lastModified (line 43) | public function lastModified(): ?int
    method mimeType (line 48) | public function mimeType(): ?string
    method extraMetadata (line 53) | public function extraMetadata(): array
    method isFile (line 58) | public function isFile(): bool
    method isDir (line 63) | public function isDir(): bool
    method withPath (line 68) | public function withPath(string $path): self
    method fromArray (line 76) | public static function fromArray(array $attributes): self
    method jsonSerialize (line 88) | public function jsonSerialize(): array

FILE: src/FileAttributesTest.php
  class FileAttributesTest (line 17) | class FileAttributesTest extends TestCase
    method exposing_some_values (line 22) | public function exposing_some_values(): void
    method exposing_all_values (line 38) | public function exposing_all_values(): void
    method implements_array_access (line 53) | public function implements_array_access(): void
    method properties_can_not_be_set (line 69) | public function properties_can_not_be_set(): void
    method properties_can_not_be_unset (line 79) | public function properties_can_not_be_unset(): void
    method json_transformations (line 91) | public function json_transformations(FileAttributes $attributes): void
    method data_provider_for_json_transformation (line 98) | public static function data_provider_for_json_transformation(): Generator

FILE: src/Filesystem.php
  class Filesystem (line 18) | class Filesystem implements FilesystemOperator
    method __construct (line 25) | public function __construct(
    method fileExists (line 36) | public function fileExists(string $location): bool
    method directoryExists (line 41) | public function directoryExists(string $location): bool
    method has (line 46) | public function has(string $location): bool
    method write (line 53) | public function write(string $location, string $contents, array $confi...
    method writeStream (line 62) | public function writeStream(string $location, $contents, array $config...
    method read (line 74) | public function read(string $location): string
    method readStream (line 79) | public function readStream(string $location)
    method delete (line 84) | public function delete(string $location): void
    method deleteDirectory (line 89) | public function deleteDirectory(string $location): void
    method createDirectory (line 94) | public function createDirectory(string $location, array $config = []):...
    method listContents (line 102) | public function listContents(string $location, bool $deep = self::LIST...
    method pipeListing (line 110) | private function pipeListing(string $location, bool $deep, iterable $l...
    method move (line 121) | public function move(string $source, string $destination, array $confi...
    method copy (line 140) | public function copy(string $source, string $destination, array $confi...
    method lastModified (line 159) | public function lastModified(string $path): int
    method fileSize (line 164) | public function fileSize(string $path): int
    method mimeType (line 169) | public function mimeType(string $path): string
    method setVisibility (line 174) | public function setVisibility(string $path, string $visibility): void
    method visibility (line 179) | public function visibility(string $path): string
    method publicUrl (line 184) | public function publicUrl(string $path, array $config = []): string
    method temporaryUrl (line 196) | public function temporaryUrl(string $path, DateTimeInterface $expiresA...
    method checksum (line 211) | public function checksum(string $path, array $config = []): string
    method resolvePublicUrlGenerator (line 232) | private function resolvePublicUrlGenerator(): ?PublicUrlGenerator
    method assertIsResource (line 251) | private function assertIsResource($contents): void
    method rewindStream (line 267) | private function rewindStream($resource): void
    method resolveConfigForMoveAndCopy (line 274) | private function resolveConfigForMoveAndCopy(array $config): Config

FILE: src/FilesystemAdapter.php
  type FilesystemAdapter (line 7) | interface FilesystemAdapter
    method fileExists (line 13) | public function fileExists(string $path): bool;
    method directoryExists (line 19) | public function directoryExists(string $path): bool;
    method write (line 25) | public function write(string $path, string $contents, Config $config):...
    method writeStream (line 33) | public function writeStream(string $path, $contents, Config $config): ...
    method read (line 39) | public function read(string $path): string;
    method readStream (line 47) | public function readStream(string $path);
    method delete (line 53) | public function delete(string $path): void;
    method deleteDirectory (line 59) | public function deleteDirectory(string $path): void;
    method createDirectory (line 65) | public function createDirectory(string $path, Config $config): void;
    method setVisibility (line 71) | public function setVisibility(string $path, string $visibility): void;
    method visibility (line 77) | public function visibility(string $path): FileAttributes;
    method mimeType (line 83) | public function mimeType(string $path): FileAttributes;
    method lastModified (line 89) | public function lastModified(string $path): FileAttributes;
    method fileSize (line 95) | public function fileSize(string $path): FileAttributes;
    method listContents (line 102) | public function listContents(string $path, bool $deep): iterable;
    method move (line 108) | public function move(string $source, string $destination, Config $conf...
    method copy (line 114) | public function copy(string $source, string $destination, Config $conf...

FILE: src/FilesystemException.php
  type FilesystemException (line 9) | interface FilesystemException extends Throwable

FILE: src/FilesystemOperationFailed.php
  type FilesystemOperationFailed (line 7) | interface FilesystemOperationFailed extends FilesystemException
    method operation (line 24) | public function operation(): string;

FILE: src/FilesystemOperator.php
  type FilesystemOperator (line 7) | interface FilesystemOperator extends FilesystemReader, FilesystemWriter

FILE: src/FilesystemReader.php
  type FilesystemReader (line 17) | interface FilesystemReader
    method fileExists (line 26) | public function fileExists(string $location): bool;
    method directoryExists (line 32) | public function directoryExists(string $location): bool;
    method has (line 38) | public function has(string $location): bool;
    method read (line 44) | public function read(string $location): string;
    method readStream (line 52) | public function readStream(string $location);
    method listContents (line 60) | public function listContents(string $location, bool $deep = self::LIST...
    method lastModified (line 66) | public function lastModified(string $path): int;
    method fileSize (line 72) | public function fileSize(string $path): int;
    method mimeType (line 78) | public function mimeType(string $path): string;
    method visibility (line 84) | public function visibility(string $path): string;

FILE: src/FilesystemTest.php
  class FilesystemTest (line 25) | class FilesystemTest extends TestCase
    method setupFilesystem (line 37) | public function setupFilesystem(): void
    method removeFiles (line 47) | public function removeFiles(): void
    method writing_and_reading_files (line 55) | public function writing_and_reading_files(): void
    method trying_to_write_with_an_invalid_stream_arguments (line 70) | public function trying_to_write_with_an_invalid_stream_arguments($inpu...
    method invalidStreamInput (line 77) | public static function invalidStreamInput(): Generator
    method writing_and_reading_a_stream (line 88) | public function writing_and_reading_a_stream(): void
    method writing_using_a_stream_wrapper (line 106) | public function writing_using_a_stream_wrapper(): void
    method checking_if_files_exist (line 121) | public function checking_if_files_exist(): void
    method checking_if_directories_exist (line 135) | public function checking_if_directories_exist(): void
    method deleting_a_file (line 149) | public function deleting_a_file(): void
    method creating_a_directory (line 160) | public function creating_a_directory(): void
    method deleting_a_directory (line 172) | public function deleting_a_directory(): void
    method listing_directory_contents (line 192) | public function listing_directory_contents(): void
    method listing_directory_contents_recursive (line 211) | public function listing_directory_contents_recursive(): void
    method copying_files (line 227) | public function copying_files(): void
    method moving_files (line 240) | public function moving_files(): void
    method fetching_last_modified (line 253) | public function fetching_last_modified(): void
    method fetching_mime_type (line 267) | public function fetching_mime_type(): void
    method fetching_file_size (line 279) | public function fetching_file_size(): void
    method ensuring_streams_are_rewound_when_writing (line 291) | public function ensuring_streams_are_rewound_when_writing(): void
    method setting_visibility (line 305) | public function setting_visibility(): void
    method protecting_against_path_traversals (line 324) | public function protecting_against_path_traversals(callable $scenario)...
    method scenariosCausingPathTraversal (line 330) | public static function scenariosCausingPathTraversal(): Generator
    method listing_exceptions_are_uniformely_represented (line 396) | public function listing_exceptions_are_uniformely_represented(): void
    method failing_to_create_a_public_url (line 417) | public function failing_to_create_a_public_url(): void
    method not_configuring_a_public_url (line 436) | public function not_configuring_a_public_url(): void
    method creating_a_public_url (line 448) | public function creating_a_public_url(): void
    method public_url_array_uses_multi_prefixer (line 463) | public function public_url_array_uses_multi_prefixer(): void
    method custom_public_url_generator (line 486) | public function custom_public_url_generator(): void
    method copying_from_and_to_the_same_location_fails (line 505) | public function copying_from_and_to_the_same_location_fails(): void
    method moving_from_and_to_the_same_location_fails (line 516) | public function moving_from_and_to_the_same_location_fails(): void
    method get_checksum_for_adapter_that_supports (line 527) | public function get_checksum_for_adapter_that_supports(): void
    method get_checksum_for_adapter_that_does_not_support (line 537) | public function get_checksum_for_adapter_that_does_not_support(): void
    method get_checksum_for_adapter_that_does_not_support_specific_algo (line 549) | public function get_checksum_for_adapter_that_does_not_support_specifi...
    method get_sha256_checksum_for_adapter_that_does_not_support (line 567) | public function get_sha256_checksum_for_adapter_that_does_not_support(...
    method get_sha256_checksum_for_adapter_that_does_not_support_while_crc32c_is_the_default (line 579) | public function get_sha256_checksum_for_adapter_that_does_not_support_...
    method unable_to_get_checksum_for_for_file_that_does_not_exist (line 592) | public function unable_to_get_checksum_for_for_file_that_does_not_exis...
    method generating_temporary_urls (line 604) | public function generating_temporary_urls(): void
    method not_being_able_to_generate_temporary_urls (line 626) | public function not_being_able_to_generate_temporary_urls(): void
    method ignoring_same_paths_for_move_and_copy (line 638) | public function ignoring_same_paths_for_move_and_copy(): void
    method failing_same_paths_for_move (line 657) | public function failing_same_paths_for_move(): void
    method failing_same_paths_for_copy (line 673) | public function failing_same_paths_for_copy(): void
    method unable_to_get_checksum_directory (line 689) | public function unable_to_get_checksum_directory(): void
    method moving_a_file_with_visibility_scenario (line 704) | public function moving_a_file_with_visibility_scenario(
    method copying_a_file_with_visibility_scenario (line 730) | public function copying_a_file_with_visibility_scenario(
    method fileMoveOrCopyScenarios (line 751) | public static function fileMoveOrCopyScenarios(): iterable

FILE: src/FilesystemWriter.php
  type FilesystemWriter (line 7) | interface FilesystemWriter
    method write (line 13) | public function write(string $location, string $contents, array $confi...
    method writeStream (line 21) | public function writeStream(string $location, $contents, array $config...
    method setVisibility (line 27) | public function setVisibility(string $path, string $visibility): void;
    method delete (line 33) | public function delete(string $location): void;
    method deleteDirectory (line 39) | public function deleteDirectory(string $location): void;
    method createDirectory (line 45) | public function createDirectory(string $location, array $config = []):...
    method move (line 51) | public function move(string $source, string $destination, array $confi...
    method copy (line 57) | public function copy(string $source, string $destination, array $confi...

FILE: src/Ftp/ConnectionProvider.php
  type ConnectionProvider (line 7) | interface ConnectionProvider
    method createConnection (line 12) | public function createConnection(FtpConnectionOptions $options);

FILE: src/Ftp/ConnectivityChecker.php
  type ConnectivityChecker (line 7) | interface ConnectivityChecker
    method isConnected (line 12) | public function isConnected($connection): bool;

FILE: src/Ftp/ConnectivityCheckerThatCanFail.php
  class ConnectivityCheckerThatCanFail (line 7) | class ConnectivityCheckerThatCanFail implements ConnectivityChecker
    method __construct (line 11) | public function __construct(private ConnectivityChecker $connectivityC...
    method failNextCall (line 15) | public function failNextCall(): void
    method isConnected (line 23) | public function isConnected($connection): bool

FILE: src/Ftp/FtpAdapter.php
  class FtpAdapter (line 37) | class FtpAdapter implements FilesystemAdapter
    method __construct (line 58) | public function __construct(
    method __destruct (line 77) | public function __destruct()
    method connection (line 85) | private function connection()
    method disconnect (line 106) | public function disconnect(): void
    method isPureFtpdServer (line 114) | private function isPureFtpdServer(): bool
    method isServerSupportingListOptions (line 125) | private function isServerSupportingListOptions(): bool
    method fileExists (line 138) | public function fileExists(string $path): bool
    method write (line 149) | public function write(string $path, string $contents, Config $config):...
    method writeStream (line 161) | public function writeStream(string $path, $contents, Config $config): ...
    method read (line 186) | public function read(string $path): string
    method readStream (line 195) | public function readStream(string $path)
    method delete (line 212) | public function delete(string $path): void
    method deleteFile (line 221) | private function deleteFile(string $path, $connection): void
    method deleteDirectory (line 231) | public function deleteDirectory(string $path): void
    method createDirectory (line 259) | public function createDirectory(string $path, Config $config): void
    method setVisibility (line 264) | public function setVisibility(string $path, string $visibility): void
    method fetchMetadata (line 275) | private function fetchMetadata(string $path, string $type): FileAttrib...
    method mimeType (line 302) | public function mimeType(string $path): FileAttributes
    method lastModified (line 319) | public function lastModified(string $path): FileAttributes
    method visibility (line 332) | public function visibility(string $path): FileAttributes
    method fileSize (line 337) | public function fileSize(string $path): FileAttributes
    method listContents (line 350) | public function listContents(string $path, bool $deep): iterable
    method normalizeListing (line 365) | private function normalizeListing(array $listing, string $prefix = '')...
    method normalizeObject (line 383) | private function normalizeObject(string $item, string $base): StorageA...
    method detectSystemType (line 394) | private function detectSystemType(string $item): string
    method normalizeWindowsObject (line 402) | private function normalizeWindowsObject(string $item, string $base): S...
    method normalizeUnixObject (line 426) | private function normalizeUnixObject(string $item, string $base): Stor...
    method listingItemIsDirectory (line 458) | private function listingItemIsDirectory(string $permissions): bool
    method normalizeUnixTimestamp (line 463) | private function normalizeUnixTimestamp(string $month, string $day, st...
    method normalizePermissions (line 479) | private function normalizePermissions(string $permissions): int
    method listDirectoryContentsRecursive (line 502) | private function listDirectoryContentsRecursive(string $directory): Ge...
    method ftpRawlist (line 524) | private function ftpRawlist(string $options, string $path): array
    method move (line 541) | public function move(string $source, string $destination, Config $conf...
    method copy (line 558) | public function copy(string $source, string $destination, Config $conf...
    method ensureParentDirectoryExists (line 577) | private function ensureParentDirectoryExists(string $path, ?string $vi...
    method ensureDirectoryExists (line 588) | private function ensureDirectoryExists(string $dirname, ?string $visib...
    method escapePath (line 621) | private function escapePath(string $path): string
    method hasFtpConnection (line 629) | private function hasFtpConnection(): bool
    method directoryExists (line 634) | public function directoryExists(string $path): bool
    method resolveConnectionRoot (line 645) | private function resolveConnectionRoot($connection): string
    method prefixer (line 667) | private function prefixer(): PathPrefixer

FILE: src/Ftp/FtpAdapterTest.php
  class FtpAdapterTest (line 15) | class FtpAdapterTest extends FtpAdapterTestCase
    method createFilesystemAdapter (line 17) | protected static function createFilesystemAdapter(): FilesystemAdapter
    method disconnect_after_destruct (line 41) | public function disconnect_after_destruct(): void
    method it_can_disconnect (line 61) | public function it_can_disconnect(): void
    method not_being_able_to_resolve_connection_root (line 76) | public function not_being_able_to_resolve_connection_root(): void
    method not_being_able_to_resolve_connection_root_pwd (line 97) | public function not_being_able_to_resolve_connection_root_pwd(): void
    method tearDown (line 115) | protected function tearDown(): void

FILE: src/Ftp/FtpAdapterTestCase.php
  class FtpAdapterTestCase (line 27) | abstract class FtpAdapterTestCase extends FilesystemAdapterTestCase
    method setUp (line 29) | protected function setUp(): void
    method resetFunctionMocks (line 42) | public function resetFunctionMocks(): void
    method clearFilesystemAdapterCache (line 47) | public static function clearFilesystemAdapterCache(): void
    method using_empty_string_for_root (line 56) | public function using_empty_string_for_root(): void
    method reconnecting_after_failure (line 80) | public function reconnecting_after_failure(): void
    method reading_a_file_twice_for_issue_1522 (line 96) | public function reading_a_file_twice_for_issue_1522(): void
    method failing_to_write_a_file (line 113) | public function failing_to_write_a_file(callable $scenario): void
    method scenariosCausingWriteFailure (line 129) | public static function scenariosCausingWriteFailure(): Generator
    method scenarios_causing_directory_deletion_to_fail (line 153) | public function scenarios_causing_directory_deletion_to_fail(callable ...
    method scenariosCausingDirectoryDeleteFailure (line 165) | public static function scenariosCausingDirectoryDeleteFailure(): Gener...
    method failing_to_copy (line 181) | public function failing_to_copy(callable $scenario): void
    method failing_to_move_because_creating_the_directory_fails (line 196) | public function failing_to_move_because_creating_the_directory_fails()...
    method scenariosCausingCopyFailure (line 208) | public static function scenariosCausingCopyFailure(): Generator
    method failing_to_delete_a_file (line 222) | public function failing_to_delete_a_file(): void
    method formatting_a_directory_listing_with_a_total_indicator (line 237) | public function formatting_a_directory_listing_with_a_total_indicator(...
    method receiving_a_windows_listing (line 259) | public function receiving_a_windows_listing(): void
    method receiving_an_invalid_windows_listing (line 279) | public function receiving_an_invalid_windows_listing(): void
    method getting_an_invalid_listing_response_for_unix_listings (line 297) | public function getting_an_invalid_listing_response_for_unix_listings(...
    method failing_to_get_the_file_size_of_a_directory (line 316) | public function failing_to_get_the_file_size_of_a_directory(): void
    method formatting_non_manual_recursive_listings (line 334) | public function formatting_non_manual_recursive_listings(): void
    method filenames_and_dirnames_with_spaces_are_supported (line 378) | public function filenames_and_dirnames_with_spaces_are_supported(): void

FILE: src/Ftp/FtpConnectionException.php
  type FtpConnectionException (line 9) | interface FtpConnectionException extends FilesystemException

FILE: src/Ftp/FtpConnectionOptions.php
  class FtpConnectionOptions (line 9) | class FtpConnectionOptions
    method __construct (line 11) | public function __construct(
    method host (line 30) | public function host(): string
    method root (line 35) | public function root(): string
    method username (line 40) | public function username(): string
    method password (line 45) | public function password(): string
    method port (line 50) | public function port(): int
    method ssl (line 55) | public function ssl(): bool
    method timeout (line 60) | public function timeout(): int
    method utf8 (line 65) | public function utf8(): bool
    method passive (line 70) | public function passive(): bool
    method transferMode (line 75) | public function transferMode(): int
    method systemType (line 80) | public function systemType(): ?string
    method ignorePassiveAddress (line 85) | public function ignorePassiveAddress(): ?bool
    method timestampsOnUnixListingsEnabled (line 90) | public function timestampsOnUnixListingsEnabled(): bool
    method recurseManually (line 95) | public function recurseManually(): bool
    method useRawListOptions (line 100) | public function useRawListOptions(): ?bool
    method fromArray (line 105) | public static function fromArray(array $options): FtpConnectionOptions

FILE: src/Ftp/FtpConnectionProvider.php
  class FtpConnectionProvider (line 11) | class FtpConnectionProvider implements ConnectionProvider
    method createConnection (line 18) | public function createConnection(FtpConnectionOptions $options)
    method createConnectionResource (line 43) | private function createConnectionResource(string $host, int $port, int...
    method authenticate (line 58) | private function authenticate(FtpConnectionOptions $options, $connecti...
    method enableUtf8Mode (line 68) | private function enableUtf8Mode(FtpConnectionOptions $options, $connec...
    method ignorePassiveAddress (line 86) | private function ignorePassiveAddress(FtpConnectionOptions $options, $...
    method makeConnectionPassive (line 102) | private function makeConnectionPassive(FtpConnectionOptions $options, ...

FILE: src/Ftp/FtpConnectionProviderTest.php
  class FtpConnectionProviderTest (line 15) | class FtpConnectionProviderTest extends TestCase
    method setUp (line 24) | protected function setUp(): void
    method setupConnectionProvider (line 32) | public function setupConnectionProvider(): void
    method resetFunctionMocks (line 40) | public function resetFunctionMocks(): void
    method connecting_successfully (line 48) | public function connecting_successfully(): void
    method not_being_able_to_enable_uft8_mode (line 70) | public function not_being_able_to_enable_uft8_mode(): void
    method uft8_mode_already_active_by_server (line 93) | public function uft8_mode_already_active_by_server(): void
    method not_being_able_to_ignore_the_passive_address (line 115) | public function not_being_able_to_ignore_the_passive_address(): void
    method not_being_able_to_make_the_connection_passive (line 138) | public function not_being_able_to_make_the_connection_passive(): void
    method not_being_able_to_connect (line 161) | public function not_being_able_to_connect(): void
    method not_being_able_to_connect_over_ssl (line 181) | public function not_being_able_to_connect_over_ssl(): void
    method not_being_able_to_authenticate (line 202) | public function not_being_able_to_authenticate(): void

FILE: src/Ftp/FtpdAdapterTest.php
  class FtpdAdapterTest (line 12) | class FtpdAdapterTest extends FtpAdapterTestCase
    method createFilesystemAdapter (line 14) | protected static function createFilesystemAdapter(): FilesystemAdapter

FILE: src/Ftp/InvalidListResponseReceived.php
  class InvalidListResponseReceived (line 10) | class InvalidListResponseReceived extends RuntimeException implements Fi...

FILE: src/Ftp/NoopCommandConnectivityChecker.php
  class NoopCommandConnectivityChecker (line 10) | class NoopCommandConnectivityChecker implements ConnectivityChecker
    method isConnected (line 12) | public function isConnected($connection): bool

FILE: src/Ftp/NoopCommandConnectivityCheckerTest.php
  class NoopCommandConnectivityCheckerTest (line 13) | class NoopCommandConnectivityCheckerTest extends TestCase
    method setUp (line 17) | protected function setUp(): void
    method detecting_a_good_connection (line 25) | public function detecting_a_good_connection(): void
    method detecting_a_closed_connection (line 43) | public function detecting_a_closed_connection(): void

FILE: src/Ftp/RawListFtpConnectivityChecker.php
  class RawListFtpConnectivityChecker (line 9) | class RawListFtpConnectivityChecker implements ConnectivityChecker
    method isConnected (line 14) | public function isConnected($connection): bool

FILE: src/Ftp/RawListFtpConnectivityCheckerTest.php
  class RawListFtpConnectivityCheckerTest (line 11) | class RawListFtpConnectivityCheckerTest extends TestCase
    method detecting_if_a_connection_is_connected (line 17) | public function detecting_if_a_connection_is_connected(): void

FILE: src/Ftp/StubConnectionProvider.php
  class StubConnectionProvider (line 6) | class StubConnectionProvider implements ConnectionProvider
    method __construct (line 10) | public function __construct(private ConnectionProvider $provider)
    method createConnection (line 14) | public function createConnection(FtpConnectionOptions $options)

FILE: src/Ftp/UnableToAuthenticate.php
  class UnableToAuthenticate (line 9) | final class UnableToAuthenticate extends RuntimeException implements Ftp...
    method __construct (line 11) | public function __construct()

FILE: src/Ftp/UnableToConnectToFtpHost.php
  class UnableToConnectToFtpHost (line 9) | final class UnableToConnectToFtpHost extends RuntimeException implements...
    method forHost (line 11) | public static function forHost(string $host, int $port, bool $ssl, str...

FILE: src/Ftp/UnableToEnableUtf8Mode.php
  class UnableToEnableUtf8Mode (line 9) | final class UnableToEnableUtf8Mode extends RuntimeException implements F...

FILE: src/Ftp/UnableToMakeConnectionPassive.php
  class UnableToMakeConnectionPassive (line 9) | class UnableToMakeConnectionPassive extends RuntimeException implements ...

FILE: src/Ftp/UnableToResolveConnectionRoot.php
  class UnableToResolveConnectionRoot (line 10) | final class UnableToResolveConnectionRoot extends RuntimeException imple...
    method __construct (line 12) | private function __construct(string $message, ?Throwable $previous = n...
    method itDoesNotExist (line 17) | public static function itDoesNotExist(string $root, string $reason = '...
    method couldNotGetCurrentDirectory (line 24) | public static function couldNotGetCurrentDirectory(string $message = '...

FILE: src/Ftp/UnableToSetFtpOption.php
  class UnableToSetFtpOption (line 9) | class UnableToSetFtpOption extends RuntimeException implements FtpConnec...
    method whileSettingOption (line 11) | public static function whileSettingOption(string $option): UnableToSet...

FILE: src/GoogleCloudStorage/GoogleCloudStorageAdapter.php
  class GoogleCloudStorageAdapter (line 46) | class GoogleCloudStorageAdapter implements FilesystemAdapter, PublicUrlG...
    method __construct (line 58) | public function __construct(
    method publicUrl (line 71) | public function publicUrl(string $path, Config $config): string
    method fileExists (line 78) | public function fileExists(string $path): bool
    method directoryExists (line 89) | public function directoryExists(string $path): bool
    method write (line 119) | public function write(string $path, string $contents, Config $config):...
    method writeStream (line 124) | public function writeStream(string $path, $contents, Config $config): ...
    method upload (line 132) | private function upload(string $path, $contents, Config $config): void
    method read (line 160) | public function read(string $path): string
    method readStream (line 171) | public function readStream(string $path)
    method delete (line 195) | public function delete(string $path): void
    method deleteDirectory (line 207) | public function deleteDirectory(string $path): void
    method createDirectory (line 225) | public function createDirectory(string $path, Config $config): void
    method setVisibility (line 234) | public function setVisibility(string $path, string $visibility): void
    method visibility (line 245) | public function visibility(string $path): FileAttributes
    method mimeType (line 258) | public function mimeType(string $path): FileAttributes
    method lastModified (line 263) | public function lastModified(string $path): FileAttributes
    method fileSize (line 268) | public function fileSize(string $path): FileAttributes
    method fileAttributes (line 273) | private function fileAttributes(string $path, string $type): FileAttri...
    method storageObjectToStorageAttributes (line 292) | public function storageObjectToStorageAttributes(StorageObject $object...
    method listContents (line 308) | public function listContents(string $path, bool $deep): iterable
    method move (line 342) | public function move(string $source, string $destination, Config $conf...
    method copy (line 352) | public function copy(string $source, string $destination, Config $conf...
    method checksum (line 377) | public function checksum(string $path, Config $config): string
    method temporaryUrl (line 398) | public function temporaryUrl(string $path, DateTimeInterface $expiresA...

FILE: src/GoogleCloudStorage/GoogleCloudStorageAdapterTest.php
  class GoogleCloudStorageAdapterTest (line 20) | class GoogleCloudStorageAdapterTest extends FilesystemAdapterTestCase
    method setUpBeforeClass (line 29) | public static function setUpBeforeClass(): void
    method bucketName (line 35) | protected static function bucketName(): string|array|false
    method visibilityHandler (line 40) | protected static function visibilityHandler(): VisibilityHandler
    method prefixPath (line 45) | public function prefixPath(string $path): string
    method prefixDirectoryPath (line 50) | public function prefixDirectoryPath(string $path): string
    method createFilesystemAdapter (line 55) | protected static function createFilesystemAdapter(): FilesystemAdapter
    method writing_with_specific_metadata (line 80) | public function writing_with_specific_metadata(): void
    method guessing_the_mime_type_when_writing (line 91) | public function guessing_the_mime_type_when_writing(): void
    method fetching_visibility_of_non_existing_file (line 102) | public function fetching_visibility_of_non_existing_file(): void
    method fetching_unknown_mime_type_of_a_file (line 114) | public function fetching_unknown_mime_type_of_a_file(): void
    method listing_a_toplevel_directory (line 122) | public function listing_a_toplevel_directory(): void
    method failing_to_write_a_file (line 131) | public function failing_to_write_a_file(): void
    method failing_to_delete_a_file (line 144) | public function failing_to_delete_a_file(): void
    method failing_to_delete_a_directory (line 157) | public function failing_to_delete_a_directory(): void
    method failing_to_retrieve_visibility (line 172) | public function failing_to_retrieve_visibility(): void

FILE: src/GoogleCloudStorage/GoogleCloudStorageAdapterWithoutAclTest.php
  class GoogleCloudStorageAdapterWithoutAclTest (line 6) | class GoogleCloudStorageAdapterWithoutAclTest extends GoogleCloudStorage...
    method visibilityHandler (line 8) | protected static function visibilityHandler(): VisibilityHandler
    method bucketName (line 13) | protected static function bucketName(): string|array|false

FILE: src/GoogleCloudStorage/PortableVisibilityHandler.php
  class PortableVisibilityHandler (line 12) | class PortableVisibilityHandler implements VisibilityHandler
    method __construct (line 20) | public function __construct(
    method setVisibility (line 27) | public function setVisibility(StorageObject $object, string $visibilit...
    method determineVisibility (line 36) | public function determineVisibility(StorageObject $object): string
    method visibilityToPredefinedAcl (line 49) | public function visibilityToPredefinedAcl(string $visibility): string

FILE: src/GoogleCloudStorage/StubRiggedBucket.php
  class StubRiggedBucket (line 11) | class StubRiggedBucket extends Bucket
    method failForObject (line 15) | public function failForObject(string $name, ?Throwable $throwable = nu...
    method failForUpload (line 20) | public function failForUpload(string $name, ?Throwable $throwable = nu...
    method object (line 25) | public function object($name, array $options = [])
    method upload (line 32) | public function upload($data, array $options = [])
    method setupTrigger (line 39) | private function setupTrigger(string $method, string $name, ?Throwable...
    method pushTrigger (line 44) | private function pushTrigger(string $method, string $name): void

FILE: src/GoogleCloudStorage/StubStorageClient.php
  class StubStorageClient (line 10) | class StubStorageClient extends StorageClient
    method __construct (line 14) | public function __construct(array $config = [])
    method bucket (line 24) | public function bucket($name, $userProject = false, array $options = [])

FILE: src/GoogleCloudStorage/UniformBucketLevelAccessVisibility.php
  class UniformBucketLevelAccessVisibility (line 9) | class UniformBucketLevelAccessVisibility implements VisibilityHandler
    method setVisibility (line 13) | public function setVisibility(StorageObject $object, string $visibilit...
    method determineVisibility (line 18) | public function determineVisibility(StorageObject $object): string
    method visibilityToPredefinedAcl (line 23) | public function visibilityToPredefinedAcl(string $visibility): string

FILE: src/GoogleCloudStorage/VisibilityHandler.php
  type VisibilityHandler (line 9) | interface VisibilityHandler
    method setVisibility (line 11) | public function setVisibility(StorageObject $object, string $visibilit...
    method determineVisibility (line 12) | public function determineVisibility(StorageObject $object): string;
    method visibilityToPredefinedAcl (line 13) | public function visibilityToPredefinedAcl(string $visibility): string;

FILE: src/GridFS/GridFSAdapter.php
  class GridFSAdapter (line 33) | class GridFSAdapter implements FilesystemAdapter
    method __construct (line 49) | public function __construct(
    method fileExists (line 59) | public function fileExists(string $path): bool
    method directoryExists (line 66) | public function directoryExists(string $path): bool
    method write (line 78) | public function write(string $path, string $contents, Config $config):...
    method writeStream (line 104) | public function writeStream(string $path, $contents, Config $config): ...
    method read (line 126) | public function read(string $path): string
    method readStream (line 136) | public function readStream(string $path)
    method delete (line 159) | public function delete(string $path): void
    method deleteDirectory (line 173) | public function deleteDirectory(string $path): void
    method createDirectory (line 183) | public function createDirectory(string $path, Config $config): void
    method setVisibility (line 204) | public function setVisibility(string $path, string $visibility): void
    method visibility (line 222) | public function visibility(string $path): FileAttributes
    method fileSize (line 233) | public function fileSize(string $path): FileAttributes
    method mimeType (line 247) | public function mimeType(string $path): FileAttributes
    method lastModified (line 266) | public function lastModified(string $path): FileAttributes
    method listContents (line 280) | public function listContents(string $path, bool $deep): iterable
    method move (line 346) | public function move(string $source, string $destination, Config $conf...
    method copy (line 370) | public function copy(string $source, string $destination, Config $conf...
    method findFile (line 402) | private function findFile(string $path): ?array
    method mapFileAttributes (line 416) | private function mapFileAttributes(array $file): FileAttributes
    method findAndDelete (line 431) | private function findAndDelete(array $filter): void

FILE: src/GridFS/GridFSAdapterTest.php
  class GridFSAdapterTest (line 25) | class GridFSAdapterTest extends TestCase
    method tearDownAfterClass (line 32) | public static function tearDownAfterClass(): void
    method fetching_contains_extra_metadata (line 42) | public function fetching_contains_extra_metadata(): void
    method fetching_last_modified_of_a_directory (line 58) | public function fetching_last_modified_of_a_directory(): void
    method fetching_mime_type_of_a_directory (line 73) | public function fetching_mime_type_of_a_directory(): void
    method reading_a_file_with_trailing_slash (line 88) | public function reading_a_file_with_trailing_slash(): void
    method reading_a_file_stream_with_trailing_slash (line 97) | public function reading_a_file_stream_with_trailing_slash(): void
    method writing_a_file_with_trailing_slash (line 106) | public function writing_a_file_with_trailing_slash(): void
    method writing_a_file_stream_with_trailing_slash (line 115) | public function writing_a_file_stream_with_trailing_slash(): void
    method writing_a_file_with_a_invalid_stream (line 125) | public function writing_a_file_with_a_invalid_stream(): void
    method delete_a_file_with_trailing_slash (line 135) | public function delete_a_file_with_trailing_slash(): void
    method reading_last_revision (line 144) | public function reading_last_revision(): void
    method listing_contents_last_revision (line 163) | public function listing_contents_last_revision(bool $deep): void
    method listing_contents_directory_with_multiple_files (line 185) | public function listing_contents_directory_with_multiple_files(): void
    method delete_all_revisions (line 207) | public function delete_all_revisions(): void
    method move_all_revisions (line 227) | public function move_all_revisions(): void
    method tearDown (line 245) | protected function tearDown(): void
    method createFilesystemAdapter (line 252) | protected static function createFilesystemAdapter(): FilesystemAdapter
    method getDatabase (line 260) | private static function getDatabase(): Database

FILE: src/InMemory/InMemoryFile.php
  class InMemoryFile (line 13) | class InMemoryFile
    method updateContents (line 19) | public function updateContents(string $contents, ?int $timestamp): void
    method lastModified (line 25) | public function lastModified(): int
    method withLastModified (line 30) | public function withLastModified(int $lastModified): self
    method read (line 38) | public function read(): string
    method readStream (line 46) | public function readStream()
    method fileSize (line 56) | public function fileSize(): int
    method mimeType (line 61) | public function mimeType(): string
    method setVisibility (line 66) | public function setVisibility(string $visibility): void
    method visibility (line 71) | public function visibility(): ?string

FILE: src/InMemory/InMemoryFilesystemAdapter.php
  class InMemoryFilesystemAdapter (line 23) | class InMemoryFilesystemAdapter implements FilesystemAdapter
    method __construct (line 33) | public function __construct(
    method fileExists (line 40) | public function fileExists(string $path): bool
    method write (line 45) | public function write(string $path, string $contents, Config $config):...
    method writeStream (line 55) | public function writeStream(string $path, $contents, Config $config): ...
    method read (line 60) | public function read(string $path): string
    method readStream (line 71) | public function readStream(string $path)
    method delete (line 82) | public function delete(string $path): void
    method deleteDirectory (line 87) | public function deleteDirectory(string $path): void
    method createDirectory (line 99) | public function createDirectory(string $path, Config $config): void
    method directoryExists (line 105) | public function directoryExists(string $path): bool
    method setVisibility (line 119) | public function setVisibility(string $path, string $visibility): void
    method visibility (line 130) | public function visibility(string $path): FileAttributes
    method mimeType (line 141) | public function mimeType(string $path): FileAttributes
    method lastModified (line 158) | public function lastModified(string $path): FileAttributes
    method fileSize (line 169) | public function fileSize(string $path): FileAttributes
    method listContents (line 180) | public function listContents(string $path, bool $deep): iterable
    method move (line 221) | public function move(string $source, string $destination, Config $conf...
    method copy (line 240) | public function copy(string $source, string $destination, Config $conf...
    method preparePath (line 257) | private function preparePath(string $path): string
    method deleteEverything (line 262) | public function deleteEverything(): void

FILE: src/InMemory/InMemoryFilesystemAdapterTest.php
  class InMemoryFilesystemAdapterTest (line 22) | class InMemoryFilesystemAdapterTest extends FilesystemAdapterTestCase
    method resetFunctionMocks (line 29) | public function resetFunctionMocks(): void
    method getting_mimetype_on_a_non_existing_file (line 40) | public function getting_mimetype_on_a_non_existing_file(): void
    method getting_last_modified_on_a_non_existing_file (line 49) | public function getting_last_modified_on_a_non_existing_file(): void
    method getting_file_size_on_a_non_existing_file (line 58) | public function getting_file_size_on_a_non_existing_file(): void
    method deleting_a_file (line 67) | public function deleting_a_file(): void
    method deleting_a_directory (line 78) | public function deleting_a_directory(): void
    method creating_a_directory_does_nothing (line 95) | public function creating_a_directory_does_nothing(): void
    method writing_with_a_stream_and_reading_a_file (line 104) | public function writing_with_a_stream_and_reading_a_file(): void
    method reading_a_stream (line 115) | public function reading_a_stream(): void
    method reading_a_non_existing_file (line 126) | public function reading_a_non_existing_file(): void
    method stream_reading_a_non_existing_file (line 135) | public function stream_reading_a_non_existing_file(): void
    method listing_all_files (line 144) | public function listing_all_files(): void
    method listing_non_recursive (line 171) | public function listing_non_recursive(): void
    method moving_a_file_successfully (line 184) | public function moving_a_file_successfully(): void
    method trying_to_move_a_non_existing_file (line 196) | public function trying_to_move_a_non_existing_file(): void
    method copying_a_file_successfully (line 205) | public function copying_a_file_successfully(): void
    method trying_to_copy_a_non_existing_file (line 217) | public function trying_to_copy_a_non_existing_file(): void
    method not_listing_directory_placeholders (line 226) | public function not_listing_directory_placeholders(): void
    method checking_for_metadata (line 238) | public function checking_for_metadata(): void
    method fetching_unknown_mime_type_of_a_file (line 257) | public function fetching_unknown_mime_type_of_a_file(): void
    method using_custom_timestamp (line 266) | public function using_custom_timestamp(): void
    method createFilesystemAdapter (line 279) | protected static function createFilesystemAdapter(): FilesystemAdapter

FILE: src/InMemory/StaticInMemoryAdapterRegistry.php
  class StaticInMemoryAdapterRegistry (line 5) | class StaticInMemoryAdapterRegistry
    method get (line 10) | public static function get(string $name = 'default'): InMemoryFilesyst...
    method deleteAllFilesystems (line 15) | public static function deleteAllFilesystems(): void

FILE: src/InMemory/StaticInMemoryAdapterRegistryTest.php
  class StaticInMemoryAdapterRegistryTest (line 8) | class StaticInMemoryAdapterRegistryTest extends InMemoryFilesystemAdapte...
    method using_different_name_to_segment_adapters (line 13) | public function using_different_name_to_segment_adapters(): void
    method files_persist_between_instances (line 30) | public function files_persist_between_instances(): void
    method tearDown (line 48) | protected function tearDown(): void
    method createFilesystemAdapter (line 53) | protected static function createFilesystemAdapter(): FilesystemAdapter

FILE: src/InvalidStreamProvided.php
  class InvalidStreamProvided (line 9) | class InvalidStreamProvided extends BaseInvalidArgumentException impleme...

FILE: src/InvalidVisibilityProvided.php
  class InvalidVisibilityProvided (line 11) | class InvalidVisibilityProvided extends InvalidArgumentException impleme...
    method withVisibility (line 13) | public static function withVisibility(string $visibility, string $expe...

FILE: src/Local/FallbackMimeTypeDetector.php
  class FallbackMimeTypeDetector (line 10) | class FallbackMimeTypeDetector implements MimeTypeDetector
    method __construct (line 20) | public function __construct(
    method detectMimeType (line 27) | public function detectMimeType(string $path, $contents): ?string
    method detectMimeTypeFromBuffer (line 32) | public function detectMimeTypeFromBuffer(string $contents): ?string
    method detectMimeTypeFromPath (line 37) | public function detectMimeTypeFromPath(string $path): ?string
    method detectMimeTypeFromFile (line 42) | public function detectMimeTypeFromFile(string $path): ?string

FILE: src/Local/LocalFilesystemAdapter.php
  class LocalFilesystemAdapter (line 50) | class LocalFilesystemAdapter implements FilesystemAdapter, ChecksumProvider
    method __construct (line 72) | public function __construct(
    method ensureRootDirectoryExists (line 95) | private function ensureRootDirectoryExists(): void
    method write (line 105) | public function write(string $path, string $contents, Config $config):...
    method writeStream (line 110) | public function writeStream(string $path, $contents, Config $config): ...
    method writeToFile (line 118) | private function writeToFile(string $path, $contents, Config $config):...
    method delete (line 137) | public function delete(string $path): void
    method deleteDirectory (line 152) | public function deleteDirectory(string $prefix): void
    method listDirectoryRecursively (line 176) | private function listDirectoryRecursively(
    method deleteFileInfoObject (line 190) | protected function deleteFileInfoObject(SplFileInfo $file): bool
    method listContents (line 202) | public function listContents(string $path, bool $deep): iterable
    method move (line 244) | public function move(string $source, string $destination, Config $conf...
    method copy (line 265) | public function copy(string $source, string $destination, Config $conf...
    method read (line 292) | public function read(string $path): string
    method readStream (line 305) | public function readStream(string $path)
    method ensureDirectoryExists (line 318) | protected function ensureDirectoryExists(string $dirname, int $visibil...
    method fileExists (line 339) | public function fileExists(string $location): bool
    method directoryExists (line 346) | public function directoryExists(string $location): bool
    method createDirectory (line 353) | public function createDirectory(string $path, Config $config): void
    method setVisibility (line 373) | public function setVisibility(string $path, string $visibility): void
    method visibility (line 383) | public function visibility(string $path): FileAttributes
    method resolveDirectoryVisibility (line 400) | private function resolveDirectoryVisibility(?string $visibility): int
    method mimeType (line 407) | public function mimeType(string $path): FileAttributes
    method lastModified (line 425) | public function lastModified(string $path): FileAttributes
    method fileSize (line 439) | public function fileSize(string $path): FileAttributes
    method checksum (line 452) | public function checksum(string $path, Config $config): string
    method listDirectory (line 466) | private function listDirectory(string $location): Generator
    method setPermissions (line 479) | private function setPermissions(string $location, int $visibility): void

FILE: src/Local/LocalFilesystemAdapterTest.php
  class LocalFilesystemAdapterTest (line 43) | class LocalFilesystemAdapterTest extends FilesystemAdapterTestCase
    method setUp (line 47) | protected function setUp(): void
    method tearDown (line 53) | protected function tearDown(): void
    method creating_a_local_filesystem_creates_a_root_directory (line 62) | public function creating_a_local_filesystem_creates_a_root_directory()...
    method creating_a_local_filesystem_does_not_create_a_root_directory_when_constructed_with_lazy_root_creation (line 71) | public function creating_a_local_filesystem_does_not_create_a_root_dir...
    method not_being_able_to_create_a_root_directory_results_in_an_exception (line 80) | public function not_being_able_to_create_a_root_directory_results_in_a...
    method falling_back_to_extension_lookup_when_finding_mime_type_of_empty_file (line 91) | public function falling_back_to_extension_lookup_when_finding_mime_typ...
    method writing_a_file (line 103) | public function writing_a_file(): void
    method writing_a_file_with_a_stream (line 117) | public function writing_a_file_with_a_stream(): void
    method deleting_a_file_during_contents_listing (line 135) | public function deleting_a_file_during_contents_listing(): void
    method writing_a_file_with_a_stream_and_visibility (line 182) | public function writing_a_file_with_a_stream_and_visibility(): void
    method writing_a_file_with_visibility (line 197) | public function writing_a_file_with_visibility(): void
    method failing_to_set_visibility (line 208) | public function failing_to_set_visibility(): void
    method failing_to_write_a_file (line 218) | public function failing_to_write_a_file(): void
    method failing_to_write_a_file_using_a_stream (line 227) | public function failing_to_write_a_file_using_a_stream(): void
    method deleting_a_file (line 241) | public function deleting_a_file(): void
    method deleting_a_file_that_does_not_exist (line 252) | public function deleting_a_file_that_does_not_exist(): void
    method deleting_a_file_that_cannot_be_deleted (line 262) | public function deleting_a_file_that_cannot_be_deleted(): void
    method checking_if_a_file_exists (line 275) | public function checking_if_a_file_exists(): void
    method checking_if_a_file_exists_that_does_not_exsist (line 286) | public function checking_if_a_file_exists_that_does_not_exsist(): void
    method listing_contents (line 296) | public function listing_contents(): void
    method listing_contents_recursively (line 312) | public function listing_contents_recursively(): void
    method listing_a_non_existing_directory (line 328) | public function listing_a_non_existing_directory(): void
    method listing_directory_contents_with_link_skipping (line 341) | public function listing_directory_contents_with_link_skipping(): void
    method listing_directory_contents_with_disallowing_links (line 357) | public function listing_directory_contents_with_disallowing_links(): void
    method retrieving_visibility_while_listing_directory_contents (line 372) | public function retrieving_visibility_while_listing_directory_contents...
    method deleting_a_directory (line 403) | public function deleting_a_directory(): void
    method deleting_directories_with_other_directories_in_it (line 419) | public function deleting_directories_with_other_directories_in_it(): void
    method deleting_a_non_existing_directory (line 431) | public function deleting_a_non_existing_directory(): void
    method not_being_able_to_delete_a_directory (line 441) | public function not_being_able_to_delete_a_directory(): void
    method not_being_able_to_delete_a_sub_directory (line 455) | public function not_being_able_to_delete_a_sub_directory(): void
    method creating_a_directory (line 469) | public function creating_a_directory(): void
    method not_being_able_to_create_a_directory (line 488) | public function not_being_able_to_create_a_directory(): void
    method creating_a_directory_is_idempotent (line 498) | public function creating_a_directory_is_idempotent(): void
    method retrieving_visibility (line 510) | public function retrieving_visibility(): void
    method not_being_able_to_retrieve_visibility (line 522) | public function not_being_able_to_retrieve_visibility(): void
    method moving_a_file (line 532) | public function moving_a_file(): void
    method moving_a_file_with_visibility (line 545) | public function moving_a_file_with_visibility(): void
    method not_being_able_to_move_a_file (line 559) | public function not_being_able_to_move_a_file(): void
    method copying_a_file (line 569) | public function copying_a_file(): void
    method copying_a_file_with_visibility (line 581) | public function copying_a_file_with_visibility(): void
    method copying_a_file_retaining_visibility (line 595) | public function copying_a_file_retaining_visibility(): void
    method not_being_able_to_copy_a_file (line 612) | public function not_being_able_to_copy_a_file(): void
    method getting_mimetype (line 622) | public function getting_mimetype(): void
    method failing_to_get_the_mimetype (line 636) | public function failing_to_get_the_mimetype(): void
    method allowing_inconclusive_mime_type (line 653) | public function allowing_inconclusive_mime_type(): void
    method fetching_unknown_mime_type_of_a_file (line 671) | public function fetching_unknown_mime_type_of_a_file(): void
    method not_being_able_to_get_mimetype (line 681) | public function not_being_able_to_get_mimetype(): void
    method getting_last_modified (line 694) | public function getting_last_modified(): void
    method not_being_able_to_get_last_modified (line 706) | public function not_being_able_to_get_last_modified(): void
    method getting_file_size (line 716) | public function getting_file_size(): void
    method not_being_able_to_get_file_size (line 727) | public function not_being_able_to_get_file_size(): void
    method reading_a_file (line 737) | public function reading_a_file(): void
    method not_being_able_to_read_a_file (line 748) | public function not_being_able_to_read_a_file(): void
    method reading_a_stream (line 758) | public function reading_a_stream(): void
    method not_being_able_to_stream_read_a_file (line 772) | public function not_being_able_to_stream_read_a_file(): void
    method assertFileHasPermissions (line 787) | private function assertFileHasPermissions(string $file, int $expectedP...
    method assertFileContains (line 798) | private function assertFileContains(string $file, string $expectedCont...
    method createFilesystemAdapter (line 805) | protected static function createFilesystemAdapter(): FilesystemAdapter
    method get_checksum_with_specified_algo (line 813) | public function get_checksum_with_specified_algo(): void

FILE: src/MountManager.php
  class MountManager (line 14) | class MountManager implements FilesystemOperator
    method __construct (line 31) | public function __construct(array $filesystems = [], array $config = [])
    method dangerouslyMountFilesystems (line 41) | public function dangerouslyMountFilesystems(string $key, FilesystemOpe...
    method extend (line 49) | public function extend(array $filesystems, array $config = []): MountM...
    method fileExists (line 58) | public function fileExists(string $location): bool
    method has (line 70) | public function has(string $location): bool
    method directoryExists (line 82) | public function directoryExists(string $location): bool
    method read (line 94) | public function read(string $location): string
    method readStream (line 106) | public function readStream(string $location)
    method listContents (line 118) | public function listContents(string $location, bool $deep = self::LIST...
    method lastModified (line 133) | public function lastModified(string $location): int
    method fileSize (line 145) | public function fileSize(string $location): int
    method mimeType (line 157) | public function mimeType(string $location): string
    method visibility (line 169) | public function visibility(string $path): string
    method write (line 181) | public function write(string $location, string $contents, array $confi...
    method writeStream (line 193) | public function writeStream(string $location, $contents, array $config...
    method setVisibility (line 200) | public function setVisibility(string $path, string $visibility): void
    method delete (line 207) | public function delete(string $location): void
    method deleteDirectory (line 219) | public function deleteDirectory(string $location): void
    method createDirectory (line 231) | public function createDirectory(string $location, array $config = []):...
    method move (line 243) | public function move(string $source, string $destination, array $confi...
    method copy (line 260) | public function copy(string $source, string $destination, array $confi...
    method publicUrl (line 285) | public function publicUrl(string $path, array $config = []): string
    method temporaryUrl (line 297) | public function temporaryUrl(string $path, DateTimeInterface $expiresA...
    method checksum (line 309) | public function checksum(string $path, array $config = []): string
    method mountFilesystems (line 321) | private function mountFilesystems(array $filesystems): void
    method guardAgainstInvalidMount (line 331) | private function guardAgainstInvalidMount(mixed $key, mixed $filesyste...
    method mountFilesystem (line 342) | private function mountFilesystem(string $key, FilesystemOperator $file...
    method determineFilesystemAndPath (line 352) | private function determineFilesystemAndPath(string $path): array
    method copyInSameFilesystem (line 369) | private function copyInSameFilesystem(
    method copyAcrossFilesystem (line 384) | private function copyAcrossFilesystem(
    method moveInTheSameFilesystem (line 410) | private function moveInTheSameFilesystem(
    method moveAcrossFilesystems (line 425) | private function moveAcrossFilesystems(string $source, string $destina...

FILE: src/MountManagerTest.php
  class MountManagerTest (line 17) | class MountManagerTest extends TestCase
    method setUp (line 44) | protected function setUp(): void
    method copying_without_retaining_visibility (line 60) | public function copying_without_retaining_visibility(): void
    method extending_without_new_mounts_is_equal_but_not_the_same (line 82) | public function extending_without_new_mounts_is_equal_but_not_the_same...
    method extending_with_new_mounts_is_not_equal (line 93) | public function extending_with_new_mounts_is_not_equal(): void
    method extending_exposes_a_usable_mount_on_the_extension (line 105) | public function extending_exposes_a_usable_mount_on_the_extension(): void
    method extending_does_not_mount_on_the_original_mount_manager (line 120) | public function extending_does_not_mount_on_the_original_mount_manager...
    method copying_while_retaining_visibility (line 134) | public function copying_while_retaining_visibility(): void
    method writing_a_file (line 156) | public function writing_a_file(): void
    method writing_a_file_with_a_stream (line 171) | public function writing_a_file_with_a_stream(): void
    method not_being_able_to_write_a_file (line 183) | public function not_being_able_to_write_a_file(): void
    method not_being_able_to_stream_write_a_file (line 195) | public function not_being_able_to_stream_write_a_file(): void
    method failing_a_one_param_method (line 216) | public function failing_a_one_param_method(string $method, FilesystemO...
    method dpMetadataRetrieverMethods (line 225) | public static function dpMetadataRetrieverMethods(): iterable
    method reading_a_file (line 242) | public function reading_a_file(): void
    method reading_a_file_as_a_stream (line 254) | public function reading_a_file_as_a_stream(): void
    method checking_existence_for_an_existing_file (line 268) | public function checking_existence_for_an_existing_file(): void
    method checking_existence_for_an_non_existing_file (line 280) | public function checking_existence_for_an_non_existing_file(): void
    method checking_existence_for_an_non_existing_directory (line 290) | public function checking_existence_for_an_non_existing_directory(): void
    method checking_existence_for_an_existing_directory (line 300) | public function checking_existence_for_an_existing_directory(): void
    method checking_existence_for_an_existing_file_using_has (line 312) | public function checking_existence_for_an_existing_file_using_has(): void
    method checking_existence_for_an_non_existing_file_using_has (line 324) | public function checking_existence_for_an_non_existing_file_using_has(...
    method checking_existence_for_an_non_existing_directory_using_has (line 334) | public function checking_existence_for_an_non_existing_directory_using...
    method checking_existence_for_an_existing_directory_using_has (line 344) | public function checking_existence_for_an_existing_directory_using_has...
    method deleting_a_file (line 356) | public function deleting_a_file(): void
    method deleting_a_directory (line 368) | public function deleting_a_directory(): void
    method setting_visibility (line 380) | public function setting_visibility(): void
    method retrieving_metadata (line 393) | public function retrieving_metadata(): void
    method creating_a_directory (line 410) | public function creating_a_directory(): void
    method list_directory (line 427) | public function list_directory(): void
    method copying_in_the_same_filesystem (line 450) | public function copying_in_the_same_filesystem(): void
    method failing_to_copy_in_the_same_filesystem (line 464) | public function failing_to_copy_in_the_same_filesystem(): void
    method failing_to_move_in_the_same_filesystem (line 477) | public function failing_to_move_in_the_same_filesystem(): void
    method moving_in_the_same_filesystem (line 490) | public function moving_in_the_same_filesystem(): void
    method moving_across_filesystem (line 504) | public function moving_across_filesystem(): void
    method failing_to_move_across_filesystem (line 518) | public function failing_to_move_across_filesystem(): void
    method failing_to_copy_across_filesystem (line 532) | public function failing_to_copy_across_filesystem(): void
    method listing_contents (line 546) | public function listing_contents(): void
    method dangerously_mounting_additional_filesystems (line 560) | public function dangerously_mounting_additional_filesystems(): void
    method guarding_against_valid_mount_identifiers (line 572) | public function guarding_against_valid_mount_identifiers(): void
    method guarding_against_mounting_invalid_filesystems (line 583) | public function guarding_against_mounting_invalid_filesystems(): void
    method guarding_against_using_paths_without_mount_prefix (line 594) | public function guarding_against_using_paths_without_mount_prefix(): void
    method guard_against_using_unknown_mount (line 604) | public function guard_against_using_unknown_mount(): void
    method generate_public_url (line 614) | public function generate_public_url(): void
    method provide_checksum (line 631) | public function provide_checksum(): void

FILE: src/PathNormalizer.php
  type PathNormalizer (line 7) | interface PathNormalizer
    method normalizePath (line 9) | public function normalizePath(string $path): string;

FILE: src/PathPrefixer.php
  class PathPrefixer (line 11) | final class PathPrefixer
    method __construct (line 15) | public function __construct(string $prefix, private string $separator ...
    method prefixPath (line 24) | public function prefixPath(string $path): string
    method stripPrefix (line 29) | public function stripPrefix(string $path): string
    method stripDirectoryPrefix (line 35) | public function stripDirectoryPrefix(string $path): string
    method prefixDirectoryPath (line 40) | public function prefixDirectoryPath(string $path): string

FILE: src/PathPrefixerTest.php
  class PathPrefixerTest (line 9) | class PathPrefixerTest extends TestCase
    method path_prefixing_with_a_prefix (line 14) | public function path_prefixing_with_a_prefix(): void
    method path_stripping_with_a_prefix (line 24) | public function path_stripping_with_a_prefix(): void
    method an_absolute_root_path_is_supported (line 36) | public function an_absolute_root_path_is_supported(string $rootPath, s...
    method dpRootPaths (line 43) | public static function dpRootPaths(): iterable
    method path_stripping_is_reversable (line 52) | public function path_stripping_is_reversable(): void
    method prefixing_without_a_prefix (line 64) | public function prefixing_without_a_prefix(): void
    method prefixing_for_a_directory (line 78) | public function prefixing_for_a_directory(): void
    method prefixing_for_a_directory_without_a_prefix (line 91) | public function prefixing_for_a_directory_without_a_prefix(): void
    method stripping_a_directory_prefix (line 104) | public function stripping_a_directory_prefix(): void

FILE: src/PathPrefixing/PathPrefixedAdapter.php
  class PathPrefixedAdapter (line 30) | class PathPrefixedAdapter implements FilesystemAdapter, PublicUrlGenerat...
    method __construct (line 36) | public function __construct(private FilesystemAdapter $adapter, string...
    method read (line 45) | public function read(string $location): string
    method readStream (line 54) | public function readStream(string $location)
    method listContents (line 63) | public function listContents(string $location, bool $deep): Generator
    method fileExists (line 70) | public function fileExists(string $location): bool
    method directoryExists (line 79) | public function directoryExists(string $location): bool
    method lastModified (line 88) | public function lastModified(string $path): FileAttributes
    method fileSize (line 97) | public function fileSize(string $path): FileAttributes
    method mimeType (line 106) | public function mimeType(string $path): FileAttributes
    method visibility (line 115) | public function visibility(string $path): FileAttributes
    method write (line 124) | public function write(string $location, string $contents, Config $conf...
    method writeStream (line 133) | public function writeStream(string $location, $contents, Config $confi...
    method setVisibility (line 142) | public function setVisibility(string $path, string $visibility): void
    method delete (line 151) | public function delete(string $location): void
    method deleteDirectory (line 160) | public function deleteDirectory(string $location): void
    method createDirectory (line 169) | public function createDirectory(string $location, Config $config): void
    method move (line 178) | public function move(string $source, string $destination, Config $conf...
    method copy (line 187) | public function copy(string $source, string $destination, Config $conf...
    method publicUrl (line 196) | public function publicUrl(string $path, Config $config): string
    method checksum (line 205) | public function checksum(string $path, Config $config): string
    method temporaryUrl (line 214) | public function temporaryUrl(string $path, DateTimeInterface $expiresA...

FILE: src/PathPrefixing/PathPrefixedAdapterTest.php
  class PathPrefixedAdapterTest (line 15) | class PathPrefixedAdapterTest extends TestCase
    method testPrefix (line 17) | public function testPrefix(): void
    method testWriteStream (line 59) | public function testWriteStream(): void
    method testEmptyPrefix (line 75) | public function testEmptyPrefix(): void
    method generating_a_public_url (line 84) | public function generating_a_public_url(): void
    method calculate_checksum_using_decorated_adapter (line 102) | public function calculate_checksum_using_decorated_adapter(): void
    method calculate_checksum_using_current_adapter (line 120) | public function calculate_checksum_using_current_adapter(): void
    method failing_to_generate_a_public_url (line 133) | public function failing_to_generate_a_public_url(): void

FILE: src/PathTraversalDetected.php
  class PathTraversalDetected (line 9) | class PathTraversalDetected extends RuntimeException implements Filesyst...
    method path (line 13) | public function path(): string
    method forPath (line 18) | public static function forPath(string $path): PathTraversalDetected

FILE: src/PhpseclibV2/ConnectionProvider.php
  type ConnectionProvider (line 12) | interface ConnectionProvider
    method provideConnection (line 14) | public function provideConnection(): SFTP;

FILE: src/PhpseclibV2/ConnectivityChecker.php
  type ConnectivityChecker (line 12) | interface ConnectivityChecker
    method isConnected (line 14) | public function isConnected(SFTP $connection): bool;

FILE: src/PhpseclibV2/FixatedConnectivityChecker.php
  class FixatedConnectivityChecker (line 12) | class FixatedConnectivityChecker implements ConnectivityChecker
    method __construct (line 24) | public function __construct(int $succeedAfter = 0)
    method isConnected (line 29) | public function isConnected(SFTP $connection): bool

FILE: src/PhpseclibV2/SftpAdapter.php
  class SftpAdapter (line 35) | class SftpAdapter implements FilesystemAdapter
    method __construct (line 57) | public function __construct(
    method fileExists (line 70) | public function fileExists(string $path): bool
    method directoryExists (line 81) | public function directoryExists(string $path): bool
    method upload (line 99) | private function upload(string $path, $contents, Config $config): void
    method ensureParentDirectoryExists (line 114) | private function ensureParentDirectoryExists(string $path, Config $con...
    method makeDirectory (line 127) | private function makeDirectory(string $directory, ?string $visibility)...
    method write (line 145) | public function write(string $path, string $contents, Config $config):...
    method writeStream (line 156) | public function writeStream(string $path, $contents, Config $config): ...
    method read (line 167) | public function read(string $path): string
    method readStream (line 180) | public function readStream(string $path)
    method delete (line 197) | public function delete(string $path): void
    method deleteDirectory (line 204) | public function deleteDirectory(string $path): void
    method createDirectory (line 212) | public function createDirectory(string $path, Config $config): void
    method setVisibility (line 217) | public function setVisibility(string $path, string $visibility): void
    method fetchFileMetadata (line 228) | private function fetchFileMetadata(string $path, string $type): FileAt...
    method mimeType (line 247) | public function mimeType(string $path): FileAttributes
    method lastModified (line 264) | public function lastModified(string $path): FileAttributes
    method fileSize (line 269) | public function fileSize(string $path): FileAttributes
    method visibility (line 274) | public function visibility(string $path): FileAttributes
    method listContents (line 279) | public function listContents(string $path, bool $deep): iterable
    method convertListingToAttributes (line 308) | private function convertListingToAttributes(string $path, array $attri...
    method move (line 329) | public function move(string $source, string $destination, Config $conf...
    method copy (line 346) | public function copy(string $source, string $destination, Config $conf...

FILE: src/PhpseclibV2/SftpAdapterTest.php
  class SftpAdapterTest (line 22) | class SftpAdapterTest extends FilesystemAdapterTestCase
    method setUpBeforeClass (line 34) | public static function setUpBeforeClass(): void
    method createFilesystemAdapter (line 41) | protected static function createFilesystemAdapter(): FilesystemAdapter
    method setupConnectionProvider (line 52) | public function setupConnectionProvider(): void
    method failing_to_create_a_directory (line 63) | public function failing_to_create_a_directory(): void
    method failing_to_write_a_file (line 75) | public function failing_to_write_a_file(): void
    method failing_to_read_a_file (line 87) | public function failing_to_read_a_file(): void
    method failing_to_read_a_file_as_a_stream (line 99) | public function failing_to_read_a_file_as_a_stream(): void
    method failing_to_write_a_file_using_streams (line 111) | public function failing_to_write_a_file_using_streams(): void
    method detecting_mimetype (line 128) | public function detecting_mimetype(): void
    method failing_to_chmod_when_writing (line 141) | public function failing_to_chmod_when_writing(): void
    method failing_to_move_a_file_cause_the_parent_directory_cant_be_created (line 154) | public function failing_to_move_a_file_cause_the_parent_directory_cant...
    method failing_to_copy_a_file (line 166) | public function failing_to_copy_a_file(): void
    method failing_to_copy_a_file_because_writing_fails (line 178) | public function failing_to_copy_a_file_because_writing_fails(): void
    method failing_to_chmod_when_writing_with_a_stream (line 192) | public function failing_to_chmod_when_writing_with_a_stream(): void
    method list_contents_directory_does_not_exist (line 210) | public function list_contents_directory_does_not_exist(): void
    method connectionProvider (line 216) | private static function connectionProvider(): ConnectionProvider
    method adapterWithInvalidRoot (line 228) | private function adapterWithInvalidRoot(): SftpAdapter

FILE: src/PhpseclibV2/SftpConnectionProvider.php
  class SftpConnectionProvider (line 15) | class SftpConnectionProvider implements ConnectionProvider
    method __construct (line 77) | public function __construct(
    method provideConnection (line 104) | public function provideConnection(): SFTP
    method setupConnection (line 128) | private function setupConnection(): SFTP
    method checkFingerprint (line 144) | private function checkFingerprint(SFTP $connection): void
    method getFingerprintFromPublicKey (line 163) | private function getFingerprintFromPublicKey(string $publicKey): string
    method authenticate (line 170) | private function authenticate(SFTP $connection): void
    method fromArray (line 181) | public static function fromArray(array $options): SftpConnectionProvider
    method authenticateWithPrivateKey (line 198) | private function authenticateWithPrivateKey(SFTP $connection): void
    method loadPrivateKey (line 213) | private function loadPrivateKey(): RSA
    method authenticateWithAgent (line 232) | private function authenticateWithAgent(SFTP $connection): void

FILE: src/PhpseclibV2/SftpConnectionProviderTest.php
  class SftpConnectionProviderTest (line 17) | class SftpConnectionProviderTest extends TestCase
    method setUp (line 19) | protected function setUp(): void
    method giving_up_after_5_connection_failures (line 31) | public function giving_up_after_5_connection_failures(): void
    method trying_until_5_tries (line 52) | public function trying_until_5_tries(): void
    method authenticating_with_a_private_key (line 72) | public function authenticating_with_a_private_key(): void
    method authenticating_with_an_invalid_private_key (line 91) | public function authenticating_with_an_invalid_private_key(): void
    method authenticating_with_an_ssh_agent (line 110) | public function authenticating_with_an_ssh_agent(): void
    method failing_to_authenticating_with_an_ssh_agent (line 128) | public function failing_to_authenticating_with_an_ssh_agent(): void
    method authenticating_with_a_private_key_and_falling_back_to_password (line 147) | public function authenticating_with_a_private_key_and_falling_back_to_...
    method not_being_able_to_authenticate_with_a_private_key (line 167) | public function not_being_able_to_authenticate_with_a_private_key(): void
    method verifying_a_fingerprint (line 186) | public function verifying_a_fingerprint(): void
    method providing_an_invalid_fingerprint (line 208) | public function providing_an_invalid_fingerprint(): void
    method providing_an_invalid_password (line 227) | public function providing_an_invalid_password(): void
    method computeFingerPrint (line 241) | private function computeFingerPrint(string $publicKey): string

FILE: src/PhpseclibV2/SftpStub.php
  class SftpStub (line 14) | class SftpStub extends SFTP
    method failOnChmod (line 21) | public function failOnChmod(string $filename): void
    method chmod (line 34) | public function chmod($mode, $filename, $recursive = false)
    method failOnPut (line 48) | public function failOnPut(string $filename): void
    method put (line 64) | public function put(
    method formatTripKey (line 87) | private function formatTripKey(...$arguments): string
    method reset (line 98) | public function reset(): void

FILE: src/PhpseclibV2/SimpleConnectivityChecker.php
  class SimpleConnectivityChecker (line 12) | class SimpleConnectivityChecker implements ConnectivityChecker
    method isConnected (line 14) | public function isConnected(SFTP $connection): bool

FILE: src/PhpseclibV2/StubSftpConnectionProvider.php
  class StubSftpConnectionProvider (line 12) | class StubSftpConnectionProvider implements ConnectionProvider
    method __construct (line 39) | public function __construct(
    method provideConnection (line 51) | public function provideConnection(): SFTP

FILE: src/PhpseclibV2/UnableToAuthenticate.php
  class UnableToAuthenticate (line 13) | class UnableToAuthenticate extends RuntimeException implements Filesyste...
    method withPassword (line 15) | public static function withPassword(): UnableToAuthenticate
    method withPrivateKey (line 20) | public static function withPrivateKey(): UnableToAuthenticate
    method withSshAgent (line 25) | public static function withSshAgent(): UnableToAuthenticate

FILE: src/PhpseclibV2/UnableToConnectToSftpHost.php
  class UnableToConnectToSftpHost (line 13) | class UnableToConnectToSftpHost extends RuntimeException implements File...
    method atHostname (line 15) | public static function atHostname(string $host): UnableToConnectToSftp...

FILE: src/PhpseclibV2/UnableToEstablishAuthenticityOfHost.php
  class UnableToEstablishAuthenticityOfHost (line 13) | class UnableToEstablishAuthenticityOfHost extends RuntimeException imple...
    method becauseTheAuthenticityCantBeEstablished (line 15) | public static function becauseTheAuthenticityCantBeEstablished(string ...

FILE: src/PhpseclibV2/UnableToLoadPrivateKey.php
  class UnableToLoadPrivateKey (line 13) | class UnableToLoadPrivateKey extends RuntimeException implements Filesys...
    method __construct (line 15) | public function __construct(string $message = "Unable to load private ...

FILE: src/PhpseclibV3/ConnectionProvider.php
  type ConnectionProvider (line 12) | interface ConnectionProvider
    method provideConnection (line 14) | public function provideConnection(): SFTP;

FILE: src/PhpseclibV3/ConnectivityChecker.php
  type ConnectivityChecker (line 9) | interface ConnectivityChecker
    method isConnected (line 11) | public function isConnected(SFTP $connection): bool;

FILE: src/PhpseclibV3/FixatedConnectivityChecker.php
  class FixatedConnectivityChecker (line 9) | class FixatedConnectivityChecker implements ConnectivityChecker
    method __construct (line 21) | public function __construct(int $succeedAfter = 0)
    method isConnected (line 26) | public function isConnected(SFTP $connection): bool

FILE: src/PhpseclibV3/SftpAdapter.php
  class SftpAdapter (line 32) | class SftpAdapter implements FilesystemAdapter
    method __construct (line 38) | public function __construct(
    method fileExists (line 51) | public function fileExists(string $path): bool
    method disconnect (line 62) | public function disconnect(): void
    method directoryExists (line 67) | public function directoryExists(string $path): bool
    method upload (line 85) | private function upload(string $path, $contents, Config $config): void
    method ensureParentDirectoryExists (line 100) | private function ensureParentDirectoryExists(string $path, Config $con...
    method makeDirectory (line 113) | private function makeDirectory(string $directory, ?string $visibility)...
    method write (line 131) | public function write(string $path, string $contents, Config $config):...
    method writeStream (line 142) | public function writeStream(string $path, $contents, Config $config): ...
    method read (line 153) | public function read(string $path): string
    method readStream (line 166) | public function readStream(string $path)
    method delete (line 183) | public function delete(string $path): void
    method deleteDirectory (line 190) | public function deleteDirectory(string $path): void
    method createDirectory (line 198) | public function createDirectory(string $path, Config $config): void
    method setVisibility (line 203) | public function setVisibility(string $path, string $visibility): void
    method fetchFileMetadata (line 214) | private function fetchFileMetadata(string $path, string $type): FileAt...
    method mimeType (line 233) | public function mimeType(string $path): FileAttributes
    method lastModified (line 250) | public function lastModified(string $path): FileAttributes
    method fileSize (line 255) | public function fileSize(string $path): FileAttributes
    method visibility (line 260) | public function visibility(string $path): FileAttributes
    method listContents (line 265) | public function listContents(string $path, bool $deep): iterable
    method convertListingToAttributes (line 294) | private function convertListingToAttributes(string $path, array $attri...
    method move (line 315) | public function move(string $source, string $destination, Config $conf...
    method copy (line 346) | public function copy(string $source, string $destination, Config $conf...
    method __destruct (line 365) | public function __destruct()

FILE: src/PhpseclibV3/SftpAdapterTest.php
  class SftpAdapterTest (line 24) | class SftpAdapterTest extends FilesystemAdapterTestCase
    method setUpBeforeClass (line 26) | public static function setUpBeforeClass(): void
    method createFilesystemAdapter (line 43) | protected static function createFilesystemAdapter(): FilesystemAdapter
    method setupConnectionProvider (line 54) | public function setupConnectionProvider(): void
    method failing_to_create_a_directory (line 65) | public function failing_to_create_a_directory(): void
    method failing_to_write_a_file (line 77) | public function failing_to_write_a_file(): void
    method failing_to_read_a_file (line 89) | public function failing_to_read_a_file(): void
    method failing_to_read_a_file_as_a_stream (line 101) | public function failing_to_read_a_file_as_a_stream(): void
    method failing_to_write_a_file_using_streams (line 113) | public function failing_to_write_a_file_using_streams(): void
    method detecting_mimetype (line 130) | public function detecting_mimetype(): void
    method failing_to_chmod_when_writing (line 143) | public function failing_to_chmod_when_writing(): void
    method failing_to_move_a_file_cause_the_parent_directory_cant_be_created (line 156) | public function failing_to_move_a_file_cause_the_parent_directory_cant...
    method failing_to_copy_a_file (line 168) | public function failing_to_copy_a_file(): void
    method failing_to_copy_a_file_because_writing_fails (line 180) | public function failing_to_copy_a_file_because_writing_fails(): void
    method failing_to_chmod_when_writing_with_a_stream (line 194) | public function failing_to_chmod_when_writing_with_a_stream(): void
    method list_contents_directory_does_not_exist (line 212) | public function list_contents_directory_does_not_exist(): void
    method it_can_proactively_close_a_connection (line 221) | public function it_can_proactively_close_a_connection(): void
    method moving_a_file_and_overwriting (line 238) | public function moving_a_file_and_overwriting(): void
    method connectionProvider (line 266) | private static function connectionProvider(): StubSftpConnectionProvider
    method adapterWithInvalidRoot (line 278) | private function adapterWithInvalidRoot(): SftpAdapter

FILE: src/PhpseclibV3/SftpConnectionProvider.php
  class SftpConnectionProvider (line 19) | class SftpConnectionProvider implements ConnectionProvider
    method __construct (line 32) | public function __construct(
    method provideConnection (line 50) | public function provideConnection(): SFTP
    method disconnect (line 86) | public function disconnect(): void
    method setupConnection (line 94) | private function setupConnection(): SFTP
    method checkFingerprint (line 111) | private function checkFingerprint(SFTP $connection): void
    method getFingerprintFromPublicKey (line 130) | private function getFingerprintFromPublicKey(string $publicKey): string
    method authenticate (line 138) | private function authenticate(SFTP $connection): void
    method authenticateWithUsernameAndPassword (line 149) | private function authenticateWithUsernameAndPassword(SFTP $connection)...
    method fromArray (line 156) | public static function fromArray(array $options): SftpConnectionProvider
    method authenticateWithPrivateKey (line 174) | private function authenticateWithPrivateKey(SFTP $connection): void
    method loadPrivateKey (line 189) | private function loadPrivateKey(): AsymmetricKey
    method authenticateWithAgent (line 206) | private function authenticateWithAgent(SFTP $connection): void

FILE: src/PhpseclibV3/SftpConnectionProviderTest.php
  class SftpConnectionProviderTest (line 26) | class SftpConnectionProviderTest extends TestCase
    method setUpBeforeClass (line 30) | public static function setUpBeforeClass(): void
    method giving_up_after_5_connection_failures (line 40) | public function giving_up_after_5_connection_failures(): void
    method trying_until_5_tries (line 61) | public function trying_until_5_tries(): void
    method authenticating_with_a_private_key (line 81) | public function authenticating_with_a_private_key(): void
    method authenticating_with_an_invalid_private_key (line 101) | public function authenticating_with_an_invalid_private_key(): void
    method authenticating_with_an_ssh_agent (line 120) | public function authenticating_with_an_ssh_agent(): void
    method failing_to_authenticating_with_an_ssh_agent (line 145) | public function failing_to_authenticating_with_an_ssh_agent(): void
    method authenticating_with_a_private_key_and_falling_back_to_password (line 164) | public function authenticating_with_a_private_key_and_falling_back_to_...
    method not_being_able_to_authenticate_with_a_private_key (line 187) | public function not_being_able_to_authenticate_with_a_private_key(): void
    method verifying_a_fingerprint (line 206) | public function verifying_a_fingerprint(): void
    method providing_an_invalid_fingerprint (line 231) | public function providing_an_invalid_fingerprint(): void
    method providing_an_invalid_password (line 250) | public function providing_an_invalid_password(): void
    method retries_several_times_until_failure (line 269) | public function retries_several_times_until_failure(): void
    method authenticate_with_supported_preferred_kex_algorithm_succeeds (line 310) | public function authenticate_with_supported_preferred_kex_algorithm_su...
    method authenticate_with_unsupported_preferred_kex_algorithm_failes (line 344) | public function authenticate_with_unsupported_preferred_kex_algorithm_...
    method computeFingerPrint (line 363) | private function computeFingerPrint(string $publicKey): string
    method runWithRetries (line 376) | public function runWithRetries(callable $scenario, ?string $expected =...

FILE: src/PhpseclibV3/SftpStub.php
  class SftpStub (line 12) | class SftpStub extends SFTP
    method failOnChmod (line 19) | public function failOnChmod(string $filename): void
    method chmod (line 32) | public function chmod($mode, $filename, $recursive = false)
    method failOnPut (line 46) | public function failOnPut(string $filename): void
    method put (line 62) | public function put(
    method formatTripKey (line 85) | private function formatTripKey(...$arguments): string
    method resetTripWires (line 96) | public function resetTripWires(): void

FILE: src/PhpseclibV3/SimpleConnectivityChecker.php
  class SimpleConnectivityChecker (line 10) | class SimpleConnectivityChecker implements ConnectivityChecker
    method __construct (line 12) | public function __construct(
    method create (line 17) | public static function create(): SimpleConnectivityChecker
    method withUsingPing (line 22) | public function withUsingPing(bool $usePing): SimpleConnectivityChecker
    method isConnected (line 30) | public function isConnected(SFTP $connection): bool

FILE: src/PhpseclibV3/StubSftpConnectionProvider.php
  class StubSftpConnectionProvider (line 9) | class StubSftpConnectionProvider implements ConnectionProvider
    method __construct (line 16) | public function __construct(
    method disconnect (line 24) | public function disconnect(): void
    method provideConnection (line 31) | public function provideConnection(): SFTP

FILE: src/PhpseclibV3/UnableToAuthenticate.php
  class UnableToAuthenticate (line 10) | class UnableToAuthenticate extends RuntimeException implements Filesyste...
    method __construct (line 14) | public function __construct(string $message, ?string $lastError = null)
    method withPassword (line 20) | public static function withPassword(?string $lastError = null): Unable...
    method withPrivateKey (line 25) | public static function withPrivateKey(?string $lastError = null): Unab...
    method withSshAgent (line 30) | public static function withSshAgent(?string $lastError = null): Unable...
    method connectionError (line 35) | public function connectionError(): ?string

FILE: src/PhpseclibV3/UnableToConnectToSftpHost.php
  class UnableToConnectToSftpHost (line 11) | class UnableToConnectToSftpHost extends RuntimeException implements File...
    method atHostname (line 13) | public static function atHostname(string $host, ?Throwable $previous =...

FILE: src/PhpseclibV3/UnableToEstablishAuthenticityOfHost.php
  class UnableToEstablishAuthenticityOfHost (line 10) | class UnableToEstablishAuthenticityOfHost extends RuntimeException imple...
    method becauseTheAuthenticityCantBeEstablished (line 12) | public static function becauseTheAuthenticityCantBeEstablished(string ...

FILE: src/PhpseclibV3/UnableToLoadPrivateKey.php
  class UnableToLoadPrivateKey (line 11) | class UnableToLoadPrivateKey extends RuntimeException implements Filesys...
    method __construct (line 13) | public function __construct(?string $message = 'Unable to load private...

FILE: src/PortableVisibilityGuard.php
  class PortableVisibilityGuard (line 7) | final class PortableVisibilityGuard
    method guardAgainstInvalidInput (line 9) | public static function guardAgainstInvalidInput(string $visibility): void

FILE: src/ProxyArrayAccessToProperties.php
  type ProxyArrayAccessToProperties (line 12) | trait ProxyArrayAccessToProperties
    method formatPropertyName (line 14) | private function formatPropertyName(string $offset): string
    method offsetExists (line 24) | public function offsetExists($offset): bool
    method offsetGet (line 36) | #[\ReturnTypeWillChange]
    method offsetSet (line 48) | #[\ReturnTypeWillChange]
    method offsetUnset (line 57) | #[\ReturnTypeWillChange]

FILE: src/ReadOnly/ReadOnlyFilesystemAdapter.php
  class ReadOnlyFilesystemAdapter (line 23) | class ReadOnlyFilesystemAdapter extends DecoratedAdapter implements File...
    method write (line 27) | public function write(string $path, string $contents, Config $config):...
    method writeStream (line 32) | public function writeStream(string $path, $contents, Config $config): ...
    method delete (line 37) | public function delete(string $path): void
    method deleteDirectory (line 42) | public function deleteDirectory(string $path): void
    method createDirectory (line 47) | public function createDirectory(string $path, Config $config): void
    method setVisibility (line 52) | public function setVisibility(string $path, string $visibility): void
    method move (line 57) | public function move(string $source, string $destination, Config $conf...
    method copy (line 62) | public function copy(string $source, string $destination, Config $conf...
    method publicUrl (line 67) | public function publicUrl(string $path, Config $config): string
    method checksum (line 76) | public function checksum(string $path, Config $config): string
    method temporaryUrl (line 85) | public function temporaryUrl(string $path, DateTimeInterface $expiresA...

FILE: src/ReadOnly/ReadOnlyFilesystemAdapterTest.php
  class ReadOnlyFilesystemAdapterTest (line 21) | class ReadOnlyFilesystemAdapterTest extends TestCase
    method can_perform_read_operations (line 26) | public function can_perform_read_operations(): void
    method cannot_write_stream (line 47) | public function cannot_write_stream(): void
    method cannot_write (line 60) | public function cannot_write(): void
    method cannot_delete_file (line 72) | public function cannot_delete_file(): void
    method cannot_delete_directory (line 87) | public function cannot_delete_directory(): void
    method cannot_create_directory (line 102) | public function cannot_create_directory(): void
    method cannot_set_visibility (line 114) | public function cannot_set_visibility(): void
    method cannot_move (line 129) | public function cannot_move(): void
    method cannot_copy (line 144) | public function cannot_copy(): void
    method generating_a_public_url (line 159) | public function generating_a_public_url(): void
    method failing_to_generate_a_public_url (line 177) | public function failing_to_generate_a_public_url(): void
    method realAdapter (line 186) | private function realAdapter(): InMemoryFilesystemAdapter

FILE: src/ResolveIdenticalPathConflict.php
  class ResolveIdenticalPathConflict (line 6) | class ResolveIdenticalPathConflict

FILE: src/StorageAttributes.php
  type StorageAttributes (line 10) | interface StorageAttributes extends JsonSerializable, ArrayAccess
    method path (line 23) | public function path(): string;
    method type (line 25) | public function type(): string;
    method visibility (line 27) | public function visibility(): ?string;
    method lastModified (line 29) | public function lastModified(): ?int;
    method fromArray (line 31) | public static function fromArray(array $attributes): StorageAttributes;
    method isFile (line 33) | public function isFile(): bool;
    method isDir (line 35) | public function isDir(): bool;
    method withPath (line 37) | public function withPath(string $path): StorageAttributes;
    method extraMetadata (line 39) | public function extraMetadata(): array;

FILE: src/SymbolicLinkEncountered.php
  class SymbolicLinkEncountered (line 9) | final class SymbolicLinkEncountered extends RuntimeException implements ...
    method location (line 13) | public function location(): string
    method atLocation (line 18) | public static function atLocation(string $pathName): SymbolicLinkEncou...

FILE: src/UnableToCheckDirectoryExistence.php
  class UnableToCheckDirectoryExistence (line 7) | class UnableToCheckDirectoryExistence extends UnableToCheckExistence
    method operation (line 9) | public function operation(): string

FILE: src/UnableToCheckExistence.php
  class UnableToCheckExistence (line 10) | class UnableToCheckExistence extends RuntimeException implements Filesys...
    method __construct (line 12) | final public function __construct(string $message = "", int $code = 0,...
    method forLocation (line 17) | public static function forLocation(string $path, ?Throwable $exception...
    method operation (line 22) | public function operation(): string

FILE: src/UnableToCheckFileExistence.php
  class UnableToCheckFileExistence (line 7) | class UnableToCheckFileExistence extends UnableToCheckExistence
    method operation (line 9) | public function operation(): string

FILE: src/UnableToCopyFile.php
  class UnableToCopyFile (line 10) | final class UnableToCopyFile extends RuntimeException implements Filesys...
    method source (line 22) | public function source(): string
    method destination (line 27) | public function destination(): string
    method fromLocationTo (line 32) | public static function fromLocationTo(
    method sourceAndDestinationAreTheSame (line 44) | public static function sourceAndDestinationAreTheSame(string $source, ...
    method because (line 49) | public static function because(string $reason, string $sourcePath, str...
    method operation (line 58) | public function operation(): string

FILE: src/UnableToCreateDirectory.php
  class UnableToCreateDirectory (line 10) | final class UnableToCreateDirectory extends RuntimeException implements ...
    method atLocation (line 15) | public static function atLocation(string $dirname, string $errorMessag...
    method dueToFailure (line 25) | public static function dueToFailure(string $dirname, Throwable $previo...
    method operation (line 36) | public function operation(): string
    method reason (line 41) | public function reason(): string
    method location (line 46) | public function location(): string

FILE: src/UnableToDeleteDirectory.php
  class UnableToDeleteDirectory (line 10) | final class UnableToDeleteDirectory extends RuntimeException implements ...
    method atLocation (line 22) | public static function atLocation(
    method operation (line 34) | public function operation(): string
    method reason (line 39) | public function reason(): string
    method location (line 44) | public function location(): string

FILE: src/UnableToDeleteFile.php
  class UnableToDeleteFile (line 10) | final class UnableToDeleteFile extends RuntimeException implements Files...
    method atLocation (line 22) | public static function atLocation(string $location, string $reason = '...
    method operation (line 31) | public function operation(): string
    method reason (line 36) | public function reason(): string
    method location (line 41) | public function location(): string

FILE: src/UnableToGeneratePublicUrl.php
  class UnableToGeneratePublicUrl (line 10) | final class UnableToGeneratePublicUrl extends RuntimeException implement...
    method __construct (line 12) | public function __construct(string $reason, string $path, ?Throwable $...
    method dueToError (line 17) | public static function dueToError(string $path, Throwable $exception):...
    method noGeneratorConfigured (line 22) | public static function noGeneratorConfigured(string $path, string $ext...

FILE: src/UnableToGenerateTemporaryUrl.php
  class UnableToGenerateTemporaryUrl (line 10) | final class UnableToGenerateTemporaryUrl extends RuntimeException implem...
    method __construct (line 12) | public function __construct(string $reason, string $path, ?Throwable $...
    method dueToError (line 17) | public static function dueToError(string $path, Throwable $exception):...
    method noGeneratorConfigured (line 22) | public static function noGeneratorConfigured(string $path, string $ext...

FILE: src/UnableToListContents.php
  class UnableToListContents (line 10) | final class UnableToListContents extends RuntimeException implements Fil...
    method atLocation (line 12) | public static function atLocation(string $location, bool $deep, Throwa...
    method operation (line 20) | public function operation(): string

FILE: src/UnableToMountFilesystem.php
  class UnableToMountFilesystem (line 9) | class UnableToMountFilesystem extends LogicException implements Filesyst...
    method becauseTheKeyIsNotValid (line 14) | public static function becauseTheKeyIsNotValid($key): UnableToMountFil...
    method becauseTheFilesystemWasNotValid (line 24) | public static function becauseTheFilesystemWasNotValid($filesystem): U...

FILE: src/UnableToMoveFile.php
  class UnableToMoveFile (line 10) | final class UnableToMoveFile extends RuntimeException implements Filesys...
    method sourceAndDestinationAreTheSame (line 22) | public static function sourceAndDestinationAreTheSame(string $source, ...
    method source (line 27) | public function source(): string
    method destination (line 32) | public function destination(): string
    method fromLocationTo (line 37) | public static function fromLocationTo(
    method because (line 50) | public static function because(
    method operation (line 63) | public function operation(): string

FILE: src/UnableToProvideChecksum.php
  class UnableToProvideChecksum (line 10) | final class UnableToProvideChecksum extends RuntimeException implements ...
    method __construct (line 12) | public function __construct(string $reason, string $path, ?Throwable $...

FILE: src/UnableToReadFile.php
  class UnableToReadFile (line 10) | final class UnableToReadFile extends RuntimeException implements Filesys...
    method fromLocation (line 22) | public static function fromLocation(string $location, string $reason =...
    method operation (line 31) | public function operation(): string
    method reason (line 36) | public function reason(): string
    method location (line 41) | public function location(): string

FILE: src/UnableToResolveFilesystemMount.php
  class UnableToResolveFilesystemMount (line 9) | class UnableToResolveFilesystemMount extends RuntimeException implements...
    method becauseTheSeparatorIsMissing (line 11) | public static function becauseTheSeparatorIsMissing(string $path): Una...
    method becauseTheMountWasNotRegistered (line 16) | public static function becauseTheMountWasNotRegistered(string $mountId...

FILE: src/UnableToRetrieveMetadata.php
  class UnableToRetrieveMetadata (line 10) | final class UnableToRetrieveMetadata extends RuntimeException implements...
    method lastModified (line 27) | public static function lastModified(string $location, string $reason =...
    method visibility (line 32) | public static function visibility(string $location, string $reason = '...
    method fileSize (line 37) | public static function fileSize(string $location, string $reason = '',...
    method mimeType (line 42) | public static function mimeType(string $location, string $reason = '',...
    method create (line 47) | public static function create(string $location, string $type, string $...
    method reason (line 57) | public function reason(): string
    method location (line 62) | public function location(): string
    method metadataType (line 67) | public function metadataType(): string
    method operation (line 72) | public function operation(): string

FILE: src/UnableToSetVisibility.php
  class UnableToSetVisibility (line 13) | final class UnableToSetVisibility extends RuntimeException implements Fi...
    method reason (line 25) | public function reason(): string
    method atLocation (line 30) | public static function atLocation(string $filename, string $extraMessa...
    method operation (line 40) | public function operation(): string
    method location (line 45) | public function location(): string

FILE: src/UnableToWriteFile.php
  class UnableToWriteFile (line 10) | final class UnableToWriteFile extends RuntimeException implements Filesy...
    method atLocation (line 22) | public static function atLocation(string $location, string $reason = '...
    method operation (line 31) | public function operation(): string
    method reason (line 36) | public function reason(): string
    method location (line 41) | public function location(): string

FILE: src/UnixVisibility/PortableVisibilityConverter.php
  class PortableVisibilityConverter (line 10) | class PortableVisibilityConverter implements VisibilityConverter
    method __construct (line 12) | public function __construct(
    method forFile (line 21) | public function forFile(string $visibility): int
    method forDirectory (line 30) | public function forDirectory(string $visibility): int
    method inverseForFile (line 39) | public function inverseForFile(int $visibility): string
    method inverseForDirectory (line 50) | public function inverseForDirectory(int $visibility): string
    method defaultForDirectories (line 61) | public function defaultForDirectories(): int
    method fromArray (line 69) | public static function fromArray(array $permissionMap, string $default...

FILE: src/UnixVisibility/PortableVisibilityConverterTest.php
  class PortableVisibilityConverterTest (line 14) | class PortableVisibilityConverterTest extends TestCase
    method determining_visibility_for_a_file (line 19) | public function determining_visibility_for_a_file(): void
    method determining_an_incorrect_visibility_for_a_file (line 29) | public function determining_an_incorrect_visibility_for_a_file(): void
    method determining_visibility_for_a_directory (line 39) | public function determining_visibility_for_a_directory(): void
    method determining_an_incorrect_visibility_for_a_directory (line 49) | public function determining_an_incorrect_visibility_for_a_directory():...
    method inversing_for_a_file (line 59) | public function inversing_for_a_file(): void
    method inversing_for_a_directory (line 70) | public function inversing_for_a_directory(): void
    method determining_default_for_directories (line 81) | public function determining_default_for_directories(): void
    method creating_from_array (line 93) | public function creating_from_array(): void

FILE: src/UnixVisibility/VisibilityConverter.php
  type VisibilityConverter (line 7) | interface VisibilityConverter
    method forFile (line 9) | public function forFile(string $visibility): int;
    method forDirectory (line 10) | public function forDirectory(string $visibility): int;
    method inverseForFile (line 11) | public function inverseForFile(int $visibility): string;
    method inverseForDirectory (line 12) | public function inverseForDirectory(int $visibility): string;
    method defaultForDirectories (line 13) | public function defaultForDirectories(): int;

FILE: src/UnreadableFileEncountered.php
  class UnreadableFileEncountered (line 9) | final class UnreadableFileEncountered extends RuntimeException implement...
    method location (line 16) | public function location(): string
    method atLocation (line 21) | public static function atLocation(string $location): UnreadableFileEnc...

FILE: src/UrlGeneration/ChainedPublicUrlGenerator.php
  class ChainedPublicUrlGenerator (line 10) | final class ChainedPublicUrlGenerator implements PublicUrlGenerator
    method __construct (line 15) | public function __construct(private iterable $generators)
    method publicUrl (line 19) | public function publicUrl(string $path, Config $config): string

FILE: src/UrlGeneration/ChainedPublicUrlGeneratorTest.php
  class ChainedPublicUrlGeneratorTest (line 9) | final class ChainedPublicUrlGeneratorTest extends TestCase
    method can_generate_url_for_supported_generator (line 14) | public function can_generate_url_for_supported_generator(): void
    method no_supported_generator_found_throws_exception (line 32) | public function no_supported_generator_found_throws_exception(): void

FILE: src/UrlGeneration/PrefixPublicUrlGenerator.php
  class PrefixPublicUrlGenerator (line 10) | class PrefixPublicUrlGenerator implements PublicUrlGenerator
    method __construct (line 14) | public function __construct(string $urlPrefix)
    method publicUrl (line 19) | public function publicUrl(string $path, Config $config): string

FILE: src/UrlGeneration/PublicUrlGenerator.php
  type PublicUrlGenerator (line 10) | interface PublicUrlGenerator
    method publicUrl (line 15) | public function publicUrl(string $path, Config $config): string;

FILE: src/UrlGeneration/ShardedPrefixPublicUrlGenerator.php
  class ShardedPrefixPublicUrlGenerator (line 13) | final class ShardedPrefixPublicUrlGenerator implements PublicUrlGenerator
    method __construct (line 22) | public function __construct(array $prefixes)
    method publicUrl (line 33) | public function publicUrl(string $path, Config $config): string

FILE: src/UrlGeneration/TemporaryUrlGenerator.php
  type TemporaryUrlGenerator (line 10) | interface TemporaryUrlGenerator
    method temporaryUrl (line 15) | public function temporaryUrl(string $path, DateTimeInterface $expiresA...

FILE: src/Visibility.php
  class Visibility (line 7) | final class Visibility

FILE: src/WebDAV/ByteMarkWebDAVServerTest.php
  class ByteMarkWebDAVServerTest (line 9) | class ByteMarkWebDAVServerTest extends WebDAVAdapterTestCase
    method createFilesystemAdapter (line 11) | protected static function createFilesystemAdapter(): FilesystemAdapter

FILE: src/WebDAV/SabreServerTest.php
  class SabreServerTest (line 10) | class SabreServerTest extends WebDAVAdapterTestCase
    method createFilesystemAdapter (line 12) | protected static function createFilesystemAdapter(): FilesystemAdapter

FILE: src/WebDAV/UrlPrefixingClientStub.php
  class UrlPrefixingClientStub (line 8) | class UrlPrefixingClientStub extends Client
    method propFind (line 13) | public function propFind($url, array $properties, $depth = 0): array

FILE: src/WebDAV/WebDAVAdapter.php
  class WebDAVAdapter (line 40) | class WebDAVAdapter implements FilesystemAdapter, PublicUrlGenerator
    method __construct (line 55) | public function __construct(
    method fileExists (line 65) | public function fileExists(string $path): bool
    method encodePath (line 82) | protected function encodePath(string $path): string
    method directoryExists (line 93) | public function directoryExists(string $path): bool
    method write (line 110) | public function write(string $path, string $contents, Config $config):...
    method writeStream (line 115) | public function writeStream(string $path, $contents, Config $config): ...
    method upload (line 123) | private function upload(string $path, mixed $contents): void
    method read (line 140) | public function read(string $path): string
    method readStream (line 157) | public function readStream(string $path)
    method delete (line 177) | public function delete(string $path): void
    method deleteDirectory (line 195) | public function deleteDirectory(string $path): void
    method createDirectory (line 212) | public function createDirectory(string $path, Config $config): void
    method setVisibility (line 246) | public function setVisibility(string $path, string $visibility): void
    method visibility (line 253) | public function visibility(string $path): FileAttributes
    method mimeType (line 258) | public function mimeType(string $path): FileAttributes
    method lastModified (line 265) | public function lastModified(string $path): FileAttributes
    method fileSize (line 272) | public function fileSize(string $path): FileAttributes
    method listContents (line 279) | public function listContents(string $path, bool $deep): iterable
    method normalizeObject (line 313) | private function normalizeObject(array $object): array
    method move (line 337) | public function move(string $source, string $destination, Config $conf...
    method manualMove (line 366) | private function manualMove(string $source, string $destination): void
    method copy (line 378) | public function copy(string $source, string $destination, Config $conf...
    method manualCopy (line 407) | private function manualCopy(string $source, string $destination): void
    method propsIsDirectory (line 418) | private function propsIsDirectory(array $properties): bool
    method createParentDirFor (line 430) | private function createParentDirFor(string $path): void
    method propFind (line 441) | private function propFind(string $path, string $section, string $prope...
    method publicUrl (line 458) | public function publicUrl(string $path, Config $config): string

FILE: src/WebDAV/WebDAVAdapterTestCase.php
  class WebDAVAdapterTestCase (line 14) | abstract class WebDAVAdapterTestCase extends FilesystemAdapterTestCase
    method setting_visibility (line 19) | public function setting_visibility(): void
    method overwriting_a_file (line 32) | public function overwriting_a_file(): void
    method creating_a_directory_with_leading_and_trailing_slashes (line 48) | public function creating_a_directory_with_leading_and_trailing_slashes...
    method copying_a_file (line 61) | public function copying_a_file(): void
    method copying_a_file_again (line 82) | public function copying_a_file_again(): void
    method moving_a_file (line 103) | public function moving_a_file(): void
    method moving_a_file_that_does_not_exist (line 128) | public function moving_a_file_that_does_not_exist(): void
    method part_of_prefix_already_exists (line 140) | public function part_of_prefix_already_exists(): void

FILE: src/WhitespacePathNormalizer.php
  class WhitespacePathNormalizer (line 7) | class WhitespacePathNormalizer implements PathNormalizer
    method normalizePath (line 9) | public function normalizePath(string $path): string
    method rejectFunkyWhiteSpace (line 17) | private function rejectFunkyWhiteSpace(string $path): void
    method normalizeRelativePath (line 24) | private function normalizeRelativePath(string $path): string

FILE: src/WhitespacePathNormalizerTest.php
  class WhitespacePathNormalizerTest (line 9) | class WhitespacePathNormalizerTest extends TestCase
    method setUp (line 16) | protected function setUp(): void
    method path_normalizing (line 26) | public function path_normalizing(string $input, string $expected): void
    method pathProvider (line 37) | public static function pathProvider(): array
    method guarding_against_path_traversal (line 67) | public function guarding_against_path_traversal(string $input): void
    method rejecting_funky_whitespace (line 78) | public function rejecting_funky_whitespace(string $path): void
    method dpFunkyWhitespacePaths (line 84) | public static function dpFunkyWhitespacePaths(): iterable
    method invalidPathProvider (line 92) | public static function invalidPathProvider(): array

FILE: src/ZipArchive/FilesystemZipArchiveProvider.php
  class FilesystemZipArchiveProvider (line 9) | class FilesystemZipArchiveProvider implements ZipArchiveProvider
    method __construct (line 16) | public function __construct(private string $filename, private int $loc...
    method createZipArchive (line 20) | public function createZipArchive(): ZipArchive
    method createParentDirectoryForZipArchive (line 30) | private function createParentDirectoryForZipArchive(string $fullPath):...
    method openZipArchive (line 43) | private function openZipArchive(): ZipArchive

FILE: src/ZipArchive/NoRootPrefixZipArchiveAdapterTest.php
  class NoRootPrefixZipArchiveAdapterTest (line 10) | final class NoRootPrefixZipArchiveAdapterTest extends ZipArchiveAdapterT...
    method getRoot (line 12) | protected static function getRoot(): string

FILE: src/ZipArchive/PrefixedRootZipArchiveAdapterTest.php
  class PrefixedRootZipArchiveAdapterTest (line 10) | final class PrefixedRootZipArchiveAdapterTest extends ZipArchiveAdapterT...
    method getRoot (line 12) | protected static function getRoot(): string

FILE: src/ZipArchive/StubZipArchive.php
  class StubZipArchive (line 9) | class StubZipArchive extends ZipArchive
    method failNextDirectoryCreation (line 17) | public function failNextDirectoryCreation(): void
    method addEmptyDir (line 28) | public function addEmptyDir($dirname, $flags = 0): bool
    method failNextWrite (line 39) | public function failNextWrite(): void
    method addFromString (line 51) | public function addFromString($localname, $contents, $flags = 0): bool
    method failNextDeleteName (line 62) | public function failNextDeleteName(): void
    method deleteName (line 70) | public function deleteName($name): bool
    method failWhenSettingVisibility (line 81) | public function failWhenSettingVisibility(): void
    method setExternalAttributesName (line 86) | public function setExternalAttributesName($name, $opsys, $attr, $flags...
    method failWhenDeletingAnIndex (line 97) | public function failWhenDeletingAnIndex(): void
    method deleteIndex (line 102) | public function deleteIndex($index): bool

FILE: src/ZipArchive/StubZipArchiveProvider.php
  class StubZipArchiveProvider (line 9) | class StubZipArchiveProvider implements ZipArchiveProvider
    method __construct (line 18) | public function __construct(private string $filename, int $localDirect...
    method createZipArchive (line 23) | public function createZipArchive(): ZipArchive
    method stubbedZipArchive (line 37) | public function stubbedZipArchive(): StubZipArchive

FILE: src/ZipArchive/UnableToCreateParentDirectory.php
  class UnableToCreateParentDirectory (line 9) | class UnableToCreateParentDirectory extends RuntimeException implements ...
    method atLocation (line 11) | public static function atLocation(string $location, string $reason = '...

FILE: src/ZipArchive/UnableToOpenZipArchive.php
  class UnableToOpenZipArchive (line 9) | final class UnableToOpenZipArchive extends RuntimeException implements Z...
    method atLocation (line 11) | public static function atLocation(string $location, string $reason = '...

FILE: src/ZipArchive/ZipArchiveAdapter.php
  class ZipArchiveAdapter (line 34) | final class ZipArchiveAdapter implements FilesystemAdapter
    method __construct (line 40) | public function __construct(
    method fileExists (line 52) | public function fileExists(string $path): bool
    method write (line 61) | public function write(string $path, string $contents, Config $config):...
    method writeStream (line 89) | public function writeStream(string $path, $contents, Config $config): ...
    method read (line 100) | public function read(string $path): string
    method readStream (line 114) | public function readStream(string $path)
    method delete (line 133) | public function delete(string $path): void
    method deleteDirectory (line 146) | public function deleteDirectory(string $path): void
    method createDirectory (line 174) | public function createDirectory(string $path, Config $config): void
    method directoryExists (line 183) | public function directoryExists(string $path): bool
    method setVisibility (line 191) | public function setVisibility(string $path, string $visibility): void
    method visibility (line 212) | public function visibility(string $path): FileAttributes
    method mimeType (line 235) | public function mimeType(string $path): FileAttributes
    method lastModified (line 252) | public function lastModified(string $path): FileAttributes
    method fileSize (line 266) | public function fileSize(string $path): FileAttributes
    method listContents (line 284) | public function listContents(string $path, bool $deep): iterable
    method yieldItemsFrom (line 327) | private function yieldItemsFrom(array $items): Generator
    method move (line 332) | public function move(string $source, string $destination, Config $conf...
    method copy (line 366) | public function copy(string $source, string $destination, Config $conf...
    method ensureParentDirectoryExists (line 380) | private function ensureParentDirectoryExists(string $path, Config $con...
    method ensureDirectoryExists (line 391) | private function ensureDirectoryExists(string $dirname, Config $config...
    method isDirectoryPath (line 420) | private function isDirectoryPath(string $path): bool
    method isAtRootDirectory (line 425) | private function isAtRootDirectory(string $directoryRoot, string $path...
    method setVisibilityAttribute (line 436) | private function setVisibilityAttribute(string $statsName, string $vis...

FILE: src/ZipArchive/ZipArchiveAdapterTestCase.php
  class ZipArchiveAdapterTestCase (line 25) | abstract class ZipArchiveAdapterTestCase extends FilesystemAdapterTestCase
    method setUp (line 34) | protected function setUp(): void
    method tearDownAfterClass (line 41) | public static function tearDownAfterClass(): void
    method tearDown (line 46) | protected function tearDown(): void
    method createFilesystemAdapter (line 51) | protected static function createFilesystemAdapter(): FilesystemAdapter
    method getRoot (line 58) | abstract protected static function getRoot(): string;
    method not_being_able_to_create_the_parent_directory (line 63) | public function not_being_able_to_create_the_parent_directory(): void
    method not_being_able_to_write_a_file_because_the_parent_directory_could_not_be_created (line 74) | public function not_being_able_to_write_a_file_because_the_parent_dire...
    method scenarios_that_cause_writing_a_file_to_fail (line 88) | public function scenarios_that_cause_writing_a_file_to_fail(callable $...
    method scenariosThatCauseWritesToFail (line 101) | public static function scenariosThatCauseWritesToFail(): Generator
    method failing_to_delete_a_file (line 119) | public function failing_to_delete_a_file(): void
    method deleting_a_directory (line 131) | public function deleting_a_directory(): void
    method deleting_a_prefixed_directory (line 150) | public function deleting_a_prefixed_directory(): void
    method list_root_directory (line 169) | public function list_root_directory(): void
    method failing_to_create_a_directory (line 183) | public function failing_to_create_a_directory(): void
    method failing_to_create_a_directory_because_setting_visibility_fails (line 195) | public function failing_to_create_a_directory_because_setting_visibili...
    method failing_to_delete_a_directory (line 207) | public function failing_to_delete_a_directory(): void
    method setting_visibility_on_a_directory (line 221) | public function setting_visibility_on_a_directory(): void
    method failing_to_move_a_file (line 233) | public function failing_to_move_a_file(): void
    method failing_to_copy_a_file (line 247) | public function failing_to_copy_a_file(): void
    method failing_to_set_visibility_because_the_file_does_not_exist (line 261) | public function failing_to_set_visibility_because_the_file_does_not_ex...
    method deleting_a_directory_with_files_in_it (line 271) | public function deleting_a_directory_with_files_in_it(): void
    method failing_to_set_visibility_because_setting_it_fails (line 285) | public function failing_to_set_visibility_because_setting_it_fails(): ...
    method moving_a_file_and_overwriting (line 300) | public function moving_a_file_and_overwriting(): void
    method removeZipArchive (line 328) | protected static function removeZipArchive(): void

FILE: src/ZipArchive/ZipArchiveException.php
  type ZipArchiveException (line 9) | interface ZipArchiveException extends FilesystemException

FILE: src/ZipArchive/ZipArchiveProvider.php
  type ZipArchiveProvider (line 9) | interface ZipArchiveProvider
    method createZipArchive (line 11) | public function createZipArchive(): ZipArchive;
Condensed preview — 293 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (785K chars).
[
  {
    "path": ".dockerignore",
    "chars": 5,
    "preview": ".git\n"
  },
  {
    "path": ".editorconfig",
    "chars": 137,
    "preview": "[*]\nindent_style = space\n\n[*.yml]\nindent_size = 2\n\n[composer.json]\nindent_size = 4\n\n[*.php]\nend_of_line = lf\ninsert_fina"
  },
  {
    "path": ".gitattributes",
    "chars": 1278,
    "preview": "* text=auto\n\n/.docker export-ignore\n/.dockerignore export-ignore\n/docker-compose.yml export-ignore\n/config.subsplit-publ"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/Bug.md",
    "chars": 501,
    "preview": "---\nname: 🐛 Bug\nabout: Did you encounter a bug?\n---\n\n### Bug Report\n\n<!-- Fill in the relevant information below to help"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/Feature_Request.md",
    "chars": 528,
    "preview": "---\nname: 🎉 Feature Request\nabout: Do you have a new feature in mind?\n---\n\n### Feature Request\n\n<!-- Fill in the relevan"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/Question.md",
    "chars": 315,
    "preview": "---\nname: ❓ Question\nabout: Are you unsure about something?\n---\n\n### Question\n\n<!-- Fill in the relevant information bel"
  },
  {
    "path": ".github/release.yml",
    "chars": 270,
    "preview": "changelog:\n  categories:\n    - title: Breaking Changes 🛠\n      labels:\n        - Semver-Major\n        - breaking-change\n"
  },
  {
    "path": ".github/stale.yml",
    "chars": 696,
    "preview": "# Number of days of inactivity before an issue becomes stale\ndaysUntilStale: 60\n# Number of days of inactivity before a "
  },
  {
    "path": ".github/workflows/publish-subsplits.yml",
    "chars": 990,
    "preview": "---\nname: Sub-Split Publishing\non:\n  push:\n    branches:\n      - 3.x\n  create:\n    tags:\n      - '3.*'\n  delete:\n    tag"
  },
  {
    "path": ".github/workflows/quality-assurance.yml",
    "chars": 2514,
    "preview": "---\nname: Quality Assurance\nconcurrency:\n  group: ${{ github.ref }}\n  cancel-in-progress: true\non:\n  push:\n    paths:\n  "
  },
  {
    "path": ".github/workflows/set-subsplit-default-branch.yml",
    "chars": 932,
    "preview": "---\nname: Update default sub-split branch\n\non: workflow_dispatch\n\njobs:\n  set-default-branch:\n    name: Set default git "
  },
  {
    "path": ".gitignore",
    "chars": 164,
    "preview": "/vendor/\n/coverage/\n/.phpunit.result.cache\n/phpunit.xml\n/composer.lock\n/index_*.php\n/.php-cs-fixer.php\n/.php-cs-fixer.ca"
  },
  {
    "path": ".php-cs-fixer.dist.php",
    "chars": 1382,
    "preview": "<?php\n\n$finder = PhpCsFixer\\Finder::create()\n    ->in([__DIR__ . '/'])\n    ->exclude(__DIR__ . '/vendor');\n\nreturn (new "
  },
  {
    "path": "CHANGELOG.md",
    "chars": 18359,
    "preview": "# Changelog\n\n## 3.32.0 - 2026-02-25\n\n### Changes\n\n- [AwsS3V3] Allow SSE-C options when fetching file metadata\n\n## 3.31.0"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 5222,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
  },
  {
    "path": "INFO.md",
    "chars": 139,
    "preview": "View the docs at: https://flysystem.thephpleague.com/docs/  \nChangelog at: https://github.com/thephpleague/flysystem/blo"
  },
  {
    "path": "LICENSE",
    "chars": 1063,
    "preview": "Copyright (c) 2013-2026 Frank de Jonge\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
  },
  {
    "path": "bin/.gitignore",
    "chars": 16,
    "preview": "renamespace.php\n"
  },
  {
    "path": "bin/check-versions.php",
    "chars": 3932,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\n/**\n * This script check for composer dependency incompatibilities:.\n *\n *  - All requi"
  },
  {
    "path": "bin/close-subsplit-prs.yml",
    "chars": 696,
    "preview": "---\nname: Close sub-split PRs\n\non:\n  push:\n    branches:\n      - 2.x\n      - 3.x\n  pull_request:\n    branches:\n      - 2"
  },
  {
    "path": "bin/set-flysystem-version.php",
    "chars": 1177,
    "preview": "<?php\n\nuse League\\Flysystem\\FileAttributes;\nuse League\\Flysystem\\Filesystem;\nuse League\\Flysystem\\Local\\LocalFilesystemA"
  },
  {
    "path": "bin/tools.php",
    "chars": 210,
    "preview": "<?php\n\ninclude_once __DIR__ . '/../vendor/autoload.php';\n\nfunction write_line(string $line)\n{\n    fwrite(STDOUT, \"{$line"
  },
  {
    "path": "bin/update-subsplit-closers.php",
    "chars": 582,
    "preview": "<?php\n\nuse League\\Flysystem\\Filesystem;\nuse League\\Flysystem\\Local\\LocalFilesystemAdapter;\n\ninclude __DIR__ . '/../vendo"
  },
  {
    "path": "composer.json",
    "chars": 2068,
    "preview": "{\n    \"name\": \"league/flysystem\",\n    \"description\": \"File storage abstraction for PHP\",\n    \"keywords\": [\n        \"file"
  },
  {
    "path": "config.subsplit-publish.json",
    "chars": 2656,
    "preview": "{\n    \"sub-splits\": [\n        {\n            \"name\": \"ftp\",\n            \"directory\": \"src/Ftp\",\n            \"target\": \"gi"
  },
  {
    "path": "docker-compose.yml",
    "chars": 2235,
    "preview": "---\nversion: \"3\"\nservices:\n  mongodb:\n    image: mongo:7\n    ports:\n      - \"27017:27017\"\n  sabredav:\n    image: php:8.1"
  },
  {
    "path": "mocked-functions.php",
    "chars": 3492,
    "preview": "<?php\n\nnamespace League\\Flysystem\\Local {\n    function rmdir(...$arguments)\n    {\n        if ( ! is_mocked('rmdir')) {\n "
  },
  {
    "path": "phpstan-baseline.neon",
    "chars": 5450,
    "preview": "parameters:\n\tignoreErrors:\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\$connection of method League\\\\\\\\Flysystem\\\\\\\\Ftp\\\\\\\\FtpAdapter"
  },
  {
    "path": "phpstan.neon",
    "chars": 1019,
    "preview": "includes:\n    - phpstan-baseline.neon\nparameters:\n    level: 6\n    paths:\n        - src\n    checkMissingIterableValueTyp"
  },
  {
    "path": "phpunit.php",
    "chars": 158,
    "preview": "<?php\n\ninclude __DIR__ . '/vendor/autoload.php';\ninclude __DIR__ . '/src/AdapterTestUtilities/test-functions.php';\ninclu"
  },
  {
    "path": "phpunit.xml.dist",
    "chars": 544,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit colors=\"true\" bootstrap=\"phpunit.php\">\n    <testsuites>\n        <testsui"
  },
  {
    "path": "readme.md",
    "chars": 3954,
    "preview": "# League\\Flysystem\n\n[![Author](https://img.shields.io/badge/author-@frankdejonge-blue.svg)](https://twitter.com/frankdej"
  },
  {
    "path": "src/AdapterTestUtilities/.gitattributes",
    "chars": 88,
    "preview": "* text=auto\n\n.github export-ignore\n.gitattributes export-ignore\nREADME.md export-ignore\n"
  },
  {
    "path": "src/AdapterTestUtilities/.github/workflows/close-subsplit-prs.yaml",
    "chars": 696,
    "preview": "---\nname: Close sub-split PRs\n\non:\n  push:\n    branches:\n      - 2.x\n      - 3.x\n  pull_request:\n    branches:\n      - 2"
  },
  {
    "path": "src/AdapterTestUtilities/ExceptionThrowingFilesystemAdapter.php",
    "chars": 4381,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\AdapterTestUtilities;\n\nuse League\\Flysystem\\Config;\nuse Leag"
  },
  {
    "path": "src/AdapterTestUtilities/FilesystemAdapterTestCase.php",
    "chars": 30231,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\AdapterTestUtilities;\n\nuse const PHP_EOL;\nuse DateInterval;\n"
  },
  {
    "path": "src/AdapterTestUtilities/README.md",
    "chars": 366,
    "preview": "## Flysystem Adapter Test Utilities\n\n> ⚠️ this is a sub-split, for pull requests and issues, visit: https://github.com/t"
  },
  {
    "path": "src/AdapterTestUtilities/RetryOnTestException.php",
    "chars": 2292,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\AdapterTestUtilities;\n\nuse const PHP_EOL;\nuse const STDOUT;\n"
  },
  {
    "path": "src/AdapterTestUtilities/ToxiproxyManagement.php",
    "chars": 2155,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\AdapterTestUtilities;\n\nuse GuzzleHttp\\Client;\n\n/**\n * This c"
  },
  {
    "path": "src/AdapterTestUtilities/composer.json",
    "chars": 669,
    "preview": "{\n    \"name\": \"league/flysystem-adapter-test-utilities\",\n    \"description\": \"Flysystem utilities for testing adapters.\","
  },
  {
    "path": "src/AdapterTestUtilities/test-functions.php",
    "chars": 1152,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nfunction return_mocked_value(string $name)\n{\n    return array_shift($_ENV['__FM:RETURNS"
  },
  {
    "path": "src/AdapterTestUtilities/test_files/unknown-mime-type.md5",
    "chars": 32,
    "preview": "141d15ed35fc57dcc3c72bba881742b1"
  },
  {
    "path": "src/AsyncAwsS3/.gitattributes",
    "chars": 167,
    "preview": "* text=auto\n\n.github export-ignore\n.gitattributes export-ignore\n.gitignore export-ignore\n**/*Test.php export-ignore\n**/*"
  },
  {
    "path": "src/AsyncAwsS3/.github/workflows/close-subsplit-prs.yaml",
    "chars": 696,
    "preview": "---\nname: Close sub-split PRs\n\non:\n  push:\n    branches:\n      - 2.x\n      - 3.x\n  pull_request:\n    branches:\n      - 2"
  },
  {
    "path": "src/AsyncAwsS3/AsyncAwsS3Adapter.php",
    "chars": 19402,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\AsyncAwsS3;\n\nuse AsyncAws\\Core\\Exception\\Http\\ClientExceptio"
  },
  {
    "path": "src/AsyncAwsS3/AsyncAwsS3AdapterTest.php",
    "chars": 16086,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\AsyncAwsS3;\n\nuse AsyncAws\\Core\\Exception\\Http\\ClientExceptio"
  },
  {
    "path": "src/AsyncAwsS3/LICENSE",
    "chars": 1063,
    "preview": "Copyright (c) 2013-2026 Frank de Jonge\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
  },
  {
    "path": "src/AsyncAwsS3/PortableVisibilityConverter.php",
    "chars": 1562,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\AsyncAwsS3;\n\nuse AsyncAws\\S3\\ValueObject\\Grant;\nuse League\\F"
  },
  {
    "path": "src/AsyncAwsS3/README.md",
    "chars": 298,
    "preview": "## Sub-split of Flysystem for AsyncAws S3.\n\n> ⚠️ this is a sub-split, for pull requests and issues, visit: https://githu"
  },
  {
    "path": "src/AsyncAwsS3/S3ClientStub.php",
    "chars": 5545,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\AsyncAwsS3;\n\nuse AsyncAws\\Core\\Exception\\Exception;\nuse Asyn"
  },
  {
    "path": "src/AsyncAwsS3/VisibilityConverter.php",
    "chars": 369,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\AsyncAwsS3;\n\nuse AsyncAws\\S3\\ValueObject\\Grant;\n\ninterface V"
  },
  {
    "path": "src/AsyncAwsS3/composer.json",
    "chars": 801,
    "preview": "{\n    \"name\": \"league/flysystem-async-aws-s3\",\n    \"description\": \"AsyncAws S3 filesystem adapter for Flysystem.\",\n    \""
  },
  {
    "path": "src/AwsS3V3/.gitattributes",
    "chars": 167,
    "preview": "* text=auto\n\n.github export-ignore\n.gitattributes export-ignore\n.gitignore export-ignore\n**/*Test.php export-ignore\n**/*"
  },
  {
    "path": "src/AwsS3V3/.github/workflows/close-subsplit-prs.yaml",
    "chars": 696,
    "preview": "---\nname: Close sub-split PRs\n\non:\n  push:\n    branches:\n      - 2.x\n      - 3.x\n  pull_request:\n    branches:\n      - 2"
  },
  {
    "path": "src/AwsS3V3/AwsS3V3Adapter.php",
    "chars": 17385,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\AwsS3V3;\n\nuse Aws\\Api\\DateTimeResult;\nuse Aws\\S3\\S3ClientInt"
  },
  {
    "path": "src/AwsS3V3/AwsS3V3AdapterTest.php",
    "chars": 15282,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\AwsS3V3;\n\nuse Aws\\Result;\nuse Aws\\S3\\S3Client;\nuse Aws\\S3\\S3"
  },
  {
    "path": "src/AwsS3V3/LICENSE",
    "chars": 1063,
    "preview": "Copyright (c) 2013-2026 Frank de Jonge\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
  },
  {
    "path": "src/AwsS3V3/PortableVisibilityConverter.php",
    "chars": 1270,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\AwsS3V3;\n\nuse League\\Flysystem\\Visibility;\n\nclass PortableVi"
  },
  {
    "path": "src/AwsS3V3/README.md",
    "chars": 288,
    "preview": "## Sub-split of Flysystem for AWS S3.\n\n> ⚠️ this is a sub-split, for pull requests and issues, visit: https://github.com"
  },
  {
    "path": "src/AwsS3V3/S3ClientStub.php",
    "chars": 4642,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\AwsS3V3;\n\nuse Aws\\Command;\nuse Aws\\CommandInterface;\nuse Aws"
  },
  {
    "path": "src/AwsS3V3/VisibilityConverter.php",
    "chars": 282,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\AwsS3V3;\n\ninterface VisibilityConverter\n{\n    public functio"
  },
  {
    "path": "src/AwsS3V3/composer.json",
    "chars": 742,
    "preview": "{\n    \"name\": \"league/flysystem-aws-s3-v3\",\n    \"description\": \"AWS S3 filesystem adapter for Flysystem.\",\n    \"keywords"
  },
  {
    "path": "src/AzureBlobStorage/.gitattributes",
    "chars": 167,
    "preview": "* text=auto\n\n.github export-ignore\n.gitattributes export-ignore\n.gitignore export-ignore\n**/*Test.php export-ignore\n**/*"
  },
  {
    "path": "src/AzureBlobStorage/.github/workflows/close-subsplit-prs.yaml",
    "chars": 696,
    "preview": "---\nname: Close sub-split PRs\n\non:\n  push:\n    branches:\n      - 2.x\n      - 3.x\n  pull_request:\n    branches:\n      - 2"
  },
  {
    "path": "src/AzureBlobStorage/AzureBlobStorageAdapter.php",
    "chars": 14202,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\AzureBlobStorage;\n\nuse DateTime;\nuse DateTimeInterface;\nuse "
  },
  {
    "path": "src/AzureBlobStorage/AzureBlobStorageAdapterTest.php",
    "chars": 6041,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\AzureBlobStorage;\n\nuse League\\Flysystem\\AdapterTestUtilities"
  },
  {
    "path": "src/AzureBlobStorage/LICENSE",
    "chars": 1063,
    "preview": "Copyright (c) 2013-2026 Frank de Jonge\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
  },
  {
    "path": "src/AzureBlobStorage/README.md",
    "chars": 162,
    "preview": "## Sub-split for Flysystem's Azure Blob Storage Adapter\n\n> ⚠️ this is a sub-split, for pull requests and issues, visit: "
  },
  {
    "path": "src/AzureBlobStorage/composer.json",
    "chars": 500,
    "preview": "{\n    \"name\": \"league/flysystem-azure-blob-storage\",\n    \"autoload\": {\n        \"psr-4\": {\n            \"League\\\\Flysystem"
  },
  {
    "path": "src/CalculateChecksumFromStream.php",
    "chars": 793,
    "preview": "<?php\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\nuse function hash_final;\nuse function hash_init;\nuse functi"
  },
  {
    "path": "src/ChecksumAlgoIsNotSupported.php",
    "chars": 169,
    "preview": "<?php\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\nuse InvalidArgumentException;\n\nfinal class ChecksumAlgoIsNo"
  },
  {
    "path": "src/ChecksumProvider.php",
    "chars": 291,
    "preview": "<?php\n\nnamespace League\\Flysystem;\n\ninterface ChecksumProvider\n{\n    /**\n     * @return string MD5 hash of the file cont"
  },
  {
    "path": "src/Config.php",
    "chars": 1421,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\nuse function array_diff_key;\nuse function array_flip;\nuse "
  },
  {
    "path": "src/ConfigTest.php",
    "chars": 1801,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\nuse PHPUnit\\Framework\\TestCase;\n\nclass ConfigTest extends "
  },
  {
    "path": "src/CorruptedPathDetected.php",
    "chars": 316,
    "preview": "<?php\n\nnamespace League\\Flysystem;\n\nuse RuntimeException;\n\nfinal class CorruptedPathDetected extends RuntimeException im"
  },
  {
    "path": "src/DecoratedAdapter.php",
    "chars": 2421,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\nabstract class DecoratedAdapter implements FilesystemAdapt"
  },
  {
    "path": "src/DirectoryAttributes.php",
    "chars": 2071,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\nclass DirectoryAttributes implements StorageAttributes\n{\n "
  },
  {
    "path": "src/DirectoryAttributesTest.php",
    "chars": 1647,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * @group core\n */\ncl"
  },
  {
    "path": "src/DirectoryListing.php",
    "chars": 2078,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\nuse ArrayIterator;\nuse Generator;\nuse IteratorAggregate;\nu"
  },
  {
    "path": "src/DirectoryListingTest.php",
    "chars": 3726,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\nuse Generator;\nuse PHPUnit\\Framework\\TestCase;\n\nuse functi"
  },
  {
    "path": "src/ExceptionInformationTest.php",
    "chars": 6280,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * @group core\n */\ncl"
  },
  {
    "path": "src/FileAttributes.php",
    "chars": 2562,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\nclass FileAttributes implements StorageAttributes\n{\n    us"
  },
  {
    "path": "src/FileAttributesTest.php",
    "chars": 3286,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\nuse Generator;\nuse PHPUnit\\Framework\\TestCase;\n\nuse Runtim"
  },
  {
    "path": "src/Filesystem.php",
    "chars": 9850,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\nuse DateTimeInterface;\nuse Generator;\nuse League\\Flysystem"
  },
  {
    "path": "src/FilesystemAdapter.php",
    "chars": 2784,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\ninterface FilesystemAdapter\n{\n    /**\n     * @throws Files"
  },
  {
    "path": "src/FilesystemException.php",
    "chars": 130,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\nuse Throwable;\n\ninterface FilesystemException extends Thro"
  },
  {
    "path": "src/FilesystemOperationFailed.php",
    "chars": 954,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\ninterface FilesystemOperationFailed extends FilesystemExce"
  },
  {
    "path": "src/FilesystemOperator.php",
    "chars": 138,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\ninterface FilesystemOperator extends FilesystemReader, Fil"
  },
  {
    "path": "src/FilesystemReader.php",
    "chars": 2169,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\nuse DateTimeInterface;\n\n/**\n * This interface contains eve"
  },
  {
    "path": "src/FilesystemTest.php",
    "chars": 26343,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\nuse DateTimeImmutable;\nuse DateTimeInterface;\nuse Generato"
  },
  {
    "path": "src/FilesystemWriter.php",
    "chars": 1448,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\ninterface FilesystemWriter\n{\n    /**\n     * @throws Unable"
  },
  {
    "path": "src/Ftp/.gitattributes",
    "chars": 171,
    "preview": "* text=auto\n\n.github export-ignore\n.gitattributes export-ignore\n.gitignore export-ignore\n**/*Test.php export-ignore\n**/*"
  },
  {
    "path": "src/Ftp/.github/workflows/close-subsplit-prs.yaml",
    "chars": 696,
    "preview": "---\nname: Close sub-split PRs\n\non:\n  push:\n    branches:\n      - 2.x\n      - 3.x\n  pull_request:\n    branches:\n      - 2"
  },
  {
    "path": "src/Ftp/ConnectionProvider.php",
    "chars": 208,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Ftp;\n\ninterface ConnectionProvider\n{\n    /**\n     * @return "
  },
  {
    "path": "src/Ftp/ConnectivityChecker.php",
    "chars": 203,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Ftp;\n\ninterface ConnectivityChecker\n{\n    /**\n     * @param "
  },
  {
    "path": "src/Ftp/ConnectivityCheckerThatCanFail.php",
    "chars": 645,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Ftp;\n\nclass ConnectivityCheckerThatCanFail implements Connec"
  },
  {
    "path": "src/Ftp/FtpAdapter.php",
    "chars": 22337,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Ftp;\n\nuse DateTime;\nuse Generator;\nuse League\\Flysystem\\Conf"
  },
  {
    "path": "src/Ftp/FtpAdapterTest.php",
    "chars": 3478,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Ftp;\n\nuse League\\Flysystem\\FilesystemAdapter;\n\nuse function "
  },
  {
    "path": "src/Ftp/FtpAdapterTestCase.php",
    "chars": 11631,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Ftp;\n\nuse Generator;\nuse League\\Flysystem\\AdapterTestUtiliti"
  },
  {
    "path": "src/Ftp/FtpConnectionException.php",
    "chars": 174,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Ftp;\n\nuse League\\Flysystem\\FilesystemException;\n\ninterface F"
  },
  {
    "path": "src/Ftp/FtpConnectionOptions.php",
    "chars": 2955,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Ftp;\n\nuse const FTP_BINARY;\n\nclass FtpConnectionOptions\n{\n  "
  },
  {
    "path": "src/Ftp/FtpConnectionProvider.php",
    "chars": 3200,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Ftp;\n\nuse const FTP_USEPASVADDRESS;\nuse function error_clear"
  },
  {
    "path": "src/Ftp/FtpConnectionProviderTest.php",
    "chars": 5590,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Ftp;\n\nuse League\\Flysystem\\AdapterTestUtilities\\RetryOnTestE"
  },
  {
    "path": "src/Ftp/FtpdAdapterTest.php",
    "chars": 732,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Ftp;\n\nuse League\\Flysystem\\FilesystemAdapter;\n\n/**\n * @group"
  },
  {
    "path": "src/Ftp/InvalidListResponseReceived.php",
    "chars": 225,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Ftp;\n\nuse League\\Flysystem\\FilesystemException;\nuse RuntimeE"
  },
  {
    "path": "src/Ftp/LICENSE",
    "chars": 1063,
    "preview": "Copyright (c) 2013-2026 Frank de Jonge\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
  },
  {
    "path": "src/Ftp/NoopCommandConnectivityChecker.php",
    "chars": 602,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Ftp;\n\nuse TypeError;\nuse ValueError;\n\nclass NoopCommandConne"
  },
  {
    "path": "src/Ftp/NoopCommandConnectivityCheckerTest.php",
    "chars": 1594,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Ftp;\n\nuse League\\Flysystem\\AdapterTestUtilities\\RetryOnTestE"
  },
  {
    "path": "src/Ftp/README.md",
    "chars": 273,
    "preview": "## Sub-split of Flysystem for FTP.\n\n> ⚠️ this is a sub-split, for pull requests and issues, visit: https://github.com/th"
  },
  {
    "path": "src/Ftp/RawListFtpConnectivityChecker.php",
    "chars": 428,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Ftp;\n\nuse ValueError;\n\nclass RawListFtpConnectivityChecker i"
  },
  {
    "path": "src/Ftp/RawListFtpConnectivityCheckerTest.php",
    "chars": 1115,
    "preview": "<?php\n\nnamespace League\\Flysystem\\Ftp;\n\nuse League\\Flysystem\\AdapterTestUtilities\\RetryOnTestException;\nuse PHPUnit\\Fram"
  },
  {
    "path": "src/Ftp/StubConnectionProvider.php",
    "chars": 402,
    "preview": "<?php\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Ftp;\n\nclass StubConnectionProvider implements ConnectionProvi"
  },
  {
    "path": "src/Ftp/UnableToAuthenticate.php",
    "chars": 301,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Ftp;\n\nuse RuntimeException;\n\nfinal class UnableToAuthenticat"
  },
  {
    "path": "src/Ftp/UnableToConnectToFtpHost.php",
    "chars": 479,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Ftp;\n\nuse RuntimeException;\n\nfinal class UnableToConnectToFt"
  },
  {
    "path": "src/Ftp/UnableToEnableUtf8Mode.php",
    "chars": 187,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Ftp;\n\nuse RuntimeException;\n\nfinal class UnableToEnableUtf8M"
  },
  {
    "path": "src/Ftp/UnableToMakeConnectionPassive.php",
    "chars": 188,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Ftp;\n\nuse RuntimeException;\n\nclass UnableToMakeConnectionPas"
  },
  {
    "path": "src/Ftp/UnableToResolveConnectionRoot.php",
    "chars": 926,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Ftp;\n\nuse RuntimeException;\nuse Throwable;\n\nfinal class Unab"
  },
  {
    "path": "src/Ftp/UnableToSetFtpOption.php",
    "chars": 353,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Ftp;\n\nuse RuntimeException;\n\nclass UnableToSetFtpOption exte"
  },
  {
    "path": "src/Ftp/composer.json",
    "chars": 638,
    "preview": "{\n    \"name\": \"league/flysystem-ftp\",\n    \"description\": \"FTP filesystem adapter for Flysystem.\",\n    \"keywords\": [\"file"
  },
  {
    "path": "src/GoogleCloudStorage/.gitattributes",
    "chars": 141,
    "preview": "* text=auto\n\n/.github export-ignore\n/.gitattributes export-ignore\n/.gitignore export-ignore\n/**/*Test.php export-ignore\n"
  },
  {
    "path": "src/GoogleCloudStorage/.github/workflows/close-subsplit-prs.yaml",
    "chars": 696,
    "preview": "---\nname: Close sub-split PRs\n\non:\n  push:\n    branches:\n      - 2.x\n      - 3.x\n  pull_request:\n    branches:\n      - 2"
  },
  {
    "path": "src/GoogleCloudStorage/GoogleCloudStorageAdapter.php",
    "chars": 13901,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\GoogleCloudStorage;\n\nuse DateTimeInterface;\nuse Google\\Cloud"
  },
  {
    "path": "src/GoogleCloudStorage/GoogleCloudStorageAdapterTest.php",
    "chars": 5062,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\GoogleCloudStorage;\n\nuse League\\Flysystem\\AdapterTestUtiliti"
  },
  {
    "path": "src/GoogleCloudStorage/GoogleCloudStorageAdapterWithoutAclTest.php",
    "chars": 421,
    "preview": "<?php\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\GoogleCloudStorage;\n\nclass GoogleCloudStorageAdapterWithoutAc"
  },
  {
    "path": "src/GoogleCloudStorage/LICENSE",
    "chars": 1063,
    "preview": "Copyright (c) 2013-2026 Frank de Jonge\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
  },
  {
    "path": "src/GoogleCloudStorage/PortableVisibilityHandler.php",
    "chars": 1924,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\GoogleCloudStorage;\n\nuse Google\\Cloud\\Core\\Exception\\NotFoun"
  },
  {
    "path": "src/GoogleCloudStorage/README.md",
    "chars": 330,
    "preview": "## Sub-split of Flysystem for Google Cloud Storage (GCS).\n\n> ⚠️ this is a sub-split, for pull requests and issues, visit"
  },
  {
    "path": "src/GoogleCloudStorage/StubRiggedBucket.php",
    "chars": 1373,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\GoogleCloudStorage;\n\nuse Google\\Cloud\\Storage\\Bucket;\nuse Lo"
  },
  {
    "path": "src/GoogleCloudStorage/StubStorageClient.php",
    "chars": 942,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\GoogleCloudStorage;\n\nuse Google\\Cloud\\Storage\\StorageClient;"
  },
  {
    "path": "src/GoogleCloudStorage/UniformBucketLevelAccessVisibility.php",
    "chars": 643,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\GoogleCloudStorage;\n\nuse Google\\Cloud\\Storage\\StorageObject;"
  },
  {
    "path": "src/GoogleCloudStorage/VisibilityHandler.php",
    "chars": 385,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\GoogleCloudStorage;\n\nuse Google\\Cloud\\Storage\\StorageObject;"
  },
  {
    "path": "src/GoogleCloudStorage/composer.json",
    "chars": 693,
    "preview": "{\n    \"name\": \"league/flysystem-google-cloud-storage\",\n    \"description\": \"Google Cloud Storage adapter for Flysystem.\","
  },
  {
    "path": "src/GridFS/.gitattributes",
    "chars": 167,
    "preview": "* text=auto\n\n.github export-ignore\n.gitattributes export-ignore\n.gitignore export-ignore\n**/*Test.php export-ignore\n**/*"
  },
  {
    "path": "src/GridFS/.github/workflows/close-subsplit-prs.yaml",
    "chars": 683,
    "preview": "---\nname: Close sub-split PRs\n\non:\n  push:\n    branches:\n      - 2.x\n      - 3.x\n  pull_request:\n    branches:\n      - 2"
  },
  {
    "path": "src/GridFS/GridFSAdapter.php",
    "chars": 15711,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\GridFS;\n\nuse League\\Flysystem\\Config;\nuse League\\Flysystem\\D"
  },
  {
    "path": "src/GridFS/GridFSAdapterTest.php",
    "chars": 7522,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\GridFS;\n\nuse League\\Flysystem\\AdapterTestUtilities\\Filesyste"
  },
  {
    "path": "src/GridFS/LICENSE",
    "chars": 1063,
    "preview": "Copyright (c) 2024-2026 Frank de Jonge\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
  },
  {
    "path": "src/GridFS/README.md",
    "chars": 296,
    "preview": "## Sub-split for Flysystem's MongoDB GridFS Adapter\n\n> ⚠️ this is a sub-split, for pull requests and issues, visit: http"
  },
  {
    "path": "src/GridFS/composer.json",
    "chars": 551,
    "preview": "{\n    \"name\": \"league/flysystem-gridfs\",\n    \"autoload\": {\n        \"psr-4\": {\n            \"League\\\\Flysystem\\\\GridFS\\\\\":"
  },
  {
    "path": "src/InMemory/.gitattributes",
    "chars": 140,
    "preview": "* text=auto\n\n.github export-ignore\n.gitattributes export-ignore\n.gitignore export-ignore\n**/*Test.php export-ignore\nREAD"
  },
  {
    "path": "src/InMemory/.github/workflows/close-subsplit-prs.yaml",
    "chars": 696,
    "preview": "---\nname: Close sub-split PRs\n\non:\n  push:\n    branches:\n      - 2.x\n      - 3.x\n  pull_request:\n    branches:\n      - 2"
  },
  {
    "path": "src/InMemory/InMemoryFile.php",
    "chars": 1476,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\InMemory;\n\nuse const FILEINFO_MIME_TYPE;\nuse finfo;\n\n/**\n * "
  },
  {
    "path": "src/InMemory/InMemoryFilesystemAdapter.php",
    "chars": 8574,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\InMemory;\n\nuse League\\Flysystem\\Config;\nuse League\\Flysystem"
  },
  {
    "path": "src/InMemory/InMemoryFilesystemAdapterTest.php",
    "chars": 8634,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\InMemory;\n\nuse League\\Flysystem\\AdapterTestUtilities\\Filesys"
  },
  {
    "path": "src/InMemory/LICENSE",
    "chars": 1063,
    "preview": "Copyright (c) 2013-2026 Frank de Jonge\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
  },
  {
    "path": "src/InMemory/README.md",
    "chars": 301,
    "preview": "## Sub-split of Flysystem for in-memory file storage.\n\n> ⚠️ this is a sub-split, for pull requests and issues, visit: ht"
  },
  {
    "path": "src/InMemory/StaticInMemoryAdapterRegistry.php",
    "chars": 465,
    "preview": "<?php\n\nnamespace League\\Flysystem\\InMemory;\n\nclass StaticInMemoryAdapterRegistry\n{\n    /** @var array<string, InMemoryFi"
  },
  {
    "path": "src/InMemory/StaticInMemoryAdapterRegistryTest.php",
    "chars": 1721,
    "preview": "<?php\n\nnamespace League\\Flysystem\\InMemory;\n\nuse League\\Flysystem\\Config;\nuse League\\Flysystem\\FilesystemAdapter;\n\nclass"
  },
  {
    "path": "src/InMemory/composer.json",
    "chars": 627,
    "preview": "{\n    \"name\": \"league/flysystem-memory\",\n    \"description\": \"In-memory filesystem adapter for Flysystem.\",\n    \"keywords"
  },
  {
    "path": "src/InvalidStreamProvided.php",
    "chars": 225,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\nuse InvalidArgumentException as BaseInvalidArgumentExcepti"
  },
  {
    "path": "src/InvalidVisibilityProvided.php",
    "chars": 553,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\nuse InvalidArgumentException;\n\nuse function var_export;\n\nc"
  },
  {
    "path": "src/Local/.gitattributes",
    "chars": 140,
    "preview": "* text=auto\n\n.github export-ignore\n.gitattributes export-ignore\n.gitignore export-ignore\n**/*Test.php export-ignore\nREAD"
  },
  {
    "path": "src/Local/.github/workflows/close-subsplit-prs.yaml",
    "chars": 696,
    "preview": "---\nname: Close sub-split PRs\n\non:\n  push:\n    branches:\n      - 2.x\n      - 3.x\n  pull_request:\n    branches:\n      - 2"
  },
  {
    "path": "src/Local/FallbackMimeTypeDetector.php",
    "chars": 1472,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Local;\n\nuse League\\MimeTypeDetection\\MimeTypeDetector;\nuse f"
  },
  {
    "path": "src/Local/LICENSE",
    "chars": 1063,
    "preview": "Copyright (c) 2013-2026 Frank de Jonge\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
  },
  {
    "path": "src/Local/LocalFilesystemAdapter.php",
    "chars": 15618,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Local;\n\nuse const DIRECTORY_SEPARATOR;\nuse const LOCK_EX;\nus"
  },
  {
    "path": "src/Local/LocalFilesystemAdapterTest.php",
    "chars": 27071,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\Local;\n\nuse const LOCK_EX;\nuse League\\Flysystem\\AdapterTestU"
  },
  {
    "path": "src/Local/README.md",
    "chars": 292,
    "preview": "## Sub-split of Flysystem for local file storage.\n\n> ⚠️ this is a sub-split, for pull requests and issues, visit: https:"
  },
  {
    "path": "src/Local/composer.json",
    "chars": 634,
    "preview": "{\n    \"name\": \"league/flysystem-local\",\n    \"description\": \"Local filesystem adapter for Flysystem.\",\n    \"keywords\": [\""
  },
  {
    "path": "src/MountManager.php",
    "chars": 15359,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\nuse DateTimeInterface;\nuse Throwable;\n\nuse function compac"
  },
  {
    "path": "src/MountManagerTest.php",
    "chars": 19830,
    "preview": "<?php\n\nnamespace League\\Flysystem;\n\nuse League\\Flysystem\\AdapterTestUtilities\\ExceptionThrowingFilesystemAdapter;\nuse Le"
  },
  {
    "path": "src/PathNormalizer.php",
    "chars": 148,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\ninterface PathNormalizer\n{\n    public function normalizePa"
  },
  {
    "path": "src/PathPrefixer.php",
    "chars": 1158,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\nuse function rtrim;\nuse function strlen;\nuse function subs"
  },
  {
    "path": "src/PathPrefixerTest.php",
    "chars": 3262,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\nuse PHPUnit\\Framework\\TestCase;\n\nclass PathPrefixerTest ex"
  },
  {
    "path": "src/PathPrefixing/.gitattributes",
    "chars": 140,
    "preview": "* text=auto\n\n.github export-ignore\n.gitattributes export-ignore\n.gitignore export-ignore\n**/*Test.php export-ignore\nREAD"
  },
  {
    "path": "src/PathPrefixing/.github/workflows/close-subsplit-prs.yaml",
    "chars": 696,
    "preview": "---\nname: Close sub-split PRs\n\non:\n  push:\n    branches:\n      - 2.x\n      - 3.x\n  pull_request:\n    branches:\n      - 2"
  },
  {
    "path": "src/PathPrefixing/LICENSE",
    "chars": 1063,
    "preview": "Copyright (c) 2013-2026 Frank de Jonge\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
  },
  {
    "path": "src/PathPrefixing/PathPrefixedAdapter.php",
    "chars": 8010,
    "preview": "<?php\n\nnamespace League\\Flysystem\\PathPrefixing;\n\nuse DateTimeInterface;\nuse Generator;\nuse League\\Flysystem\\CalculateCh"
  },
  {
    "path": "src/PathPrefixing/PathPrefixedAdapterTest.php",
    "chars": 5236,
    "preview": "<?php\n\nnamespace League\\Flysystem\\PathPrefixing;\n\nuse League\\Flysystem\\ChecksumProvider;\nuse League\\Flysystem\\Config;\nus"
  },
  {
    "path": "src/PathPrefixing/README.md",
    "chars": 324,
    "preview": "## Sub-split of Flysystem for path prefixed adapter decoration.\n\n> ⚠️ this is a sub-split, for pull requests and issues,"
  },
  {
    "path": "src/PathPrefixing/composer.json",
    "chars": 581,
    "preview": "{\n    \"name\": \"league/flysystem-path-prefixing\",\n    \"description\": \"Path prefixing filesystem adapter for Flysystem.\",\n"
  },
  {
    "path": "src/PathTraversalDetected.php",
    "chars": 482,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem;\n\nuse RuntimeException;\n\nclass PathTraversalDetected extends"
  },
  {
    "path": "src/PhpseclibV2/.gitattributes",
    "chars": 167,
    "preview": "* text=auto\n\n.github export-ignore\n.gitattributes export-ignore\n.gitignore export-ignore\n**/*Test.php export-ignore\n**/*"
  },
  {
    "path": "src/PhpseclibV2/.github/workflows/close-subsplit-prs.yaml",
    "chars": 696,
    "preview": "---\nname: Close sub-split PRs\n\non:\n  push:\n    branches:\n      - 2.x\n      - 3.x\n  pull_request:\n    branches:\n      - 2"
  },
  {
    "path": "src/PhpseclibV2/ConnectionProvider.php",
    "chars": 360,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\PhpseclibV2;\n\nuse phpseclib\\Net\\SFTP;\n\n/**\n * @deprecated Th"
  },
  {
    "path": "src/PhpseclibV2/ConnectivityChecker.php",
    "chars": 373,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\PhpseclibV2;\n\nuse phpseclib\\Net\\SFTP;\n\n/**\n * @deprecated Th"
  },
  {
    "path": "src/PhpseclibV2/FixatedConnectivityChecker.php",
    "chars": 841,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\PhpseclibV2;\n\nuse phpseclib\\Net\\SFTP;\n\n/**\n * @deprecated Th"
  },
  {
    "path": "src/PhpseclibV2/README.md",
    "chars": 444,
    "preview": "# CAUTION: This package is deprecated since Flysystem 3.0 Instead, use the [Flysystem for SFTP v3](https://github.com/th"
  },
  {
    "path": "src/PhpseclibV2/SftpAdapter.php",
    "chars": 12174,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\PhpseclibV2;\n\nuse League\\Flysystem\\Config;\nuse League\\Flysys"
  },
  {
    "path": "src/PhpseclibV2/SftpAdapterTest.php",
    "chars": 5947,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\PhpseclibV2;\n\nuse League\\Flysystem\\AdapterTestUtilities\\File"
  },
  {
    "path": "src/PhpseclibV2/SftpConnectionProvider.php",
    "chars": 6147,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\PhpseclibV2;\n\nuse phpseclib\\Crypt\\RSA;\nuse phpseclib\\Net\\SFT"
  },
  {
    "path": "src/PhpseclibV2/SftpConnectionProviderTest.php",
    "chars": 6606,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\PhpseclibV2;\n\nuse phpseclib\\Net\\SFTP;\nuse PHPUnit\\Framework\\"
  },
  {
    "path": "src/PhpseclibV2/SftpStub.php",
    "chars": 2384,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\PhpseclibV2;\n\nuse phpseclib\\Net\\SFTP;\n\n/**\n * @internal This"
  },
  {
    "path": "src/PhpseclibV2/SimpleConnectivityChecker.php",
    "chars": 472,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\PhpseclibV2;\n\nuse phpseclib\\Net\\SFTP;\n\n/**\n * @deprecated Th"
  },
  {
    "path": "src/PhpseclibV2/StubSftpConnectionProvider.php",
    "chars": 1274,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\PhpseclibV2;\n\nuse phpseclib\\Net\\SFTP;\n\n/**\n * @deprecated Th"
  },
  {
    "path": "src/PhpseclibV2/UnableToAuthenticate.php",
    "chars": 903,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\PhpseclibV2;\n\nuse League\\Flysystem\\FilesystemException;\nuse "
  },
  {
    "path": "src/PhpseclibV2/UnableToConnectToSftpHost.php",
    "chars": 599,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\PhpseclibV2;\n\nuse League\\Flysystem\\FilesystemException;\nuse "
  },
  {
    "path": "src/PhpseclibV2/UnableToEstablishAuthenticityOfHost.php",
    "chars": 698,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\PhpseclibV2;\n\nuse League\\Flysystem\\FilesystemException;\nuse "
  },
  {
    "path": "src/PhpseclibV2/UnableToLoadPrivateKey.php",
    "chars": 549,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\PhpseclibV2;\n\nuse League\\Flysystem\\FilesystemException;\nuse "
  },
  {
    "path": "src/PhpseclibV2/composer.json",
    "chars": 646,
    "preview": "{\n    \"name\": \"league/flysystem-sftp\",\n    \"description\": \"SFTP filesystem adapter for Flysystem.\",\n    \"keywords\": [\"fl"
  },
  {
    "path": "src/PhpseclibV3/.gitattributes",
    "chars": 166,
    "preview": "* text=auto\n\n.github export-ignore\n.gitattributes export-ignore\n.gitignore export-ignore\n**/*Test.php export-ignore\n**/*"
  },
  {
    "path": "src/PhpseclibV3/.github/workflows/close-subsplit-prs.yaml",
    "chars": 696,
    "preview": "---\nname: Close sub-split PRs\n\non:\n  push:\n    branches:\n      - 2.x\n      - 3.x\n  pull_request:\n    branches:\n      - 2"
  },
  {
    "path": "src/PhpseclibV3/ConnectionProvider.php",
    "chars": 217,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\PhpseclibV3;\n\nuse phpseclib3\\Net\\SFTP;\n\n/**\n * @method void "
  },
  {
    "path": "src/PhpseclibV3/ConnectivityChecker.php",
    "chars": 191,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\PhpseclibV3;\n\nuse phpseclib3\\Net\\SFTP;\n\ninterface Connectivi"
  },
  {
    "path": "src/PhpseclibV3/FixatedConnectivityChecker.php",
    "chars": 645,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\PhpseclibV3;\n\nuse phpseclib3\\Net\\SFTP;\n\nclass FixatedConnect"
  },
  {
    "path": "src/PhpseclibV3/LICENSE",
    "chars": 1063,
    "preview": "Copyright (c) 2013-2026 Frank de Jonge\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
  },
  {
    "path": "src/PhpseclibV3/README.md",
    "chars": 301,
    "preview": "## Sub-split of Flysystem for SFTP using phpseclib v3.\n\n> ⚠️ this is a sub-split, for pull requests and issues, visit: h"
  },
  {
    "path": "src/PhpseclibV3/SftpAdapter.php",
    "chars": 12647,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\PhpseclibV3;\n\nuse League\\Flysystem\\Config;\nuse League\\Flysys"
  },
  {
    "path": "src/PhpseclibV3/SftpAdapterTest.php",
    "chars": 7757,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\PhpseclibV3;\n\nuse League\\Flysystem\\AdapterTestUtilities\\File"
  },
  {
    "path": "src/PhpseclibV3/SftpConnectionProvider.php",
    "chars": 6467,
    "preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace League\\Flysystem\\PhpseclibV3;\n\nuse League\\Flysystem\\FilesystemException;\nuse "
  }
]

// ... and 93 more files (download for full content)

About this extraction

This page contains the full source code of the thephpleague/flysystem GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 293 files (720.5 KB), approximately 184.8k tokens, and a symbol index with 1627 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!