🔨 Prefixes all PHP namespaces in a file/directory to isolate the code bundled in PHARs.

Overview

PHP-Scoper

Package version Build Status Scrutinizer Code Quality Code Coverage Slack License

PHP-Scoper is a tool which essentially moves any body of code, including all dependencies such as vendor directories, to a new and distinct namespace.

Goal

PHP-Scoper's goal is to make sure that all code for a project lies in a distinct PHP namespace. This is necessary, for example, when building PHARs that:

  • Bundle their own vendor dependencies; and
  • Load/execute code from arbitrary PHP projects with similar dependencies

When a package (of possibly different versions) exists, and is found in both a PHAR and the executed code, the one from the PHAR will be used. This means these PHARs run the risk of raising conflicts between their bundled vendors and the vendors of the project they are interacting with, leading to issues that are potentially very difficult to debug due to dissimilar or unsupported package versions.

Table of Contents

Installation

Phive

You can install PHP-Scoper with Phive

$ phive install humbug/php-scoper --force-accept-unsigned

To upgrade php-scoper use the following command:

$ phive update humbug/php-scoper --force-accept-unsigned

PHAR

The preferred method of installation is to use the PHP-Scoper PHAR, which can be downloaded from the most recent Github Release.

Composer

You can install PHP-Scoper with Composer:

composer global require humbug/php-scoper

If you cannot install it because of a dependency conflict or you prefer to install it for your project, we recommend you to take a look at bamarni/composer-bin-plugin. Example:

composer require --dev bamarni/composer-bin-plugin
composer bin php-scoper config minimum-stability dev
composer bin php-scoper config prefer-stable true 
composer bin php-scoper require --dev humbug/php-scoper

Keep in mind however that this library is not designed to be extended.

Usage

php-scoper add-prefix

This will prefix all relevant namespaces in code found in the current working directory. The prefixed files will be accessible in a build folder. You can then use the prefixed code to build your PHAR.

Warning: After prefixing the files, if you are relying on Composer for the autoloading, dumping the autoloader again is required.

For a more concrete example, you can take a look at PHP-Scoper's build step in Makefile, especially if you are using Composer as there are steps both before and after running PHP-Scoper to consider.

Refer to TBD for an in-depth look at scoping and building a PHAR taken from PHP-Scoper's makefile.

Configuration

If you need more granular configuration, you can create a scoper.inc.php by running the command php-scoper init. A different file/location can be passed with a --config option.

<?php declare(strict_types=1);

// scoper.inc.php

use Isolated\Symfony\Component\Finder\Finder;

return [
    'prefix' => null,                       // string|null
    'finders' => [],                        // Finder[]
    'patchers' => [],                       // callable[]
    'files-whitelist' => [],                // string[]
    'whitelist' => [],                      // string[]
    'expose-global-constants' => true,   // bool
    'expose-global-classes' => true,     // bool
    'expose-global-functions' => true,   // bool
    'exclude-constants' => [],             // string[]
    'exclude-classes' => [],               // string[]
    'exclude-functions' => [],             // string[]
];

Prefix

The prefix to be used to isolate the code. If null or '' (empty string) is given, then a random prefix will be automatically generated.

Finders and paths

By default when running php-scoper add-prefix, it will prefix all relevant code found in the current working directory. You can however define which files should be scoped by using Finders in the configuration:

<?php declare(strict_types=1);

// scoper.inc.php

use Isolated\Symfony\Component\Finder\Finder;

return [
    'finders' => [
        Finder::create()->files()->in('src'),
        Finder::create()
            ->files()
            ->ignoreVCS(true)
            ->notName('/LICENSE|.*\\.md|.*\\.dist|Makefile|composer\\.json|composer\\.lock/')
            ->exclude([
                'doc',
                'test',
                'test_old',
                'tests',
                'Tests',
                'vendor-bin',
            ])
            ->in('vendor'),
        Finder::create()->append([
            'bin/php-scoper',
            'composer.json',
        ])
    ],
];

Besides the finder, you can also add any path via the command:

php-scoper add-prefix file1.php bin/file2.php

Paths added manually are appended to the paths found by the finders.

Patchers

When scoping PHP files, there will be scenarios where some of the code being scoped indirectly references the original namespace. These will include, for example, strings or string manipulations. PHP-Scoper has limited support for prefixing such strings, so you may need to define patchers, one or more callables in a scoper.inc.php configuration file which can be used to replace some of the code being scoped.

Here's a simple example:

  • Class names in strings.

You can imagine instantiating a class from a variable which is based on a known namespace, but also on a variable classname which is selected at runtime. Perhaps code similar to:

$type = 'Foo'; // determined at runtime
$class = 'Humbug\\Format\\Type\\' . $type;

If we scoped the Humbug namespace to PhpScoperABC\Humbug, then the above snippet would fail as PHP-Scoper cannot interpret the above as being a namespaced class. To complete the scoping successfully, a) the problem must be located and b) the offending line replaced.

The patched code which would resolve this issue might be:

$type = 'Foo'; // determined at runtime
$scopedPrefix = array_shift(explode('\\', __NAMESPACE__));
$class = $scopedPrefix . '\\Humbug\\Format\\Type\\' . $type;

This and similar issues may arise after scoping, and can be debugged by running the scoped code and checking for issues. For this purpose, having a couple of end to end tests to validate post-scoped code or PHARs is recommended.

Applying such a change can be achieved by defining a suitable patcher in scoper.inc.php:

<?php declare(strict_types=1);

// scoper.inc.php

return [
    'patchers' => [
        function (string $filePath, string $prefix, string $content): string {
            //
            // PHP-Parser patch conditions for file targets
            //
            if ($filePath === '/path/to/offending/file') {
                return preg_replace(
                    "%\$class = 'Humbug\\\\Format\\\\Type\\\\' . \$type;%",
                    '$class = \'' . $prefix . '\\\\Humbug\\\\Format\\\\Type\\\\\' . $type;',
                    $content
                );
            }
            return $content;
        },
    ],
];

Whitelisted files

For the files listed in files-whitelist, their content will be left untouched during the scoping process.

Excluded Symbols

Symbols can be marked as excluded as follows:

<?php declare(strict_types=1);

// scoper.inc.php

return [
    'exclude-classes' => ['Stringeable'],
    'exclude-functions' => ['str_contains'],
    'exclude-constants' => ['PHP_EOL'],
];

This enriches the list of Symbols PHP-Scoper's Reflector considers as "internal", i.e. PHP engine or extension symbols and that will be left completely untouched.

This feature should be use very carefully as it can easily break the Composer autoloading and is recommended to be used only for compensating missing symbols from the PhpStorm's stubs shipped with PHP-Scoper.

Whitelist

PHP-Scoper's goal is to make sure that all code for a project lies in a distinct PHP namespace. However, you may want to share a common API between the bundled code of your PHAR and the consumer code. For example if you have a PHPUnit PHAR with isolated code, you still want the PHAR to be able to understand the PHPUnit\Framework\TestCase class.

Constants & Classes & functions from the global namespace

By default, PHP-Scoper will prefix the user defined constants, classes and functions belonging to the global namespace. You can however change that setting for them to be prefixed as usual unless explicitly whitelisted:

<?php declare(strict_types=1);

// scoper.inc.php

return [
    'expose-global-constants' => false,
    'expose-global-classes' => false,
    'expose-global-functions' => false,
];

Symbols

You can whitelist classes, interfaces, constants and functions like so like so:

<?php declare(strict_types=1);

// scoper.inc.php

return [
    'whitelist' => [
        'PHPUnit\Framework\TestCase',
        'PHPUNIT_VERSION',
        'iter\count',
        'Acme\Foo*', // Warning: will not whitelist sub namespaces like Acme\Foo\Bar but will whitelist symbols like
                     // Acme\Foo or Acme\Fooo
    ],
];

Caveats

This will not work on traits and this alias mechanism is case insensitive, i.e. when passing 'iter\count', if a class Iter\Count is found, this class will also be whitelisted.

Implementation insights

Class whitelisting

The class aliasing mechanism is done like follows:

  • Prefix the class or interface as usual
  • Append a class_alias() statement at the end of the class/interface declaration to link the prefixed symbol to the non prefixed one
  • Append a class_exists() statement right after the autoloader is registered to trigger the loading of the method which will ensure the class_alias() statement is executed

It is done this way to ensure prefixed and whitelisted classes can co-exist together without breaking the autoloading. The class_exists() statements are dumped in vendor/scoper-autoload.php, do not forget to include this file in favour of vendor/autoload.php. This part is however sorted out by Box if you are using it with the PhpScoper compactor.

So if you have the following file with a whitelisted class:

<?php

namespace Acme;

class Foo {}

The scoped file will look like this:

<?php

namespace Humbug\Acme;

class Foo {}

\class_alias('Humbug\\Acme\\Foo', 'Acme\\Foo', \false);

With:

<?php

// scoper-autoload.php @generated by PhpScoper

$loader = require_once __DIR__.'/autoload.php';

class_exists('Humbug\\Acme\\Foo');   // Triggers the autoloading of
                                    // `Humbug\Acme\Foo` after the
                                    // Composer autoload is registered

return $loader;
Constants whitelisting

The constant aliasing mechanism is done by transforming the constant declaration into a define() statement when this is not already the case. Note that there is a difference here since define() defines a constant at runtime whereas const defines it at compile time. You have a more details post regarding the differences here

Give the following file with a whitelisted constant:

<?php

namespace Acme;

const FOO = 'X';

The scoped file will look like this:

<?php

namespace Humbug\Acme;

\define('FOO', 'X');
Functions whitelisting

The function aliasing mechanism is done by declaring the original function as an alias of the prefixed one in the vendor/scoper-autoload.php file.

Given the following file with a function declaration:

<?php

// No namespace: this is the global namespace

if (!function_exists('dd')) {
    function dd() {}
}

The file will be scoped as usual in order to avoid any autoloading issue:

<?php

namespace PhpScoperPrefix;

if (!function_exists('PhpScoperPrefix\dd')) {
    function dd() {...}
}

And the following function which will serve as an alias will be declared in the scoper-autoload.php file:

<?php

// scoper-autoload.php @generated by PhpScoper

$loader = require_once __DIR__.'/autoload.php';

if (!function_exists('dd')) {
    function dd() {
        return \PhpScoperPrefix\dd(...func_get_args());
    }
}

return $loader;

Namespaces whitelisting

If you want to be more generic and whitelist a whole namespace, you can do it so like this:

<?php declare(strict_types=1);

// scoper.inc.php

return [
    'whitelist' => [
        'PHPUnit\Framework\*',
    ],
];

Now anything under the PHPUnit\Framework namespace will not be prefixed. Note this works as well for the global namespace:

<?php declare(strict_types=1);

// scoper.inc.php

return [
    'whitelist' => [
        '*',
    ],
];

Note that this may lead to autoloading issues. Indeed if you have the following package:

{
    "autoload": {
        "psr-4": {
            "PHPUnit\\": "src"
        }
    }
}

And whitelist the namespace PHPUnit\Framework\*, then the autoloading for this package will be faulty and will not work. For this to work, the whole package PHPUnit\* would need to be whitelisted.

Warning: the following is not a namespace whitelist:

<?php declare(strict_types=1);

// scoper.inc.php

return [
    'whitelist' => [
        'PHPUnit\F*',   // Will only whitelist symbols such as PHPUnit\F or PHPunit\Foo, but not symbols belonging to
                        // sub-namespaces like PHPunit\Foo\Bar
    ],
];

Building a Scoped PHAR

With Box

If you are using Box to build your PHAR, you can use the existing PHP-Scoper integration. Box will take care of most of the things for you so you should only have to adjust the PHP-Scoper configuration to your needs.

Without Box

Step 1: Configure build location and prep vendors

Assuming you do not need any development dependencies, run:

composer install --no-dev --prefer-dist

This will allow you to save time in the scoping process by not processing unnecessary files.

Step 2: Run PHP-Scoper

PHP-Scoper copies code to a new location during prefixing, leaving your original code untouched. The default location is ./build. You can change the default location using the --output-dir option. By default, it also generates a random prefix string. You can set a specific prefix string using the --prefix option. If automating builds, you can set the --force option to overwrite any code existing in the output directory without being asked to confirm.

Onto the basic command assuming default options from your project's root directory:

bin/php-scoper add-prefix

As there are no path arguments, the current working directory will be scoped to ./build in its entirety. Of course, actual prefixing is limited to PHP files, or PHP scripts. Other files are copied unchanged, though we also need to scope certain Composer related files.

Speaking of scoping Composer related files... The next step is to dump the Composer autoloader if we depend on it, so everything works as expected:

composer dump-autoload --working-dir build --classmap-authoritative

Recommendations

There is 3 things to manage when dealing with isolated PHARs:

  • The dependencies: which dependencies are you shipping? Fine controlled ones managed with a composer.lock or you always ship your application with up to date dependencies?
  • The PHAR format: there is some incompatibilities such as realpath() which will no longer work for the files within the PHAR since the paths are not virtual.
  • Isolating the code: due to the dynamic nature of PHP, isolating your dependencies will never be a trivial task and as a result you should have some end-to-end test to ensure your isolated code is working properly. You will also likely need to configure the whitelists or patchers.

As a result, you should have end-to-end tests for your (at the minimum) your released PHAR.

Since dealing with the 3 issues mentioned above at once can be tedious, it is highly recommended to have several tests for each steps.

For example you can have a test for both your non-isolated PHAR and your isolated PHAR, this way you will know which step is causing an issue. If the isolated PHAR is not working, you can try to test the isolated code directly outside the PHAR to make sure the scoping process is not the issue.

To check if the isolated code is working correctly, you have a number of solutions:

Also take into consideration that bundling code in a PHAR is not guaranteed to work out of the box either. Indeed there is a number of things such as

For this reason, you should also h

Limitations

Dynamic symbols

PHP-Scoper tries to prefix strings as well whenever possible. There will however be cases in which it will not be possible such as:

  • strings in regexps, e.g. /^Acme\\\\Foo/
  • concatenated strings strings, e.g.:
    • $class = 'Symfony\\Component\\'.$name;
    • const X = 'Symfony\\Component' . '\\Yaml\\Ya_1';

Date symbols

You code may be using a convention for the date string formats which could be mistaken for classes, e.g.:

const ISO8601_BASIC = 'Ymd\THis\Z';

In this scenario, PHP-Scoper has no way to tell that string 'Ymd\THis\Z' does not refer to a symbol but is a date format. In this case, you will have to rely on patchers. Note however that PHP-Scoper will be able to handle some cases such as, see the date-spec.

Heredoc values

If you consider the following code:

<?php

<<<PHP_HEREDOC
<?php

use Acme\Foo;

PHP_HEREDOC;

The content of PHP_HEREDOC will not be prefixed. Some partial support could be added in the future but is bound to be very limited due to the dynamic nature of heredocs. If you consider the following for example:

<?php

<<<EOF
<?php

{$namespaceLine}

// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.

if (\\class_exists(\\Container{$hash}\\{$options['class']}::class, false)) {
    // no-op
} elseif (!include __DIR__.'/Container{$hash}/{$options['class']}.php') {
    touch(__DIR__.'/Container{$hash}.legacy');
    return;
}

if (!\\class_exists({$options['class']}::class, false)) {
    \\class_alias(\\Container{$hash}\\{$options['class']}::class, {$options['class']}::class, false);
}

return new \\Container{$hash}\\{$options['class']}(array(
    'container.build_hash' => '$hash',
    'container.build_id' => '$id',
    'container.build_time' => $time,
), __DIR__.\\DIRECTORY_SEPARATOR.'Container{$hash}');

EOF;

It would be very hard to properly scope the relevant classes.

Callables

If you consider the two following values:

['Acme\Foo', 'bar'];
'Acme\Foo::bar';

The classes used there will not be scoped. It should not be impossible to add support for it but it is currently not supported. See #286.

String values

PHP-Scoper tries whenever possible to prefix strings as well:

class_exists('Acme\Foo');

// Will be prefixed into:

\class_exists('Humbug\Acme\Foo');

PHP-Scoper uses a regex to determine if the string is a class name that must be prefixed. But there is bound to have confusing cases. For example:

  • If you have a plain string 'Acme\Foo' which has nothing to do with a class, PHP-Parser will not be able to tell and will prefix it

  • Classes belonging to the global scope: 'Foo' or 'Acme_Foo', because there is no way to know if it is a class name or a random string except for a handful of methods:

  • class_alias()

  • class_exists()

  • define()

  • defined()

  • function_exists()

  • interface_exists()

  • is_a()

  • is_subclass_of()

  • trait_exists()

Native functions and constants shadowing

In the following example:

<?php

namespace Foo;

is_array([]);

No use statement is used for the function is_array. This means that PHP will try to load the function \Foo\is_array and if fails to do so will fallback on \is_array (note that PHP does so only for functions and constants: not classes).

In order to bring some performance optimisation, the call will nonetheless be prefixed in \is_array. This will break your code if you were relying on \Foo\is_array instead. This however should be extremely rare, so if that happens you have two solutions: use a patcher or simpler remove any ambiguity by making use of a use statement (which is unneeded outside of the context of prefixing your code):

<?php

namespace Foo;

use function Foo\is_array;

is_array([]);

The situation is exactly the same for constants.

Grouped constants whitelisting

When a grouped constant declaration like the following is given:

const X = 'foo', Y = 'bar';

PHP-Scoper will not be able to whitelist either X or Y. The statement above should be replaced by multiple constant statements:

const X = 'foo';
const Y = 'bar';

Composer Autoloader

PHP-Scoper does not support prefixing the dumped Composer autoloader and autoloading files. This is why you have to manually dump the autoloader again after prefixing an application.

Note: when using Box, Box is able to take care of that step for you.

PHP-Scoper also can not handle Composers static file autoloaders. This is due to Composer loading files based on a hash which is generated from package name and relative file path. For a workaround see #298.

Composer Plugins

Composer plugins are not supported. The issue is that for whitelisting symbols PHP-Scoper relies on the fact that you should load the vendor/scoper-autoload.php file instead of vendor/autoload.php to trigger the loading of the right classes with their class aliases. However Composer does not do that and as a result interfaces such as Composer\Plugin\Capability\Capable are prefixed but the alias is not registered.

This cannot be changed easily so for now when you are using an isolated version of Composer, you will need to use the --no-plugins option.

PSR-0 Partial support

As of now, given the following directory structure:

src/
  JsonMapper.php
  JsonMapper/
    Exception.php

with the following configuration:

{
  "autoload": {
     "psr-0": {"JsonMapper": "src/"}
  }
}

The autoloading will not work. Indeed, PHP-Scoper attempts to support PSR-0 by transforming it to PSR-4, i.e. in the case above:

{
  "autoload": {
     "psr-4": {"PhpScoperPrefix\\JsonMapper": "src/"}
  }
}

If this will work for the classes under src/JsonMapper/, it will not for JsonMapper.php.

WordPress

As of now PHP-Scoper does not easily allow to completely leave unchanged non-included third-party code causing some hurdles with Wordpress plugins. There is a standing issue about providing a better integration out of the box (See #303) but alternatively you can already use WP React Starter which is a boilerplate for WordPress plugins.

If you are not able to migrate you can have a look at the solution itself, read more about it here #303 (comment).

Contributing

Contribution Guide

Credits

Project originally created by: Bernhard Schussek (@webmozart) which has now been moved under the Humbug umbrella.

Comments
  • [Scoper] Scoping autoloaded files result in an autoload conflict

    [Scoper] Scoping autoloaded files result in an autoload conflict

    Edit to avoid to summarise the state of this issue.

    When scoping a package which has autoloaded files, the scoped files will keep the same hash. As a result if your current application/library is using the scoped package and has files with the same hash, only one file will be loaded which results in undesirable behaviours.

    It appears the hash strategy is not something we can change composer/composer#7942 and changing the package name of the scoped packages has undesirable side effects so it is not a solution either.

    @jarrodbell https://github.com/humbug/php-scoper/issues/298#issuecomment-678089152 and @ondrejmirtes https://github.com/humbug/php-scoper/issues/298#issuecomment-683425709 made it work by changing it after the composer dump process as part of the scoping build process.

    The discussion is carrying from that point to figure out if there is a way PHP-Scoper could fix it by itself without further actions from the user.


    Bug report

    | Question | Answer | ------------| --------------- | Box version | PHP Scoper version 0.11.4 2018-11-13 08:49:16 UTC | PHP version | PHP 7.1.22 | Platform with version | Ubuntu 16.04.5 LTS | Github Repo | https://github.com/mollie/mollie-api-php

    We are using php-scoper in our client to generate a release for integrators to be used in for example Wordpress. When it is used there, there are often more packages with Guzzle via composer.

    When this happens they will get the exception: Uncaught Error: Call to undefined function GuzzleHttp\choose_handler()

    This is because the corresponding guzzlehttp/guzzle/src/functions_include.php is not loaded for the second implementation due to the composer file require hash being the same.

    Below there is an example of our package being ran alongside another guzzle package. This is a var_dump inside the composer_real.php where the functions_include is being required if the file hash is not already loaded.

    array(3) {
      ["c964ee0ededf28c96ebd9db5099ef910"]=>
      string(99) "{path_to_site}/vendor/composer/../guzzlehttp/promises/src/functions_include.php"
      ["a0edc8309cc5e1d60e3047b5df6b7052"]=>
      string(95) "{path_to_site}/vendor/composer/../guzzlehttp/psr7/src/functions_include.php"
      ["37a3dc5111fe8f707ab4c132ef1dbc62"]=>
      string(97) "{path_to_site}/vendor/composer/../guzzlehttp/guzzle/src/functions_include.php"
    }
    array(3) {
      ["c964ee0ededf28c96ebd9db5099ef910"]=>
      string(106) "{path_to_site}/guzzle/vendor/composer/../guzzlehttp/promises/src/functions_include.php"
      ["a0edc8309cc5e1d60e3047b5df6b7052"]=>
      string(102) "{path_to_site}/guzzle/vendor/composer/../guzzlehttp/psr7/src/functions_include.php"
      ["37a3dc5111fe8f707ab4c132ef1dbc62"]=>
      string(104) "{path_to_site}k/guzzle/vendor/composer/../guzzlehttp/guzzle/src/functions_include.php"
    }
    

    So this causes only the first implementation it's choose_handler function to be available.

    I'm not really sure if this bug should be reported here, but i'm curious to your expert opinion about this. Might it be worth it to also scope the files that outta be required by composer? To avoid some of them not being loaded? As manipulating the hash in above example would fix the problem.

    bug critical bug 
    opened by Smitsel 56
  • composer.json is preffixed but also empty autoload psr-4 section is added

    composer.json is preffixed but also empty autoload psr-4 section is added

    Original

    File /vendor/latte/latte/composer.json

    	"autoload": {
    		"classmap": ["src/"]
    	},
    

    Prefixed

        "autoload": {
            "classmap": [
                "src\/"
            ],
            "psr-4": []
        },
    

    Related to: https://github.com/rectorphp/rector/pull/319

    opened by TomasVotruba 30
  • Add PHP 8 support

    Add PHP 8 support

    Waiting for:

    • [x] https://github.com/oradwell/covers-validator to be PHP 8 compatible
    • [x] fix e2e_0211 - 8.0
    • [x] fix e2e_027
    • [x] fix e2e_028 - 7.3 (@smoench)
    • [x] fix e2e_028 - 8.0 (@smoench)
    opened by smoench 26
  • PEAR-style non-namespaced PSR-0 class not available in autoloader

    PEAR-style non-namespaced PSR-0 class not available in autoloader

    Bug report

    | Question | Answer | ------------| --------------- | Box version | 3.6.0 | PHP version | 7.3 | Platform with version | MacOS 10.13.16 | Github Repo | - https://github.com/vimeo/psalm

    Reproduction

    Run

    composer bin box install
    vendor/bin/box --debug compile
    

    Notice the autoload_classmap.php in .box_dump is missing an entry for JsonMapper (but has other entries).

    This class isn't used in Psalm-proper, but it is used in Psalm's language server (which @greg0ire is working to enable in the phar via a --language-server flag)

    Here's the (hopefully temporary) hack I'm using to work around it: https://github.com/vimeo/psalm/compare/phar-compat#diff-feb180cea6e9d88bcfcbbbf7addc6efaR25

    opened by muglug 21
  • Third-party code whitelisting

    Third-party code whitelisting

    Hi! In my unscoped files I'm using a third party class constant \Foo::BAR. When my files are getting scoped, this constant becomes \PREFIX\Foo:BAR. Is there any way I could prevent this?

    enhancement help wanted 
    opened by kmgalanakis 18
  • First prototype of php-scoper

    First prototype of php-scoper

    This is the beginning of php-scoper implementation (cf https://github.com/webmozart/php-scoper/issues/1). Here is the checklist of what is done, and what is remaining:

    • [x] Manage single files
    • [x] Manage multiple files (should be good, not tested yet)
    • [x] Manage directories
    • [x] "Namespace" prefixing
    • [x] "Use namespace" prefixing
    • [x] "FQ namespace" prefixing
    • [x] Manage single files
    • [ ] Keep coding style of input file
    • [x] Output management (what do we display ?)
    • [x] Error management
    • [x] Tests

    @webmozart : Can I have your opinion of this implementation ?

    How I see the next steps:

    • Find a way to replace an expression "on the fly". Currently all the tree is updated, then dumped into the initial file. I lose all the initial coding style
    • Do you have an idea of what should be displayed to the user when he runs the command ?
    • I named my class "Scoper" with a "Scope" function. Maybe I should call it "Prefixer" with a "Prefix" function instead. I don't know, but I can change the names if it is more appropriate

    All feedback is really welcome

    opened by matthieuauger 18
  • PSR-0/4 dependencies are not correctly prefixed

    PSR-0/4 dependencies are not correctly prefixed

    Bug report

    This is related to https://github.com/humbug/php-scoper/issues/127, but it feels like a regression has happened and now PSR-4 and PSR-0 namespaces aren't prefixed in the Composer autoloader files.

    Using the test repo here,

    • composer install
    • ./vendor/bin/php-scoper add-prefix --output-dir=build-prefixed --force --prefix=Mutant

    autoload_static.php:

    public static $prefixLengthsPsr4 = array(
    		'S' => array(
    			'Symfony\\Polyfill\\Php73\\'       => 23,
    			'Symfony\\Polyfill\\Mbstring\\'    => 26,
    			'Symfony\\Polyfill\\Ctype\\'       => 23,
    			'Symfony\\Contracts\\Service\\'    => 26,
    			'Symfony\\Component\\Finder\\'     => 25,
    			'Symfony\\Component\\Filesystem\\' => 29,
    			'Symfony\\Component\\Console\\'    => 26,
    			'ScoperBug\\'                      => 10,
    		),
    		'P' => array(
    			'Psr\\Container\\'  => 14,
    			'PhpParser\\'       => 10,
    			'PackageVersions\\' => 16,
    		),
    		'H' => array( 'Humbug\\PhpScoper\\' => 17 ),
    	);
    	public static $prefixDirsPsr4 = array(
    		'Symfony\\Polyfill\\Php73\\'       => array( 0 => __DIR__ . '/..' . '/symfony/polyfill-php73' ),
    		'Symfony\\Polyfill\\Mbstring\\'    => array( 0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring' ),
    		'Symfony\\Polyfill\\Ctype\\'       => array( 0 => __DIR__ . '/..' . '/symfony/polyfill-ctype' ),
    		'Symfony\\Contracts\\Service\\'    => array( 0 => __DIR__ . '/..' . '/symfony/service-contracts' ),
    		'Symfony\\Component\\Finder\\'     => array( 0 => __DIR__ . '/..' . '/symfony/finder' ),
    		'Symfony\\Component\\Filesystem\\' => array( 0 => __DIR__ . '/..' . '/symfony/filesystem' ),
    		'Symfony\\Component\\Console\\'    => array( 0 => __DIR__ . '/..' . '/symfony/console' ),
    		'ScoperBug\\'                      => array( 0 => __DIR__ . '/../..' . '/src' ),
    		'Psr\\Container\\'                 => array( 0 => __DIR__ . '/..' . '/psr/container/src' ),
    		'PhpParser\\'                      => array( 0 => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser' ),
    		'PackageVersions\\'                => array( 0 => __DIR__ . '/..' . '/ocramius/package-versions/src/PackageVersions' ),
    		'Humbug\\PhpScoper\\'              => array( 0 => __DIR__ . '/..' . '/humbug/php-scoper/src' ),
    	);
    	public static $prefixesPsr0 = array( 'P' => array( 'Pimple' => array( 0 => __DIR__ . '/..' . '/pimple/pimple/src' ) ) );
    

    The public static $classMap = array( is correctly prefixed

    autoload_real.php

    ClassLoader isn't prefixed here -

        private static $loader;
        public static function loadClassLoader($class)
        {
            if ('Composer\\Autoload\\ClassLoader' === $class) {
                require __DIR__ . '/ClassLoader.php';
            }
        }
    

    autoload_psr4.php

    The array key strings of the class aren't namespaced.

    // autoload_psr4.php @generated by Composer
    $vendorDir = \dirname( \dirname( __FILE__ ) );
    $baseDir   = \dirname( $vendorDir );
    
    return array( 'Symfony\\Polyfill\\Php73\\'       => array( $vendorDir . '/symfony/polyfill-php73' ),
                  'Symfony\\Polyfill\\Mbstring\\'    => array( $vendorDir . '/symfony/polyfill-mbstring' ) );
    

    autoload_namespaces.php

    Same as autoload_psr4.php.

    | Question | Answer | ------------| --------------- | Box version | 0.12.4 | PHP version | 7.2.1 | Platform with version | MacOS | Github Repo | https://github.com/polevaultweb/php-scoper-bug

    scoper.inc.php
    <?php
    
    declare(strict_types=1);
    
    use Isolated\Symfony\Component\Finder\Finder;
    
    return [
    ];
    
    
    Output
    $ command
    > output
    
    opened by polevaultweb 15
  • Setup the fixtures for the Symfony support

    Setup the fixtures for the Symfony support

    Closes #182

    • [x] Yaml support
      • [x] Class param
      • [x] Class as service ID
      • [x] Class as alias
      • [x] Class as alias shortcut
      • [x] Class as argument
      • [x] Class as tag element
      • [x] Whitelisted class
      • [x] Class belonging to a whitelisted namespace
    • [x] XML support
      • [x] Class param
      • [x] Class as service ID
      • [x] Class as alias
      • [x] Class as alias shortcut
      • [x] Class as argument
      • [x] Class as tag element
      • [x] Whitelisted class
      • [x] Class belonging to a whitelisted namespace
    • [ ] PHP support
      • [ ] Class param
      • [ ] Class as service ID
      • [ ] Class as alias
      • [ ] Class as alias shortcut
      • [ ] Class as argument
      • [ ] Class as tag element
      • [ ] Whitelisted class
      • [ ] Class belonging to a whitelisted namespace
    • [ ] Neon support?
    opened by theofidry 15
  • Add windows support

    Add windows support

    When I try to run php-scoper add-prefix in my simple project I get an Exception:

    [Symfony\Component\Filesystem\Exception\IOException]                          
    Failed to create "C:\www\test\public\wp-content\plugins\asdasdasdsad\buildC:\www\test\public\wp-content\plugins\asdasdasdsad": mkdir(): No such file or directory.   
    

    As you can see the path is duplicated. Using output dir / working dir parameters doesn't help.

    I'm on Windows 10 using the MINGW64 command line.

    enhancement 
    opened by Kubitomakita 15
  • Composer\InstalledVersions not found

    Composer\InstalledVersions not found

    I'm trying to use scoper on my project where I use Composer\InstalledVersions class. After running scoper the class gets prefixed with _PhpScoper2d7049acc8b0 and becomes _PhpScoper2d7049acc8b0\Composer\InstalledVersions. After running scoper I run composer dump --classmap-authoritative from within build/ directory.

    Now when I try to run my application I get an error: Uncaught Error: Class '_PhpScoperb8eeadf8a1cd\Composer\InstalledVersions'

    I've found that reference to this class is in vendor/composer/autoload_classmap.php file, but it's referencing a non-prefixed version:

    'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
    

    Is there anything I'm doing wrong?

    opened by martinssipenko 13
  • Whitelisting

    Whitelisting

    Hi!

    At the PHPUnit Code Sprint here in Hamburg yesterday and today, @kambo-1st worked on https://github.com/sebastianbergmann/phpunit/issues/2015. Based on his findings, we came to the conclusion that (at least) the {classes|interfaces|traits} of phpunit/phpunit and phpunit/phpunit-mock-objects need to be whitelisted when building a prefixed PHAR. By whitelisting we mean that the names of these units of code are not prefixed. The code that declares these units of code needs to be processed, though, as it need to be updated to used the prefixed names of the other dependencies.

    A problem that we ran into is the fact that php-scoper requires a list of the classes to be whitelisted. Is there any way that whitelisting could work based on namespace names or (FQCN) class name prefixes?

    opened by sebastianbergmann 13
  • Error while running add-prefix command

    Error while running add-prefix command

    Bug report

    | Question | Answer | Getting error while running the php-scoper add-prefix command

    I came across php-scoper because I was experiencing dependency hell in my custom wordpress plugin. I just want to prefix one package(guzzlehttp). I found implementing php-scoper to be extremely hard and i'm probably doing it all wrong.

    I get the following error while running the php-scoper add-prefix command

    In Filesystem.php line 95:

    Failed to create "C:/Users/singa/source/repos/WIP/woocommerce-xero-integration/woocommerce-xero-integration/woocommerce-xero-integration/dependencies/vendorC:\Users\singa\source\repos\WIP\woocommerce-xero-integration\woocommerce-xero-integration\woocommerce-xero-integration\vendor\guzzlehttp\guzzle\src": mkdir(): No such file or directory

    | --------------- | PHP-Scoper version | x.y.z 0.18 | PHP version | x.y.z 8.1 | Platform with version | e.g. Ubuntu/Windows/MacOS Windows | Github Repo | -

    scoper.inc.php
    <?php
    
    declare(strict_types=1);
    
    use Isolated\Symfony\Component\Finder\Finder;
    
    return [
    ];
    
    
    Output
    $ command
    > output
    
    opened by AnirudhSingal91 6
  • Add a dry-run command

    Add a dry-run command

    It could be useful to have a command akin to the box process command which can dump the result, allowing the user to check the influence of the config used on the file.

    enhancement 
    opened by theofidry 0
  • Add better PHPUnit support

    Add better PHPUnit support

    See https://gist.github.com/sebastianbergmann/9eba10f9e61c576950df8bcd37712992#file-phar-md.

    It would be interesting to have PHPUnit, as we have Infection, part of the e2e test suite.

    enhancement 
    opened by theofidry 3
  • Review various string usages

    Review various string usages

    In https://github.com/humbug/php-scoper/pull/556/files a ComposerPatcher has been introduced to fix a few string usages. However at first glance they should be cases already handled hence should be investigated

    bug 
    opened by theofidry 0
  • php-scoper as docker image

    php-scoper as docker image

    Feature Request

    Hello! In fact this is not a feature request, is a feature I've already done and maybe you want to adopt it as part of the php-scoper community 😄

    I've made a php-scoper docker image based on the official composer docker image so you are able to use it as cli tool with docker.

    If you are interested in making an 'official' version or referencing it in the project you can take all the information needed from here:

    https://github.com/Rzial/docker-php-scoper https://hub.docker.com/r/rzial/php-scoper

    opened by Rzial 0
Releases(0.18.2)
  • 0.18.2(Jan 5, 2023)

    Bugfixes

    • fix: Handle the case where the Compoer InstalledVersions.php file is not present (#830)
    • fix: Fix conflicting humbug_phpscoper_expose_class class declaration (#831, #811)

    Misc

    • ci: Simplify the security check workflow (#812)
    • ci: Simplify the build workflow (#813)
    • chore: Fix makefile CS (#814)
    • ci: Review the Lint workflow (#815)
    • chore: Remove PHPCS configuration file (#816)
    • chore: Add gitignore sort (#817)
    • ci: Add a meta build for the ComposerRootVersion tests (#818)
    • ci: Remove matrix from jobs that are not matrices (#819)
    • ci: Introduce a meta build for the unit tests (#820)
    • chore: Move PHP-CS-Fixer and PHPUnit artefacts to the build directory (#821)
    • chore: Exclude more files from the release artefact (#822)
    • chore: Extract the e2e make test rules into a dedicated file (#825)
    • chore: Tweak the ComposerRootVersionChecker related make commands (#826)
    • chore: Add undesired lock files to the gitignore (#827)
    • chore: Remove some commands from being documented in the Makefile (#828)
    • chore(makefile): Improve the outdated_fixtures command (#829)
    • chore(makefile): Re-organise the make commands (#824)
    • chore: Use build directory instead of dist (#833)
    Source code(tar.gz)
    Source code(zip)
    php-scoper.phar(1.13 MB)
    php-scoper.phar.asc(598 bytes)
  • 0.18.1(Dec 24, 2022)

  • 0.18.0(Dec 23, 2022)

    Features

    • feat: Update dependencies (#802)

    Bugfixes

    • fix: Bump the Composer root version (#787)
    • fix: Remove unnecessary polyfill (#794)
    • fix: Allow to use the default value for the output directory (#801)

    Misc

    • ci(refactor): Update the GitHub Actions steps (#785)
    • ci(fix): Remove the env from the Composer root version (#788)
    • refactor: Rework the composer root version checker into a proper sub-project (#789)
    • fix: Fix the RootVersionChecker (#790)
    • ci(refactor): Simplify the Composer installation in the CI (#791)
    • ci(fix): Fix a test name (#795)
    • ci(fix): Fix the lint jobs (#796)
    • refactor: Rework the makefile test with FidryMakefile (#792)
    • fix: Fix the e2e test 035 (#793)
    • ci(feat): Add PHP 8.2 for the build (#797)
    • refactor: Remove remaining usages of whitelist (#780)
    • ci(feat): Add a new meta job for the protected branch rules for the tests (#799)
    • ci(feat): Run the e2e tests on PHP 8.2 and also with different Composer versions (#798)
    • build(fix): Remove unnecessary files from the exported archive (#800)
    • ci(fix): Update actions/upload-artifact to v3 (from v2) (#803)
    Source code(tar.gz)
    Source code(zip)
    php-scoper.phar(1.14 MB)
  • 0.18.0-rc.0(Nov 20, 2022)

    This release is a another big release. It really aims at tackling some fundamental and long-standing issues that are preventing a 1.x release. The two main problems being:

    • The handling of polyfills and declaring or usage of global constants as seen in (#)
    • The broken autoloading of files (see #298)

    This release is an RC as this brings significant changes that I would like to pay more attention to and evaluate or it will affect big users such as PHPUnit, PHPStan, Infection or Rector.

    Feature

    • Fix internal symbol declarations (#706 #710, #722)
    • [BC break] Update the default config to expose the global symbols by default (#710)
    • Fix the support of Composer autoloaded files (#773, #774)
    • Complete the support for PHP 8.1 features
      • Add enum support (#725)
      • Add support for Attributes (#738)
      • Add tests for other PHP 8.0 & 8.1 features (#729, #730, #731, #732, #733, #734)
    • Add support for Symfony6 (#711)
    • Add support for Laravel9 (#747)
    • Improve the scoper autoload file:
      • Change the link for the alias docs in the scoped autoload (#714)
      • Make function alias declaration one-liners (#715)
      • Sort the exposed function entries (#716)
      • Declare a function humbug_php_scoper_expose_class() to simplify the class alias declarations (#718)
      • Group function declarations by namespace (#719)
    • Update all dependencies (#704, #772)
    • Unmark PatcherChain#getPatchers() as internal (#737)
    • [BC Break] Don't allow empty string as a symbol regex or name (#741)
    • [BC Break] Remove the deprecated whitelist setting (#742)
    • Add output-dir configuration option (#632)
    • Add Configuration::withPatcher() factory (#749)
    • [BC Break] Remove deprecated ConfigurableScoper (#705)

    Bugfixes

    • Fix InstalledVersions installed (#712)
    • Use the recorded symbols to decide when to add the class_alias statements (#724)
    • Preserve the files permissions (#753)
    • Fix the inspect-symbol command slowness (#755)
    • Fix regex cannot have the i flag (#759)
    • Fix define check of class constant (#745, #746)

    Misc

    • Various documentation improvements (#739, #744, #763, #768, #770)
    • Various internal refactorings (#702 #717, #720, #723, #735, #740, #743, #750, #754, #756, #758, #761, #764, #757, #760, #765, #766, #767, #769, #775, #776)
    • Set bamarni.foward-command to false (#703)
    • Add a build to check dependencies for security vulnerabilities (#736)
    • Consolidate some tests (#709, #721, #748, #777, #778, #779)
    Source code(tar.gz)
    Source code(zip)
    php-scoper.phar(1.13 MB)
    php-scoper.phar.asc(598 bytes)
  • 0.17.7(Nov 4, 2022)

  • 0.17.6(Sep 28, 2022)

  • 0.17.5(Jun 26, 2022)

  • 0.17.4(Jun 19, 2022)

  • 0.17.3(Jun 19, 2022)

  • 0.17.2(Feb 21, 2022)

  • 0.17.1(Feb 19, 2022)

  • 0.17.0(Feb 13, 2022)

    Features

    • Improve PHP 8.1 support
      • Fix deprecations (#617, #543)
      • Add support for union and intersection types (#644)
    • Add InspectSymbols command (#619)
    • Add support for regexes for excluded symbols (#660)

    Bugfixes

    • Patch various symbols not interpreted as internal (#626)
    • Stops the process if says no when PHP-Scoper asks if the output directory can be deleted (#631)
    • Fix autoload generator links (#630)

    Docs

    • Document the idiomatic way to include polyfills (#636)
    • Replace incorrect usage of files-whitelist by exclude-files (#651)

    Misc

    • Move default file name to the ConfigurationFactory (#621)
    • Prefer newline over writing empty string (#622)
    • Improve tests(#624, #648, #654, #659)
    • Move EnrichedReflector into a factory service (#625)
    • Build the PHAR in multiple PHP versions for better testing (#628)
    • Add Configuration::withPrefix() (#629)
    • Add outdated-fixtures command by (#641)
    • Improve NamespaceRegistry (#645)
    • Simplify TraverserFactory (#653)
    • Introduce a Printer abstraction (#655)
    • Adapt printer API to preserve formatting (#652)
    Source code(tar.gz)
    Source code(zip)
    php-scoper.phar(1.07 MB)
  • 0.16.2(Jan 30, 2022)

  • 0.16.1(Jan 30, 2022)

  • 0.16.0(Jan 30, 2022)

    Breaking Changes

    • files-whitelist has been renamed into exclude-files
    • whitelist-global-constants has been renamed into expose-global-constants
    • whitelist-global-classes has been renamed into expose-global-classes
    • whitelist-global-functions has been renamed into expose-global-functions
    • whitelist has been deprecated in favour of the exclude-* and expose-* entries and will be removed in 0.17.0

    Features

    • Bump min PHP version to 7.4 (#474)
    • Improve file whitelist (renamed excluded files) performances (#445)
    • Rework the whole "whitelist" logic to split it into two concepts: exclude and expose. Excluded symbols are treated as PHP internal symbols i.e. left untouched. Exposed symbols are symbols that will remain accessible after scoping. More details in the docs and the following related PRs:
      • Allow to register internal symbols & namespaces (#493, #494, #520, #570) via the config entries exclude-{namespaces, constants, classes, functions}
      • Rename the whitelist-global-{constants, classes, functions} to expose-global-{constants, classes, functions} (#517)
      • Move from whitelist to expose-{namespaces, constants, classes, functions} (#519, #521, #522, #525, #526, #527, #553, #608)
    • Change default expose global symbols from true to false (#523)
    • Fix (some) PHP8.1 compatibility (#528)
    • Remove Composer1 support (#544, #556)
    • Add multi-const statement support (#571)
    • Rename "whitelisted files" to "excluded files" (#611)

    Bugfixes

    • Fix polyfills shipped within PHP-Scoper (#481)
    • Fix prefix validation (#490)
    • Fix scoping of typed properties (#499)
    • Fix scoping of NULL (#500)
    • Fix scoping of closures return type (#524)
    • Fix doc link (#531, #385)
    • Fix regex detection (#596)
    • Restrict regex delimiters allowed (#598)

    Misc

    • Various Makefile improvements (#476, #588)
    • Various code improvements:
      • Switch to the Safe API when possible (#475)
      • Leverage PHP 7.4 (#478, #491)
      • Integrate FidryConsole (#418)
      • Validate the prefix in the Configuration instead of the command (#482)
      • Refactor AddPrefixCommand (#483)
      • Make prefix non-nullable (#485)
      • Use self instead of this for PHPUnit assertions (#487)
      • Move creation of the config into a dedicated factory class (#488)
      • Move Prefix validation to the Configuration class (#489)
      • Make PHPUnit data providers static (#518)
      • Introduce ScoperFactory (#492)
      • Refactor various classes (#495, #502, #503, #504, #505, #506, #507, #508, #509, #564, #566, #569, #573, #574, #578, #580, #576, #581, #585, #586, #587, #591, #592, #594, #602, #603, #604, #552)
      • Replace PHP-Scoper name resolver by the PHP-Parser one (Part 1) (#496)
      • Introduce static utility method for reflector (#554)
      • Make methods static when possible (#558)
      • Move the prefix, patchers and whitelist out of the Scoper interface (#555)
      • Introduce a Patcher interface (#562)
      • Introduce SymbolsRegistry (#567)
      • Introduce the EnrichedReflector (#575)
      • Introduce NamespaceRegistry (#582)
      • Introduce SymbolsConfiguration (#584)
      • Introduce SymbolRegistry (singular) (#593)
    • Improve the CI (#544, #545, #546, #547, #550, #551, #560, #568)
    • Update composer config to allow plugins (#561, #605)
    • Fix Box (#590)
    • Enrich spec failure message (#599)
    • Update the doc (#610)
    Source code(tar.gz)
    Source code(zip)
  • 0.15.0(May 10, 2021)

  • 0.14.1(Apr 14, 2021)

  • 0.14.0(Dec 21, 2020)

  • 0.13.10(Nov 29, 2020)

  • 0.13.9(Nov 6, 2020)

    Bugfixes

    • Update composer/package-versions-deprecated (#428)
    • Fix internal constants (#425)

    Misc

    • Update phpstan (#427)
    • Add lint workflow for phpstan and phpcs (#431)
    • Force use statements for global function, constants and classes if they are not colliding (#432)
    • Upgrade Symfony dependencies (#429)
    Source code(tar.gz)
    Source code(zip)
    php-scoper.phar(785.55 KB)
  • 0.13.8(Oct 29, 2020)

  • 0.13.7(Oct 21, 2020)

  • 0.13.6(Oct 12, 2020)

  • 0.13.5(Sep 16, 2020)

  • 0.13.4(Sep 7, 2020)

  • 0.13.3(Aug 7, 2020)

  • 0.13.2(Jun 14, 2020)

  • 0.13.1(Jan 22, 2020)

  • 0.13.0(Dec 13, 2019)

    Features

    • Add support for PHP 7.4 new features (#359)

    Bugfixes

    • Fix string resolution with leading backslash (#363)
    • Add e2e test to ensure the isolated finder exists (#364)

    Misc

    • Update dependencies (#358)
    • Remove unnecessary constants from the reflector (#360)
    • Update phpstan (#361)
    • Update Infection (#362)
    Source code(tar.gz)
    Source code(zip)
    php-scoper.phar(731.80 KB)
  • 0.12.4(Jun 26, 2019)

Owner
Humbug
Humbug is a Mutation Testing framework for PHP to measure the real effectiveness of your test suites. We also maintain some PHAR distribution tools.
Humbug
YCOM Impersonate. Login as selected YCOM user 🧙‍♂️in frontend.

YCOM Impersonate Login as selected YCOM user in frontend. Features: Backend users with admin rights or YCOM[] rights, can be automatically logged in v

Friends Of REDAXO 17 Sep 12, 2022
Composer bin plugin — Isolate your bin dependencies

Composer bin plugin — Isolate your bin dependencies Table of Contents Why? How does this plugin work? Installation Usage Example The all bin namespace

Bilal Amarni 394 Jan 7, 2023
Easily add sub domains to your CakePHP application using route prefixes

Easily add sub domains to your CakePHP application using route prefixes. Based on code created by chinpei215.

multidimension.al 4 Feb 28, 2019
📦🚀 Fast, zero config application bundler with PHARs.

Fork of the unmaintained box2 project. This project needs your help! Upgrading from Box2? Checkout the upgrade guide! Goal The Box application simplif

Box Project 865 Dec 26, 2022
An application for building and managing Phars.

An application for building and managing Phars.

Box Project 1.2k Nov 9, 2022
Directory for storing files from PHP and Logic classes

Curso Logica e PHP (C4) ✔️ Diretório para guardar os arquivos das aulas de PHP e lógica Seção 1 - Introdução Seção 2 - Lógica com VisualG e Nocões de

Bruno Henrique 1 Jan 28, 2022
Compares two directories and removes the duplicate files from the second directory.

How does the HRZ Duplicate Refiner work? 1- Compares two directories : patternDir: the directory used as the pattern & does not change. victimDir: A d

Hamidreza Zolfaghar 2 May 6, 2022
This composer plugin removes unnecessary development files and directories from vendor directory

Composer Vendor Cleaner This composer plugin removes unnecessary development files and directories from vendor directory. Installation Local installat

Libor M. 15 Dec 16, 2022
Victor The Cleaner for Composer - This tool removes unnecessary files and directories from Composer vendor directory.

Victor The Cleaner for Composer This tool removes unnecessary files and directories from Composer vendor directory. The Cleaner leaves only directorie

David Grudl 133 Oct 26, 2022
Integrates the ClassicPress Plugin Directory and any plugin stored in GitHub (tagged with classicpress-plugin) in the ClassicPress Admin

ClassicPress Plugin Directory Adds a new screen in a ClassicPress Install where you can browse, install, activate, deactivate, update, delete and pagi

TukuToi 3 Dec 27, 2022
Optimizes class loading performance by generating a single PHP file containing all of the autoloaded files.

Class Preloader for PHP This tool is used to generate a single PHP script containing all of the classes required for a specific use case. Using a sing

Class Preloader 356 Nov 26, 2022
Ip2region is a offline IP location library with accuracy rate of 99.9% and 0.0x millseconds searching performance. DB file is ONLY a few megabytes with all IP address stored. binding for Java,PHP,C,Python,Nodejs,Golang,C#,lua. Binary,B-tree,Memory searching algorithm

Ip2region是什么? ip2region - 准确率99.9%的离线IP地址定位库,0.0x毫秒级查询,ip2region.db数据库只有数MB,提供了java,php,c,python,nodejs,golang,c#等查询绑定和Binary,B树,内存三种查询算法。 Ip2region特性

Lion 12.6k Dec 30, 2022
:globe_with_meridians: List of all countries with names and ISO 3166-1 codes in all languages and data formats.

symfony upgrade fixer • twig gettext extractor • wisdom • centipede • permissions handler • extraload • gravatar • locurro • country list • transliter

Saša Stamenković 5k Dec 22, 2022
Control all text in multiple file bad words filter with worps

About Worps | PHP! Control all text in multiple file bad words filter with worps If you try online Click What to do use for worps Create new object Wo

null 1 Dec 30, 2021
File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery

File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.

Sebastian Tschan 31.1k Dec 30, 2022
KodExplorer is a file manager for web. It is also a web code editor, which allows you to develop websites directly within the web browser.

KodExplorer is a file manager for web. It is also a web code editor, which allows you to develop websites directly within the web browser.

warlee 5.5k Feb 10, 2022
Result of our code-along meetup writing PHP 8.1 code

PHP 8.1 Demo Code This code demonstrates various PHP 8.0 and 8.1 features in a realistic, functional (but incomplete) codebase. The code is part of so

azPHP 2 Nov 14, 2021
Dead Code Detector (DCD) for PHP code.

This project is no longer maintained and its repository is only kept for archival purposes. PHP Dead Code Detector (PHPDCD) phpdcd is a Dead Code Dete

Sebastian Bergmann 406 Dec 30, 2022
⚗️ Adds code analysis to Laravel improving developer productivity and code quality.

⚗️ About Larastan Larastan was created by Can Vural and Nuno Maduro, got artwork designed by @Caneco, is maintained by Can Vural, Nuno Maduro, and Vik

Nuno Maduro 4.4k Jan 4, 2023