Repository: helios-ag/FMElfinderBundle Branch: main Commit: fa0247c4e43d Files: 81 Total size: 314.6 KB Directory structure: gitextract_hjyck40z/ ├── .devcontainer/ │ └── devcontainer.json ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── Bug_report.md │ │ └── Feature_request.md │ ├── PULL_REQUEST_TEMPLATE.md │ ├── dependabot.yml │ └── workflows/ │ └── test.yaml ├── .gitignore ├── .php-cs-fixer.php ├── .symfony.bundle.yaml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── composer.json ├── config/ │ ├── command.yaml │ ├── elfinder.yaml │ └── form.yaml ├── docs/ │ ├── advanced-configuration.md │ ├── ckeditor-integration.md │ ├── configuration-dump.md │ ├── cors-support.md │ ├── elfinder-form-type.md │ ├── events-listeners-subscribers.md │ ├── flysystem.md │ ├── summernote-integration.md │ └── tinymce-integration.md ├── phpunit.xml.dist ├── src/ │ ├── Bridge/ │ │ └── ElFinderBridge.php │ ├── Command/ │ │ └── ElFinderInstallerCommand.php │ ├── Configuration/ │ │ ├── ElFinderConfigurationProviderInterface.php │ │ └── ElFinderConfigurationReader.php │ ├── Connector/ │ │ └── ElFinderConnector.php │ ├── Controller/ │ │ └── ElFinderController.php │ ├── DependencyInjection/ │ │ ├── Compiler/ │ │ │ ├── ElFinderConfigurationPass.php │ │ │ └── TwigFormPass.php │ │ ├── Configuration.php │ │ └── FMElfinderExtension.php │ ├── ElFinder/ │ │ └── ElFinder.php │ ├── Event/ │ │ ├── ElFinderPostExecutionEvent.php │ │ └── ElFinderPreExecutionEvent.php │ ├── FMElfinderBundle.php │ ├── Form/ │ │ └── Type/ │ │ └── ElFinderType.php │ ├── Loader/ │ │ ├── ElFinderLoader.php │ │ └── ElFinderLoaderInterface.php │ ├── Resources/ │ │ ├── config/ │ │ │ └── routing.yaml │ │ ├── public/ │ │ │ └── tinymceElfinder.js │ │ └── views/ │ │ ├── Elfinder/ │ │ │ ├── ckeditor.html.twig │ │ │ ├── elfinder_type.html.twig │ │ │ ├── fm_tinymce.html.twig │ │ │ ├── helper/ │ │ │ │ ├── _summernote.html.twig │ │ │ │ ├── _tinymce.html.twig │ │ │ │ ├── _tinymce4.html.twig │ │ │ │ ├── _tinymce5.html.twig │ │ │ │ └── main.js.twig │ │ │ ├── simple.html.twig │ │ │ ├── summernote.html.twig │ │ │ ├── tinymce.html.twig │ │ │ └── tinymce4.html.twig │ │ └── Form/ │ │ └── elfinder_widget.html.twig │ ├── Security/ │ │ └── ElfinderSecurityInterface.php │ ├── Session/ │ │ └── ElFinderSession.php │ └── Twig/ │ └── Extension/ │ └── FMElfinderExtension.php └── tests/ ├── Command/ │ └── ElFinderInstallerCommandTest.php ├── Configuration/ │ └── ElFinderConfigurationReaderTest.php ├── DependencyInjection/ │ ├── Compiler/ │ │ └── TwigFormPassTest.php │ ├── ConfigurationLoadTest.php │ └── FMElfinderExtensionTest.php ├── Event/ │ ├── ElFinderPostExecutionEventTest.php │ └── ElFinderPreExecutionEventTest.php ├── FMElfinderBundleTest.php ├── Fixtures/ │ └── config/ │ ├── config.php │ └── config.yml ├── Form/ │ └── Type/ │ └── ElFinderTypeTest.php ├── Functional/ │ ├── AppKernel.php │ └── config/ │ ├── config.yml │ ├── config_test.yml │ └── routing.yml ├── Loader/ │ └── ElFinderLoaderTest.php ├── Twig/ │ └── Extension/ │ └── FMElfinderExtensionTest.php ├── autoload.php └── bootstrap.php ================================================ FILE CONTENTS ================================================ ================================================ FILE: .devcontainer/devcontainer.json ================================================ // For format details, see https://aka.ms/devcontainer.json. For config options, see the // README at: https://github.com/devcontainers/templates/tree/main/src/php { "name": "FM Elfinder Bundle Dev Container", // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile "image": "mcr.microsoft.com/devcontainers/php:0-8.2", // Features to add to the dev container. More info: https://containers.dev/features. // "features": {}, // Configure tool-specific properties. "customizations": { // Configure properties specific to VS Code. "vscode": { "settings": {}, "extensions": [ "streetsidesoftware.code-spell-checker" ] } } // Use 'postCreateCommand' to run commands after the container is created. // "postCreateCommand": "sudo chmod a+x \"$(pwd)\" && sudo rm -rf /var/www/html && sudo ln -s \"$(pwd)\" /var/www/html" // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. // "remoteUser": "root" } ================================================ FILE: .github/ISSUE_TEMPLATE/Bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve --- **Describe the bug** Explain what you wanted to do and the wrong result you got. **To Reproduce** Steps to reproduce this error and also, the FMElfinderBundle version used. **(OPTIONAL) Additional context** If they are useful, include logs, code samples, screenshots, etc. ================================================ FILE: .github/ISSUE_TEMPLATE/Feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project --- **Short description of what this feature will allow to do:** _(One short paragraph is enough)_ **Example of how to use this feature** _(Show some PHP code and/or YAML config explaining how to use this feature in a real app)_ ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: composer directory: "/" schedule: interval: weekly open-pull-requests-limit: 10 ================================================ FILE: .github/workflows/test.yaml ================================================ # OS: Linux; Symfony: latest stable; PHP: all the commonly used versions supported by this bundle name: "Tests" on: pull_request: push: branches: - 'main' env: fail-fast: true jobs: tests: name: "PHP ${{ matrix.php-version }}" runs-on: 'ubuntu-latest' continue-on-error: false strategy: matrix: php-version: ['8.1', '8.2', '8.3', '8.4', '8.5'] steps: - name: 'Checkout code' uses: actions/checkout@v4 - name: 'Install PHP with extensions' uses: shivammathur/setup-php@2.27.1 with: coverage: xdebug php-version: ${{ matrix.php-version }} tools: composer:v2 extensions: mbstring, intl ini-values: date.timezone=UTC - name: 'Install project dependencies' run: | composer global config --no-plugins allow-plugins.symfony/flex true composer global require --no-progress --no-scripts --no-plugins symfony/flex composer update --no-interaction --prefer-dist --optimize-autoloader --prefer-stable vendor/bin/simple-phpunit install - name: 'Run tests' run: XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-clover ./coverage.xml - name: codecov uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./coverage.xml verbose: true # optional (default = false) ================================================ FILE: .gitignore ================================================ composer.lock Tests/cache Tests/log Tests/Functional/cache Tests/Functional/log vendor .php-cs-fixer.cache clover.xml .vscode .phpunit.result.cache ###> symfony/framework-bundle ### /.env.local /.env.local.php /.env.*.local /config/secrets/prod/prod.decrypt.private.php /public/bundles/ /var/ /vendor/ ###< symfony/framework-bundle ### /.phpunit.cache /phpunit.xml /bin ================================================ FILE: .php-cs-fixer.php ================================================ setRiskyAllowed(false) ->setRules([ '@Symfony' => true, '@PHP80Migration' => true, 'array_syntax' => ['syntax' => 'short'], 'combine_consecutive_unsets' => true, // one should use PHPUnit methods to set up expected exception instead of annotations 'general_phpdoc_annotation_remove' => [ 'annotations' => [ 'author', 'package', 'expectedException', 'expectedExceptionMessage', 'expectedExceptionMessageRegExp', ], ], 'function_typehint_space' => false, 'no_empty_phpdoc' => true, 'global_namespace_import' => ['import_classes' => true, 'import_functions' => true, 'import_constants' => true], 'no_superfluous_phpdoc_tags' => ['allow_mixed' => false, 'allow_unused_params' => false], 'phpdoc_line_span' => ['property' => 'single'], 'heredoc_to_nowdoc' => true, 'list_syntax' => ['syntax' => 'short'], 'blank_line_before_statement' => ['statements' => ['if', 'break', 'continue', 'declare', 'return', 'throw', 'try', 'yield']], 'no_extra_blank_lines' => [ 'tokens' => [ 'break', 'continue', 'extra', 'return', 'throw', 'use', 'parenthesis_brace_block', 'square_brace_block', 'curly_brace_block', ], ], 'echo_tag_syntax' => true, 'method_argument_space' => false, 'no_useless_else' => true, 'no_useless_return' => true, 'ordered_class_elements' => true, 'ordered_imports' => ['sort_algorithm' => 'alpha', 'imports_order' => ['const', 'class', 'function']], 'php_unit_test_class_requires_covers' => true, 'phpdoc_align' => [ 'tags' => [ 'param', 'return', 'throws', 'type', 'var' ], ], 'phpdoc_add_missing_param_annotation' => true, 'phpdoc_order' => true, 'phpdoc_no_alias_tag' => ['replacements' => ['link' => 'website']], 'phpdoc_summary' => false, 'phpdoc_to_comment' => false, 'phpdoc_types_order' => false, // breaks psalm-specific notation sometimes! 'semicolon_after_instruction' => true, 'single_blank_line_at_eof' => true, 'single_line_throw' => false, 'types_spaces' => false, 'binary_operator_spaces' => [ 'default' => 'single_space', 'operators' => [ '=' => 'align_single_space_minimal', '-=' => 'align_single_space_minimal', '+=' => 'align_single_space_minimal', '=>' => 'align_single_space_minimal', '===' => null, '??=' => 'align_single_space_minimal', ], ], 'concat_space' => [ 'spacing' => 'one', ], 'operator_linebreak' => ['only_booleans' => true, 'position' => 'end'], 'yoda_style' => false, ]) ->setFinder( PhpCsFixer\Finder::create() ->in(__DIR__ . '/src') ); ================================================ FILE: .symfony.bundle.yaml ================================================ branches: ["main"] maintained_branches: ["main"] current_branch: "main" dev_branch: "main" dev_branch_alias: "12.x" doc_dir: "docs/" ================================================ FILE: CHANGELOG.md ================================================ # ## [12.1.2](https://github.com/helios-ag/FMElfinderBundle/tree/12.1.2) (2022-01-21) **Merged pull requests:** - Fix elfinder\_tinymce\_init4 duplicate definition [\#473](https://github.com/helios-ag/FMElfinderBundle/pull/473) ## [12.1.1](https://github.com/helios-ag/FMElfinderBundle/tree/12.1.1) (2022-01-21) **Closed issues:** - ElFinderType in EasyAdmin 4.x \(with Symfony 6.x\) form shows only a text field [\#472](https://github.com/helios-ag/FMElfinderBundle/issues/472) - Symfony 6.0 [\#464](https://github.com/helios-ag/FMElfinderBundle/issues/464) - Deprecation in Symfony 5.4: "...ConfigurationInterface::getConfigTreeBuilder\(\)" might add "TreeBuilder" as a native return type declaration [\#461](https://github.com/helios-ag/FMElfinderBundle/issues/461) - is can cdn config? [\#460](https://github.com/helios-ag/FMElfinderBundle/issues/460) - Easyadmin CollectionField not working [\#457](https://github.com/helios-ag/FMElfinderBundle/issues/457) - Deprecation \(Since Symfony 5.3\) : RegisterListenersPass configuration [\#456](https://github.com/helios-ag/FMElfinderBundle/issues/456) ## [12.1](https://github.com/helios-ag/FMElfinderBundle/tree/12.1) (2022-01-09) **Closed issues:** - Considering tagging a new release [\#463](https://github.com/helios-ag/FMElfinderBundle/issues/463) - Directory removed in public after composer install [\#459](https://github.com/helios-ag/FMElfinderBundle/issues/459) - Error after all steps \(Symfony 5\) [\#458](https://github.com/helios-ag/FMElfinderBundle/issues/458) **Merged pull requests:** - Allow SF6 [\#471](https://github.com/helios-ag/FMElfinderBundle/pull/471) - Directly inject twig [\#469](https://github.com/helios-ag/FMElfinderBundle/pull/469) - Added symfony 6 to deps [\#466](https://github.com/helios-ag/FMElfinderBundle/pull/466) ## [11.0](https://github.com/helios-ag/FMElfinderBundle/tree/11.0) (2021-08-29) **Closed issues:** - Support implementation of a custom driver class [\#449](https://github.com/helios-ag/FMElfinderBundle/issues/449) - Lost logged user [\#446](https://github.com/helios-ag/FMElfinderBundle/issues/446) - Duplicated Bucket Name in Endpoint URL [\#439](https://github.com/helios-ag/FMElfinderBundle/issues/439) - Unable to run elfinder:install via absolute path [\#431](https://github.com/helios-ag/FMElfinderBundle/issues/431) - Pass formTypeId to custom editor [\#420](https://github.com/helios-ag/FMElfinderBundle/issues/420) - Browser hangs when opening folder in form editor [\#413](https://github.com/helios-ag/FMElfinderBundle/issues/413) - Very slow for large data [\#410](https://github.com/helios-ag/FMElfinderBundle/issues/410) - Symfony5 - elfinder:install [\#407](https://github.com/helios-ag/FMElfinderBundle/issues/407) **Merged pull requests:** - Tinymce5 [\#455](https://github.com/helios-ag/FMElfinderBundle/pull/455) - Symfony bundle config [\#454](https://github.com/helios-ag/FMElfinderBundle/pull/454) - Use github CI [\#452](https://github.com/helios-ag/FMElfinderBundle/pull/452) - Replaced deprecated calls [\#451](https://github.com/helios-ag/FMElfinderBundle/pull/451) - Improved error message for custom adapter service. [\#448](https://github.com/helios-ag/FMElfinderBundle/pull/448) - Fix typos in elfinder\_type.html.twig [\#447](https://github.com/helios-ag/FMElfinderBundle/pull/447) - Upgrade to GitHub-native Dependabot [\#440](https://github.com/helios-ag/FMElfinderBundle/pull/440) - Add missing constant [\#437](https://github.com/helios-ag/FMElfinderBundle/pull/437) ## [10.1](https://github.com/helios-ag/FMElfinderBundle/tree/10.1) (2021-01-29) **Closed issues:** - PHP8.0 and Symfony 5.2 [\#432](https://github.com/helios-ag/FMElfinderBundle/issues/432) - Cross-Site Scripting reflected [\#430](https://github.com/helios-ag/FMElfinderBundle/issues/430) - Symfony 4.4 - elfinder:install [\#427](https://github.com/helios-ag/FMElfinderBundle/issues/427) - Failed to load ressource elfinder.main.js:1 Symfony 5 [\#426](https://github.com/helios-ag/FMElfinderBundle/issues/426) - Good syntaxe for README [\#421](https://github.com/helios-ag/FMElfinderBundle/issues/421) - relative\_path missing from doc [\#417](https://github.com/helios-ag/FMElfinderBundle/issues/417) - Styling issue & missing buttons/text [\#416](https://github.com/helios-ag/FMElfinderBundle/issues/416) - More one home folder [\#412](https://github.com/helios-ag/FMElfinderBundle/issues/412) - Add elfinder:install command to composer scripts via flex recipe [\#408](https://github.com/helios-ag/FMElfinderBundle/issues/408) - ElFinderType in EasyAdmin [\#406](https://github.com/helios-ag/FMElfinderBundle/issues/406) - Missing upgrade notes? [\#405](https://github.com/helios-ag/FMElfinderBundle/issues/405) - Blank page displayed [\#402](https://github.com/helios-ag/FMElfinderBundle/issues/402) - Can't install assets [\#401](https://github.com/helios-ag/FMElfinderBundle/issues/401) - baseUrl configuration [\#397](https://github.com/helios-ag/FMElfinderBundle/issues/397) - Combine SF roles and FMElfinderBundle [\#393](https://github.com/helios-ag/FMElfinderBundle/issues/393) - Unable to make elfinder installing and working on Symfony 4.4 [\#389](https://github.com/helios-ag/FMElfinderBundle/issues/389) - Image compression [\#380](https://github.com/helios-ag/FMElfinderBundle/issues/380) - Symfony 5 support [\#377](https://github.com/helios-ag/FMElfinderBundle/issues/377) **Merged pull requests:** - Added option to select docroot [\#436](https://github.com/helios-ag/FMElfinderBundle/pull/436) - Apply fixes from StyleCI [\#435](https://github.com/helios-ag/FMElfinderBundle/pull/435) - Symfony 5.2 and PHP 8.0 [\#433](https://github.com/helios-ag/FMElfinderBundle/pull/433) - Apply fixes from StyleCI [\#425](https://github.com/helios-ag/FMElfinderBundle/pull/425) - Pass formTypeId to custom editor [\#424](https://github.com/helios-ag/FMElfinderBundle/pull/424) - Fix elfinder:install root dir [\#418](https://github.com/helios-ag/FMElfinderBundle/pull/418) - Apply fixes from StyleCI [\#415](https://github.com/helios-ag/FMElfinderBundle/pull/415) - More one home folder [\#411](https://github.com/helios-ag/FMElfinderBundle/pull/411) - Add support for the quarantine parameter [\#403](https://github.com/helios-ag/FMElfinderBundle/pull/403) - Update events-listeners-subscribers.md [\#400](https://github.com/helios-ag/FMElfinderBundle/pull/400) - Fix Yaml syntax issue [\#398](https://github.com/helios-ag/FMElfinderBundle/pull/398) ## [10.0.4](https://github.com/helios-ag/FMElfinderBundle/tree/10.0.4) (2020-02-11) **Closed issues:** - AWS S3 upload issue [\#388](https://github.com/helios-ag/FMElfinderBundle/issues/388) - chunk upload feature [\#358](https://github.com/helios-ag/FMElfinderBundle/issues/358) **Merged pull requests:** - yml extensions changed to yaml [\#396](https://github.com/helios-ag/FMElfinderBundle/pull/396) - Setting MIME reply to text/javascript for mainJS [\#395](https://github.com/helios-ag/FMElfinderBundle/pull/395) - Using asset\(\) to ensure the URL is correct \(if website not deployed under /\) [\#394](https://github.com/helios-ag/FMElfinderBundle/pull/394) ## [10.0.3](https://github.com/helios-ag/FMElfinderBundle/tree/10.0.3) (2020-01-26) **Closed issues:** - S3 Thumbnail issue [\#369](https://github.com/helios-ag/FMElfinderBundle/issues/369) - Retrieve file name on remove command [\#298](https://github.com/helios-ag/FMElfinderBundle/issues/298) - Error when selecting a file [\#290](https://github.com/helios-ag/FMElfinderBundle/issues/290) - Is there any way to disabled/remove some actions based on the user role [\#289](https://github.com/helios-ag/FMElfinderBundle/issues/289) - Upload failure on symfony 2.7.\* [\#272](https://github.com/helios-ag/FMElfinderBundle/issues/272) **Merged pull requests:** - changed path in require and added maxconn option [\#392](https://github.com/helios-ag/FMElfinderBundle/pull/392) ## [10.0.2](https://github.com/helios-ag/FMElfinderBundle/tree/10.0.2) (2020-01-25) **Merged pull requests:** - Fixed description for aws [\#391](https://github.com/helios-ag/FMElfinderBundle/pull/391) - Fixed wrong import [\#390](https://github.com/helios-ag/FMElfinderBundle/pull/390) ## [10.0.1](https://github.com/helios-ag/FMElfinderBundle/tree/10.0.1) (2020-01-14) **Closed issues:** - PHP 7.2 Function create\_function\(\) is deprecated [\#376](https://github.com/helios-ag/FMElfinderBundle/issues/376) - ElFinderLoader::encode\($path\) does not return any valid result [\#368](https://github.com/helios-ag/FMElfinderBundle/issues/368) - Symfony\Bundle\FrameworkBundle\Controller\Controller is deprecated [\#361](https://github.com/helios-ag/FMElfinderBundle/issues/361) - The ElfinderController::loadAction never return a Symfony Response [\#352](https://github.com/helios-ag/FMElfinderBundle/issues/352) - Max upload size [\#311](https://github.com/helios-ag/FMElfinderBundle/issues/311) - Unable to upload "test.jpg". "test.jpg" transfer error. [\#295](https://github.com/helios-ag/FMElfinderBundle/issues/295) - Feature request: Add volume icon config. [\#294](https://github.com/helios-ag/FMElfinderBundle/issues/294) - El finder showing folder not found. [\#286](https://github.com/helios-ag/FMElfinderBundle/issues/286) - modifity root dir in listener [\#274](https://github.com/helios-ag/FMElfinderBundle/issues/274) - Error on upload : Unknow command [\#271](https://github.com/helios-ag/FMElfinderBundle/issues/271) - Unable to override properly the configuration provider - the right way ? [\#257](https://github.com/helios-ag/FMElfinderBundle/issues/257) **Merged pull requests:** - Routing file extension changed to yaml [\#387](https://github.com/helios-ag/FMElfinderBundle/pull/387) - Update flysystem.md [\#386](https://github.com/helios-ag/FMElfinderBundle/pull/386) ## [10](https://github.com/helios-ag/FMElfinderBundle/tree/10) (2020-01-12) **Merged pull requests:** - Symfony5 [\#379](https://github.com/helios-ag/FMElfinderBundle/pull/379) ## [9.3.2](https://github.com/helios-ag/FMElfinderBundle/tree/9.3.2) (2019-11-21) **Closed issues:** - Summernote insertion of an image or a link to a pdf file [\#372](https://github.com/helios-ag/FMElfinderBundle/issues/372) - Service as Driver, Driver not found [\#267](https://github.com/helios-ag/FMElfinderBundle/issues/267) - How to set s3 file acl to public-read after upload? [\#259](https://github.com/helios-ag/FMElfinderBundle/issues/259) **Merged pull requests:** - Update twig extension to use supported Twig classes instead of legacy ones [\#374](https://github.com/helios-ag/FMElfinderBundle/pull/374) - PDF fix \#372 [\#373](https://github.com/helios-ag/FMElfinderBundle/pull/373) - Replaced old templates for gh issues [\#371](https://github.com/helios-ag/FMElfinderBundle/pull/371) - Removed deprecated settings [\#370](https://github.com/helios-ag/FMElfinderBundle/pull/370) - Update README.md [\#367](https://github.com/helios-ag/FMElfinderBundle/pull/367) ## [9.3.1](https://github.com/helios-ag/FMElfinderBundle/tree/9.3.1) (2019-07-28) **Merged pull requests:** - Apply fixes from StyleCI [\#366](https://github.com/helios-ag/FMElfinderBundle/pull/366) - This is to add an opportunity for injecting S3 options like ACL permissions [\#365](https://github.com/helios-ag/FMElfinderBundle/pull/365) - Allow endpoint and path-style endpoint configuration for aws\_s3\_v3 [\#362](https://github.com/helios-ag/FMElfinderBundle/pull/362) ## [9.3](https://github.com/helios-ag/FMElfinderBundle/tree/9.3) (2019-05-11) **Closed issues:** - How to remove toolbar / hide tollbar : Any idea [\#356](https://github.com/helios-ag/FMElfinderBundle/issues/356) - Help: multiple: true for multiple slection [\#355](https://github.com/helios-ag/FMElfinderBundle/issues/355) - Modify the path dynamically [\#354](https://github.com/helios-ag/FMElfinderBundle/issues/354) - Plugins configuration does not work [\#353](https://github.com/helios-ag/FMElfinderBundle/issues/353) - Symfony 4.2 deprecation: A tree builder without a root node is deprecated [\#346](https://github.com/helios-ag/FMElfinderBundle/issues/346) - .tmb location [\#345](https://github.com/helios-ag/FMElfinderBundle/issues/345) **Merged pull requests:** - Add homeFolder to url [\#359](https://github.com/helios-ag/FMElfinderBundle/pull/359) - fixed call to a protected member [\#357](https://github.com/helios-ag/FMElfinderBundle/pull/357) ## [9.2.1](https://github.com/helios-ag/FMElfinderBundle/tree/9.2.1) (2019-03-10) **Closed issues:** - Mission option tmpPath under onedrive\_setting [\#351](https://github.com/helios-ag/FMElfinderBundle/issues/351) - Find file by Hash in controller\(backend\) [\#341](https://github.com/helios-ag/FMElfinderBundle/issues/341) - FIX : Popup elfinder [\#270](https://github.com/helios-ag/FMElfinderBundle/issues/270) - Option buttons issue in modal [\#266](https://github.com/helios-ag/FMElfinderBundle/issues/266) - Adding a prompt box when duplicate folders in S3 Volume Driver [\#251](https://github.com/helios-ag/FMElfinderBundle/issues/251) - Plugin Sanitizer won't work. [\#248](https://github.com/helios-ag/FMElfinderBundle/issues/248) - Can the parent directories to be set from the URL handled in a better way? [\#244](https://github.com/helios-ag/FMElfinderBundle/issues/244) **Merged pull requests:** - Fix tree builder deprecation [\#350](https://github.com/helios-ag/FMElfinderBundle/pull/350) - Post execution event fix [\#349](https://github.com/helios-ag/FMElfinderBundle/pull/349) - Travis test [\#348](https://github.com/helios-ag/FMElfinderBundle/pull/348) - Fix deprecation for symfony/config 4.2+ [\#347](https://github.com/helios-ag/FMElfinderBundle/pull/347) - Update satooshi/php-coveralls requirement from ~1 to ~2 [\#344](https://github.com/helios-ag/FMElfinderBundle/pull/344) ## [9.2](https://github.com/helios-ag/FMElfinderBundle/tree/9.2) (2018-12-11) **Merged pull requests:** - Apply fixes from StyleCI [\#343](https://github.com/helios-ag/FMElfinderBundle/pull/343) - replaced hash with getpath [\#342](https://github.com/helios-ag/FMElfinderBundle/pull/342) ## [9.1.1](https://github.com/helios-ag/FMElfinderBundle/tree/9.1.1) (2018-11-01) **Closed issues:** - How to give upload path for browser server [\#335](https://github.com/helios-ag/FMElfinderBundle/issues/335) - How can I set privateKey for Flysystem ftp\(sftp\) [\#332](https://github.com/helios-ag/FMElfinderBundle/issues/332) - Invalid parameters for command "mkdir" [\#288](https://github.com/helios-ag/FMElfinderBundle/issues/288) **Merged pull requests:** - Throw not found exception on unknown instance [\#338](https://github.com/helios-ag/FMElfinderBundle/pull/338) - Explicitly call resize\(\) after registering handler to always trigger resize on first load [\#337](https://github.com/helios-ag/FMElfinderBundle/pull/337) - Added azure support via flysystem [\#336](https://github.com/helios-ag/FMElfinderBundle/pull/336) ## [9.1](https://github.com/helios-ag/FMElfinderBundle/tree/9.1) (2018-10-10) **Closed issues:** - Driver "elFinderVolumeFlysystem" does not exist ? [\#327](https://github.com/helios-ag/FMElfinderBundle/issues/327) - Options not passed properly with dropbox2 driver ? [\#325](https://github.com/helios-ag/FMElfinderBundle/issues/325) - Public link from dropbox volume [\#324](https://github.com/helios-ag/FMElfinderBundle/issues/324) **Merged pull requests:** - Apply fixes from StyleCI [\#334](https://github.com/helios-ag/FMElfinderBundle/pull/334) - Separated sftp and ftp settings, added additional fields to sftp [\#333](https://github.com/helios-ag/FMElfinderBundle/pull/333) - Updated Changelog and referenced version 9 of the bundle in Readme [\#331](https://github.com/helios-ag/FMElfinderBundle/pull/331) ## [9](https://github.com/helios-ag/FMElfinderBundle/tree/9) (2018-10-06) **Closed issues:** - Twig error after updating [\#330](https://github.com/helios-ag/FMElfinderBundle/issues/330) - Problem with uploading image using CKEditor [\#320](https://github.com/helios-ag/FMElfinderBundle/issues/320) - JqueryUi name mismatch [\#314](https://github.com/helios-ag/FMElfinderBundle/issues/314) - version 8 doesn't work with symfony-cmf/media-bundle [\#313](https://github.com/helios-ag/FMElfinderBundle/issues/313) - Using collection form type of elfinder form type not working well [\#310](https://github.com/helios-ag/FMElfinderBundle/issues/310) - Folder .tmb is locked, unable to move the directory. [\#307](https://github.com/helios-ag/FMElfinderBundle/issues/307) - Unable to find template "FMElfinderBundle:Form:elfinder\_widget.html.twig" [\#306](https://github.com/helios-ag/FMElfinderBundle/issues/306) - Notice: Undefined index: instance\_name stfalcon\_tinymce [\#285](https://github.com/helios-ag/FMElfinderBundle/issues/285) - How to assign a home folder to a user? [\#276](https://github.com/helios-ag/FMElfinderBundle/issues/276) - Quarantine configuration option invalid. [\#256](https://github.com/helios-ag/FMElfinderBundle/issues/256) - unable to upload image [\#255](https://github.com/helios-ag/FMElfinderBundle/issues/255) - Is it able to fetch\(GET\) filename only \(don't want to display thumbnails\) on ELFinder's display [\#243](https://github.com/helios-ag/FMElfinderBundle/issues/243) **Merged pull requests:** - Volume drivers [\#329](https://github.com/helios-ag/FMElfinderBundle/pull/329) - Update configuration to match elfinder volume configuration. [\#326](https://github.com/helios-ag/FMElfinderBundle/pull/326) - New way to referencing controller [\#323](https://github.com/helios-ag/FMElfinderBundle/pull/323) - Apply fixes from StyleCI [\#322](https://github.com/helios-ag/FMElfinderBundle/pull/322) - Changed directory structure [\#321](https://github.com/helios-ag/FMElfinderBundle/pull/321) - Change default /assets path to assets [\#317](https://github.com/helios-ag/FMElfinderBundle/pull/317) - Allow Flysystem filesystem service to be injected directly without ex… [\#280](https://github.com/helios-ag/FMElfinderBundle/pull/280) ## [8.0.3](https://github.com/helios-ag/FMElfinderBundle/tree/8.0.3) (2018-05-25) **Closed issues:** - Migrate to FOSCKEditorBundle [\#316](https://github.com/helios-ag/FMElfinderBundle/issues/316) **Merged pull requests:** - Compatibility to SF4 in FMElfinderExtension.php [\#318](https://github.com/helios-ag/FMElfinderBundle/pull/318) ## [8.0.2](https://github.com/helios-ag/FMElfinderBundle/tree/8.0.2) (2018-05-25) **Closed issues:** - Blank Screen?? [\#315](https://github.com/helios-ag/FMElfinderBundle/issues/315) - Invalid backend configuration. Readable volumes not available [\#312](https://github.com/helios-ag/FMElfinderBundle/issues/312) - Configure Elfinder Bundle to connect with a MySQL database [\#300](https://github.com/helios-ag/FMElfinderBundle/issues/300) - Support for "encoding" at fm\_elfinder.instances.instance\_name.connector.roots.connector\_name [\#291](https://github.com/helios-ag/FMElfinderBundle/issues/291) - srcset possible? [\#264](https://github.com/helios-ag/FMElfinderBundle/issues/264) - How to preview image and show image thumb? [\#258](https://github.com/helios-ag/FMElfinderBundle/issues/258) - multiple file select [\#254](https://github.com/helios-ag/FMElfinderBundle/issues/254) - Use original library studio-42/elfinder [\#247](https://github.com/helios-ag/FMElfinderBundle/issues/247) - fm-elfinder-php-connector error [\#225](https://github.com/helios-ag/FMElfinderBundle/issues/225) - wrong assets path requested [\#213](https://github.com/helios-ag/FMElfinderBundle/issues/213) - Issue with plugins \(with solution\) [\#208](https://github.com/helios-ag/FMElfinderBundle/issues/208) - Issue for custom service driver \(with solution\) [\#205](https://github.com/helios-ag/FMElfinderBundle/issues/205) - How to dynamicly create folder ? [\#189](https://github.com/helios-ag/FMElfinderBundle/issues/189) - Accepted configuration for "attributes" under "roots" is incorrect [\#188](https://github.com/helios-ag/FMElfinderBundle/issues/188) - Bug on getUrl function with HomeFolder [\#161](https://github.com/helios-ag/FMElfinderBundle/issues/161) - Backwards slash as directory separator on windows web servers. [\#113](https://github.com/helios-ag/FMElfinderBundle/issues/113) ## [8.0.1](https://github.com/helios-ag/FMElfinderBundle/tree/8.0.1) (2018-04-04) **Merged pull requests:** - Fix default encoding parameter value [\#309](https://github.com/helios-ag/FMElfinderBundle/pull/309) ## [8.0](https://github.com/helios-ag/FMElfinderBundle/tree/8.0) (2018-04-01) **Closed issues:** - Update to latest version of elFinder [\#301](https://github.com/helios-ag/FMElfinderBundle/issues/301) - edit twig files [\#287](https://github.com/helios-ag/FMElfinderBundle/issues/287) - Optional prefix not implemented for flysystem aws\_s3\_v3 adapter [\#237](https://github.com/helios-ag/FMElfinderBundle/issues/237) **Merged pull requests:** - Dev [\#308](https://github.com/helios-ag/FMElfinderBundle/pull/308) ## [7.0.1](https://github.com/helios-ag/FMElfinderBundle/tree/7.0.1) (2018-01-22) **Closed issues:** - Symfony 4 compatibility [\#299](https://github.com/helios-ag/FMElfinderBundle/issues/299) - Make bundle compatible with Symfony 4.0 [\#296](https://github.com/helios-ag/FMElfinderBundle/issues/296) **Merged pull requests:** - Fixed twig extension for SF4. [\#302](https://github.com/helios-ag/FMElfinderBundle/pull/302) ## [7.0](https://github.com/helios-ag/FMElfinderBundle/tree/7.0) (2017-12-10) **Closed issues:** - Multiple AppKernel class [\#282](https://github.com/helios-ag/FMElfinderBundle/issues/282) - is there any way to disable/enable commands using config.yml [\#281](https://github.com/helios-ag/FMElfinderBundle/issues/281) - Is is possible to create unique filenames? [\#279](https://github.com/helios-ag/FMElfinderBundle/issues/279) - Strange characters when inserting images [\#278](https://github.com/helios-ag/FMElfinderBundle/issues/278) - AutoResize plugin not working [\#277](https://github.com/helios-ag/FMElfinderBundle/issues/277) - Uploading png works, jpg fails [\#275](https://github.com/helios-ag/FMElfinderBundle/issues/275) - Symfony 3.x support? [\#273](https://github.com/helios-ag/FMElfinderBundle/issues/273) - Option: URL [\#268](https://github.com/helios-ag/FMElfinderBundle/issues/268) - Notice: Undefined variable: header [\#265](https://github.com/helios-ag/FMElfinderBundle/issues/265) - Unable to connect to backend. [\#262](https://github.com/helios-ag/FMElfinderBundle/issues/262) - Cant Connect to Backend [\#261](https://github.com/helios-ag/FMElfinderBundle/issues/261) - enable popup [\#260](https://github.com/helios-ag/FMElfinderBundle/issues/260) - ckeditor integration [\#221](https://github.com/helios-ag/FMElfinderBundle/issues/221) - Expand "elfinder" type [\#200](https://github.com/helios-ag/FMElfinderBundle/issues/200) - Usage of "elfinder" Form Type in version "~6" [\#196](https://github.com/helios-ag/FMElfinderBundle/issues/196) - Rewrite elfinder form type in pure js [\#102](https://github.com/helios-ag/FMElfinderBundle/issues/102) **Merged pull requests:** - Sf4 [\#297](https://github.com/helios-ag/FMElfinderBundle/pull/297) - Consistent urls [\#293](https://github.com/helios-ag/FMElfinderBundle/pull/293) - Fix Symfony versions [\#292](https://github.com/helios-ag/FMElfinderBundle/pull/292) - Apply fixes from StyleCI [\#284](https://github.com/helios-ag/FMElfinderBundle/pull/284) - Readme patch [\#283](https://github.com/helios-ag/FMElfinderBundle/pull/283) - Update Readme.md [\#269](https://github.com/helios-ag/FMElfinderBundle/pull/269) ## [6.2.1](https://github.com/helios-ag/FMElfinderBundle/tree/6.2.1) (2016-09-03) **Merged pull requests:** - made archivers node optional [\#263](https://github.com/helios-ag/FMElfinderBundle/pull/263) ## [6.2](https://github.com/helios-ag/FMElfinderBundle/tree/6.2) (2016-07-26) **Closed issues:** - Againe stop to work!! [\#252](https://github.com/helios-ag/FMElfinderBundle/issues/252) - Notice: ob\_end\_clean\(\): failed to delete buffer. No buffer to delete \(FlySystem S3 adapter\) [\#249](https://github.com/helios-ag/FMElfinderBundle/issues/249) - use cumsom theme [\#246](https://github.com/helios-ag/FMElfinderBundle/issues/246) - Cannot work, still get error: Unable to connect to the backend. [\#241](https://github.com/helios-ag/FMElfinderBundle/issues/241) - Special characters in filename not allowing to upload files [\#239](https://github.com/helios-ag/FMElfinderBundle/issues/239) - How to reset the field [\#227](https://github.com/helios-ag/FMElfinderBundle/issues/227) - Request: Custom Flysystem adapter [\#224](https://github.com/helios-ag/FMElfinderBundle/issues/224) - Can't create archive. [\#220](https://github.com/helios-ag/FMElfinderBundle/issues/220) - No callback sync to form field [\#212](https://github.com/helios-ag/FMElfinderBundle/issues/212) - Send it to Server returns ckeditor instance [\#165](https://github.com/helios-ag/FMElfinderBundle/issues/165) **Merged pull requests:** - Improved configuration for archivers support [\#253](https://github.com/helios-ag/FMElfinderBundle/pull/253) - Use locale from request object if it is not provided in configuration. [\#250](https://github.com/helios-ag/FMElfinderBundle/pull/250) - add fileMode connector option [\#245](https://github.com/helios-ag/FMElfinderBundle/pull/245) - add missing documentation [\#242](https://github.com/helios-ag/FMElfinderBundle/pull/242) - Configuration Reader upated to allow usage of Google Cloud Storage In… [\#240](https://github.com/helios-ag/FMElfinderBundle/pull/240) ## [6.1.2](https://github.com/helios-ag/FMElfinderBundle/tree/6.1.2) (2016-04-26) **Closed issues:** - Missing file extension [\#236](https://github.com/helios-ag/FMElfinderBundle/issues/236) **Merged pull requests:** - added aws s3 v3 optional\_prefix parameter [\#238](https://github.com/helios-ag/FMElfinderBundle/pull/238) ## [6.1.1](https://github.com/helios-ag/FMElfinderBundle/tree/6.1.1) (2016-03-29) **Closed issues:** - When upload image file, elfinder say「unable to connect to backend.」 [\#229](https://github.com/helios-ag/FMElfinderBundle/issues/229) - Dynamic path doesn't work after upgrading from 5 to 6 [\#228](https://github.com/helios-ag/FMElfinderBundle/issues/228) **Merged pull requests:** - wrap jQuery around DOMContentLoaded [\#235](https://github.com/helios-ag/FMElfinderBundle/pull/235) - Applied fixes from StyleCI [\#233](https://github.com/helios-ag/FMElfinderBundle/pull/233) - Flysystem custom adapter [\#232](https://github.com/helios-ag/FMElfinderBundle/pull/232) - Applied fixes from StyleCI [\#231](https://github.com/helios-ag/FMElfinderBundle/pull/231) - Rackspace driver and allowcustom options [\#230](https://github.com/helios-ag/FMElfinderBundle/pull/230) ## [6.1](https://github.com/helios-ag/FMElfinderBundle/tree/6.1) (2016-02-27) **Closed issues:** - Custom Elfinder theme [\#222](https://github.com/helios-ag/FMElfinderBundle/issues/222) **Merged pull requests:** - composer tweak, summernote helper blank line added and removed blank … [\#226](https://github.com/helios-ag/FMElfinderBundle/pull/226) - fixed simple template and improved readme file [\#223](https://github.com/helios-ag/FMElfinderBundle/pull/223) ## [6.0.3](https://github.com/helios-ag/FMElfinderBundle/tree/6.0.3) (2016-02-19) **Closed issues:** - Content of Elfinder page is not displayed [\#218](https://github.com/helios-ag/FMElfinderBundle/issues/218) **Merged pull requests:** - tmbURL unit test merge fix [\#217](https://github.com/helios-ag/FMElfinderBundle/pull/217) ## [6.0.2](https://github.com/helios-ag/FMElfinderBundle/tree/6.0.2) (2016-01-24) **Closed issues:** - Symfony 2.8 Asset folder not find. [\#210](https://github.com/helios-ag/FMElfinderBundle/issues/210) - How can get url that selected Image? [\#209](https://github.com/helios-ag/FMElfinderBundle/issues/209) - config Elfinder Form Type have problem [\#204](https://github.com/helios-ag/FMElfinderBundle/issues/204) - Bad asset path [\#203](https://github.com/helios-ag/FMElfinderBundle/issues/203) - Used "helios-ag/fm-elfinder-bundle": "~6" shows nothing [\#202](https://github.com/helios-ag/FMElfinderBundle/issues/202) - Full absolute path to image [\#199](https://github.com/helios-ag/FMElfinderBundle/issues/199) - How to show only certain mime types from configuration? [\#193](https://github.com/helios-ag/FMElfinderBundle/issues/193) - Amazon s3 integration [\#191](https://github.com/helios-ag/FMElfinderBundle/issues/191) **Merged pull requests:** - Fix case of tmbURL option [\#216](https://github.com/helios-ag/FMElfinderBundle/pull/216) - file URL double slashes removal + unit tests [\#215](https://github.com/helios-ag/FMElfinderBundle/pull/215) - CKEditor integration doc homeFolder precision [\#214](https://github.com/helios-ag/FMElfinderBundle/pull/214) - events doc precision [\#211](https://github.com/helios-ag/FMElfinderBundle/pull/211) - Used asset function to valid addresses of assets [\#207](https://github.com/helios-ag/FMElfinderBundle/pull/207) - Replaced {% include %} by {{ include\(\) }} [\#206](https://github.com/helios-ag/FMElfinderBundle/pull/206) - contributing info [\#201](https://github.com/helios-ag/FMElfinderBundle/pull/201) - Applied fixes from StyleCI [\#198](https://github.com/helios-ag/FMElfinderBundle/pull/198) - Patch 1 [\#197](https://github.com/helios-ag/FMElfinderBundle/pull/197) ## [6.0.1](https://github.com/helios-ag/FMElfinderBundle/tree/6.0.1) (2015-12-08) **Closed issues:** - Symfony 3.0 [\#190](https://github.com/helios-ag/FMElfinderBundle/issues/190) **Merged pull requests:** - Bundle configuration for visible mime types [\#195](https://github.com/helios-ag/FMElfinderBundle/pull/195) ## [6.0](https://github.com/helios-ag/FMElfinderBundle/tree/6.0) (2015-12-06) **Closed issues:** - FMElfinderBundle shows white window [\#184](https://github.com/helios-ag/FMElfinderBundle/issues/184) - fabric.image.fromURL [\#183](https://github.com/helios-ag/FMElfinderBundle/issues/183) - Access to the encode/decode function From onPreExecute [\#174](https://github.com/helios-ag/FMElfinderBundle/issues/174) **Merged pull requests:** - updated readme, before tagging [\#194](https://github.com/helios-ag/FMElfinderBundle/pull/194) - fixed aws\_s3\_v3 configuration [\#192](https://github.com/helios-ag/FMElfinderBundle/pull/192) - Applied fixes from StyleCI [\#187](https://github.com/helios-ag/FMElfinderBundle/pull/187) - \[WIP\] Sf3 [\#179](https://github.com/helios-ag/FMElfinderBundle/pull/179) ## [5.3](https://github.com/helios-ag/FMElfinderBundle/tree/5.3) (2015-11-15) **Merged pull requests:** - fm\_tinymce\_bundle [\#182](https://github.com/helios-ag/FMElfinderBundle/pull/182) ## [5.2.1](https://github.com/helios-ag/FMElfinderBundle/tree/5.2.1) (2015-11-12) **Closed issues:** - Assets not found [\#180](https://github.com/helios-ag/FMElfinderBundle/issues/180) **Merged pull requests:** - Fix paths for elfinder-component 2.0 compatibility [\#181](https://github.com/helios-ag/FMElfinderBundle/pull/181) ## [5.2](https://github.com/helios-ag/FMElfinderBundle/tree/5.2) (2015-11-09) **Closed issues:** - Encode / Decode Path [\#169](https://github.com/helios-ag/FMElfinderBundle/issues/169) - Wrong mime type with flysystem s3 driver [\#164](https://github.com/helios-ag/FMElfinderBundle/issues/164) - FMElfinderBundle shows nothing [\#159](https://github.com/helios-ag/FMElfinderBundle/issues/159) - Why this bundle generates Symfony2 doctrine migration file? [\#157](https://github.com/helios-ag/FMElfinderBundle/issues/157) - Path error with nested folders \(uploads/bob\) [\#152](https://github.com/helios-ag/FMElfinderBundle/issues/152) - GridFs support ? \(Flysystem / Gaufrette\) [\#145](https://github.com/helios-ag/FMElfinderBundle/issues/145) - \[bug\] asset can not load from relative path [\#142](https://github.com/helios-ag/FMElfinderBundle/issues/142) - Dynamic path depending on the user ? [\#138](https://github.com/helios-ag/FMElfinderBundle/issues/138) - Relative path option not works as expected [\#116](https://github.com/helios-ag/FMElfinderBundle/issues/116) - How to override the paste method [\#98](https://github.com/helios-ag/FMElfinderBundle/issues/98) **Merged pull requests:** - increased number of tests [\#178](https://github.com/helios-ag/FMElfinderBundle/pull/178) - coveralls support [\#177](https://github.com/helios-ag/FMElfinderBundle/pull/177) - Access to the encode/decode function From onPreExecute \(2/2\) [\#176](https://github.com/helios-ag/FMElfinderBundle/pull/176) - readme split [\#175](https://github.com/helios-ag/FMElfinderBundle/pull/175) - encode/decode access from FMElfinderBundle Loader \(2/2\) [\#172](https://github.com/helios-ag/FMElfinderBundle/pull/172) - bower component [\#167](https://github.com/helios-ag/FMElfinderBundle/pull/167) ## [5.1](https://github.com/helios-ag/FMElfinderBundle/tree/5.1) (2015-09-24) **Closed issues:** - Error - Window does not connect folders [\#158](https://github.com/helios-ag/FMElfinderBundle/issues/158) - S3 Driver [\#153](https://github.com/helios-ag/FMElfinderBundle/issues/153) **Merged pull requests:** - Applied fixes from StyleCI [\#163](https://github.com/helios-ag/FMElfinderBundle/pull/163) - Summernote support [\#162](https://github.com/helios-ag/FMElfinderBundle/pull/162) - Events unit tests [\#150](https://github.com/helios-ag/FMElfinderBundle/pull/150) ## [5.0.5](https://github.com/helios-ag/FMElfinderBundle/tree/5.0.5) (2015-07-16) **Closed issues:** - Unable to connect to the backend. [\#149](https://github.com/helios-ag/FMElfinderBundle/issues/149) - Issue with adding images to ckeditor [\#148](https://github.com/helios-ag/FMElfinderBundle/issues/148) - FMElfinder not created and an input persists [\#146](https://github.com/helios-ag/FMElfinderBundle/issues/146) - Uncaught TypeError: a.indexOf is not a function \(IvoryCkEditor Insert Image\) [\#144](https://github.com/helios-ag/FMElfinderBundle/issues/144) - Overriding templates [\#143](https://github.com/helios-ag/FMElfinderBundle/issues/143) - Table created and not used. [\#141](https://github.com/helios-ag/FMElfinderBundle/issues/141) - Elfinder Form Type [\#140](https://github.com/helios-ag/FMElfinderBundle/issues/140) - Disallow creating/uploading new folder [\#139](https://github.com/helios-ag/FMElfinderBundle/issues/139) - showhidden: false ! [\#136](https://github.com/helios-ag/FMElfinderBundle/issues/136) - can't access to assets JS and CSS [\#129](https://github.com/helios-ag/FMElfinderBundle/issues/129) - Plugin ?? [\#127](https://github.com/helios-ag/FMElfinderBundle/issues/127) - Undefined index: ckeditor [\#121](https://github.com/helios-ag/FMElfinderBundle/issues/121) **Merged pull requests:** - region & signature S3 configuration parameters needed [\#156](https://github.com/helios-ag/FMElfinderBundle/pull/156) - reworked on relative\(absolute from root\) paths [\#154](https://github.com/helios-ag/FMElfinderBundle/pull/154) - Expose pathPrefix to custom editors [\#151](https://github.com/helios-ag/FMElfinderBundle/pull/151) - readme small improvements, and newline chars at end of files [\#147](https://github.com/helios-ag/FMElfinderBundle/pull/147) - Fixed configuration loading of attributes. [\#137](https://github.com/helios-ag/FMElfinderBundle/pull/137) - Command execution events + subrequests support + volume\_id setting [\#128](https://github.com/helios-ag/FMElfinderBundle/pull/128) ## [5.0.4](https://github.com/helios-ag/FMElfinderBundle/tree/5.0.4) (2015-04-11) **Merged pull requests:** - Scrutinizer enabled [\#135](https://github.com/helios-ag/FMElfinderBundle/pull/135) ## [5.0.3](https://github.com/helios-ag/FMElfinderBundle/tree/5.0.3) (2015-04-03) **Merged pull requests:** - Allow setting the directoryPerm parameter [\#133](https://github.com/helios-ag/FMElfinderBundle/pull/133) - Fixed configuration loading for root parameter \(ftp\) [\#132](https://github.com/helios-ag/FMElfinderBundle/pull/132) ## [5.0.2](https://github.com/helios-ag/FMElfinderBundle/tree/5.0.2) (2015-04-02) **Closed issues:** - php 5.4 syntax used \(symfony2 and the bundle itself state minimum requirement to \>= php 5.3.3\) [\#130](https://github.com/helios-ag/FMElfinderBundle/issues/130) - Incorrect path [\#125](https://github.com/helios-ag/FMElfinderBundle/issues/125) - assetic generation path [\#40](https://github.com/helios-ag/FMElfinderBundle/issues/40) **Merged pull requests:** - array short syntax removed [\#131](https://github.com/helios-ag/FMElfinderBundle/pull/131) ## [5.0.1](https://github.com/helios-ag/FMElfinderBundle/tree/5.0.1) (2015-03-23) **Closed issues:** - Permission / Override configuration [\#100](https://github.com/helios-ag/FMElfinderBundle/issues/100) - ReferenceError: $ is not defined [\#87](https://github.com/helios-ag/FMElfinderBundle/issues/87) **Merged pull requests:** - Fix bug "pathPrefix" when use Form Type [\#124](https://github.com/helios-ag/FMElfinderBundle/pull/124) ## [5](https://github.com/helios-ag/FMElfinderBundle/tree/5) (2015-03-21) **Merged pull requests:** - Component [\#123](https://github.com/helios-ag/FMElfinderBundle/pull/123) ## [4.0.2](https://github.com/helios-ag/FMElfinderBundle/tree/4.0.2) (2015-03-20) **Closed issues:** - S3 folder not shown after creation [\#120](https://github.com/helios-ag/FMElfinderBundle/issues/120) - Path issues and upload [\#118](https://github.com/helios-ag/FMElfinderBundle/issues/118) - ElFinder and two or more instances with ckeditor [\#117](https://github.com/helios-ag/FMElfinderBundle/issues/117) - liip image [\#84](https://github.com/helios-ag/FMElfinderBundle/issues/84) **Merged pull requests:** - connector options override [\#122](https://github.com/helios-ag/FMElfinderBundle/pull/122) - S3 example configuration and url fix [\#119](https://github.com/helios-ag/FMElfinderBundle/pull/119) ## [4.0.1](https://github.com/helios-ag/FMElfinderBundle/tree/4.0.1) (2015-02-21) **Merged pull requests:** - Added homeFolder parameter to ElFinderType [\#115](https://github.com/helios-ag/FMElfinderBundle/pull/115) ## [4.0](https://github.com/helios-ag/FMElfinderBundle/tree/4.0) (2015-02-18) ### - Support new drivers via FlySystem [\#105](https://github.com/helios-ag/FMElfinderBundle/issues/105) **Closed issues:** - Enable CORS [\#106](https://github.com/helios-ag/FMElfinderBundle/issues/106) - Wrong url when select the picture [\#99](https://github.com/helios-ag/FMElfinderBundle/issues/99) - dynamic 'path' setting ? [\#91](https://github.com/helios-ag/FMElfinderBundle/issues/91) **Merged pull requests:** - updated README [\#114](https://github.com/helios-ag/FMElfinderBundle/pull/114) - conv to unix [\#112](https://github.com/helios-ag/FMElfinderBundle/pull/112) - flysystem driver support [\#111](https://github.com/helios-ag/FMElfinderBundle/pull/111) - CORS and home folder guides [\#110](https://github.com/helios-ag/FMElfinderBundle/pull/110) - Multiple upload folder by instance [\#109](https://github.com/helios-ag/FMElfinderBundle/pull/109) - Non hard exit [\#108](https://github.com/helios-ag/FMElfinderBundle/pull/108) - Add triggering of change event [\#107](https://github.com/helios-ag/FMElfinderBundle/pull/107) - overridable loader [\#104](https://github.com/helios-ag/FMElfinderBundle/pull/104) - IvoryCKEditor sample was incorrect [\#103](https://github.com/helios-ag/FMElfinderBundle/pull/103) ## [3.4](https://github.com/helios-ag/FMElfinderBundle/tree/3.4) (2015-01-20) **Merged pull requests:** - Allow custom template renderer [\#97](https://github.com/helios-ag/FMElfinderBundle/pull/97) ## [3.3](https://github.com/helios-ag/FMElfinderBundle/tree/3.3) (2015-01-17) **Closed issues:** - Relative path image [\#93](https://github.com/helios-ag/FMElfinderBundle/issues/93) - attach files? [\#90](https://github.com/helios-ag/FMElfinderBundle/issues/90) - There is no "uglifycss" filter [\#77](https://github.com/helios-ag/FMElfinderBundle/issues/77) **Merged pull requests:** - Fix test [\#96](https://github.com/helios-ag/FMElfinderBundle/pull/96) - plugin\_support [\#95](https://github.com/helios-ag/FMElfinderBundle/pull/95) ## [3.2.1](https://github.com/helios-ag/FMElfinderBundle/tree/3.2.1) (2015-01-06) **Merged pull requests:** - tinymce relative path [\#94](https://github.com/helios-ag/FMElfinderBundle/pull/94) ## [3.2](https://github.com/helios-ag/FMElfinderBundle/tree/3.2) (2014-12-28) **Closed issues:** - add class. ``form-control`` [\#88](https://github.com/helios-ag/FMElfinderBundle/issues/88) **Merged pull requests:** - Assetic [\#92](https://github.com/helios-ag/FMElfinderBundle/pull/92) ## [2.3.3](https://github.com/helios-ag/FMElfinderBundle/tree/2.3.3) (2014-12-06) **Closed issues:** - multi path folder. [\#86](https://github.com/helios-ag/FMElfinderBundle/issues/86) - get error - Undefined index: ckeditor - [\#85](https://github.com/helios-ag/FMElfinderBundle/issues/85) - Elfinder form type in form type collection [\#81](https://github.com/helios-ag/FMElfinderBundle/issues/81) - BC between 2.5 and 2.5.1 [\#80](https://github.com/helios-ag/FMElfinderBundle/issues/80) - Feature Request: ability to inject the VolumeDriver as a Service [\#66](https://github.com/helios-ag/FMElfinderBundle/issues/66) **Merged pull requests:** - Noassetic [\#89](https://github.com/helios-ag/FMElfinderBundle/pull/89) ## [3.1](https://github.com/helios-ag/FMElfinderBundle/tree/3.1) (2014-11-09) **Closed issues:** - Customizing Elfinder form [\#82](https://github.com/helios-ag/FMElfinderBundle/issues/82) - Request : change the folder path [\#68](https://github.com/helios-ag/FMElfinderBundle/issues/68) **Merged pull requests:** - restored ability to use services as drivers [\#83](https://github.com/helios-ag/FMElfinderBundle/pull/83) ## [3.0](https://github.com/helios-ag/FMElfinderBundle/tree/3.0) (2014-11-07) **Closed issues:** - unable to add symfony service as a volume driver [\#79](https://github.com/helios-ag/FMElfinderBundle/issues/79) **Merged pull requests:** - Update README.md [\#78](https://github.com/helios-ag/FMElfinderBundle/pull/78) ## [2.3.2](https://github.com/helios-ag/FMElfinderBundle/tree/2.3.2) (2014-10-29) **Merged pull requests:** - Made the changes of patch 2.5.1 available in 2.3 [\#76](https://github.com/helios-ag/FMElfinderBundle/pull/76) ## [2.5.1](https://github.com/helios-ag/FMElfinderBundle/tree/2.5.1) (2014-10-24) **Closed issues:** - How to disable command? [\#74](https://github.com/helios-ag/FMElfinderBundle/issues/74) - Injecting Non existent Service Symfony \<=2.3 [\#71](https://github.com/helios-ag/FMElfinderBundle/issues/71) - Symfony version in composer.json [\#61](https://github.com/helios-ag/FMElfinderBundle/issues/61) **Merged pull requests:** - Multiple elfinder instances in one page/form [\#75](https://github.com/helios-ag/FMElfinderBundle/pull/75) ## [2.5](https://github.com/helios-ag/FMElfinderBundle/tree/2.5) (2014-10-11) ## [2.3.1](https://github.com/helios-ag/FMElfinderBundle/tree/2.3.1) (2014-10-10) ## [2.3.0](https://github.com/helios-ag/FMElfinderBundle/tree/2.3.0) (2014-10-03) **Closed issues:** - Relative path in 'form' instance [\#72](https://github.com/helios-ag/FMElfinderBundle/issues/72) - Unrecognized options "instances" under "fm\_elfinder" [\#67](https://github.com/helios-ag/FMElfinderBundle/issues/67) **Merged pull requests:** - Fix dialog icons css [\#73](https://github.com/helios-ag/FMElfinderBundle/pull/73) - showhidden in another node [\#70](https://github.com/helios-ag/FMElfinderBundle/pull/70) - Required only necessary dependencies [\#69](https://github.com/helios-ag/FMElfinderBundle/pull/69) ## [2.1](https://github.com/helios-ag/FMElfinderBundle/tree/2.1) (2014-08-24) **Closed issues:** - Upload file window [\#65](https://github.com/helios-ag/FMElfinderBundle/issues/65) - Change of image URL [\#64](https://github.com/helios-ag/FMElfinderBundle/issues/64) ## [v2.0](https://github.com/helios-ag/FMElfinderBundle/tree/v2.0) (2014-08-09) **Closed issues:** - DataFixtures error? [\#62](https://github.com/helios-ag/FMElfinderBundle/issues/62) - \[Insight\] The Symfony Dependency Injection Container should not be passed as an argument [\#57](https://github.com/helios-ag/FMElfinderBundle/issues/57) - Image absolute/relative path [\#56](https://github.com/helios-ag/FMElfinderBundle/issues/56) **Merged pull requests:** - Wrap READ and WRITE columns in quotes [\#63](https://github.com/helios-ag/FMElfinderBundle/pull/63) - 2.0 [\#60](https://github.com/helios-ag/FMElfinderBundle/pull/60) - Update composer.json [\#59](https://github.com/helios-ag/FMElfinderBundle/pull/59) - Update ElFinderFile.php [\#58](https://github.com/helios-ag/FMElfinderBundle/pull/58) ## [1.5](https://github.com/helios-ag/FMElfinderBundle/tree/1.5) (2014-05-09) **Closed issues:** - Standalone elfinder [\#55](https://github.com/helios-ag/FMElfinderBundle/issues/55) - Is or will be there a way to set metadata for media files in elfinder? [\#54](https://github.com/helios-ag/FMElfinderBundle/issues/54) - S3 integration [\#53](https://github.com/helios-ag/FMElfinderBundle/issues/53) - ElFinder resize doesn't update image dimensions [\#52](https://github.com/helios-ag/FMElfinderBundle/issues/52) - config error - parse asset\[bundles/stfalcontinymce/vendor/ [\#48](https://github.com/helios-ag/FMElfinderBundle/issues/48) ## [1.4.2](https://github.com/helios-ag/FMElfinderBundle/tree/1.4.2) (2013-12-19) **Merged pull requests:** - Add a Bitdeli Badge to README [\#51](https://github.com/helios-ag/FMElfinderBundle/pull/51) ## [1.4.1](https://github.com/helios-ag/FMElfinderBundle/tree/1.4.1) (2013-11-13) **Closed issues:** - Hi [\#46](https://github.com/helios-ag/FMElfinderBundle/issues/46) - default \(ckeditor\) template requires yui\_css and yui\_js filters [\#44](https://github.com/helios-ag/FMElfinderBundle/issues/44) - Configuration of elfinder path [\#42](https://github.com/helios-ag/FMElfinderBundle/issues/42) - Problems with dump assets image path and CSSEMBED [\#34](https://github.com/helios-ag/FMElfinderBundle/issues/34) **Merged pull requests:** - document new config options, fix ckeditor compressed template [\#50](https://github.com/helios-ag/FMElfinderBundle/pull/50) - Use request locale as default [\#49](https://github.com/helios-ag/FMElfinderBundle/pull/49) ## [1.4](https://github.com/helios-ag/FMElfinderBundle/tree/1.4) (2013-10-03) **Closed issues:** - Cannot rename files/folders [\#45](https://github.com/helios-ag/FMElfinderBundle/issues/45) - Installation problem [\#41](https://github.com/helios-ag/FMElfinderBundle/issues/41) - so slow ? [\#35](https://github.com/helios-ag/FMElfinderBundle/issues/35) **Merged pull requests:** - Cmf [\#47](https://github.com/helios-ag/FMElfinderBundle/pull/47) - fix dialog image position [\#43](https://github.com/helios-ag/FMElfinderBundle/pull/43) ## [1.3](https://github.com/helios-ag/FMElfinderBundle/tree/1.3) (2013-08-27) **Closed issues:** - no \_popup.js in STFalconTinyMCE public resources [\#39](https://github.com/helios-ag/FMElfinderBundle/issues/39) - typo? in docs - step 3 [\#38](https://github.com/helios-ag/FMElfinderBundle/issues/38) - in Prod mode error 500 [\#36](https://github.com/helios-ag/FMElfinderBundle/issues/36) - Integration with Tinymce 4 [\#33](https://github.com/helios-ag/FMElfinderBundle/issues/33) - Standalone filebrowser usage [\#28](https://github.com/helios-ag/FMElfinderBundle/issues/28) **Merged pull requests:** - Tinymce4 [\#37](https://github.com/helios-ag/FMElfinderBundle/pull/37) ## [1.2](https://github.com/helios-ag/FMElfinderBundle/tree/1.2) (2013-08-03) **Closed issues:** - RangeError when loading elfinder [\#31](https://github.com/helios-ag/FMElfinderBundle/issues/31) **Merged pull requests:** - Fix \#31 Uncaught RangeError: Maximum call stack size exceeded in some browsers [\#32](https://github.com/helios-ag/FMElfinderBundle/pull/32) - added feature to use a symfony service as a volumeDriver [\#30](https://github.com/helios-ag/FMElfinderBundle/pull/30) - Added support for an optional 'url' parameter in the 'roots' section [\#29](https://github.com/helios-ag/FMElfinderBundle/pull/29) ## [1.1](https://github.com/helios-ag/FMElfinderBundle/tree/1.1) (2013-06-12) **Closed issues:** - Dependency twig-bundle is wrong for SF 2.3 [\#26](https://github.com/helios-ag/FMElfinderBundle/issues/26) - Image path in CSS are broken [\#25](https://github.com/helios-ag/FMElfinderBundle/issues/25) **Merged pull requests:** - Issues \#25 & \#26 fix [\#27](https://github.com/helios-ag/FMElfinderBundle/pull/27) ## [1.0](https://github.com/helios-ag/FMElfinderBundle/tree/1.0) (2013-06-07) **Closed issues:** - Missing icon images [\#23](https://github.com/helios-ag/FMElfinderBundle/issues/23) - CSS generation with assetic [\#20](https://github.com/helios-ag/FMElfinderBundle/issues/20) - Variable "fullscreen" does not exist and images not loading [\#17](https://github.com/helios-ag/FMElfinderBundle/issues/17) - Elfinder slow loading [\#15](https://github.com/helios-ag/FMElfinderBundle/issues/15) - Bad asset URL [\#14](https://github.com/helios-ag/FMElfinderBundle/issues/14) - Standalone filebrowser [\#13](https://github.com/helios-ag/FMElfinderBundle/issues/13) - Javascripts missing [\#12](https://github.com/helios-ag/FMElfinderBundle/issues/12) - Dependency error [\#11](https://github.com/helios-ag/FMElfinderBundle/issues/11) - Overriding FMElfinderLoader [\#9](https://github.com/helios-ag/FMElfinderBundle/issues/9) - Assetic cssrewrite css image path [\#3](https://github.com/helios-ag/FMElfinderBundle/issues/3) - Browse Image Return Value in Integration with CKEditor [\#2](https://github.com/helios-ag/FMElfinderBundle/issues/2) - install error [\#1](https://github.com/helios-ag/FMElfinderBundle/issues/1) **Merged pull requests:** - Fix for images in CSS for newer version of AsseticBundle and cssrewriter [\#24](https://github.com/helios-ag/FMElfinderBundle/pull/24) - fix templates & filters for assetic [\#22](https://github.com/helios-ag/FMElfinderBundle/pull/22) - Update compiled path for assetic js & css [\#21](https://github.com/helios-ag/FMElfinderBundle/pull/21) - fullscreen option [\#18](https://github.com/helios-ag/FMElfinderBundle/pull/18) - El finder php [\#16](https://github.com/helios-ag/FMElfinderBundle/pull/16) - Integration with TinyMCE bundle [\#10](https://github.com/helios-ag/FMElfinderBundle/pull/10) - Update README.md [\#8](https://github.com/helios-ag/FMElfinderBundle/pull/8) - TinyMCE integration + Multiple roots configuration [\#6](https://github.com/helios-ag/FMElfinderBundle/pull/6) - Elfinder fullscreen [\#5](https://github.com/helios-ag/FMElfinderBundle/pull/5) - Ckeditor integration fix [\#4](https://github.com/helios-ag/FMElfinderBundle/pull/4) ================================================ FILE: CONTRIBUTING.md ================================================ Contribution Guidelines ======================= First of all, each single contribution is appreciated, whether a typo fix, improved documentation, a fixed bug or a whole new feature. ## Making your changes 1. Fork the repository on GitHub 2. Pull requests must be sent from a new hotfix/feature branch, not from `master`. 3. Make your modifications, coding standard for the project is [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) 4. Commit small logical changes, each with a descriptive commit message. Please don't mix unrelated changes in a single commit. ## Commit messages Please format your commit messages as follows: Short summary of the change (up to 50 characters) Optionally add a more extensive description of your change after a blank line. Wrap the lines in this and the following paragraphs after 72 characters. ## Submitting your changes 1. Push your changes to a topic branch in your fork of the repository. 2. [Submit a pull request][pr] to the original repository. Describe your changes as short as possible, but as detailed as needed for others to get an overview of your modifications. ## Further information * [General GitHub documentation][gh-help] * [GitHub pull request documentation][gh-pr] [gh-help]: https://help.github.com [gh-pr]: https://help.github.com/send-pull-requests [issue]: https://github.com/helios-ag/FMElfinderBundle/issues/new [pr]: https://github.com/helios-ag/FMElfinderBundle/pull/new ================================================ FILE: LICENSE ================================================ Copyright (c) 2012- Al Ganiev 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: README.md ================================================ FMElfinderBundle ================ [ElFinder](https://github.com/Studio-42/elFinder) integration in Symfony ### Code Quality Assurance ### | Tests | Coverage| License | Version | |-------------|-----------------|-----------------|----------------| |[![Tests - Linux](https://github.com/helios-ag/FMElfinderBundle/actions/workflows/test.yaml/badge.svg)](https://github.com/helios-ag/FMElfinderBundle/actions/workflows/test.yaml)|[![codecov](https://codecov.io/gh/helios-ag/FMElfinderBundle/graph/badge.svg?token=JcZh9UHGKs)](https://codecov.io/gh/helios-ag/FMElfinderBundle)|[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)|[![Latest Stable Version](https://poser.pugx.org/helios-ag/fm-elfinder-bundle/v/stable.svg)](https://packagist.org/packages/helios-ag/fm-elfinder-bundle)| | Downloads | |----------| |[![Total Downloads](https://poser.pugx.org/helios-ag/fm-elfinder-bundle/downloads.svg)](https://packagist.org/packages/helios-ag/fm-elfinder-bundle)| **elFinder** is an open-source file manager for web, written in JavaScript using jQuery UI. Creation is inspired by simplicity and convenience of Finder program used in Mac OS X operating system. Recommended bundles to use with: | FMTinyMCEBundle | FOSCKEditorBundle | FMSummernoteBundle | | ------------------------|-------------|-----------------| |[![FMTinyMCEBundle](https://img.shields.io/badge/FMTinyMCEBundle-download-brightgreen.svg)](https://github.com/helios-ag/FMTinyMCEBundle)|[![FOSCKEditorBundle](https://img.shields.io/badge/FOSCKEditorBundle-download-orange.svg)](https://github.com/FriendsOfSymfony/FOSCKEditorBundle)|[![FMSummernoteBundle](https://img.shields.io/badge/FMSummernoteBundle-download-brightgreen.svg)](https://github.com/helios-ag/summernote-bundle)| **Table of contents** - [Installation](#installation) - [Step 1: Installation](#step-1-installation) - [Step 2: Enable the bundle](#step-2-enable-the-bundle-optional) - [Step 3: Import FMElfinderBundle routing file](#step-3-import-fmelfinderbundle-routing-file) - [Step 4: Securing paths](#step-4-configure-your-applications-securityyaml) - [Basic configuration](#basic-configuration) - [Add configuration options to your config.yaml](#add-configuration-options-to-your-configyaml) - [Use multiple upload folder by instance](#use-multiple-upload-folder-by-instance) - [CORS support](/docs/cors-support.md) - [Events listeners / subscribers](/docs/events-listeners-subscribers.md) - [Events](/docs/events-listeners-subscribers.md#events) - [Sub requests](/docs/events-listeners-subscribers.md#sub-requests) - [Elfinder Form Type](/docs/elfinder-form-type.md) - [Configuration](/docs/elfinder-form-type.md#configuration) - [EasyAdmin 2.x](/docs/elfinder-form-type.md#easyadmin-2x-integration) - [EasyAdmin 3.x/4.x](/docs/elfinder-form-type.md#easyadmin-3x/4x-integration) - [CKEditor integration](/docs/ckeditor-integration.md) - [Installation](/docs/ckeditor-integration.md#step-1-installation) - [Configuration](/docs/ckeditor-integration.md#step-2-configure-ckeditor-setting-via-settingsyml-or-through-form-builder) - [TinyMCE integration](/docs/tinymce-integration.md) - [Integration with TinyMCE 3](/docs/tinymce-integration.md#tinymce-3x) - [Integration with TinyMCE 4](/docs/tinymce-integration.md#tinymce-4x) - [Summernote integration](/docs/summernote-integration.md) - [Advanced configuration](/docs/advanced-configuration.md) - [Custom configuration provider](/docs/advanced-configuration.md#custom-configuration-provider) - [Custom loader](/docs/advanced-configuration.md#custom-loader) - [Plugins](/docs/advanced-configuration.md#plugins) - [Service as volume driver](/docs/advanced-configuration.md#symfony-service-as-a-volume-driver) - [Flysystem configuration](/docs/advanced-configuration.md#flysystem-configuration) - [Configuration dump](/docs/configuration-dump.md) ## Installation ### Step 1: Installation For Symfony Flex installation you need to enable community recipes: ```sh composer config extra.symfony.allow-contrib true ``` Install ```sh composer require helios-ag/fm-elfinder-bundle ``` Copy elfinder assets to public folder ```sh bin/console elfinder:install ``` ### Step 2: Enable the bundle (Optional) Enable the bundle in the kernel (not needed with symfony flex): ```php ``` ## Flysystem configuration Since 4.0 bundle supports [flysystem](https://github.com/thephpleague/flysystem) filesystem abstraction library Example configuration can be found here [Flysystem](/docs/flysystem.md) ================================================ FILE: docs/ckeditor-integration.md ================================================ # CKEditor integration Mostly filebrowsers used with WYSIWYG editors to upload images and other files. There are two bundles to work with CKEditor available: [TrsteelCKEditorBundle](https://github.com/trsteel88/TrsteelCkeditorBundle) and [FOSCKEditorBundle](https://github.com/FriendsOfSymfony/FOSCKEditorBundle) Both will work with this bundle. ## Step 1: Installation Install both bundles according README files ## Step 2: Configure CKEditor setting via settings.yml or through form builder: ```yaml trsteel_ckeditor: ... filebrowser_image_browse_url: route: elfinder route_parameters: instance: ckeditor ``` or if you prefer FOSCKEditorBundle ```yaml fos_ck_editor: default_config: default configs: default: filebrowserBrowseRoute: elfinder filebrowserBrowseRouteParameters: [] ``` Note that instance name should be the same as configured in elfinder bundle ```php // applies to Ivory CKEditor Bundle $form = $this->createFormBuilder() ->add('content', 'ckeditor', array( 'config' => array( 'filebrowserBrowseRoute' => 'elfinder', 'filebrowserBrowseRouteParameters' => array( 'instance' => 'default', 'homeFolder' => '' ) ), ), )) ->getForm() ; ``` ElFinder will be available under Insert Image dialog ================================================ FILE: docs/configuration-dump.md ================================================ # Bundle configuration dump ``` # Default configuration for extension with alias: "fm_elfinder" fm_elfinder: configuration_provider: fm_elfinder.configurator.default assets_path: assets loader: fm_elfinder.loader.default instances: # Required # Prototype name: locale: null cors_support: false editor: simple editor_template: null fullscreen: true theme: smoothness include_assets: true tinymce_popup_path: '' relative_path: true path_prefix: / visible_mime_types: [] connector: debug: false binds: # Prototype name: # Prototype name: ~ plugins: # Prototype name: # Prototype name: ~ roots: # Required # Prototype name: driver: LocalFileSystem # Required volume_id: 0 path: '' autoload: false phash: '' trash_hash: '' locale: '' i18n_folder_name: false mime_detect: auto mimefile: '' security_voter: '' start_path: '' encoding: UTF-8 url: '' alias: '' img_lib: auto tmb_path: .tmb tmb_path_mode: 511 tmb_url: '' tmb_size: 48 tmb_crop: true tmb_bg_color: '#ffffff' copy_overwrite: true copy_join: true copy_from: true copy_to: true upload_overwrite: true fileMode: 420 upload_allow: # Default: - image upload_deny: # Default: - all upload_order: # Defaults: - deny - allow upload_max_size: 0 defaults: # Prototype defaults: ~ attributes: # Prototype - pattern: ~ read: true write: true locked: false hidden: false accepted_name: '/^\w[\w\s\.\%\-]*$/u' show_hidden: false disabled_commands: [] tree_deep: 0 check_subfolders: 1 separator: / date_format: 'j M Y H:i' time_format: 'H:i' archive_mimes: [] archivers: enabled: false create: # Prototype - cmd: ~ argc: ~ ext: ~ extract: # Prototype - cmd: ~ argc: ~ ext: ~ flysystem: enabled: false filesystem: '' type: '' adapter_service: '' options: local: enabled: false path: '' ftp: enabled: false host: '' username: '' password: '' port: 21 passive: true ssl: true timeout: 30 root: / directoryPerm: 484 sftp: enabled: false host: '' username: '' password: '' port: 21 privateKey: '' timeout: 10 root: / azure: enabled: false account_name: '' account_key: '' container_name: '' aws_s3_v2: enabled: false key: '' secret: '' region: '' bucket_name: '' optional_prefix: '' base_url: '' aws_s3_v3: enabled: false key: '' secret: '' region: '' version: '' bucket_name: '' optional_prefix: '' endpoint: '' use_path_style_endpoint: false use_aws_shared_config_files: true options: enabled: false ACL: '' copy_com: enabled: false consumer_key: '' consumer_secret: '' access_token: '' token_secret: '' optional_prefix: '' gridfs: enabled: false db_name: '' zip: enabled: false path: '' dropbox: enabled: false app: '' token: '' rackspace: enabled: false username: '' apikey: '' endpoint: '' container: '' region: '' glide_url: '' glide_key: '' plugins: # Prototype name: # Prototype name: ~ driver_options: # Prototype name: # Prototype name: ~ dropbox2_settings: enabled: false app_key: ~ app_secret: ~ access_token: ~ aliasFormat: '%s@Dropbox' path: / separator: / acceptedName: '%s@Dropbox' rootCssClass: elfinder-navbar-root-dropbox publishPermission: requested_visibility: public getThumbSize: medium box_settings: enabled: false client_id: ~ client_secret: ~ accessToken: ~ root: Box.com path: / separator: / tmbPath: '' tmbURL: '' tmpPath: '' acceptedName: '#^[^/\?*:|"<>]*[^./\?*:|"<>]$#' rootCssClass: elfinder-navbar-root-box onedrive_settings: enabled: false client_id: ~ client_secret: ~ accessToken: ~ root: OneDrive.com OneDriveApiClient: '' path: / separator: / tmbPath: '' tmbURL: '' tmpPath: '' acceptedName: '#^[^/\?*:|"<>]*[^./\?*:|"<>]$#' rootCssClass: elfinder-navbar-root-onedrive useApiThumbnail: true ftp_settings: enabled: false host: ~ user: ~ password: ~ path: ~ s3_settings: enabled: false access_key: ~ secret_key: ~ bucket: ~ tmp_path: ~ signature: ~ region: ~ mysql_settings: enabled: false host: ~ user: ~ pass: ~ db: ~ port: null socket: null files_table: elfinder_file tmbPath: '' tmpPath: '' rootCssClass: elfinder-navbar-root-sql noSessionCache: hasdirs ``` ================================================ FILE: docs/cors-support.md ================================================ # CORS support If you want access connector URL from an other domain on the client side, simply configure FMElFinder bundle as you used to, and add the `cors_support: true` option to the cross domain instance: ```yaml # app/config/config.yml fm_elfinder: instances: default: locale: %locale% # defaults to current request locale cors_support: true # allows cross domain responses handling (default false) editor: ckeditor # other options are tinymce, tinymce4, form, custom and simple, # ... ``` Then you have to add the CORS headers (`Access-Control-Allow-Origin`) to the response. It can be easily done with [NelmioCORSBundle](https://github.com/nelmio/NelmioCorsBundle "NelmioCORSBundle") : ```yaml # app/config/config.yml nelmio_cors: defaults: allow_credentials: false allow_origin: [] allow_headers: [] allow_methods: [] expose_headers: [] max_age: 0 hosts: [] paths: '^/efconnect': allow_origin: ['*'] allow_headers: ['X-Custom-Auth', 'Content-Type', 'X-Requested-With'] allow_methods: ['POST', 'GET', 'PATCH', 'PUT', 'DELETE'] max_age: 3600 allow_credentials: true ``` ================================================ FILE: docs/elfinder-form-type.md ================================================ # Elfinder Form Type ## Configuration Bundle come with custom form type, ``, that provide elfinder callback (opens Elfinder window). First, define instance with editor set to "form": ```yaml fm_elfinder: instances: form: locale: '%locale%' # defaults to current request locale editor: form # other choices are tinymce or simple, and form show_hidden: false # defaults to false fullscreen: true # defaults true, applies to simple and ckeditor editors connector: debug: false # defaults to false roots: # at least one root must be defined uploads: driver: LocalFileSystem path: uploads upload_allow: ['image/png', 'image/jpg', 'image/jpeg'] upload_deny: ['all'] upload_max_size: 2M ``` On the second step, add to your form builder (or form class), elfinder type, and pass instance and `enable` parameters: ```php // ... use FM\ElfinderBundle\Form\Type\ElFinderType; // ... $form = $this->createFormBuilder() ->add('elfinder', ElFinderType::class, ['instance' => 'form', 'enable' => true]) ->getForm(); ``` ```jinja
{{ form_widget(form) }}
``` ## EasyAdmin 2.x integration To get to work with EasyAdmin bundle (2.x): ```yaml - { property: 'images', type: 'collection', label: 'Images', type_options: { allow_add: false, allow_delete: false, entry_type: 'FM\ElfinderBundle\Form\Type\ElFinderType' }} ``` and `easyadmin.yaml` ```yaml design: form_theme: - '@EasyAdmin/form/bootstrap_4.html.twig' - '@FMElfinder/Form/elfinder_widget.html.twig' ``` ## EasyAdmin 3.x/4.x integration Almost same as for 2.x, but you need to add ```php // ProjectCrudController.php // ... public function configureFields(string $pageName): iterable { // ... yield Field::new('image', 'Image') ->setFormType(ElFinderType::class) ->setFormTypeOptions([ 'instance' => 'default', 'enable' => true, ]) ->onlyOnForms() ; // ... } public function configureCrud(Crud $crud): Crud { return $crud // ... ->addFormTheme('@FMElfinder/Form/elfinder_widget.html.twig') ; } ``` Collection field: ```php return [ Field::new('cover', 'Cover')->setFormType(ElFinderType::class) ->setFormTypeOptions( [ 'instance' => 'image_form', 'attr' => ['class' => 'col-6'], ] ) ->hideOnIndex(), CollectionField::new('photos', 'Photos') ->setEntryType(PhotoType::class) ]; ``` ```php public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('path', ElFinderType::class, [ 'instance' => 'image_form', 'enable' => true ]) ->add('translations', TranslationsType::class, [ 'fields' => [ 'description' => [ 'field_type' => CKEditorType::class, 'label' => 'Description', ], ], ]); } ``` And override elfidner_widget.html.twig ```js live('click', '[data-type="elfinder-input-field"]', function (event) { var id = $(this).attr('id'); var childWin = window.open("{{path('elfinder', {'instance': instance, 'homeFolder': homeFolder })}}?id="+id, "popupWindow", "height=450, width=900"); }); ``` ================================================ FILE: docs/events-listeners-subscribers.md ================================================ # Events listeners / subscribers ## Events The bundle is throwing some events during an elFinder command execution : - `FM\ElfinderBundle\Event\ElFinderEvents::PRE_EXECUTION` : `fm_elfinder.event.pre_execution` - `FM\ElfinderBundle\Event\ElFinderEvents::POST_EXECUTION` : `fm_elfinder.event.post_execution` The pre execution event has its own class (`FM\ElfinderBundle\Event\ElFinderPreExecutionEvent`) which contains the http request object, the elFinder instance name and the home folder. The post execution event (`FM\ElfinderBundle\Event\ElFinderPostExecutionEvent`) has the same attributes than the pre execution events, plus the command result and a `hasErrors()` function indicating if errors has been encountered during command execution. The result to return to the elFinder.js client can be modified with the post execution event using the `setResult` function on this event. You can register event listeners with the `fm_elfinder.event_listener` tag and event subscribers with the `fm_elfinder.event_subscriber` tag. **Note:** you must set the [`cors_support`](https://github.com/helios-ag/FMElfinderBundle/blob/master/docs/cors-support.md "CORS Support documentation") option to `true` to use events. If you don't, the symfony life cycle won't end properly and the post execution event won't be dispatched. Only use the NelmioCORSBundle if your elFinder client is on an other domain. You can access to all commands names [here](https://github.com/helios-ag/ElFinderPHP/blob/master/src/ElFinder.php#L61 "elFinder commands"). ## Sub requests Events allows you to perform sub requests (only for commands used with HTTP GET method, i.e. not to upload a file). These subrequests are working the same way than `forward` function on symfony controllers, and are also hookable. **Note:** You will have to set a `volume_id` to your instance's root to be sure the volume is mounted with the same ID between each requests. Here is an exemple of event listener on the post execution event, making a sub request : ```xml ``` ```php // src/AppBundle/EventListener/ElFinder/PostExecutionListener.php namespace AppBundle\EventListener\ElFinder; use FM\ElfinderBundle\Event\ElFinderPostExecutionEvent; class PostExecutionListener { /** * @param ElFinderPostExecutionEvent $event */ public function onPostExecute(ElFinderPostExecutionEvent $event) { if (!$event->hasErrors() && $event->getCommand() == 'tmb') { // 'tmb', 'mkdir', 'open', etc... // do your stuff here // ... // you can perform a sub request $queryParameters = $event->getRequest()->query->all(); // getting original request parameters $queryParameters['cmd'] = 'info'; // changing the command to execute in sub request $jsonResponse = $event->subRequest(array( 'instance' => $event->getInstance(), // you can also make a subrequest on an other instance 'homeFolder' => $event->getHomeFolder() // and an other homeFolder ), $queryParameters); $data = json_decode($jsonResponse->getContent()); // work with sub request data // ... } } } ``` ================================================ FILE: docs/flysystem.md ================================================ Flysystem example configuration =============================== You will need library files to work with Flysystem: First add flysystem elfinder driver: ```sh composer require barryvdh/elfinder-flysystem-driver ``` Depending which driver you want to use, you need require appropriate driver, for example: ```sh composer require league/flysystem-aws-s3-v3 ``` Below example of configuring flysystem: ```yaml fm_elfinder: instances: default: locale: %locale% # defaults to current request locale editor: ckeditor # other options are tinymce, tinymce4, form, custom and simple fullscreen: true # defaults true, applies to simple and ckeditor editors connector: debug: false # defaults to false roots: # at least one root must be defined local: driver: Flysystem path: uploads flysystem: type: local options: local: path: %kernel.root_dir%/../web/uploads/ upload_allow: ['all'] #upload_allow: ['image/png', 'image/jpg', 'image/jpeg'] #upload_deny: ['all'] upload_max_size: 2M dropbox: driver: Flysystem path: uploads flysystem: type: dropbox options: dropbox: app: YourAppname // see dropbox developer site token: ToKeN // can be aquired via developer console upload_allow: ['all'] aws_s3: driver: Flysystem path: uploads url: 'http://[my-bucket-name].s3.[region].amazonaws.com' tmb_url: 'self' # For thumbnail generation on aws flysystem: type: aws_s3_v3 options: aws_s3_v3: version: 'latest' key: 'MY_AWS_KEY' secret: 'MY_AWS_SECRET' region: 'MY_AWS_REGION' bucket_name: 'MY_BUCKET_NAME' upload_allow: ['all'] ``` for more options see [ElFinderConfigurationReader.php](https://github.com/helios-ag/FMElfinderBundle/blob/master/Configuration/ElFinderConfigurationReader.php) # Amazon S3 Configuration To work with your S3 account and upload your files directly to S3 you have to set the following properties in your config file (config.yml). ```yaml fm_elfinder: instances: default: locale: %locale% editor: ckeditor fullscreen: true relative_path: false connector: debug: false roots: aws_s3: driver: Flysystem path: uploads url: 'http://[my-bucket-name].s3.[region].amazonaws.com' tmb_url: 'self' # For thumbnail generation on aws flysystem: type: aws_s3_v3 options: aws_s3_v3: version: 'latest' key: 'MY_AWS_KEY' secret: 'MY_AWS_SECRET' region: 'MY_AWS_REGION' bucket_name: 'MY_BUCKET_NAME' upload_allow: ['all'] ``` In that case you use an S3 domain so the **relative_path** have to be false and the url have to be set to your S3 or Cloudfront Domain if you have mapped S3 directly to your filesystem work with the relative path. If you don't set the **relative_path** to false you get a wrong URL after inserting that image to CKEditor for example. Define the variables in your config.yml or set it directly. If you don't use subdomain that contains your `bucket_name` and want to use your own **endpoint** make sure to set **use_path_style_endpoint** to `true` so that it will format the url correctly. To prevent AWS PHP SDK from verifying the presence of a shared configuration in .aws/configuration make sure to set **use_aws_shared_config_files** to `false`. Also possible to define Flysystem adapters as services, it can be useful for self written adapters. To use adapter as service, define it under 'services' node in your services.yml (or use DI) ```services.yml services: local_adapter: class: League\Flysystem\Adapter\Local arguments: ["%kernel.root_dir%/../web/uploads/"] ``` and configure flysystem node accordingly to use it ```config.yml fm_elfinder: instances: adapter: locale: %locale% editor: simple relative_path: true connector: roots: uploads: show_hidden: false driver: Flysystem # !set driver to Flysystem flysystem: type: custom # !set type to custom, it will tell bundle to use custom driver adapter_service: 'local_adapter' # select previously configured adapter service options: path: '' upload_allow: ['all'] ``` ================================================ FILE: docs/summernote-integration.md ================================================ # Summernote integration Update the editor property in your app/config.yml Set Summernote editor type: ```yaml fm_elfinder: editor: summernote ``` Edit template that contains summernote instance (the same way as for tinymce) ```jinja {{ elfinder_summernote_init('instance_name') }} {{ summernote_init() }} ``` Don't forget to enable elfinder plugin in summernote configuration. ================================================ FILE: docs/tinymce-integration.md ================================================ # TinyMCE integration You can integrate TinyMCE byself or use Bundles that already add TinyMCE functionality to your Symfony project. Below instruction how to integrate [FMElfinderBundle](https://github.com/helios-ag/FMElfinderBundle) with [TinyMCEBundle](https://github.com/stfalcon/TinymceBundle) How to use ElfinderBundle with [TinyMCEBundle](https://github.com/stfalcon/TinymceBundle) ## TinyMCE 3.x Instruction for version 0.2.1 (TinyMCE 3.x) Download bundles, configure, dump and install assets as written in installation steps **Configuration** Update the editor property in your app/config.yml Set TinyMce popup path: ```yaml fm_elfinder: editor: tinymce tinymce_popup_path: "asset[bundles/stfalcontinymce/vendor/tiny_mce/tiny_mce_popup.js]" ``` Under tinymce configuration node, theme configuration, add: file_browser_callback : 'elFinderBrowser' ```yaml stfalcon_tinymce: theme: simple: file_browser_callback : 'elFinderBrowser' ``` after ( {{ tinymce_init() }} ) function call place ElfinderBundle's function: ```jinja {{ elfinder_tinymce_init('instance_name', {'width':'900', 'height': '450', 'title':'ElFinder 2.0'}) }} ``` as shown below ```jinja {{ tinymce_init() }} {{ elfinder_tinymce_init('instance_name') }} ``` instance_name is an instance of elfinder's configuration ## TinyMCE 4.x Update the editor property in your app/config.yml ```yaml fm_elfinder: editor: tinymce4 ``` Under tinymce configuration node, theme configuration, add: file_browser_callback : elFinderBrowser ```yaml stfalcon_tinymce: theme: simple: file_browser_callback : elFinderBrowser ``` before ( {{ tinymce_init() }} ) function call (order is important) place ElfinderBundle's function: {{ elfinder_tinymce_init4('instance_name', {'width':'900', 'height': '450', 'title':'ElFinder 2.0'} ) }} as shown below ```jinja {{ elfinder_tinymce_init4('instance_name') }} {{ tinymce_init() }} ``` instance_name is instance of elfinder configuration ================================================ FILE: phpunit.xml.dist ================================================ ./tests ./ ./src/Controller ./src/Resources ./tests ./vendor ================================================ FILE: src/Bridge/ElFinderBridge.php ================================================ session) { $opts = array_merge($opts, ['session' => $this->session]); } parent::__construct($opts); } public function setSession($session) { $this->session = $session; } public function getVolumes(): array { return $this->volumes; } /** * @param array $opts */ protected function mountVolumes($opts) { foreach ($opts['roots'] as $i => $o) { $volume = null; if (isset($o['service'])) { $driver = $o['service']; if ($driver instanceof elFinderVolumeDriver) { $volume = $driver; unset($opts['roots'][$i]); } } if ($volume && $volume->mount($o)) { // unique volume id (ends on "_") - used as prefix to files hash $id = $volume->id(); $this->volumes[$id] = $volume; if (!$this->default && $volume->isReadable()) { $this->default = $this->volumes[$id]; } } } parent::mountVolumes($opts); } } ================================================ FILE: src/Command/ElFinderInstallerCommand.php ================================================ addOption('docroot', null, InputOption::VALUE_OPTIONAL, 'Website document root.', 'public') ->addOption('elfinder-vendor-dir', null, InputOption::VALUE_REQUIRED, 'Vendor containing elfinder assets', 'studio-42/elfinder') ->setHelp(<<<'EOF' Default docroot: public You can pass docroot: Where to install elfinder php %command.full_name% --docroot=public_html EOF ); } protected function execute(InputInterface $input, OutputInterface $output): int { $io = new SymfonyStyle($input, $output); $dr = $input->getOption('docroot'); $vendorDir = $input->getOption('elfinder-vendor-dir'); $io->title('elFinder Installer'); $io->comment(sprintf('Trying to install elfinder to %s directory', $dr)); $rootDir = $this->parameterBag->get('kernel.project_dir'); $publicDir = sprintf('%s/%s/bundles/fmelfinder', $rootDir, $dr); $reflection = new ReflectionClass(\Composer\Autoload\ClassLoader::class); $vendorRootDir = dirname($reflection->getFileName(), 3) . '/vendor'; $io->note(sprintf('Starting to install elfinder to %s folder', $publicDir)); // validate $vendorDir to match namespace/vendor name if (!preg_match('/^([a-z0-9-]+)\/([a-z0-9-]+)$/i', $vendorDir)) { $io->error(sprintf('Invalid vendor directory name %s', $vendorDir)); return Command::FAILURE; } $this->fileSystem->mirror($vendorRootDir . '/' . $vendorDir . '/' . self::ELFINDER_CSS_DIR, $publicDir . '/css'); $this->fileSystem->mirror($vendorRootDir . '/' . $vendorDir . '/' . self::ELFINDER_IMG_DIR, $publicDir . '/img'); $this->fileSystem->mirror($vendorRootDir . '/' . $vendorDir . '/' . self::ELFINDER_JS_DIR, $publicDir . '/js'); $this->fileSystem->mirror($vendorRootDir . '/' . $vendorDir . '/' . self::ELFINDER_SOUNDS_DIR, $publicDir . '/sounds'); $io->success('elFinder assets successfully installed'); return Command::SUCCESS; } } ================================================ FILE: src/Configuration/ElFinderConfigurationProviderInterface.php ================================================ parameters = $parameters; $this->requestStack = $requestStack; $this->container = $container; } public function getConfiguration(string $instance): array { $request = $this->requestStack->getCurrentRequest(); $efParameters = $this->parameters; $parameters = $efParameters['instances'][$instance]; $options = []; $options['corsSupport'] = $parameters['cors_support']; $options['debug'] = $parameters['connector']['debug']; $options['bind'] = $parameters['connector']['binds']; $options['plugin'] = $parameters['connector']['plugins']; $options['roots'] = []; foreach ($parameters['connector']['roots'] as $parameter) { $path = $parameter['path']; $homeFolder = $request->attributes->get('homeFolder'); $pathAndHomeFolder = $homeFolder ? sprintf('%s/%s', $path, $homeFolder) : $path; if ($parameter['flysystem']['enabled']) { if ($parameter['flysystem']['filesystem']) { $serviceName = $parameter['flysystem']['filesystem']; $filesystem = $this->getFlysystemFilesystem($serviceName); } else { $adapter = $parameter['flysystem']['type']; // ftp ex. $serviceName = $parameter['flysystem']['adapter_service']; $opt = $parameter['flysystem']['options']; $filesystem = $this->configureFlysystem($opt, $adapter, $serviceName); } } $driver = $this->container->has($parameter['driver']) ? $this->container->get($parameter['driver']) : false; $driverOptions = [ 'driver' => $parameter['driver'], 'service' => $driver, 'glideURL' => $parameter['glide_url'], 'glideKey' => $parameter['glide_key'], 'plugin' => $options['plugin'], 'path' => $pathAndHomeFolder, 'startPath' => $parameter['start_path'], 'encoding' => $parameter['encoding'], 'URL' => $this->getURL($parameter, $request, $homeFolder, $path), 'alias' => $parameter['alias'], 'mimeDetect' => $parameter['mime_detect'], 'mimefile' => $parameter['mimefile'], 'imgLib' => $parameter['img_lib'], 'tmbPath' => $parameter['tmb_path'], 'tmbPathMode' => $parameter['tmb_path_mode'], 'tmbURL' => $parameter['tmb_url'], 'tmbSize' => $parameter['tmb_size'], 'tmbCrop' => $parameter['tmb_crop'], 'tmbBgColor' => $parameter['tmb_bg_color'], 'copyOverwrite' => $parameter['copy_overwrite'], 'copyJoin' => $parameter['copy_join'], 'copyFrom' => $parameter['copy_from'], 'copyTo' => $parameter['copy_to'], 'uploadOverwrite' => $parameter['upload_overwrite'], 'uploadAllow' => $parameter['upload_allow'], 'uploadDeny' => $parameter['upload_deny'], 'uploadMaxSize' => $parameter['upload_max_size'], 'uploadMaxConn' => $parameter['upload_max_conn'], 'defaults' => $parameter['defaults'], 'attributes' => $parameter['attributes'], 'acceptedName' => $parameter['accepted_name'], 'disabled' => $parameter['disabled_commands'], 'treeDeep' => $parameter['tree_deep'], 'checkSubfolders' => $parameter['check_subfolders'], 'separator' => $parameter['separator'], 'timeFormat' => $parameter['time_format'], 'archiveMimes' => $parameter['archive_mimes'], 'archivers' => $parameter['archivers'], 'fileMode' => $parameter['fileMode'], 'trashHash' => $parameter['trash_hash'], ]; if (null !== $parameter['quarantine']) { $driverOptions['quarantine'] = $parameter['quarantine']; } if ($parameter['volume_id'] > 0) { $driverOptions['id'] = $parameter['volume_id']; } if (!$parameter['show_hidden']) { $driverOptions['accessControl'] = [$this, 'access']; } if ($parameter['security_voter']) { /** @var ElfinderSecurityInterface $voter */ $voter = $this->container->get($parameter['security_voter']); $driverOptions['disabled'] = $this->parseSecurityConfiguration($voter); } if ('Flysystem' == $parameter['driver']) { $driverOptions['filesystem'] = $filesystem; } $options['roots'][] = array_merge($driverOptions, $this->configureDriver($parameter)); } return $options; } /** * Simple function to demonstrate how to control file access using "accessControl" callback. * This method will disable accessing files/folders starting from '.' (dot). * * @param string $attr attribute name (read|write|locked|hidden) * @param string $path file path relative to volume root directory started with directory separator * * @return bool|null */ public function access($attr, $path, $data, $volume) { return 0 === strpos(basename($path), '.') // if file/folder begins with '.' (dot) ? !('read' == $attr || 'write' == $attr) // set read+write to false, other (locked+hidden) set to true : null; // else elFinder decide it itself } /** * @return array */ protected function parseSecurityConfiguration(ElfinderSecurityInterface $voter) { $configuration = $voter->getConfiguration(); if (!is_array($configuration)) { throw new Exception('ElfinderSecurityVoter should return array'); } foreach ($configuration as $role => $commands) { if ($this->container->get('security.authorization_checker')->isGranted($role)) { return $commands; } } return []; } private function getURL(array $parameter, Request $request, string $homeFolder, string $path): string { if (isset($parameter['url']) && $parameter['url']) { if (0 === strpos($parameter['url'], 'http')) { return str_replace('{homeFolder}', $homeFolder, $parameter['url']); } $path = $parameter['url'] . '/' . $homeFolder; } else { $path = $path . '/' . $homeFolder; } return $request->getUriForPath('/' . trim($path, '/')); } /** * @return Filesystem */ private function configureFlysystem($opt, $adapter, $serviceName) { $filesystem = null; switch ($adapter) { case 'local': $filesystem = new Filesystem(new Local($opt['local']['path'])); break; case 'ftp': $settings = [ 'host' => $opt['ftp']['host'], 'username' => $opt['ftp']['username'], 'password' => $opt['ftp']['password'], /* optional config settings */ 'port' => $opt['ftp']['port'], 'root' => $opt['ftp']['root'], 'passive' => $opt['ftp']['passive'], 'ssl' => $opt['ftp']['ssl'], 'timeout' => $opt['ftp']['timeout'], 'directoryPerm' => $opt['ftp']['directoryPerm'], ]; $filesystem = new Filesystem(new Ftp($settings)); break; case 'sftp': $settings = [ 'host' => $opt['sftp']['host'], 'port' => $opt['sftp']['port'], 'username' => $opt['sftp']['username'], 'password' => $opt['sftp']['password'], 'privateKey' => $opt['sftp']['privateKey'], 'root' => $opt['sftp']['root'], 'timeout' => $opt['sftp']['timeout'], ]; $filesystem = new Filesystem(new SftpAdapter($settings)); break; case 'azure': $client = BlobRestProxy::createBlobService( sprintf('DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=%s;', $opt['azure']['account_name'], $opt['azure']['account_key']) ); $adapter = new AzureBlobStorageAdapter($client, $opt['azure']['container_name']); $filesystem = new Filesystem($adapter); break; case 'aws_s3_v2': $options = [ 'key' => $opt['aws_s3_v2']['key'], 'secret' => $opt['aws_s3_v2']['secret'], 'region' => $opt['aws_s3_v2']['region'], ]; if (isset($opt['aws_s3_v2']['base_url']) && $opt['aws_s3_v2']['base_url']) { $options['base_url'] = $opt['aws_s3_v2']['base_url']; } $client = S3Client::factory($options); $filesystem = new Filesystem(new AwsS3v2($client, $opt['aws_s3_v2']['bucket_name'], $opt['aws_s3_v2']['optional_prefix'])); break; case 'aws_s3_v3': $s3Options = [ 'region' => $opt['aws_s3_v3']['region'], 'version' => $opt['aws_s3_v3']['version'], 'endpoint' => $opt['aws_s3_v3']['endpoint'], 'use_path_style_endpoint' => $opt['aws_s3_v3']['use_path_style_endpoint'], 'use_aws_shared_config_files' => $opt['aws_s3_v3']['use_aws_shared_config_files'], ]; if (!empty($opt['aws_s3_v3']['key']) && !empty($opt['aws_s3_v3']['secret'])) { $s3Options['credentials'] = [ 'key' => $opt['aws_s3_v3']['key'], 'secret' => $opt['aws_s3_v3']['secret'], ]; } $client = new S3Client($s3Options); $filesystem = new Filesystem(new AwsS3v3($client, $opt['aws_s3_v3']['bucket_name'], $opt['aws_s3_v3']['optional_prefix'], null, null, $opt['aws_s3_v3']['options'] ?? [])); break; case 'copy_com': $client = new API( $opt['copy_com']['consumer_key'], $opt['copy_com']['consumer_secret'], $opt['copy_com']['access_token'], $opt['copy_com']['token_secret'] ); $filesystem = new Filesystem(new CopyAdapter($client, $opt['copy_com']['optional_prefix'])); break; case 'gridfs': $mongoClient = new MongoClient(); $gridFs = $mongoClient->selectDB($opt['gridfs']['db_name'])->getGridFS(); $filesystem = new Filesystem(new GridFSAdapter($gridFs)); break; case 'zip': $filesystem = new Filesystem(new ZipArchiveAdapter($opt['zip']['path'])); break; case 'dropbox': $filesystem = new Filesystem(new DropboxAdapter(new Client($opt['dropbox']['token']))); break; case 'rackspace': $client = new Rackspace(Rackspace::$opt['rackspace']['endpoint'], [ 'username' => $opt['rackspace']['username'], 'apiKey' => $opt['rackspace']['apikey'], ]); $store = $client->objectStoreService('cloudFiles', $opt['rackspace']['region']); $container = $store->getContainer($opt['rackspace']['container']); $filesystem = new Filesystem(new RackspaceAdapter($container)); break; case 'custom': $adapter = $this->container->get($serviceName); try { $filesystem = new Filesystem($adapter); } catch (TypeError $error) { throw new Exception(sprintf('Service %s is not an instance of %s.', $serviceName, AdapterInterface::class)); } break; } return $filesystem; } private function getFlysystemFilesystem(string $serviceName): Filesystem { $filesystem = $this->container->get($serviceName); if (!is_object($filesystem) || (!$filesystem instanceof Filesystem)) { throw new Exception(sprintf('Service %s is not an instance of %s.', $serviceName, Filesystem::class)); } return $filesystem; } private function configureDriver(array $parameter): array { $settings = []; switch (strtolower($parameter['driver'])) { case 'ftp': $settings['host'] = $parameter['ftp_settings']['host']; $settings['user'] = $parameter['ftp_settings']['user']; $settings['pass'] = $parameter['ftp_settings']['password']; $settings['path'] = $parameter['ftp_settings']['path']; break; case 'mysql': $settings['host'] = $parameter['mysql_settings']['host']; $settings['user'] = $parameter['mysql_settings']['user']; $settings['pass'] = $parameter['mysql_settings']['pass']; $settings['db'] = $parameter['mysql_settings']['db']; $settings['port'] = $parameter['mysql_settings']['port']; $settings['socket'] = $parameter['mysql_settings']['socket']; $settings['files_table'] = $parameter['mysql_settings']['files_table']; $settings['tmbPath'] = $parameter['mysql_settings']['tmbPath']; $settings['tmpPath'] = $parameter['mysql_settings']['tmpPath']; $settings['rootCssClass'] = $parameter['mysql_settings']['rootCssClass']; $settings['noSessionCache'] = explode(',', $parameter['mysql_settings']['noSessionCache']); break; case 'dropbox2': $settings['app_key'] = $parameter['dropbox2_settings']['app_key']; $settings['app_secret'] = $parameter['dropbox2_settings']['app_secret']; $settings['access_token'] = $parameter['dropbox2_settings']['access_token']; $settings['aliasFormat'] = $parameter['dropbox2_settings']['aliasFormat']; $settings['path'] = $parameter['dropbox2_settings']['path']; $settings['separator'] = $parameter['dropbox2_settings']['separator']; $settings['acceptedName'] = $parameter['dropbox2_settings']['acceptedName']; $settings['rootCssClass'] = $parameter['dropbox2_settings']['rootCssClass']; $settings['publishPermission'] = $parameter['dropbox2_settings']['publishPermission']; $settings['getThumbSize'] = $parameter['dropbox2_settings']['getThumbSize']; break; case 'onedrive': $settings['client_id'] = $parameter['onedrive_settings']['client_id']; $settings['client_secret'] = $parameter['onedrive_settings']['client_secret']; $settings['accessToken'] = $parameter['onedrive_settings']['accessToken']; $settings['root'] = $parameter['onedrive_settings']['root']; $settings['OneDriveApiClient'] = $parameter['onedrive_settings']['OneDriveApiClient']; $settings['path'] = $parameter['onedrive_settings']['path']; $settings['separator'] = $parameter['onedrive_settings']['separator']; $settings['tmbPath'] = $parameter['onedrive_settings']['tmbPath']; $settings['tmbURL'] = $parameter['onedrive_settings']['tmbURL']; $settings['tmpPath'] = $parameter['onedrive_settings']['tmpPath']; $settings['acceptedName'] = $parameter['onedrive_settings']['acceptedName']; $settings['rootCssClass'] = $parameter['onedrive_settings']['rootCssClass']; $settings['useApiThumbnail'] = $parameter['onedrive_settings']['useApiThumbnail']; break; case 'box': $settings['client_id'] = $parameter['box_settings']['client_id']; $settings['client_secret'] = $parameter['box_settings']['client_secret']; $settings['accessToken'] = $parameter['box_settings']['accessToken']; $settings['root'] = $parameter['box_settings']['root']; $settings['path'] = $parameter['box_settings']['path']; $settings['separator'] = $parameter['box_settings']['separator']; $settings['tmbPath'] = $parameter['box_settings']['tmbPath']; $settings['tmbURL'] = $parameter['box_settings']['tmbURL']; $settings['acceptedName'] = $parameter['box_settings']['acceptedName']; $settings['rootCssClass'] = $parameter['box_settings']['rootCssClass']; break; default: break; } return $settings; } } ================================================ FILE: src/Connector/ElFinderConnector.php ================================================ execute($queryParameters); } public function execute($queryParameters) { $isPost = 'POST' == $_SERVER['REQUEST_METHOD']; $src = 'POST' == $_SERVER['REQUEST_METHOD'] ? array_merge($_POST, $queryParameters) : $queryParameters; if ($isPost && !$src && $rawPostData = @file_get_contents('php://input')) { // for support IE XDomainRequest() $parts = explode('&', $rawPostData); foreach ($parts as $part) { [$key, $value] = array_pad(explode('=', $part), 2, ''); $src[$key] = rawurldecode($value); } $_POST = $src; $_REQUEST = array_merge_recursive($src, $_REQUEST); } $cmd = $src['cmd'] ?? ''; $args = []; if (!function_exists('json_encode')) { $error = $this->elFinder->error(elFinder::ERROR_CONF, elFinder::ERROR_CONF_NO_JSON); return $this->output(['error' => '{"error":["' . implode('","', $error) . '"]}', 'raw' => true]); } if (!$this->elFinder->loaded()) { return $this->output(['error' => $this->elFinder->error(elFinder::ERROR_CONF, elFinder::ERROR_CONF_NO_VOL), 'debug' => $this->elFinder->mountErrors]); } // telepat_mode: on if (!$cmd && $isPost) { return $this->output(['error' => $this->elFinder->error(elFinder::ERROR_UPLOAD, elFinder::ERROR_UPLOAD_TOTAL_SIZE), 'header' => 'Content-Type: text/html']); } // telepat_mode: off if (!$this->elFinder->commandExists($cmd)) { return $this->output(['error' => $this->elFinder->error(elFinder::ERROR_UNKNOWN_CMD)]); } // collect required arguments to exec command foreach ($this->elFinder->commandArgsList($cmd) as $name => $req) { $arg = 'FILES' == $name ? $_FILES : ($src[$name] ?? ''); if (!is_array($arg)) { $arg = trim($arg); } if ($req && (!isset($arg) || '' === $arg)) { return $this->output(['error' => $this->elFinder->error(elFinder::ERROR_INV_PARAMS, $cmd)]); } $args[$name] = $arg; } $args['debug'] = isset($src['debug']) && $src['debug']; return $this->output($this->elFinder->exec($cmd, $this->input_filter($args))); } protected function output(array $data) { if (isset($data['pointer'])) { parent::output($data); } return $data; } } ================================================ FILE: src/Controller/ElFinderController.php ================================================ twig = $twig; $this->params = $params; $this->loader = $loader; } /** * Renders Elfinder. * * @throws Exception */ public function show(Request $request, string $instance, string $homeFolder): Response { $efParameters = $this->params; if (empty($efParameters['instances'][$instance])) { throw new NotFoundHttpException('Instance not found'); } $parameters = $efParameters['instances'][$instance]; if (empty($parameters['locale'])) { $parameters['locale'] = $request->getLocale(); } $assetsPath = $efParameters['assets_path']; $result = $this->selectEditor($parameters, $instance, $homeFolder, $assetsPath, $request->query->get('id')); return new Response($this->twig->render($result['template'], $result['params'])); } public function load(SessionInterface $session, HttpKernelInterface $httpKernel, EventDispatcherInterface $eventDispatcher, Request $request, string $instance, string $homeFolder): JsonResponse { $loader = $this->loader; $efParameters = $this->params; $loader->initBridge($instance, $efParameters); // builds up the Bridge object for the loader with the given instance if ($loader instanceof ElFinderLoader) { $loader->setSession($session); } $preExecutionEvent = new ElFinderPreExecutionEvent($request, $httpKernel, $instance, $homeFolder); $eventDispatcher->dispatch($preExecutionEvent); $result = $loader->load($request); // the instance is already set $postExecutionEvent = new ElFinderPostExecutionEvent($request, $httpKernel, $instance, $homeFolder, $result); $eventDispatcher->dispatch($postExecutionEvent); // returning result (who may have been modified by a post execution event listener) return new JsonResponse($postExecutionEvent->getResult()); } public function mainJS(): Response { $version = new EmptyVersionStrategy(); $package = new Package($version); $mainUrl = $package->getUrl(sprintf('%s/bundles/fmelfinder/js', $this->params['assets_path'])); return new Response( $this->twig->render('@FMElfinder/Elfinder/helper/main.js.twig',['mainUrl' => $mainUrl]), 200, [ 'Content-type' => 'text/javascript', ] ); } /** * @throws Exception */ private function selectEditor(array $parameters, string $instance, string $homeFolder, string $assetsPath, ?string $formTypeId = null): array { $editor = $parameters['editor']; $locale = $parameters['locale'] ?: $this->container->getParameter('locale'); $fullScreen = $parameters['fullscreen']; $relativePath = $parameters['relative_path']; $pathPrefix = $parameters['path_prefix']; $theme = $parameters['theme']; // convert to javascript array $onlyMimes = count($parameters['visible_mime_types']) ? "['" . implode("','", $parameters['visible_mime_types']) . "']" : '[]'; $result = []; switch ($editor) { case 'custom': if (empty($parameters['editor_template'])) { throw new Exception("Configuration error : 'custom' editor must define 'editor_template' parameter"); } $result['template'] = $parameters['editor_template']; $result['params'] = [ 'locale' => $locale, 'fullscreen' => $fullScreen, 'instance' => $instance, 'homeFolder' => $homeFolder, 'relative_path' => $relativePath, 'prefix' => $assetsPath, 'theme' => $theme, 'pathPrefix' => $pathPrefix, 'onlyMimes' => $onlyMimes, 'id' => $formTypeId, ]; return $result; case 'ckeditor': $result['template'] = '@FMElfinder/Elfinder/ckeditor.html.twig'; $result['params'] = [ 'locale' => $locale, 'fullscreen' => $fullScreen, 'instance' => $instance, 'homeFolder' => $homeFolder, 'relative_path' => $relativePath, 'prefix' => $assetsPath, 'theme' => $theme, 'pathPrefix' => $pathPrefix, 'onlyMimes' => $onlyMimes, ]; return $result; case 'summernote': $result['template'] = '@FMElfinder/Elfinder/summernote.html.twig'; $result['params'] = [ 'locale' => $locale, 'fullscreen' => $fullScreen, 'instance' => $instance, 'homeFolder' => $homeFolder, 'relative_path' => $relativePath, 'prefix' => $assetsPath, 'theme' => $theme, 'pathPrefix' => $pathPrefix, 'onlyMimes' => $onlyMimes, ]; return $result; case 'tinymce': $result['template'] = '@FMElfinderBundle/Elfinder/tinymce.html.twig'; $result['params'] = [ 'locale' => $locale, 'tinymce_popup_path' => $parameters['tinymce_popup_path'], 'instance' => $instance, 'homeFolder' => $homeFolder, 'prefix' => $assetsPath, 'theme' => $theme, 'pathPrefix' => $pathPrefix, 'onlyMimes' => $onlyMimes, ]; return $result; case 'tinymce4': $result['template'] = '@FMElfinder/Elfinder/tinymce4.html.twig'; $result['params'] = [ 'locale' => $locale, 'instance' => $instance, 'homeFolder' => $homeFolder, 'relative_path' => $relativePath, 'prefix' => $assetsPath, 'theme' => $theme, 'pathPrefix' => $pathPrefix, 'onlyMimes' => $onlyMimes, ]; return $result; case 'fm_tinymce': $result['template'] = '@FMElfinder/Elfinder/fm_tinymce.html.twig'; $result['params'] = [ 'locale' => $locale, 'instance' => $instance, 'homeFolder' => $homeFolder, 'relative_path' => $relativePath, 'prefix' => $assetsPath, 'theme' => $theme, 'pathPrefix' => $pathPrefix, 'onlyMimes' => $onlyMimes, ]; return $result; case 'form': $result['template'] = '@FMElfinder/Elfinder/elfinder_type.html.twig'; $result['params'] = [ 'locale' => $locale, 'fullscreen' => $fullScreen, 'instance' => $instance, 'homeFolder' => $homeFolder, 'id' => $formTypeId, 'relative_path' => $relativePath, 'prefix' => $assetsPath, 'theme' => $theme, 'pathPrefix' => $pathPrefix, 'onlyMimes' => $onlyMimes, ]; return $result; default: $result['template'] = '@FMElfinder/Elfinder/simple.html.twig'; $result['params'] = [ 'locale' => $locale, 'fullscreen' => $fullScreen, 'instance' => $instance, 'homeFolder' => $homeFolder, 'prefix' => $assetsPath, 'onlyMimes' => $onlyMimes, 'theme' => $theme, 'pathPrefix' => $pathPrefix, ]; return $result; } } } ================================================ FILE: src/DependencyInjection/Compiler/ElFinderConfigurationPass.php ================================================ hasDefinition('event_dispatcher') && !$container->hasAlias('event_dispatcher')) { return; } $listeners = $container->findTaggedServiceIds('fm_elfinder.listener'); $subscribers = $container->findTaggedServiceIds('fm_elfinder.subscriber'); foreach ($listeners as $serviceId => $tags) { @trigger_error('Using "fm_elfinder.listener" tag is deprecated, use "kernel.event_listener" instead.', E_USER_DEPRECATED); } foreach ($subscribers as $serviceId => $tags) { @trigger_error('Using "fm_elfinder.subscriber" tag is deprecated, use "kernel.event_subscriber" instead.', E_USER_DEPRECATED); } if (count($listeners) > 0 || count($subscribers) > 0) { $pass = new RegisterListenersPass('event_dispatcher', 'fm_elfinder.listener', 'fm_elfinder.subscriber'); $pass->process($container); } } } ================================================ FILE: src/DependencyInjection/Compiler/TwigFormPass.php ================================================ hasParameter('twig.form.resources')) { return; } $container->setParameter('twig.form.resources', array_merge( ['@FMElfinder/Form/elfinder_widget.html.twig'], $container->getParameter('twig.form.resources') )); } } ================================================ FILE: src/DependencyInjection/Configuration.php ================================================ getRootNode(); $rootNode ->fixXmlConfig('instance') ->children() ->scalarNode('configuration_provider')->defaultValue('fm_elfinder.configurator.default')->end() ->scalarNode('assets_path')->defaultValue('assets')->end() ->scalarNode('loader')->defaultValue('fm_elfinder.loader.default')->end() ->arrayNode('instances') ->isRequired() ->requiresAtLeastOneElement() ->useAttributeAsKey('name') ->prototype('array') ->children() ->scalarNode('locale')->defaultNull()->end() ->booleanNode('cors_support')->defaultFalse()->end() ->scalarNode('editor')->defaultValue('simple')->end() ->scalarNode('editor_template')->defaultNull()->end() ->booleanNode('fullscreen')->defaultTrue()->end() ->booleanNode('multi_home_folder')->defaultFalse()->end() ->scalarNode('folder_separator')->defaultValue('')->end() ->scalarNode('theme')->defaultValue('smoothness')->end() // jQuery UI theme name ->scalarNode('tinymce_popup_path')->defaultValue('')->end() ->booleanNode('relative_path')->defaultTrue()->end() ->scalarNode('path_prefix')->defaultValue('/')->end() ->arrayNode('where_is_multi') ->beforeNormalization() ->ifTrue(function ($v) { return is_string($v); }) ->then(function ($v) { return array_map('trim', explode(',', $v)); }) ->end() ->prototype('scalar')->end() ->defaultValue([]) ->end() ->arrayNode('visible_mime_types') ->beforeNormalization() ->ifTrue(function ($v) { return is_string($v); }) ->then(function ($v) { return array_map('trim', explode(',', $v)); }) ->end() ->prototype('scalar')->end() ->defaultValue([]) ->end() ->arrayNode('connector') ->addDefaultsIfNotSet() ->fixXmlConfig('root') ->children() ->booleanNode('debug')->defaultFalse()->end() ->append($this->createBindsNode()) ->append($this->createPluginsNode()) ->arrayNode('roots') ->useAttributeAsKey('name') ->isRequired() ->requiresAtLeastOneElement() ->prototype('array') ->children() ->scalarNode('driver') ->isRequired() ->end() // driver ->integerNode('volume_id')->defaultValue(0)->min(0)->end() ->scalarNode('path')->defaultValue('')->end() ->booleanNode('autoload')->defaultFalse()->end() ->scalarNode('phash')->defaultValue('')->end() ->scalarNode('trash_hash')->defaultValue('')->end() ->scalarNode('locale')->defaultValue('')->end() ->booleanNode('i18n_folder_name')->defaultFalse()->end() ->scalarNode('mime_detect')->defaultValue('auto')->end() ->scalarNode('mimefile')->defaultValue('')->end() ->scalarNode('security_voter')->defaultValue('')->end() ->scalarNode('start_path')->defaultValue('')->end() ->scalarNode('encoding')->defaultValue('UTF-8')->end() ->scalarNode('url')->defaultValue('')->end() ->scalarNode('alias')->defaultValue('')->end() ->scalarNode('img_lib')->defaultValue('auto')->end() ->scalarNode('tmb_path')->defaultValue('.tmb')->end() ->scalarNode('tmb_path_mode')->defaultValue(0777)->end() ->scalarNode('tmb_url')->defaultValue('')->end() ->integerNode('tmb_size')->defaultValue(48)->end() ->booleanNode('tmb_crop')->defaultTrue()->end() ->scalarNode('tmb_bg_color')->defaultValue('#ffffff')->end() ->scalarNode('quarantine')->defaultNull()->end() ->booleanNode('copy_overwrite')->defaultTrue()->end() ->booleanNode('copy_join')->defaultTrue()->end() ->booleanNode('copy_from')->defaultTrue()->end() ->booleanNode('copy_to')->defaultTrue()->end() ->booleanNode('upload_overwrite')->defaultTrue()->end() ->scalarNode('fileMode')->defaultValue(0644)->end() ->arrayNode('upload_allow') ->beforeNormalization() ->ifTrue(function ($v) { return is_string($v); }) ->then(function ($v) { return array_map('trim', explode(',', $v)); }) ->end() ->prototype('scalar')->end() ->defaultValue(['image']) ->end() // upload_allow ->arrayNode('upload_deny') ->beforeNormalization() ->ifTrue(function ($v) { return is_string($v); }) ->then(function ($v) { return array_map('trim', explode(',', $v)); }) ->end() ->prototype('scalar')->end() ->defaultValue(['all']) ->end() // upload_deny ->arrayNode('upload_order') ->beforeNormalization() ->ifTrue(function ($v) { return is_string($v); }) ->then(function ($v) { return array_map('trim', explode(',', $v)); }) ->end() ->prototype('scalar')->end() ->defaultValue(['deny', 'allow']) ->end() // upload_order ->scalarNode('upload_max_size')->defaultValue(0)->end() ->integerNode('upload_max_conn')->defaultValue(3)->end() ->arrayNode('defaults') ->useAttributeAsKey('defaults') ->normalizeKeys(false) ->prototype('boolean')->end() ->defaultValue(['read' => true, 'write' => true]) ->end() // defaults ->arrayNode('attributes') ->prototype('array') ->children() ->scalarNode('pattern')->end() ->scalarNode('read')->defaultValue(true)->end() ->scalarNode('write')->defaultValue(true)->end() ->scalarNode('locked')->defaultValue(false)->end() ->scalarNode('hidden')->defaultValue(false)->end() ->end() ->end() ->defaultValue([]) ->end() // attributes ->scalarNode('accepted_name')->defaultValue('/^\w[\w\s\.\%\-]*$/u')->end() ->booleanNode('show_hidden')->defaultFalse()->end() ->arrayNode('disabled_commands') ->beforeNormalization() ->ifTrue(function ($v) { return is_string($v); }) ->then(function ($v) { return array_map('trim', explode(',', $v)); }) ->end() ->prototype('scalar')->end() ->defaultValue([]) ->end() // disabled_commands ->integerNode('tree_deep')->defaultValue(0)->end() ->integerNode('check_subfolders')->defaultValue(1)->end() ->scalarNode('separator')->defaultValue(DIRECTORY_SEPARATOR)->end() ->scalarNode('date_format')->defaultValue('j M Y H:i')->end() ->scalarNode('time_format')->defaultValue('H:i')->end() ->arrayNode('archive_mimes') ->beforeNormalization() ->ifTrue(function ($v) { return is_string($v); }) ->then(function ($v) { return array_map('trim', explode(',', $v)); }) ->end() ->prototype('scalar')->end() ->defaultValue([]) ->end() // archive_mimes ->arrayNode('archivers') ->canBeEnabled() ->children() ->arrayNode('create') ->prototype('array') ->children() ->scalarNode('cmd')->end() ->scalarNode('argc')->end() ->scalarNode('ext')->end() ->end() ->end() ->end() ->arrayNode('extract') ->prototype('array') ->children() ->scalarNode('cmd')->end() ->scalarNode('argc')->end() ->scalarNode('ext')->end() ->end() ->end() ->end() ->end() ->end() // archivers ->arrayNode('flysystem') ->canBeEnabled() ->children() ->scalarNode('filesystem')->defaultValue('')->end() ->scalarNode('type')->defaultValue('')->end() ->scalarNode('adapter_service')->defaultValue('')->end() ->append($this->createFlysystemNode()) ->end() ->end() ->scalarNode('glide_url')->defaultValue('')->end() ->scalarNode('glide_key')->defaultValue('')->end() ->append($this->createPluginsNode()) ->append($this->createDriverOptionsNode()) ->arrayNode('dropbox2_settings') ->canBeEnabled() ->children() ->scalarNode('app_key')->end() ->scalarNode('app_secret')->end() ->scalarNode('access_token')->end() ->scalarNode('aliasFormat')->defaultValue('%s@Dropbox')->end() ->scalarNode('path')->defaultValue('/')->end() ->scalarNode('separator')->defaultValue('/')->end() ->scalarNode('acceptedName')->defaultValue('%s@Dropbox')->end() ->scalarNode('rootCssClass')->defaultValue('elfinder-navbar-root-dropbox')->end() ->arrayNode('publishPermission') ->children() ->scalarNode('requested_visibility')->defaultValue('public')->end() ->end() ->end() ->scalarNode('getThumbSize')->defaultValue('medium')->end() ->end() ->end() ->arrayNode('box_settings') ->canBeEnabled() ->children() ->scalarNode('client_id')->end() ->scalarNode('client_secret')->end() ->scalarNode('accessToken')->end() ->scalarNode('root')->defaultValue('Box.com')->end() ->scalarNode('path')->defaultValue('/')->end() ->scalarNode('separator')->defaultValue('/')->end() ->scalarNode('tmbPath')->defaultValue('')->end() ->scalarNode('tmbURL')->defaultValue('')->end() ->scalarNode('tmpPath')->defaultValue('')->end() ->scalarNode('acceptedName')->defaultValue('#^[^/\\?*:|"<>]*[^./\\?*:|"<>]$#')->end() ->scalarNode('rootCssClass')->defaultValue('elfinder-navbar-root-box')->end() ->end() ->end() ->arrayNode('onedrive_settings') ->canBeEnabled() ->children() ->scalarNode('client_id')->end() ->scalarNode('client_secret')->end() ->scalarNode('accessToken')->end() ->scalarNode('root')->defaultValue('OneDrive.com')->end() ->scalarNode('OneDriveApiClient')->defaultValue('')->end() ->scalarNode('path')->defaultValue('/')->end() ->scalarNode('separator')->defaultValue('/')->end() ->scalarNode('tmbPath')->defaultValue('')->end() ->scalarNode('tmbURL')->defaultValue('')->end() ->scalarNode('tmpPath')->defaultValue('')->end() ->scalarNode('acceptedName')->defaultValue('#^[^/\\?*:|"<>]*[^./\\?*:|"<>]$#')->end() ->scalarNode('rootCssClass')->defaultValue('elfinder-navbar-root-onedrive')->end() ->booleanNode('useApiThumbnail')->defaultTrue()->end() ->end() ->end() ->arrayNode('ftp_settings') ->canBeEnabled() ->children() ->scalarNode('host')->end() ->scalarNode('user')->end() ->scalarNode('password')->end() ->scalarNode('path')->end() ->end() ->end() ->arrayNode('mysql_settings') ->canBeEnabled() ->children() ->scalarNode('host')->end() ->scalarNode('user')->end() ->scalarNode('pass')->end() ->scalarNode('db')->end() ->scalarNode('port')->defaultNull()->end() ->scalarNode('socket')->defaultNull()->end() ->scalarNode('files_table')->defaultValue('elfinder_file')->end() ->scalarNode('tmbPath')->defaultValue('')->end() ->scalarNode('tmpPath')->defaultValue('')->end() ->scalarNode('rootCssClass')->defaultValue('elfinder-navbar-root-sql')->end() ->scalarNode('noSessionCache')->defaultValue('hasdirs')->end() ->end() ->end() ->end() ->end() ->end() ->end() ->end() ->end(); return $treeBuilder; } /** * @return NodeDefinition the Flysystem node */ private function createFlysystemNode() { return $this->createNode('options') ->children() ->arrayNode('local') ->canBeEnabled() ->children() ->scalarNode('path')->defaultvalue('')->end() ->end() ->end() ->arrayNode('ftp') ->canBeEnabled() ->children() ->scalarNode('host')->defaultValue('')->end() ->scalarNode('username')->defaultValue('')->end() ->scalarNode('password')->defaultValue('')->end() ->integerNode('port')->defaultValue(21)->end() ->booleanNode('passive')->defaultTrue()->end() ->booleanNode('ssl')->defaultTrue()->end() ->integerNode('timeout')->defaultValue(30)->end() ->scalarNode('root')->defaultValue('/')->end() ->integerNode('directoryPerm')->defaultValue(0744)->end() ->end() ->end() ->arrayNode('sftp') ->canBeEnabled() ->children() ->scalarNode('host')->defaultValue('')->end() ->scalarNode('username')->defaultValue('')->end() ->scalarNode('password')->defaultValue('')->end() ->integerNode('port')->defaultValue(21)->end() ->scalarNode('privateKey')->defaultValue('')->end() ->integerNode('timeout')->defaultValue(10)->end() ->scalarNode('root')->defaultValue('/')->end() ->end() ->end() ->arrayNode('azure') ->canBeEnabled() ->children() ->scalarNode('account_name')->defaultvalue('')->end() ->scalarNode('account_key')->defaultvalue('')->end() ->scalarNode('container_name')->defaultvalue('')->end() ->end() ->end() ->arrayNode('aws_s3_v2') ->canBeEnabled() ->children() ->scalarNode('key')->defaultvalue('')->end() ->scalarNode('secret')->defaultvalue('')->end() ->scalarNode('region')->defaultvalue('')->end() ->scalarNode('bucket_name')->defaultvalue('')->end() ->scalarNode('optional_prefix')->defaultvalue('')->end() ->scalarNode('base_url')->defaultvalue('')->end() ->end() ->end() ->arrayNode('aws_s3_v3') ->canBeEnabled() ->children() ->scalarNode('key')->defaultvalue('')->end() ->scalarNode('secret')->defaultvalue('')->end() ->scalarNode('region')->defaultvalue('')->end() ->scalarNode('version')->defaultvalue('')->end() ->scalarNode('bucket_name')->defaultvalue('')->end() ->scalarNode('optional_prefix')->defaultvalue('')->end() ->scalarNode('endpoint')->defaultNull()->end() ->booleanNode('use_path_style_endpoint')->defaultFalse()->end() ->booleanNode('use_aws_shared_config_files')->defaultTrue()->end() ->arrayNode('options') ->canBeEnabled() ->children() ->scalarNode('ACL')->defaultvalue('')->end() ->end() ->end() ->end() ->end() ->arrayNode('copy_com') ->canBeEnabled() ->children() ->scalarNode('consumer_key')->defaultvalue('')->end() ->scalarNode('consumer_secret')->defaultvalue('')->end() ->scalarNode('access_token')->defaultvalue('')->end() ->scalarNode('token_secret')->defaultvalue('')->end() ->scalarNode('optional_prefix')->defaultvalue('')->end() ->end() ->end() ->arrayNode('gridfs') ->canBeEnabled() ->children() ->scalarNode('db_name')->defaultvalue('')->end() ->end() ->end() ->arrayNode('zip') ->canBeEnabled() ->children() ->scalarNode('path')->defaultvalue('')->end() ->end() ->end() ->arrayNode('dropbox') ->canBeEnabled() ->children() ->scalarNode('app')->defaultvalue('')->end() ->scalarNode('token')->defaultvalue('')->end() ->end() ->end() ->arrayNode('rackspace') ->canBeEnabled() ->children() ->scalarNode('username')->defaultValue('')->end() ->scalarNode('apikey')->defaultValue('')->end() ->scalarNode('endpoint')->defaultValue('')->end() ->scalarNode('container')->defaultValue('')->end() ->scalarNode('region')->defaultValue('')->end() ->end() ->end() ->end(); } /** * @return NodeDefinition the plugins node */ private function createPluginsNode() { return $this->createNode('plugins') ->useAttributeAsKey('name') ->prototype('array') ->useAttributeAsKey('name') ->prototype('variable')->end() ->end(); } /** * @return NodeDefinition the bind node */ private function createBindsNode() { return $this->createNode('binds') ->useAttributeAsKey('name') ->prototype('array') ->useAttributeAsKey('name') ->prototype('variable')->end() ->end(); } /** * @return NodeDefinition the bind node */ private function createDriverOptionsNode() { return $this->createNode('driver_options') ->useAttributeAsKey('name') ->prototype('array') ->useAttributeAsKey('name') ->prototype('variable')->end() ->end(); } /** * @param string $name the node name * * @return NodeDefinition the node */ private function createNode($name) { $treeBuilder = new TreeBuilder($name); if (method_exists($treeBuilder, 'getRootNode')) { $rootNode = $treeBuilder->getRootNode(); } else { $rootNode = $treeBuilder->root($name); } return $rootNode; } } ================================================ FILE: src/DependencyInjection/FMElfinderExtension.php ================================================ processConfiguration(new Configuration(), $configs); $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../../config')); $loader->load('elfinder.yaml'); $loader->load('form.yaml'); $loader->load('command.yaml'); $container->setParameter('fm_elfinder', $config); $repo = $container->getDefinition(ElFinderController::class); $repo->replaceArgument(1, $config); $container->setAlias('fm_elfinder.configurator', $config['configuration_provider']); $container->setAlias('fm_elfinder.loader', $config['loader']); $container->getAlias('fm_elfinder.loader')->setPublic(true); } public function getNamespace(): string { return 'http://helios-ag.github.io/schema/dic/fm_elfinder'; } } ================================================ FILE: src/ElFinder/ElFinder.php ================================================ =')) { ini_set('internal_encoding', 'UTF-8'); ini_set('default_charset', 'UTF-8'); } // define accept constant of server commands path !defined('ELFINDER_TAR_PATH') && define('ELFINDER_TAR_PATH', 'tar'); !defined('ELFINDER_GZIP_PATH') && define('ELFINDER_GZIP_PATH', 'gzip'); !defined('ELFINDER_BZIP2_PATH') && define('ELFINDER_BZIP2_PATH', 'bzip2'); !defined('ELFINDER_XZ_PATH') && define('ELFINDER_XZ_PATH', 'xz'); !defined('ELFINDER_ZIP_PATH') && define('ELFINDER_ZIP_PATH', 'zip'); !defined('ELFINDER_UNZIP_PATH') && define('ELFINDER_UNZIP_PATH', 'unzip'); !defined('ELFINDER_RAR_PATH') && define('ELFINDER_RAR_PATH', 'rar'); !defined('ELFINDER_UNRAR_PATH') && define('ELFINDER_UNRAR_PATH', 'unrar'); !defined('ELFINDER_7Z_PATH') && define('ELFINDER_7Z_PATH', ('WIN' === substr(PHP_OS, 0, 3)) ? '7z' : '7za'); !defined('ELFINDER_CONVERT_PATH') && define('ELFINDER_CONVERT_PATH', 'convert'); !defined('ELFINDER_EXIFTRAN_PATH') && define('ELFINDER_EXIFTRAN_PATH', 'exiftran'); !defined('ELFINDER_JPEGTRAN_PATH') && define('ELFINDER_JPEGTRAN_PATH', 'jpegtran'); !defined('ELFINDER_FFMPEG_PATH') && define('ELFINDER_FFMPEG_PATH', 'ffmpeg'); !defined('ELFINDER_IMAGEMAGICK_PS') && define('ELFINDER_IMAGEMAGICK_PS', false); // for backward compat $this->version = (string) self::$ApiVersion; // set error handler of WARNING, NOTICE $errLevel = E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE | E_RECOVERABLE_ERROR; if (defined('E_DEPRECATED')) { $errLevel |= E_DEPRECATED | E_USER_DEPRECATED; } set_error_handler(elFinder::phpErrorHandler(...), $errLevel); // Associative array of files to delete at the end of script: ['temp file path' => true] $GLOBALS['elFinderTempFiles'] = []; // regist Shutdown function register_shutdown_function(['elFinder', 'onShutdown']); // convert PATH_INFO to GET query if (!empty($_SERVER['PATH_INFO'])) { $_ps = explode('/', trim($_SERVER['PATH_INFO'], '/')); if (!isset($_GET['cmd'])) { $_cmd = $_ps[0]; if (isset($this->commands[$_cmd])) { $_GET['cmd'] = $_cmd; $_i = 1; foreach (array_keys($this->commands[$_cmd]) as $_k) { if (isset($_ps[$_i])) { if (!isset($_GET[$_k])) { $_GET[$_k] = $_ps[$_i]; } } else { break; } } } } } // set elFinder instance self::$instance = $this; // setup debug mode $this->debug = (isset($opts['debug']) && $opts['debug'] ? true : false); if ($this->debug) { error_reporting(defined('ELFINDER_DEBUG_ERRORLEVEL') ? ELFINDER_DEBUG_ERRORLEVEL : -1); ini_set('diaplay_errors', '1'); // clear output buffer and stop output filters while (ob_get_level() && ob_end_clean()) { } } if (!interface_exists('elFinderSessionInterface')) { include_once dirname(__FILE__) . '/elFinderSessionInterface.php'; } // session handler if (!empty($opts['session']) && $opts['session'] instanceof elFinderSessionInterface) { $this->session = $opts['session']; } else { $sessionOpts = [ 'base64encode' => !empty($opts['base64encodeSessionData']), 'keys' => [ 'default' => !empty($opts['sessionCacheKey']) ? $opts['sessionCacheKey'] : 'elFinderCaches', 'netvolume' => !empty($opts['netVolumesSessionKey']) ? $opts['netVolumesSessionKey'] : 'elFinderNetVolumes', ], ]; $this->session = new elFinderSession($sessionOpts); } // try session start | restart $this->session->start(); $sessionUseCmds = []; if (isset($opts['sessionUseCmds']) && is_array($opts['sessionUseCmds'])) { $sessionUseCmds = $opts['sessionUseCmds']; } // set self::$volumesCnt by HTTP header "X-elFinder-VolumesCntStart" if (isset($_SERVER['HTTP_X_ELFINDER_VOLUMESCNTSTART']) && ($volumesCntStart = intval($_SERVER['HTTP_X_ELFINDER_VOLUMESCNTSTART']))) { self::$volumesCnt = $volumesCntStart; } $this->time = $this->utime(); $this->sessionCloseEarlier = isset($opts['sessionCloseEarlier']) ? (bool) $opts['sessionCloseEarlier'] : true; $this->sessionUseCmds = array_flip($sessionUseCmds); $this->timeout = ($opts['timeout'] ?? 0); $this->uploadTempPath = ($opts['uploadTempPath'] ?? ''); $this->callbackWindowURL = ($opts['callbackWindowURL'] ?? ''); $this->maxTargets = (isset($opts['maxTargets']) ? intval($opts['maxTargets']) : $this->maxTargets); self::$commonTempPath = ($opts['commonTempPath'] ?? './.tmp'); if (!is_writable(self::$commonTempPath)) { self::$commonTempPath = sys_get_temp_dir(); if (!is_writable(self::$commonTempPath)) { self::$commonTempPath = ''; } } if (isset($opts['connectionFlagsPath']) && is_writable($opts['connectionFlagsPath'])) { self::$connectionFlagsPath = $opts['connectionFlagsPath']; } else { self::$connectionFlagsPath = self::$commonTempPath; } if (!empty($opts['tmpLinkPath'])) { self::$tmpLinkPath = $opts['tmpLinkPath']; } if (!empty($opts['tmpLinkUrl'])) { self::$tmpLinkUrl = $opts['tmpLinkUrl']; } if (!empty($opts['tmpLinkLifeTime'])) { self::$tmpLinkLifeTime = $opts['tmpLinkLifeTime']; } if (!empty($opts['textMimes']) && is_array($opts['textMimes'])) { self::$textMimes = $opts['textMimes']; } $this->maxArcFilesSize = isset($opts['maxArcFilesSize']) ? intval($opts['maxArcFilesSize']) : 0; $this->optionsNetVolumes = (isset($opts['optionsNetVolumes']) && is_array($opts['optionsNetVolumes'])) ? $opts['optionsNetVolumes'] : []; if (isset($opts['itemLockExpire'])) { $this->itemLockExpire = intval($opts['itemLockExpire']); } // deprecated settings $this->netVolumesSessionKey = !empty($opts['netVolumesSessionKey']) ? $opts['netVolumesSessionKey'] : 'elFinderNetVolumes'; self::$sessionCacheKey = !empty($opts['sessionCacheKey']) ? $opts['sessionCacheKey'] : 'elFinderCaches'; // check session cache $_optsMD5 = md5(json_encode($opts['roots'])); if ($this->session->get('_optsMD5') !== $_optsMD5) { $this->session->set('_optsMD5', $_optsMD5); } // setlocale and global locale regists to elFinder::locale self::$locale = !empty($opts['locale']) ? $opts['locale'] : ('WIN' === substr(PHP_OS, 0, 3) ? 'C' : 'en_US.UTF-8'); if (false === setlocale(LC_ALL, self::$locale)) { self::$locale = setlocale(LC_ALL, '0'); } // set defaultMimefile self::$defaultMimefile = ($opts['defaultMimefile'] ?? ''); // bind events listeners if (!empty($opts['bind']) && is_array($opts['bind'])) { $_req = 'POST' == $_SERVER['REQUEST_METHOD'] ? $_POST : $_GET; $_reqCmd = $_req['cmd'] ?? ''; foreach ($opts['bind'] as $cmd => $handlers) { $doRegist = (false !== strpos($cmd, '*')); if (!$doRegist) { $doRegist = ($_reqCmd && in_array($_reqCmd, array_map(elFinder::getCmdOfBind(...), explode(' ', $cmd)))); } if ($doRegist) { // for backward compatibility if (!is_array($handlers)) { $handlers = [$handlers]; } else { if (2 === count($handlers) && is_object($handlers[0])) { $handlers = [$handlers]; } } foreach ($handlers as $handler) { if ($handler) { if (is_string($handler) && strpos($handler, '.')) { [$_domain, $_name, $_method] = array_pad(explode('.', $handler), 3, ''); if (0 === strcasecmp($_domain, 'plugin')) { if ($plugin = $this->getPluginInstance($_name, $opts['plugin'][$_name] ?? []) and method_exists($plugin, $_method)) { $this->bind($cmd, $plugin->$_method(...)); } } } else { $this->bind($cmd, $handler); } } } } } } if (!isset($opts['roots']) || !is_array($opts['roots'])) { $opts['roots'] = []; } // check for net volumes stored in session $netVolumes = $this->getNetVolumes(); foreach ($netVolumes as $key => $root) { if (!isset($root['id'])) { // given fixed unique id if (!$root['id'] = $this->getNetVolumeUniqueId($netVolumes)) { $this->mountErrors[] = 'Netmount Driver "' . $root['driver'] . '" : Could\'t given volume id.'; continue; } } $opts['roots'][$key] = $root; } $this->mountVolumes($opts); // if at least one readable volume - ii desu >_< $this->loaded = !empty($this->default); // restore error handler for now restore_error_handler(); } /** * Mount volumes. * * Instantiate corresponding driver class and * add it to the list of volumes. * * @param array $opts */ protected function mountVolumes($opts) { foreach ($opts['roots'] as $i => $o) { $class = 'elFinderVolume' . ($o['driver'] ?? ''); if (class_exists($class)) { $volume = new $class(); try { if ($this->maxArcFilesSize && (empty($o['maxArcFilesSize']) || $this->maxArcFilesSize < $o['maxArcFilesSize'])) { $o['maxArcFilesSize'] = $this->maxArcFilesSize; } // pass session handler $volume->setSession($this->session); if ($volume->mount($o)) { // unique volume id (ends on "_") - used as prefix to files hash $id = $volume->id(); $this->volumes[$id] = $volume; if ((!$this->default || $volume->root() !== $volume->defaultPath()) && $volume->isReadable()) { $this->default = $this->volumes[$id]; } } else { $this->removeNetVolume($i, $volume); $this->mountErrors[] = 'Driver "' . $class . '" : ' . implode(' ', $volume->error()); } } catch (Exception $e) { $this->removeNetVolume($i, $volume); $this->mountErrors[] = 'Driver "' . $class . '" : ' . $e->getMessage(); } } else { $this->removeNetVolume($i, $volume); $this->mountErrors[] = 'Driver "' . $class . '" does not exist'; } } } } ================================================ FILE: src/Event/ElFinderPostExecutionEvent.php ================================================ result = $result; } /** * Tells if execution has encountered errors. */ public function hasErrors(): bool { return isset($this->result['error']); } public function getResult(): array { return $this->result; } public function setResult(array $result): void { $this->result = $result; } } ================================================ FILE: src/Event/ElFinderPreExecutionEvent.php ================================================ request = $request; $this->httpKernel = $httpKernel; $this->instance = $instance; $this->homeFolder = $homeFolder; } /** * Makes a sub request to elFinder. * Function based on 'forward' function from Symfony controllers. * * @see https://github.com/symfony/symfony/blob/2.5/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php * * @param array $path An array of path parameters * @param array $query An array of query parameters * * @return \Symfony\Component\HttpFoundation\Response A Response instance */ public function subRequest(array $path, array $query) { $path['_controller'] = 'FMElfinderBundle:ElFinder:load'; $subRequest = $this->request->duplicate($query, null, $path); return $this->httpKernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST); } /** * Returns executed command. */ public function getCommand(): string { return $this->request->query->get('cmd'); } public function getRequest(): Request { return $this->request; } public function getInstance(): string { return $this->instance; } public function getHomeFolder(): string { return $this->homeFolder; } } ================================================ FILE: src/FMElfinderBundle.php ================================================ addCompilerPass(new TwigFormPass()); $container->addCompilerPass(new ElFinderConfigurationPass()); } } ================================================ FILE: src/Form/Type/ElFinderType.php ================================================ setAttribute('enable', $options['enable']); if ($builder->getAttribute('enable')) { $builder->setAttribute('instance', $options['instance']); } $builder->setAttribute('homeFolder', $options['homeFolder']); } /** * {@inheritdoc} */ public function buildView(FormView $view, FormInterface $form, array $options): void { $view->vars['enable'] = $options['enable']; if ($options['enable']) { $view->vars['instance'] = $options['instance']; $view->vars['homeFolder'] = $options['homeFolder']; } } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver): void { $resolver ->setDefaults([ 'enable' => true, 'instance' => 'default', 'homeFolder' => '', ]) ->setAllowedTypes('enable', 'bool') ->setAllowedTypes('instance', ['string', 'null']) ->setAllowedTypes('homeFolder', ['string', 'null']); } /** * {@inheritdoc} */ public function getParent(): ?string { if (method_exists('Symfony\Component\Form\AbstractType', 'getBlockPrefix')) { return 'Symfony\Component\Form\Extension\Core\Type\TextType'; } return 'text'; } /** * {@inheritdoc} */ public function getName(): string { return $this->getBlockPrefix(); } /** * {@inheritdoc} */ public function getBlockPrefix(): string { return 'elfinder'; } } ================================================ FILE: src/Loader/ElFinderLoader.php ================================================ configurator = $configurator; } /** * @throws Exception */ public function configure(): array { $configurator = $this->configurator; return $configurator->getConfiguration($this->instance); } /** * Configure the Bridge to ElFinder. * @throws Exception */ public function initBridge(string $instance, array $efParameters): void { $this->setInstance($instance); $arrayInstance = $efParameters['instances'][$instance]; $whereIsMulti = $arrayInstance['where_is_multi']; $multiHome = $arrayInstance['multi_home_folder']; $separator = $arrayInstance['folder_separator']; $this->config = $this->configure(); if (count($whereIsMulti) > 0) { foreach ($whereIsMulti as $key => $value) { if ($multiHome) { $this->config[$key][$value]['path'] = str_replace($separator, '/', $this->config[$key][$value]['path']); $this->config[$key][$value]['URL'] = str_replace($separator, '/', $this->config[$key][$value]['URL']); } } } $this->bridge = new ElFinderBridge($this->config); if ($this->session) { $this->bridge->setSession($this->session); } } /** * Starts ElFinder. */ public function load(Request $request): array|string { $connector = new ElFinderConnector($this->bridge); if ($this->config['corsSupport']) { return $connector->execute($request->query->all()); } return $connector->run($request->query->all()); } public function setInstance(string $instance): void { $this->instance = $instance; } public function setConfigurator(ElFinderConfigurationProviderInterface $configurator): void { $this->configurator = $configurator; } /** * Encode path into hash. */ public function encode(string $path): mixed { $aPathEncoded = []; $volumes = $this->bridge->getVolumes(); foreach ($volumes as $hashId => $volume) { $aPathEncoded[$hashId] = $volume->getHash($path); } if (1 == count($aPathEncoded)) { return array_values($aPathEncoded)[0]; } elseif (count($aPathEncoded) > 1) { return $aPathEncoded; } return false; } /** * Decode path from hash. */ public function decode(string $hash): string { $volume = $this->bridge->getVolume($hash); /* @var $volume \elFinderVolumeDriver */ return (!empty($volume)) ? $volume->getPath($hash) : false; } public function setSession(?SessionInterface $session): void { $this->session = $session; } } ================================================ FILE: src/Loader/ElFinderLoaderInterface.php ================================================ '); if (opts.nodeId) { elfNode.attr('id', opts.nodeId); delete opts.nodeId; } // upload target folder hash const uploadTargetHash = opts.uploadTargetHash || 'L1_Lw'; delete opts.uploadTargetHash; // get elFinder insrance const getfm = open => { // CSS class name of TinyMCE conntainer const cls = (tinymce.majorVersion < 5)? 'mce-container' : 'tox'; return new Promise((resolve, reject) => { // elFinder instance let elf; // Execute when the elFinder instance is created const done = () => { if (open) { // request to open folder specify if (!Object.keys(elf.files()).length) { // when initial request elf.one('open', () => { elf.file(open)? resolve(elf) : reject(elf, 'errFolderNotFound'); }); } else { // elFinder has already been initialized new Promise((res, rej) => { if (elf.file(open)) { res(); } else { // To acquire target folder information elf.request({cmd: 'parents', target: open}).done(e =>{ elf.file(open)? res() : rej(); }).fail(() => { rej(); }); } }).then(() => { if (elf.cwd().hash == open) { resolve(elf); } else { // Open folder after folder information is acquired elf.exec('open', open).done(() => { resolve(elf); }).fail(err => { reject(elf, err? err : 'errFolderNotFound'); }); } }).catch((err) => { reject(elf, err? err : 'errFolderNotFound'); }); } } else { // show elFinder manager only resolve(elf); } }; // Check elFinder instance if (elf = elfNode.elfinder('instance')) { // elFinder instance has already been created done(); } else { // To create elFinder instance elf = elfNode.dialogelfinder(Object.assign({ // dialog title title : 'File Manager', // start folder setting startPathHash : open? open : void(0), // Set to do not use browser history to un-use location.hash useBrowserHistory : false, // Disable auto open autoOpen : false, // elFinder dialog width width : '90%', // elFinder dialog height height : '90%', // set getfile command options commandsOptions : { getfile: { oncomplete : 'close' } }, bootCallback : (fm) => { // set z-index fm.getUI().css('z-index', parseInt($('body>.'+cls+':last').css('z-index')) + 100); }, getFileCallback : (files, fm) => {} }, opts)).elfinder('instance'); done(); } }); }; this.browser = function(callback, value, meta) { getfm().then(fm => { let cgf = fm.getCommand('getfile'); const regist = () => { fm.options.getFileCallback = cgf.callback = (file, fm) => { var url, reg, info; // URL normalization url = fm.convAbsUrl(file.url); // Make file info info = file.name + ' (' + fm.formatSize(file.size) + ')'; // Provide file and text for the link dialog if (meta.filetype == 'file') { callback(url, {text: info, title: info}); } // Provide image and alt text for the image dialog if (meta.filetype == 'image') { callback(url, {alt: info}); } // Provide alternative source and posted for the media dialog if (meta.filetype == 'media') { callback(url); } }; fm.getUI().dialogelfinder('open'); }; if (cgf) { // elFinder booted regist(); } else { // elFinder booting now fm.bind('init', () => { cgf = fm.getCommand('getfile'); regist(); }); } }); return false; }; this.uploadHandler = function (blobInfo, success, failure) { new Promise(function(resolve, reject) { getfm(uploadTargetHash).then(fm => { let fmNode = fm.getUI(), file = blobInfo.blob(), clipdata = true; const err = (e) => { var dlg = e.data.dialog || {}; if (dlg.hasClass('elfinder-dialog-error') || dlg.hasClass('elfinder-confirm-upload')) { fmNode.dialogelfinder('open'); fm.unbind('dialogopened', err); } }, closeDlg = () => { if (!fm.getUI().find('.elfinder-dialog-error:visible,.elfinder-confirm-upload:visible').length) { fmNode.dialogelfinder('close'); } }; // check file object if (file.name) { // file blob of client side file object clipdata = void(0); } // Bind err function and exec upload fm.bind('dialogopened', err).exec('upload', { files: [file], target: uploadTargetHash, clipdata: clipdata, // to get unique name on connector dropEvt: {altKey: true, ctrlKey: true} // diable watermark on demo site }, void(0), uploadTargetHash) .done(data => { if (data.added && data.added.length) { fm.url(data.added[0].hash, { async: true }).done(function(url) { // prevent to use browser cache url += (url.match(/\?/)? '&' : '?') + '_t=' + data.added[0].ts; resolve(fm.convAbsUrl(url)); }).fail(function() { reject(fm.i18n('errFileNotFound')); }); } else { reject(fm.i18n(data.error? data.error : 'errUpload')); } }) .fail(err => { const error = fm.parseError(err); reject(fm.i18n(error? (error === 'userabort'? 'errAbort' : error) : 'errUploadNoFiles')); }) .always(() => { fm.unbind('dialogopened', err); closeDlg(); }); }).catch((fm, err) => { const error = fm.parseError(err); reject(fm.i18n(error? (error === 'userabort'? 'errAbort' : error) : 'errUploadNoFiles')); }); }).then((url) => { success(url); }).catch((err) => { failure(err); }); }; }; ================================================ FILE: src/Resources/views/Elfinder/ckeditor.html.twig ================================================
================================================ FILE: src/Resources/views/Elfinder/elfinder_type.html.twig ================================================
================================================ FILE: src/Resources/views/Elfinder/fm_tinymce.html.twig ================================================
================================================ FILE: src/Resources/views/Elfinder/helper/_summernote.html.twig ================================================ ================================================ FILE: src/Resources/views/Elfinder/helper/_tinymce.html.twig ================================================ ================================================ FILE: src/Resources/views/Elfinder/helper/_tinymce4.html.twig ================================================ ================================================ FILE: src/Resources/views/Elfinder/helper/_tinymce5.html.twig ================================================ ================================================ FILE: src/Resources/views/Elfinder/helper/main.js.twig ================================================ (function(){ "use strict"; var // jQuery and jQueryUI version jqver = '3.3.1', uiver = '1.12.1', // Detect language (optional) lang = (function() { var locq = window.location.search, map = { 'pt' : 'pt_BR', 'ug' : 'ug_CN', 'zh' : 'zh_CN' }, full = { 'zh_tw' : 'zh_TW', 'zh_cn' : 'zh_CN', 'fr_ca' : 'fr_CA' }, fullLang, locm, lang; if (locq && (locm = locq.match(/lang=([a-zA-Z_-]+)/))) { // detection by url query (?lang=xx) fullLang = locm[1]; } else { // detection by browser language fullLang = (navigator.browserLanguage || navigator.language || navigator.userLanguage || ''); } fullLang = fullLang.replace('-', '_').substr(0,5).toLowerCase(); if (full[fullLang]) { lang = full[fullLang]; } else { lang = (fullLang || 'en').substr(0,2); if (map[lang]) { lang = map[lang]; } } return lang; })(), // Start elFinder (REQUIRED) start = function(elFinder, editors, config) { // load jQueryUI CSS elFinder.prototype.loadCss('//cdnjs.cloudflare.com/ajax/libs/jqueryui/'+uiver+'/themes/smoothness/jquery-ui.css'); $(function() { var optEditors = { commandsOptions: { edit: { editors: Array.isArray(editors)? editors : [] } } }, opts = {}; // Interpretation of "elFinderConfig" if (config && config.managers) { $.each(config.managers, function(id, mOpts) { opts = Object.assign(opts, config.defaultOpts || {}); // editors marges to opts.commandOptions.edit try { mOpts.commandsOptions.edit.editors = mOpts.commandsOptions.edit.editors.concat(editors || []); } catch(e) { Object.assign(mOpts, optEditors); } // Make elFinder $('#' + id).elfinder( // 1st Arg - options $.extend(true, { lang: lang }, opts, mOpts || {}), // 2nd Arg - before boot up function function(fm, extraObj) { // `init` event callback function fm.bind('init', function() { // Optional for Japanese decoder "encoding-japanese" if (fm.lang === 'ja') { require( [ 'encoding-japanese' ], function(Encoding) { if (Encoding && Encoding.convert) { fm.registRawStringDecoder(function(s) { return Encoding.convert(s, {to:'UNICODE',type:'string'}); }); } } ); } }); } ); }); } else { alert('"elFinderConfig" object is wrong.'); } }); }, // JavaScript loader (REQUIRED) load = function() { require([ 'elfinder' , 'extras/editors.default.min' // load text, image editors , 'elFinderConfig' // , 'extras/quicklook.googledocs.min' // optional preview for GoogleApps contents on the GoogleDrive volume ], start, function(error) { alert(error.message); } ); }, // is IE8 or :? for determine the jQuery version to use (optional) old = (typeof window.addEventListener === 'undefined' && typeof document.getElementsByClassName === 'undefined') || (!window.chrome && !document.unqueID && !window.opera && !window.sidebar && 'WebkitAppearance' in document.documentElement.style && document.body.style && typeof document.body.style.webkitFilter === 'undefined'); // config of RequireJS (REQUIRED) require.config({ baseUrl : "{{ mainUrl }}", paths : { 'jquery' : '//cdnjs.cloudflare.com/ajax/libs/jquery/'+(old? '1.12.4' : jqver)+'/jquery.min', 'jquery-ui': '//cdnjs.cloudflare.com/ajax/libs/jqueryui/'+uiver+'/jquery-ui.min', 'elfinder' : 'elfinder.min', 'encoding-japanese': '//cdn.rawgit.com/polygonplanet/encoding.js/1.0.26/encoding.min' }, waitSeconds : 10 // optional }); // load JavaScripts (REQUIRED) load(); })(); ================================================ FILE: src/Resources/views/Elfinder/simple.html.twig ================================================
================================================ FILE: src/Resources/views/Elfinder/summernote.html.twig ================================================
================================================ FILE: src/Resources/views/Elfinder/tinymce.html.twig ================================================
================================================ FILE: src/Resources/views/Elfinder/tinymce4.html.twig ================================================
================================================ FILE: src/Resources/views/Form/elfinder_widget.html.twig ================================================ {% block elfinder_widget %} {% if enable and instance is defined %} {% endif %} {% endblock %} ================================================ FILE: src/Security/ElfinderSecurityInterface.php ================================================ array('rm','delete')); * First items (roles) in array has higher priority. */ public function getConfiguration(): array; } ================================================ FILE: src/Session/ElFinderSession.php ================================================ session = $session; } public function start() { $this->session->start(); } public function close() { $this->session->save(); } public function get($key, $empty = '') { return $this->session->get($key, $empty); } public function set($key, $data) { $this->session->set($key, $data); } public function remove($key) { $this->session->remove($key); } } ================================================ FILE: src/Twig/Extension/FMElfinderExtension.php ================================================ twig = $twig; } /** * {@inheritdoc} * * @return array */ public function getFunctions(): array { $options = ['is_safe' => ['html']]; return [ new TwigFunction('elfinder_tinymce_init', $this->tinymce(...), $options), new TwigFunction('elfinder_tinymce_init4', $this->tinymce4(...), $options), new TwigFunction('elfinder_tinymce_init5', $this->tinymce5(...), $options), new TwigFunction('elfinder_summernote_init', $this->summernote(...), $options), ]; } /** * @throws LoaderError * @throws RuntimeError * @throws SyntaxError */ public function tinymce(string $instance = 'default', array $parameters = ['width' => 900, 'height' => 450, 'title' => 'elFinder 2.0']): string { if (!is_string($instance)) { throw new RuntimeError('The function can be applied to strings only.'); } return $this->twig->render( '@FMElfinder/Elfinder/helper/_tinymce.html.twig', [ 'instance' => $instance, 'width' => $parameters['width'], 'height' => $parameters['height'], 'title' => $parameters['title'], ] ); } /** * @throws LoaderError * @throws RuntimeError * @throws SyntaxError */ public function tinymce4(string $instance = 'default', array $parameters = ['width' => 900, 'height' => 450, 'title' => 'elFinder 2.0']): string { return $this->twig->render( '@FMElfinder/Elfinder/helper/_tinymce4.html.twig', [ 'instance' => $instance, 'width' => $parameters['width'], 'height' => $parameters['height'], 'title' => $parameters['title'], ] ); } public function tinymce5(string $instance = 'default'): string { return $this->twig->render( '@FMElfinder/Elfinder/helper/_tinymce5.html.twig', [ 'instance' => $instance, ] ); } /** * @throws LoaderError * @throws RuntimeError * @throws SyntaxError */ public function summernote( string $instance = 'default', string $selector = '.summernote', array $parameters = ['width' => 900, 'height' => 450, 'title' => 'elFinder 2.0'] ): string { return $this->twig->render( '@FMElfinder/Elfinder/helper/_summernote.html.twig', [ 'instance' => $instance, 'selector' => $selector, 'width' => $parameters['width'], 'height' => $parameters['height'], 'title' => $parameters['title'], ] ); } /** * (non-PHPdoc). * * @see Twig_ExtensionInterface::getName() */ public function getName(): string { return 'fm_elfinder_init'; } } ================================================ FILE: tests/Command/ElFinderInstallerCommandTest.php ================================================ vendorDir = dirname($reflection->getFileName(), 3) . DIRECTORY_SEPARATOR . 'vendor'; $this->projectDir = dirname($this->vendorDir); $this->fileSystem = $this->createMock(Filesystem::class); $this->parameterBag = $this->createMock(ParameterBagInterface::class); $this->parameterBag ->method('get') ->willReturnMap([ ['kernel.project_dir', $this->projectDir] ]); $application = new Application(); $command = new ElFinderInstallerCommand($this->fileSystem, $this->parameterBag); $application->addCommands([$command]); $this->commandTester = new CommandTester($application->find('elfinder:install')); } public function testExecuteWithDefaultDocroot(): void { $this->assertFileSystemOperations('public'); $this->commandTester->execute([]); $this->assertCommandOutput(); $this->assertEquals(0, $this->commandTester->getStatusCode()); } public function testExecuteWithCustomDocroot(): void { $this->assertFileSystemOperations('custom'); $this->commandTester->execute(['--docroot' => 'custom']); $this->assertCommandOutput(); $this->assertEquals(0, $this->commandTester->getStatusCode()); } private function assertFileSystemOperations(string $docroot): void { $expectedCalls = [ [ $this->vendorDir . '/studio-42/elfinder/css', $this->projectDir . "/$docroot/bundles/fmelfinder/css" ], [ $this->vendorDir . '/studio-42/elfinder/img', $this->projectDir . "/$docroot/bundles/fmelfinder/img" ], [ $this->vendorDir . '/studio-42/elfinder/js', $this->projectDir . "/$docroot/bundles/fmelfinder/js" ], [ $this->vendorDir . '/studio-42/elfinder/sounds', $this->projectDir . "/$docroot/bundles/fmelfinder/sounds" ] ]; $callIndex = 0; $this->fileSystem ->expects($this->exactly(4)) ->method('mirror') ->willReturnCallback(function ($source, $target) use (&$callIndex, $expectedCalls) { $this->assertEquals($expectedCalls[$callIndex][0], $source, "Incorrect source path for call $callIndex"); $this->assertEquals($expectedCalls[$callIndex][1], $target, "Incorrect target path for call $callIndex"); $callIndex++; }); } private function assertCommandOutput(): void { $output = $this->commandTester->getDisplay(); $this->assertStringContainsString('elFinder Installer', $output); $this->assertStringContainsString('elFinder assets successfully installed', $output); } } ================================================ FILE: tests/Configuration/ElFinderConfigurationReaderTest.php ================================================ createMock('Symfony\Component\DependencyInjection\ContainerInterface'); $this->elFinderVolumeMock = $this->createMock('\elFinderVolumeLocalFileSystem'); $containerMock ->expects($this->any()) ->method('has') ->willReturn(true); $containerMock ->expects($this->any()) ->method('get') ->willReturnMap([ [ 'elfinder.driver.local', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $this->elFinderVolumeMock, ], ]); /** @var \Symfony\Component\HttpFoundation\RequestStack $requestStack|\PHPUnit_Framework_MockObject_MockObject */ $requestStack = $this->createMock('Symfony\Component\HttpFoundation\RequestStack'); /** @var \Symfony\Component\HttpFoundation\Request $requestObject */ $requestObject = $this->createPartialMock('Symfony\Component\HttpFoundation\Request', ['getScheme', 'getHttpHost', 'getBaseUrl']); $requestObject ->expects($this->any()) ->method('getScheme') ->willReturn('http'); $requestObject ->expects($this->any()) ->method('getHttpHost') ->willReturn('test.com'); $requestObject ->expects($this->any()) ->method('getBaseUrl') ->willReturn('/unit-test'); $requestObject->attributes = $attributesObject; $requestStack ->expects($this->any()) ->method('getCurrentRequest') ->willReturn($requestObject); $params = [ 'instances' => [ 'default' => [ 'cors_support' => '', 'connector' => [ 'debug' => '', 'binds' => '', 'plugins' => '', 'roots' => [ 'uploads' => [ 'flysystem' => ['enabled' => false], 'volume_id' => 0, 'security_voter' => '', 'show_hidden' => false, 'path' => '', 'driver' => 'LocalFileSystem', 'glide_url' => '', 'glide_key' => '', 'plugins' => '', 'start_path' => '', 'encoding' => '', 'alias' => '', 'mime_detect' => '', 'mimefile' => '', 'img_lib' => '', 'tmb_path' => '', 'tmb_path_mode' => '', 'tmb_url' => '', 'tmb_size' => '', 'tmb_crop' => '', 'tmb_bg_color' => '', 'copy_overwrite' => '', 'copy_join' => '', 'copy_from' => '', 'copy_to' => '', 'upload_overwrite' => '', 'upload_allow' => '', 'upload_deny' => '', 'upload_max_size' => '', 'upload_max_conn' => 3, 'defaults' => '', 'attributes' => '', 'accepted_name' => '', 'disabled_commands' => '', 'tree_deep' => '', 'check_subfolders' => '', 'separator' => '', 'time_format' => '', 'archive_mimes' => '', 'archivers' => '', 'fileMode' => '', 'quarantine' => null, 'trash_hash' => null, ], ], ], ], 'with_path_with_url' => [ 'cors_support' => true, 'connector' => [ 'debug' => '', 'binds' => '', 'plugins' => '', 'roots' => [ 'uploads' => [ 'flysystem' => ['enabled' => false], 'volume_id' => 1, 'security_voter' => '', 'show_hidden' => false, 'path' => '/home', 'driver' => 'LocalFileSystem', 'url' => 'home-url', 'glide_url' => '', 'glide_key' => '', 'plugins' => '', 'driver_options' => '', 'start_path' => '', 'encoding' => '', 'alias' => '', 'mime_detect' => '', 'mimefile' => '', 'img_lib' => '', 'tmb_path' => '', 'tmb_path_mode' => '', 'tmb_url' => '', 'tmb_size' => '', 'tmb_crop' => '', 'tmb_bg_color' => '', 'copy_overwrite' => '', 'copy_join' => '', 'copy_from' => '', 'copy_to' => '', 'upload_overwrite' => '', 'upload_allow' => '', 'upload_deny' => '', 'upload_max_size' => '', 'upload_max_conn' => 3, 'defaults' => '', 'attributes' => '', 'accepted_name' => '', 'disabled_commands' => '', 'tree_deep' => '', 'check_subfolders' => '', 'separator' => '', 'time_format' => '', 'archive_mimes' => '', 'archivers' => '', 'fileMode' => '', 'quarantine' => null, 'trash_hash' => null, ], ], ], ], 'without_path_with_url' => [ 'cors_support' => true, 'connector' => [ 'debug' => '', 'binds' => '', 'plugins' => '', 'roots' => [ 'uploads' => [ 'flysystem' => ['enabled' => false], 'volume_id' => 2, 'security_voter' => '', 'show_hidden' => false, 'path' => '', 'driver' => 'LocalFileSystem', 'url' => 'home-url-without-path', 'glide_url' => '', 'glide_key' => '', 'plugins' => '', 'driver_options' => '', 'start_path' => '', 'encoding' => '', 'alias' => '', 'mime_detect' => '', 'mimefile' => '', 'img_lib' => '', 'tmb_path' => '', 'tmb_path_mode' => '', 'tmb_url' => '', 'tmb_size' => '', 'tmb_crop' => '', 'tmb_bg_color' => '', 'copy_overwrite' => '', 'copy_join' => '', 'copy_from' => '', 'copy_to' => '', 'upload_overwrite' => '', 'upload_allow' => '', 'upload_deny' => '', 'upload_max_size' => '', 'upload_max_conn' => 3, 'defaults' => '', 'attributes' => '', 'accepted_name' => '', 'disabled_commands' => '', 'tree_deep' => '', 'check_subfolders' => '', 'separator' => '', 'time_format' => '', 'archive_mimes' => '', 'archivers' => '', 'fileMode' => '', 'quarantine' => null, 'trash_hash' => null, ], ], ], ], 'without_path_with_url_absolute_homeFolder' => [ 'cors_support' => true, 'connector' => [ 'debug' => '', 'binds' => '', 'plugins' => '', 'roots' => [ 'uploads' => [ 'flysystem' => ['enabled' => false], 'volume_id' => 2, 'security_voter' => '', 'show_hidden' => false, 'path' => '', 'driver' => 'LocalFileSystem', 'url' => 'https://test.com/{homeFolder}', 'glide_url' => '', 'glide_key' => '', 'plugins' => '', 'driver_options' => '', 'start_path' => '', 'encoding' => '', 'alias' => '', 'mime_detect' => '', 'mimefile' => '', 'img_lib' => '', 'tmb_path' => '', 'tmb_path_mode' => '', 'tmb_url' => '', 'tmb_size' => '', 'tmb_crop' => '', 'tmb_bg_color' => '', 'copy_overwrite' => '', 'copy_join' => '', 'copy_from' => '', 'copy_to' => '', 'upload_overwrite' => '', 'upload_allow' => '', 'upload_deny' => '', 'upload_max_size' => '', 'upload_max_conn' => 3, 'defaults' => '', 'attributes' => '', 'accepted_name' => '', 'disabled_commands' => '', 'tree_deep' => '', 'check_subfolders' => '', 'separator' => '', 'time_format' => '', 'archive_mimes' => '', 'archivers' => '', 'fileMode' => '', 'quarantine' => null, 'trash_hash' => null, ], ], ], ], ], ]; return new ElFinderConfigurationReader($params, $requestStack, $containerMock); } private function getDefaultAttributesObject() { /** @var \Symfony\Component\HttpFoundation\ParameterBag $attributesObject */ $attributesObject = $this->createMock('\Symfony\Component\HttpFoundation\ParameterBag'); $attributesObject ->expects($this->any()) ->method('get') ->willReturn(''); return $attributesObject; } private function getHomeFolderAwareAttributesObject() { /** @var \Symfony\Component\HttpFoundation\ParameterBag $attributesObject */ $attributesObject = $this->createMock('\Symfony\Component\HttpFoundation\ParameterBag'); $attributesObject ->expects($this->any()) ->method('get') ->with($this->equalTo('homeFolder')) ->willReturn('bob'); return $attributesObject; } public function testConfiguration(): void { $reader = $this->getConfigurationReader($this->getDefaultAttributesObject()); $configuration = $reader->getConfiguration('default'); $this->assertArrayHasKey('roots', $configuration); $this->assertArrayHasKey('corsSupport', $configuration); $this->assertSame('LocalFileSystem', $configuration['roots'][0]['driver']); } public function testSubClassOfHelper(): void { $rc = new \ReflectionClass('FM\ElfinderBundle\Configuration\ElFinderConfigurationReader'); $this->assertTrue($rc->isSubclassOf('FM\ElfinderBundle\Configuration\ElFinderConfigurationProviderInterface')); } public function testAccessHidden(): void { $reader = $this->getConfigurationReader($this->getDefaultAttributesObject()); $hiddenPath = '.hiddenPath'; $this->assertFalse($reader->access('read', $hiddenPath, 'dummy', 'dummy')); $this->assertFalse($reader->access('write', $hiddenPath, 'dummy', 'dummy')); } public function testAccessVisible() { $reader = $this->getConfigurationReader($this->getDefaultAttributesObject()); $visiblePath = 'hiddenPath'; $this->assertNull($reader->access('read', $visiblePath, 'dummy', 'dummy')); $this->assertNull($reader->access('write', $visiblePath, 'dummy', 'dummy')); } public function testPathAndUrlAndHomeFolder(): void { // with path and without homeFolder $reader = $this->getConfigurationReader($this->getDefaultAttributesObject()); $configuration = $reader->getConfiguration('with_path_with_url'); $this->assertEquals('/home', $configuration['roots'][0]['path']); $this->assertEquals('http://test.com/unit-test/home-url', $configuration['roots'][0]['URL']); // with path and with homeFolder $reader = $this->getConfigurationReader($this->getHomeFolderAwareAttributesObject()); $configuration = $reader->getConfiguration('with_path_with_url'); $this->assertEquals('/home/bob', $configuration['roots'][0]['path']); $this->assertEquals('http://test.com/unit-test/home-url/bob', $configuration['roots'][0]['URL']); // without path and without homeFolder $reader = $this->getConfigurationReader($this->getDefaultAttributesObject()); $configuration = $reader->getConfiguration('without_path_with_url'); $this->assertEquals('', $configuration['roots'][0]['path']); $this->assertEquals('http://test.com/unit-test/home-url-without-path', $configuration['roots'][0]['URL']); // without path and with homeFolder $reader = $this->getConfigurationReader($this->getHomeFolderAwareAttributesObject()); $configuration = $reader->getConfiguration('without_path_with_url'); $this->assertEquals('/bob', $configuration['roots'][0]['path']); $this->assertEquals('http://test.com/unit-test/home-url-without-path/bob', $configuration['roots'][0]['URL']); // without path and with url absolute and homeFolder $reader = $this->getConfigurationReader($this->getHomeFolderAwareAttributesObject()); $configuration = $reader->getConfiguration('without_path_with_url_absolute_homeFolder'); $this->assertEquals('/bob', $configuration['roots'][0]['path']); $this->assertEquals('https://test.com/bob', $configuration['roots'][0]['URL']); } public function testAccessTmbURLOption(): void { $reader = $this->getConfigurationReader($this->getDefaultAttributesObject()); $configuration = $reader->getConfiguration('default'); $this->assertArrayHasKey('tmbURL', $configuration['roots'][0]); } } ================================================ FILE: tests/DependencyInjection/Compiler/TwigFormPassTest.php ================================================ process($container); $this->assertFalse($container->hasParameter('twig.form.resources')); $container = new ContainerBuilder(); $container->setParameter('twig.form.resources', []); $pass->process($container); $this->assertEquals([ '@FMElfinder/Form/elfinder_widget.html.twig', ], $container->getParameter('twig.form.resources')); } } ================================================ FILE: tests/DependencyInjection/ConfigurationLoadTest.php ================================================ 'app.configurator.custom', 'assets_path' => 'assets', 'loader' => 'fm_elfinder.loader.default', 'instances' => [ 'default' => [ 'locale' => 'en', 'editor' => 'tinymce', 'theme' => 'smoothness', 'editor_template' => 'Elfinder/editor.html.twig', 'fullscreen' => false, 'where_is_multi' => [], 'multi_home_folder' => false, 'folder_separator' => '', 'cors_support' => false, 'tinymce_popup_path' => '/pop-up', 'relative_path' => false, 'path_prefix' => '/', 'visible_mime_types' => [], 'connector' => [ 'debug' => true, 'binds' => [], 'plugins' => [], 'roots' => [ 'uploads' => [ 'driver' => 'LocalFileSystem', 'volume_id' => 0, 'security_voter' => '', 'phash' => '', 'trash_hash' => 'trash_hash', 'i18n_folder_name' => false, 'locale' => '', 'disabled_commands' => [], 'plugins' => [], 'driver_options' => [], 'path' => 'uploads', 'show_hidden' => true, 'flysystem' => [ 'filesystem' => '', 'enabled' => false, 'type' => '', 'adapter_service' => '', ], 'start_path' => '', 'encoding' => 'UTF-8', 'url' => '', 'mime_detect' => 'auto', 'mimefile' => '', 'img_lib' => 'auto', 'tmb_path' => '.tmb', 'tmb_url' => '', 'tmb_size' => 48, 'tmb_crop' => true, 'tmb_bg_color' => '#ffffff', 'tmb_path_mode' => 511, 'copy_overwrite' => true, 'copy_join' => true, 'copy_from' => true, 'copy_to' => true, 'upload_overwrite' => true, 'fileMode' => 0644, 'attributes' => [ 'some_pattern' => [ 'pattern' => '/^some_pattern$/', 'read' => true, 'write' => true, 'locked' => false, 'hidden' => false, ], ], 'accepted_name' => '/^\w[\w\s\.\%\-]*$/u', 'check_subfolders' => 1, 'separator' => DIRECTORY_SEPARATOR, 'date_format' => 'j M Y H:i', 'time_format' => 'H:i', 'archive_mimes' => [], 'archivers' => [ 'enabled' => false, 'create' => [], 'extract' => [], ], 'glide_url' => '', 'glide_key' => '', 'alias' => 'foo', 'tree_deep' => 1, 'upload_allow' => ['image/png', 'image/jpg', 'image/jpeg'], 'upload_order' => ['deny', 'allow'], 'defaults' => ['read' => true, 'write' => true], 'upload_deny' => ['all'], 'upload_max_size' => 0, 'upload_max_conn' => 3, 'dropbox2_settings' => [ 'aliasFormat' => '%s@Dropbox', 'path' => '/', 'separator' => '/', 'acceptedName' => '%s@Dropbox', 'rootCssClass' => 'elfinder-navbar-root-dropbox', 'getThumbSize' => 'medium', 'app_key' => 'some_consumer', 'app_secret' => 'con$umer', 'enabled' => true, ], 'box_settings' => [ 'client_id' => 'some_consumer', 'client_secret' => 'con$umer', 'accessToken' => 'token', 'root' => 'Box.com', 'path' => '/', 'separator' => '/', 'tmbPath' => '', 'tmbURL' => '', 'tmpPath' => '', 'acceptedName' => '#^[^/\?*:|"<>]*[^./\?*:|"<>]$#', 'rootCssClass' => 'elfinder-navbar-root-box', 'enabled' => true, ], 'onedrive_settings' => [ 'client_id' => 'some_consumer', 'client_secret' => 'con$umer', 'accessToken' => 'token', 'root' => 'OneDrive.com', 'OneDriveApiClient' => '', 'path' => '/', 'separator' => '/', 'tmbPath' => '', 'tmbURL' => '', 'tmpPath' => '', 'acceptedName' => '#^[^/\?*:|"<>]*[^./\?*:|"<>]$#', 'rootCssClass' => 'elfinder-navbar-root-onedrive', 'useApiThumbnail' => true, 'enabled' => true, ], 'ftp_settings' => [ 'host' => '127.0.0.1', 'user' => 'root', 'enabled' => true, ], 'mysql_settings' => [ 'enabled' => true, 'host' => 'localhost', 'files_table' => 'elfinder_file', 'port' => null, 'socket' => null, 'tmbPath' => '', 'tmpPath' => '', 'rootCssClass' => 'elfinder-navbar-root-sql', 'noSessionCache' => 'hasdirs', ], 'autoload' => false, 'quarantine' => null, ], ], ], ], ], ]; $this->assertProcessedConfigurationEquals($expectedConfiguration, [__DIR__.'/../Fixtures/'.$path]); } public static function getSupportsAllConfigFormatsData(): array { return [ 'yml' => ['config/config.yml'], 'php' => ['config/config.php'], ]; } } ================================================ FILE: tests/DependencyInjection/FMElfinderExtensionTest.php ================================================ load(); $this->assertContainerBuilderHasAlias('fm_elfinder.configurator'); $this->assertContainerBuilderHasService('fm_elfinder.loader'); $this->assertContainerBuilderHasService('fm_elfinder.configurator.default'); $this->assertContainerBuilderHasService('twig.extension.fm_elfinder_init'); } public function testMinimumConfiguration() { $this->container = new ContainerBuilder(); $loader = new FMElfinderExtension(); $loader->load([$this->getMinimalConfiguration()], $this->container); $this->assertTrue($this->container instanceof ContainerBuilder); } protected function getMinimalConfiguration(): array { $yaml = <<<'EOF' instances: default: locale: '%locale%' editor: simple # other choices are tinymce or simple fullscreen: true connector: debug: true # defaults to false roots: # at least one root must be defined uploads: driver: LocalFileSystem path: uploads upload_allow: ['image/png', 'image/jpg', 'image/jpeg'] upload_deny: ['all'] upload_max_size: 2M EOF; $parser = new Parser(); return $parser->parse($yaml); } } ================================================ FILE: tests/Event/ElFinderPostExecutionEventTest.php ================================================ createMock('Symfony\Component\HttpKernel\HttpKernelInterface'); $event = new ElFinderPostExecutionEvent($request, $httpKernel, 'testInstance', 'testHomeFolder', []); $this->assertEquals(false, $event->hasErrors()); $event = new ElFinderPostExecutionEvent($request, $httpKernel, 'testInstance', 'testHomeFolder', ['error' => true]); $this->assertEquals(true, $event->hasErrors()); } } ================================================ FILE: tests/Event/ElFinderPreExecutionEventTest.php ================================================ $command]); $httpKernel = $this->createMock('Symfony\Component\HttpKernel\HttpKernelInterface'); $event = new ElFinderPreExecutionEvent($request, $httpKernel, 'testInstance', 'testHomeFolder'); $this->assertEquals($command, $event->getCommand()); } public function testSubRequest() { $request = new Request(['cmd' => 'info']); $httpKernel = $this->createMock('Symfony\Component\HttpKernel\HttpKernelInterface'); $httpKernel ->expects($this->once()) ->method('handle'); $event = new ElFinderPreExecutionEvent($request, $httpKernel, 'testInstance', 'testHomeFolder'); $jsonResponse = $event->subRequest([ 'instance' => $event->getInstance(), 'homeFolder' => $event->getHomeFolder(), ], $request->query->all()); } } ================================================ FILE: tests/FMElfinderBundleTest.php ================================================ assertInstanceOf(Bundle::class, $bundle); } } ================================================ FILE: tests/Fixtures/config/config.php ================================================ loadFromExtension('fm_elfinder', [ 'configuration_provider' => 'app.configurator.custom', 'instances' => [ 'default' => [ 'locale' => 'en', 'cors_support' => false, 'editor' => 'tinymce', 'editor_template' => 'Elfinder/editor.html.twig', 'fullscreen' => false, 'tinymce_popup_path' => '/pop-up', 'relative_path' => false, 'connector' => [ 'debug' => true, 'roots' => [ 'uploads' => [ 'driver' => 'LocalFileSystem', 'path' => 'uploads', 'show_hidden' => true, 'trash_hash' => 'trash_hash', 'alias' => 'foo', 'check_subfolders' => 1, 'tree_deep' => 1, 'upload_allow' => ['image/png', 'image/jpg', 'image/jpeg'], 'upload_deny' => ['all'], 'upload_max_size' => 0, 'upload_max_conn' => 3, 'dropbox2_settings' => [ 'app_key' => 'some_consumer', 'app_secret' => 'con$umer', ], 'box_settings' => [ 'client_id' => 'some_consumer', 'client_secret' => 'con$umer', 'accessToken' => 'token', ], 'onedrive_settings' => [ 'client_id' => 'some_consumer', 'client_secret' => 'con$umer', 'accessToken' => 'token', ], 'ftp_settings' => [ 'host' => '127.0.0.1', 'user' => 'root', ], 'mysql_settings' => [ 'host' => 'localhost', ], 'attributes' => [ 'some_pattern' => [ 'pattern' => '/^some_pattern$/', 'read' => true, 'write' => true, 'locked' => false, 'hidden' => false, ], ], ], ], ], ], ], ]); ================================================ FILE: tests/Fixtures/config/config.yml ================================================ fm_elfinder: configuration_provider: app.configurator.custom instances: default: locale: en editor: tinymce editor_template: Elfinder/editor.html.twig fullscreen: false tinymce_popup_path: /pop-up relative_path: false connector: debug: true roots: uploads: driver: LocalFileSystem path: uploads show_hidden: true trash_hash: trash_hash check_subfolders: 1 alias: foo tree_deep: 1 upload_allow: ['image/png', 'image/jpg', 'image/jpeg'] dropbox2_settings: app_key: some_consumer app_secret: con$umer onedrive_settings: client_id: some_consumer client_secret: con$umer accessToken: token box_settings: client_id: some_consumer client_secret: con$umer accessToken: token ftp_settings: host: 127.0.0.1 user: root mysql_settings: host: localhost attributes: some_pattern: pattern: '/^some_pattern$/' read: true write: true locked: false hidden: false ================================================ FILE: tests/Form/Type/ElFinderTypeTest.php ================================================ assertEquals('elfinder', $type->getName()); } public function testConfigureOptions() { $resolver = new OptionsResolver(); $type = new ElFinderType(); $type->configureOptions($resolver); $this->assertTrue($resolver->isDefined('enable')); $this->assertTrue($resolver->isDefined('instance')); $this->assertTrue($resolver->isDefined('homeFolder')); } public function testBuildView() { $options = [ 'instance' => 'default1', 'enable' => true, 'homeFolder' => '/home', ]; $view = new FormView(); $type = new ElFinderType(); $form = $this->createMock('Symfony\Component\Form\Test\FormInterface'); $type->buildView($view, $form, $options); foreach ($options as $name => $value) { $this->assertArrayHasKey($name, $view->vars); $this->assertEquals($value, $view->vars[$name]); } } } ================================================ FILE: tests/Functional/AppKernel.php ================================================ load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml'); } } ================================================ FILE: tests/Functional/config/config.yml ================================================ framework: secret: "thisismysecret" router: resource: "%kernel.root_dir%/config/routing.yaml" strict_requirements: ~ form: ~ csrf_protection: ~ validation: { enable_annotations: true } templating: engines: ['twig'] default_locale: "en" trusted_hosts: ~ trusted_proxies: ~ session: # handler_id set to null will use default session handler from php.ini handler_id: ~ fragments: ~ http_method_override: true # ElFinder file manager fm_elfinder: instances: default: locale: en # defaults to current request locale editor: custom # other options are tinymce, tinymce4, form, custom and simple, cors_support: true # full symfony life cycle fullscreen: true # defaults true, applies to simple and ckeditor editors connector: debug: false # defaults to false roots: # at least one root must be defined uploads: show_hidden: false # defaults to false driver: LocalFileSystem volume_id: 1 path: uploads ================================================ FILE: tests/Functional/config/config_test.yml ================================================ imports: - { resource: config.yml } framework: test: ~ session: storage_id: session.storage.mock_file profiler: collect: false ================================================ FILE: tests/Functional/config/routing.yml ================================================ # ElFinder file manager elfinder: resource: "@FMElfinderBundle/Resources/config/routing.yaml" ================================================ FILE: tests/Loader/ElFinderLoaderTest.php ================================================ configuratorMock = $this->createMock(ElFinderConfigurationProviderInterface::class); $this->configuratorMock->expects($this->any()) ->method('getConfiguration') ->willReturn(['parameters' => []]); $this->loader = new ElFinderLoader($this->configuratorMock); $this->loader->setInstance('minimal'); } public function testConfigure() { $this->loader->configure(); $this->assertEquals(['parameters' => []], $this->configuratorMock->getConfiguration('minimal')); } } ================================================ FILE: tests/Twig/Extension/FMElfinderExtensionTest.php ================================================ twig = new Environment(new FilesystemLoader([__DIR__.'/../../../src/Resources/views/Elfinder/helper'])); $this->extension = new FMElfinderExtension($this->twig); $this->twig->addExtension($this->extension); $loader = new YamlFileLoader(new FileLocator(__DIR__.'/../../../src/Resources/config')); $routes = new RouteCollection(); $collection = $loader->load('routing.yaml'); $routes->addCollection($collection); $this->twig->addExtension(new RoutingExtension(new UrlGenerator($routes, new RequestContext()))); } public function testRenderTinyMCE3() { $testData = $this->twig->render('_tinymce.html.twig', ['instance' => 'minimal']); $expected = <<<'EOF' EOF; $this->assertSame($this->normalizeOutput($expected), $this->normalizeOutput($testData)); } public function testRenderTinyMCE4() { $testData = $this->twig->render('_tinymce4.html.twig', ['instance' => 'minimal']); $expected = <<<'EOF' EOF; $this->assertSame($this->normalizeOutput($expected), $this->normalizeOutput($testData)); } public function testRenderSummernote() { $testData = $this->twig->render('_summernote.html.twig', ['instance' => 'minimal']); $expected = <<<'EOF' EOF; $this->assertSame($this->normalizeOutput($expected), $this->normalizeOutput($testData)); } public function testName() { $this->assertEquals('fm_elfinder_init', $this->extension->getName()); } /** * {@inheritdoc} */ protected function tearDown(): void { unset($this->template); unset($this->twig); } /** * Normalizes the output by removing the heading whitespaces. * * @param string $output the output * * @return string the normalized output */ protected function normalizeOutput($output) { return preg_replace("/\r|\n/", '', str_replace(PHP_EOL, '', str_replace(' ', '', $output))); } public function testSubClassOfTwigExtension() { $rc = new \ReflectionClass('FM\ElfinderBundle\Twig\Extension\FMElfinderExtension'); $this->assertTrue($rc->isSubclassOf('Twig\Extension\AbstractExtension')); } public function testSummernoteInstanceNotString() { $this->expectException(\Twig\Error\LoaderError::class); $this->extension->summernote(1); } public function testTinyMCEInstanceNotString() { $this->expectException(\Twig\Error\LoaderError::class); $this->extension->tinymce(1); } public function testTinyMCE4InstanceNotString() { $this->expectException(\Twig\Error\LoaderError::class); $this->extension->tinymce4(1); } public function testGetFunctions() { $twigFunctions = $this->extension->getFunctions(); foreach ($twigFunctions as $twigFunction) { $this->assertInstanceOf('Twig\TwigFunction', $twigFunction); } } } ================================================ FILE: tests/autoload.php ================================================ loadClass(...));