Skip to content

Commit

Permalink
Allow to whitelist functions (#241)
Browse files Browse the repository at this point in the history
  • Loading branch information
theofidry authored Jul 3, 2018
1 parent 683e75c commit bdd6cd5
Show file tree
Hide file tree
Showing 17 changed files with 584 additions and 90 deletions.
19 changes: 18 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ tm: bin/phpunit

.PHONY: e2e
e2e: ## Run end-to-end tests
e2e: e2e_004 e2e_005 e2e_011 e2e_013 e2e_014 e2e_015 e2e_016 e2e_017 e2e_018 e2e_019 e2e_020 e2e_021 e2e_022 e2e_023 e2e_024
e2e: e2e_004 e2e_005 e2e_011 e2e_013 e2e_014 e2e_015 e2e_016 e2e_017 e2e_018 e2e_019 e2e_020 e2e_021 e2e_022 e2e_023 e2e_024 e2e_025

PHPSCOPER=bin/php-scoper.phar

Expand Down Expand Up @@ -238,6 +238,20 @@ e2e_024: bin/php-scoper.phar fixtures/set024/vendor
php build/set024/main.php > build/set024/output
diff fixtures/set024/expected-output build/set024/output

.PHONY: e2e_025
e2e_025: ## Run end-to-end tests for the fixture set 025 — Whitelisting a vendor function
e2e_025: bin/php-scoper.phar fixtures/set025/vendor
$(PHPNOGC) $(PHPSCOPER) add-prefix \
--working-dir=fixtures/set025 \
--output-dir=../../build/set025 \
--force \
--no-interaction \
--stop-on-failure
composer --working-dir=build/set025 dump-autoload

php build/set025/main.php > build/set025/output
diff fixtures/set025/expected-output build/set025/output


.PHONY: tb
BLACKFIRE=blackfire
Expand Down Expand Up @@ -358,6 +372,9 @@ fixtures/set023/composer.lock: fixtures/set023/composer.json
fixtures/set024/composer.lock: fixtures/set024/composer.json
@echo fixtures/set024/composer.lock is not up to date.

fixtures/set025/composer.lock: fixtures/set025/composer.json
@echo fixtures/set025/composer.lock is not up to date.

bin/php-scoper.phar: bin/php-scoper src vendor scoper.inc.php box.json
$(BOX) compile
touch $@
Expand Down
108 changes: 85 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,13 @@ potentially very difficult to debug due to dissimilar or unsupported package ver
- [Finders and paths](#finders-and-paths)
- [Patchers](#patchers)
- [Whitelist][whitelist]
- [Constants from the global namespace whitelisting](#constants-from-the-global-namespace-whitelisting)
- [Classes & Constants whitelisting](#classes--constants-whitelisting)
- [Global user functions](#global-user-functions)
- [Constants & functions from the global namespace](#constants--functions-from-the-global-namespace)
- [Symbols](#symbols)
- [Caveats](#caveats)
- [Implementation insights](#implementation-insights)
- [Class whitelisting](#class-whitelisting)
- [Constants whitelisting](#constants-whitelisting)
- [Functions whitelisting](#functions-whitelisting)
- [Namespaces whitelisting](#namespaces-whitelisting)
- [Building a scoped PHAR](#building-a-scoped-phar)
- [With Box](#with-box)
Expand Down Expand Up @@ -266,11 +270,11 @@ a PHPUnit PHAR with isolated code, you still want the PHAR to be able to
understand the `PHPUnit\Framework\TestCase` class.


### Constants from the global namespace whitelisting
### Constants & functions from the global namespace

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

```php
<?php declare(strict_types=1);
Expand All @@ -279,13 +283,14 @@ prefixed as usual unless explicitely whitelisted:

return [
'whitelist-global-constants' => false,
'whitelist-global-functions' => false,
];
```


### Classes & Constants whitelisting
### Symbols

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

```php
<?php declare(strict_types=1);
Expand All @@ -296,11 +301,21 @@ return [
'whitelist' => [
'PHPUnit\Framework\TestCase',
'PHPUNIT_VERSION',
'iter\count',
],
];
```

This will _not_ work on traits or functions.
#### 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
Expand All @@ -316,31 +331,78 @@ 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][box]
if you are using it with the [`PhpScoper` compactor][php-scoper-integration].

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

```php
<?php

namespace Acme;

class Foo {}
```

The scoped file will look like this:

```php
<?php

namespace Humbug\Acme;

class Foo {}

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

With:

```php
<?php

// scoper-autoload.php @generated by PhpScoper

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

class_alias('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](https://stackoverflow.com/a/3193704/3902761)
post regarding the differences [here](https://stackoverflow.com/a/3193704/3902761)

Give the following file with a whitelisted constant:

### Global user functions
```php
<?php

By default, functions declared by users in the global namespace are whitelisted:
namespace Acme;

```php
<?php declare(strict_types=1);
const FOO = 'X';
```

// scoper.inc.php
The scoped file will look like this:

use Isolated\Symfony\Component\Finder\Finder;
```php
<?php

return [
'whitelist-global-functions' => true,
];
namespace Humbug\Acme;

\define('FOO', 'X');
```

So when you declare a function like so:
##### 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
<?php
Expand Down Expand Up @@ -377,7 +439,7 @@ $loader = require_once __DIR__.'/autoload.php';

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

Expand Down
5 changes: 5 additions & 0 deletions fixtures/set025/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"require": {
"nikic/iter": "^1.6"
}
}
62 changes: 62 additions & 0 deletions fixtures/set025/composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions fixtures/set025/expected-output
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
array(5) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(4)
[4]=>
int(5)
}
19 changes: 19 additions & 0 deletions fixtures/set025/main.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Acme;

use function call_user_func;
use function file_exists;
use function iter\toArray;

if (file_exists($autoload = __DIR__ . '/vendor/scoper-autoload.php')) {
require_once $autoload;
} else {
require_once __DIR__ . '/vendor/autoload.php';
}

$range = '\iter\range'.'';

var_dump(toArray(call_user_func($range, 1, 5)));
19 changes: 19 additions & 0 deletions fixtures/set025/scoper.inc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

/*
* This file is part of the humbug/php-scoper package.
*
* Copyright (c) 2017 Théo FIDRY <[email protected]>,
* Pádraic Brady <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

return [
'whitelist' => [
'iter\RANGE', // Use a case mismatch on purpose: function references should be case insensitive
],
];
56 changes: 56 additions & 0 deletions specs/func-declaration/global.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,62 @@
'whitelist-global-functions' => true,
],

'Simple function declaration' => <<<'PHP'
<?php
function foo() {}
----
<?php
namespace Humbug;
function foo()
{
}

PHP
,

'Simple whitelisted function' => [
'whitelist' => ['foo'],
'payload' => <<<'PHP'
<?php
function foo() {}
----
<?php
namespace Humbug;
function foo()
{
}

PHP
],

'Simple whitelisted function with global functions non whitelisted' => [
'whitelist-global-functions' => false,
'whitelist' => ['foo'],
'payload' => <<<'PHP'
<?php
function foo() {}
----
<?php
namespace Humbug;
function foo()
{
}

PHP
],

[
'spec' => <<<'SPEC'
Function declaration in the global namespace:
Expand Down
Loading

0 comments on commit bdd6cd5

Please sign in to comment.