Git Product home page Git Product logo

xdebug-handler's Introduction

Composer

Dependency Management for PHP

Composer helps you declare, manage, and install dependencies of PHP projects.

See https://getcomposer.org/ for more information and documentation.

Continuous Integration

Installation / Usage

Download and install Composer by following the official instructions.

For usage, see the documentation.

Packages

Find public packages on Packagist.org.

For private package hosting take a look at Private Packagist.

Community

Follow @packagist or @seldaek on Twitter for announcements, or check the #composerphp hashtag.

For support, Stack Overflow offers a good collection of Composer related questions, or you can use the GitHub discussions.

Please note that this project is released with a Contributor Code of Conduct. By participating in this project and its community you agree to abide by those terms.

Requirements

Latest Composer

PHP 7.2.5 or above for the latest version.

Composer 2.2 LTS (Long Term Support)

PHP versions 5.3.2 - 8.1 are still supported via the LTS releases of Composer (2.2.x). If you run the installer or the self-update command the appropriate Composer version for your PHP should be automatically selected.

Binary dependencies

  • 7z (or 7zz)
  • unzip (if 7z is missing)
  • gzip
  • tar
  • unrar
  • xz
  • Git (git)
  • Mercurial (hg)
  • Fossil (fossil)
  • Perforce (p4)
  • Subversion (svn)

It's important to note that the need for these binary dependencies may vary depending on individual use cases. However, for most users, only 2 dependencies are essential for Composer: 7z (or 7zz or unzip), and git.

Authors

See also the list of contributors who participated in this project.

Security Reports

Please send any sensitive issue to [email protected]. Thanks!

License

Composer is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

xdebug-handler's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

xdebug-handler's Issues

Release process ?

Hi !
Is there any release process that users can be aware about?

We have bunch of good changes already merged to master, but not released:
1.1.0...master

Unclear relevance for Composer

README contains:

Originally written as part of composer/composer, now extracted and made available as a stand-alone library.

My interpretation was that this code had been written in Composer, but that the Composer project then decided the code should be removed from Composer, so the code was made available in a new project. But my colleague Jonny Bradley points out that this issue seems to be solved in current Composer, so perhaps "extracted" should not be understood as "moved out" but as "copied".

Please make the README clear about whether the code is currently part of official Composer.

Fun intersection with apc and Macs running Vagrant

When XDebug is turned on, and the XDebugHandler is initialised, on a Vagrant boxes with a CentOS installation, there's the following error when running Psalm:

PHP Fatal error:  PHP Startup: apc_mmap: mkstemp on /tmp/apc.KyxDdB failed: in Unknown on line 0

It's triggered when calling passthru.

This only happens when running Vagrant on macs, not on Linux.

I very much doubt this is the fault of XDebugHandler, but it obviously triggers the issue.

Restarted (child) process does not return color output (automatically)

Following #86. I've created small reproducer repository for those issues:
https://github.com/k911/composer-xdebug-handler-signals-bug-reproducer

Composer\XdebugHandler does not detect properly (or at least automatically) TTY support in restarted process, which changes behaviour of CLI command.

Reproducer file colors.php

Requirements: xdebug and extension enabled

  1. At first run command without restarting process

    ➜ APP_ALLOW_XDEBUG=1 php colors.php

    Output:

    color-output

    Which is expected.

  2. Then, execute script without APP_ALLOW_XDEBUG environment variable

    ➜ php colors.php

    Output:

    no-color-output

I know, I still probably can force color output when using option like --ansi for some CLI tools, but in my opinion this should be detected automatically.

Proposed solution

Use for example symfony/process which can detect it in one line:
https://github.com/k911/swoole-bundle/blob/0dc13f00b5604cbae4e20147bdbce04e4d98eb9d/src/Common/XdebugHandler/XdebugHandler.php#L74

INI file and broken disable_functions

I have an issue, when the copied ini file have proc_open in disable_functions, because of broken merging of additional files. This causes composer to stop working.

This is simplified reproduction of this issue:

php.ini - default from compilation

disable_functions=proc_open

And additional ini files

01-first.ini - this contains some rules in [PATH=..] section

[PATH=/var/www/html]
memory_limit=512G

02-second.ini - this contains rules without sections

disable_functions=""

Composer from these files will produce following ini file:

disable_functions=proc_open
[PATH=/var/www/html]
memory_limit=512G
disable_functions=""

As you can see disable_functions="" is no longer applicable to all scripts but only to /var/www/html. In addition to this also all composer settings are ignored as well, since these are in PATH section.

Cleanups now that proc_open is used

I wonder.. is Process::supportsColor and the whole colorOption concept still needed? I am guessing this was all workarounds because STDOUT wasn't bound properly in the child process. Not urgent by any means, but it might be good to clean things up.

PHP Warning: proc_open(): Exec failed: No such file or directory in phar

php 8.1.23 + Xdebug 3
Debian GNU/Linux 11 (bullseye)
nginx 1.18 + php-fpm
Laravel 10.33.0
Composer version 2.7.4

I get this error

PHP Warning:  proc_open(): Exec failed: No such file or directory in phar:///usr/local/bin/composer_php81/vendor/composer/xdebug-handler/src/XdebugHandler.php on line 300 
PHP Stack trace:
PHP   1. {main}() /usr/local/bin/composer_php81:0
PHP   2. require() /usr/local/bin/composer_php81:29
PHP   3. Composer\XdebugHandler\XdebugHandler->check() phar:///usr/local/bin/composer_php81/bin/composer:29
PHP   4. Composer\XdebugHandler\XdebugHandler->restart($command = [0 => '', 1 => '-n', 2 => '-c', 3 => '/tmp/NylWn5', 4 => '/usr/local/bin/composer', 5 => 'install', 6 => '--dry-run']) phar:///usr/local/bin/composer_php81/vendor/composer/xdebug-handler/src/XdebugHandler.php:149 
PHP   5. Composer\XdebugHandler\XdebugHandler->doRestart($command = [0 => '', 1 => '-n', 2 => '-c', 3 => '/tmp/NylWn5', 4 => '/usr/local/bin/composer', 5 => 'install', 6 => '--dry-run']) phar:///usr/local/bin/composer_php81/vendor/composer/xdebug-handler/src/XdebugHandler.php:274 
PHP   6. proc_open($command = [0 => '', 1 => '-n', 2 => '-c', 3 => '/tmp/NylWn5', 4 => '/usr/local/bin/composer', 5 => 'install', 6 => '--dry-run'], $descriptor_spec = [], $pipes = NULL) phar:///usr/local/bin/composer_php81/vendor/composer/xdebug-handler/src/XdebugHandler.php:300 
Return code: 127

I try run this script from browser. (over nginx+php-fpm)

        $descriptors = [
            0 => ['pipe', 'r'], // stdin
            1 => ['pipe', 'w'], // stdout
            2 => ['pipe', 'w']  // stderr
        ];

        $process = proc_open('composer install --dry-run', $descriptors, $pipes);

        if (is_resource($process)) {
            fclose($pipes[0]);

            $output = stream_get_contents($pipes[1]);
            fclose($pipes[1]);

            $errors = stream_get_contents($pipes[2]);
            fclose($pipes[2]);

            $returnCode = proc_close($process);

            dump("Output: $output");
            dump("Errors: $errors");
            dump("Return code: $returnCode");
        }

`ini_get` returning invalid values in some environments when php.ini is copied into tmp folder

I have an open issue on the PHPStan repo, which uses this library to detect if xdebug is running or not.

That issue probably explains it better than I can summarize here, but the tl/dr is that they're calling ini_get on post_max_size and it's returning '' in my environment. It appears to be happening when the php.ini is copied into a /tmp folder. If I call ini_get on post_max_size from the "normal" location, it returns the accurate value.

I'm not sure the next steps, but would love to get any eyes on it and happy to debug further!

Fix color output handling

XdebugHandler only recognizes --ansi and --no-ansi command-line options, so we need to incorporate some of the other commonly used options:

--color, --colors, --color=..., --colors=...

I'll keep the changes small and simple.

Signals are not passed to the restarted (child) process

I've created small reproducer repository for this:
https://github.com/k911/composer-xdebug-handler-signals-bug-reproducer

Reproducer file: signals.php

Requirements: xdebug and pcntl PHP extensions enabled

  1. At first run command without restarting process, and after some time press CTRL-C combination (or send SIGINT signal, using kill -SIGINT PID)

    ➜ APP_ALLOW_XDEBUG=1 php signals.php
    
    # output:
    # 
    # Hello from PID: 11087
    # Started!
    # ^C
    # Stopping..
    # Stopped after 974 ms

    This is expected behaviour.

  2. Then, execute script without APP_ALLOW_XDEBUG environment variable

    ➜ php signals.php 
    
    # output:
    #
    # Hello from PID: 11677
    # Hello from PID: 11678
    # Started!
    # ^C

    As you can see, process was stopped, but signal handler were never executed, because CLI sends it to first process, not to the child. Of course, I could send signal to second (child) process, which will handle signal and end process, but it makes CLI commands being unfriendly for end users.

Proposed solution

Use for example symfony/process package, to create restarted process, and either pass all signals to child process or allow to customize it.

You can see POC solution here: https://github.com/k911/swoole-bundle/blob/0dc13f00b5604cbae4e20147bdbce04e4d98eb9d/src/Common/XdebugHandler/XdebugHandler.php#L79-L90

Save original xdebug settings

It would be great to store somewhere original xdebug parameters.

Q: Why do I need this?
A: Our application works on top of phpunit and we would like to know whether code coverage parameter was enabled after xdebug handler restarted process or not. Mostly it is needed for xdebug 3 and we would like to get at least xdebug.mode (for xdebug 3) and xdebug.coverage_enable (for xdebug < 3)

There is a workaround:
We may get and parse all ini files through XdebugHandler::getRestartSettings()['inis'] on our end but it would be good to have this feature in xdebug-handler.

I can spend some time and prepare a pull request if you think that it will be good to have such feature.

Escaping of arguments strips-out non-ASCII characters.

Description is copied from cakephp/debug_kit#637

DebugKit somehow corrupts base paths of programs run by composer when xdebug is installed on Linux.

Create a project directory, containg unicode characters in it's path, e.g.: /home/example/Пример/test/.
Create there following files: composer.json, and build.xml

composer.json

{
    "name": "test/example",
    "description": "",
    "homepage": "http://example.com",
    "type": "project",
    "license": "MIT",
    "require": {
        "cakephp/debug_kit": "^3.15.0",
        "phing/phing": "^2.16"
    },
    "scripts": {
        "build": "phing"
    }
}

build.xml

<?xml version="1.0" encoding="UTF-8"?>

<project default="build" basedir="." phingVersion="2.16.0">
    <!-- main tasks -->
    <target name="build">
        <exec executable="composer" checkreturn="true" logoutput="true">
            <arg value="validate"/>
            <arg value="--no-check-lock"/>
            <arg value="--no-interaction"/>
        </exec>
    </target>
</project>

Run composer run build. It will fail because of a corrupt path.

> phing
Buildfile: /home/example/Пример/test/build.xml

build.xml > build:

     [exec] Could not open input file: /home/example//test/vendor/bin/composer

BUILD FAILED

Expected

> phing
Buildfile: /home/example/Пример/test/build.xml

build.xml > build:

     [exec] ./composer.json is valid

BUILD FINISHED

Total time: 0.2745 seconds

Remove cakephp/debug_kit from composer.json, run composer update and then run composer run build. The build command will finish successfully.

Support modern PHP for version 2

We could consider dropping support for older PHPs for version 2. Any dependents that support a PHP version less than whatever we decide our minimum is should be able to require ^1.4 || ^2.0, so their code will need to work with both versions.

Looking at all the dependents listed on Packagist, the vast majority do not extend the class so this is very simple (see item 1 below) and for those few that do extend the class it shouldn't really be any harder. The BC breaks will be:

  1. Constructor $colorOption optional param dropped:
    Using new XdebugHandler('myapp') would also work for 1.x because proc_open is used (unless only passthru is available). Using new XdebugHandler('myapp', '--ansi') would also work for 2.x since the extra param is ignored.

  2. Protected restart param $command changed from a string to an array:
    By not typehinting the method it can be used by 1.x and 2.x (unless $command is modified, which would require a little work - although this is not seen in any dependents).

  3. Protected requiresRestart param $isLoaded changed to $default:
    By not typehinting the method it can be used by 1.x and 2.x since both are boolean.

  4. The process will not restart if xdebug mode is off:
    This is not relevant to the code.

@Seldaek Interested in your input here. Perhaps a minimum of 7.1, although the xdebug mode stuff is only relevant on 7.2 upwards.

Merge all ini data to catch command-line ini settings

It is not possible to know if PHP is started with any -d ini value(s) so these will not be used for the restart.

As a workaround (to fix specific Composer issues) xdebug-handler adds memory_limit, disable_functions and allow_url_fopen to the temporary ini file. I PR-ed a way of including all ini settings but there was concern about the extra time this adds to the restart: composer/composer#6036

I have now set up a repo so that this can be tested on different set-ups: https://github.com/johnstevenson/xdebug-ini-test

Also included is a docker php image that uses a lot of ini files (58). Its test results can be seen here: https://travis-ci.org/johnstevenson/xdebug-ini-test

In my view, the more robust method of merging all ini data adds a negligible amount of time to the restart and is a fix-and-forget solution. Feedback appreciated. @Seldaek I would be interested to see if you still see the "3-400ms" lag and how this is split up (between ini creation and start-up times).

Possible performance issue with version 2.0.4

Hi :)

We're using FriendsOfPHP/PHP-CS-Fixer version 3.0.4 which relies on this package composer/xdebug-handler in version 2.

Since the recent upgrade from xdebug-handler version 2.0.3 to 2.0.4, PHP-CS-Fixer seems to be suffering from an important performance drop.

More details and procedure to reproduce the issue on the ticket I opened on their repository: PHP-CS-Fixer/PHP-CS-Fixer#6310

Question of PHPRC

Why was it decided to use -c over PHPRC?

With the latter, the process is straightforward:

  • Create our our php.ini with all other files merged it.
  • Set PHPRC to point to a directory with our php.ini, set PHP_INI_SCAN_DIR to an empty string, with previous values saved somewhere.
  • Run the original command as it is in $argv in the updated environment.
  • Restore original PHPRC and PHP_INI_SCAN_DIR.

No need to twiddle with command line options. No need for any workarounds. All other php invocations will a vanilla environment transparently. Hence, this is also backward compatible.

Using our xdebug-free environment for any of sub-processes is as simple as setting our custom values for PHPRC and PHP_INI_SCAN_DIR. This can be done from a callback like below, so a user won't even need to know the details:

XdebugHandler::runWithoutXdebug(function () {
    $process = new Process();
    // and so on
});

getRestartSettings() and specifically getRestartSettings()['tmpIni'] will became redundant with this approach. All complexity will be hidden from a user.

(I've already changed Infection's xdebug-handler to follow roughly this approach, with success, and I think this project can be made to adopt it too. Surely not without an owner's approval.)

Usage as a standalone binary

Would it be possible to implement a standalone binary based on the library that would run an arbitrary PHP application that doesn't have xdebug-handler bundled?

For instance, there's no plan to adapt it by PHPUnit (sebastianbergmann/phpunit#3544). Not having Xdebug loaded may significantly improve test performance, and code coverage may be collected by other means than Xdebug (e.g. PCOV).

Blocking 1.0 release

It would be nice to have a list of what's blocking 1.0 release to contribute and have a rough ETA for adoption. Feel free to edit this issue or create milestone

How to replace colorOption in 2.0?

Hi,
I upgraded to version 2.0 and the 2nd constructor parameter vanished. I used to pass --ansi in there so that Symfony Console apps could continue to be in color.

What can I do in 2.0 to restore this behaviour? Thanks!

Robustness of the persistent option

When the persistent mode is used but PHP_INI_SCAN_DIR is ignored by the target binary, xdebug-handler will not notice that it didn't succeed. I am wondering if xdebug-handler should somehow detect that there was a problem.

See NixOS/nixpkgs#221845 for a case where that happened because of the specific way nix packages PHP.

Proposal: Disable Scan Directories Feature when restarting

I'am using php in a standard docker container FROM php:7.4-fpm which is compiled with --with-config-file-scan-dir

root@dev-6b74fdbbb-gwbnb:/var/www# php -i | grep scan
Configure Command => './configure' '--build=x86_64-linux-gnu' '--with-config-file-path=/usr/local/etc/php' '--with-config-file-scan-dir=/usr/local/etc/php/conf.d' '--enable-option-checking=fatal' '--with-mhash' '--with-pic' '--enable-ftp' '--enable-mbstring' '--enable-mysqlnd' '--with-password-argon2' '--with-sodium=shared' '--with-pdo-sqlite=/usr' '--with-sqlite3=/usr' '--with-curl' '--with-libedit' '--with-openssl' '--with-zlib' '--with-pear' '--with-libdir=lib/x86_64-linux-gnu' '--enable-fpm' '--with-fpm-user=www-data' '--with-fpm-group=www-data' '--disable-cgi' 'build_alias=x86_64-linux-gnu'

This leads to duplicate module loading when the temporary INI-File is generated from php_ini_scanned_files()

if ($scanned = php_ini_scanned_files()) {

I propose that the proc_open call should be provided with the PHP_INI_SCAN_DIR environment variable pointing to an directory containing an empty ini-file to resolve this issue:

$process = proc_open($cmd, array(), $pipes,null,['PHP_INI_SCAN_DIR' => '/tmp/test-scan-dir']);

$process = proc_open($cmd, array(), $pipes);

root@dev-6b74fdbbb-gwbnb:/var/www# ls /tmp/test-scan-dir/ -la
total 24
drwxr-xr-x 2 root root  4096 Oct 20 15:38 .
drwxrwxrwt 1 root root 20480 Oct 20 17:46 ..
-rw-r--r-- 1 root root     0 Oct 20 15:38 empty.ini
root@dev-6b74fdbbb-gwbnb:/var/www# cat /tmp/test-scan-dir/empty.ini 

Note the comment in the PHP Manual:
https://www.php.net/manual/en/configuration.file.php#configuration.file.scan

If a blank directory is given in PHP_INI_SCAN_DIR, PHP will also scan the directory given at compile time via --with-config-file-scan-dir.

Alternatively the temporary INI-File could be stored in a directory and included this why and not by using the -c-Flag:

array_push($php, '-n', '-c', $this->tmpIni);

I've encountered this issue in https://github.com/phpstan/phpstan.

Unable to abort restarted process with Ctrl-C

Version 1.4.2 suppresses the SIGINT signal, and that suppression is inherited by the restarted process.

The reason for this explained in POSIX.1

Signals set to the default action (SIG_DFL) in the calling process image shall be set to the default action in the new process image. Except for SIGCHLD, signals set to be ignored (SIG_IGN) by the calling process image shall be set to be ignored by the new process image. Signals set to be caught by the calling process image shall be set to the default action in the new process image (see <signal.h>).

So, unless the application restores the signal handler or sets its own you cannot stop it with SIGINT anymore.

Originally posted by @weirdan in #108 (comment)

Reproduce repo
https://github.com/weirdan/xdebug-handler-unstoppable

Reproduce steps

  • git clone [email protected]:weirdan/xdebug-handler-unstoppable
  • cd xdebug-handler-unstoppable
  • composer install
  • php test.php
  • Press Ctrl-C

Expected result
The process should be aborted.

Actual result
The process is not aborted.

Additional details
Downgrading composer/xdebug-helper to 1.4.1 fixes the issue.

image

This library does not work when invoking a Phar via a relative path

When the phar is invoked manually (e.g. php -d zend_extension=xdebug.so build/phan.phar), xdebug-handler fails to detect that the file exists.

Adding debugging statements, I see that the Phar path (i.e. $args[0]) gets replaced by '--' (EDIT: Because it fails to detect that the file exists, xdebug-handler attempts to pass the phar (I assume) over stdin, which doesn't work. That causes the phar to hang after the restart, with no output)

Patching getCommand() to use the following check would make it not replace the relative path with --: if (!file_exists($args[0]) && !file_exists(getcwd() . '/' . $args[0])) {

  • Obviously, you'd have to check if something is an absolute path, the above snippet is not what you'd really want to use. Something more like the below would make sense. I'm not sure if that's 100% correct -- You may wish to limit this to Phars only for now via https://secure.php.net/manual/en/phar.running.php (Feel free to use the below helper)
    public static function absScriptPath(string $relative_path)
    {   
        // Make sure its actually relative
        if (\DIRECTORY_SEPARATOR === \substr($relative_path, 0, 1)) {
            return $relative_path;
        }
        // Check for absolute path in windows, e.g. C:\ (https://en.wikipedia.org/wiki/Drive_letter_assignment)
        if (\DIRECTORY_SEPARATOR === "\\" &&
                \strlen($relative_path) > 3 &&
                \ctype_alpha($relative_path[0]) &&
                $relative_path[1] === ':' &&
                \strspn($relative_path, '/\\', 2, 1)) {
            return $relative_path;
        }

        return getcwd() . DIRECTORY_SEPARATOR . $relative_path;
    } 

https://stackoverflow.com/a/18378785 sounds like it describes the generic problem for Phars:

Working with file paths and Phar archives in PHP can be tricky. The PHP code inside of a Phar file will treat relative paths as being relative to the Phar archive, not relative to the current working directory.


My use case is building phars for https://github.com/phan/phan/releases

Xdebug 3 support

Xdebug 3 has an "off" switch so we can either set XDEBUG_MODE=off in env, or pass -dxdebug.mode=off to PHP when restarting. It should simplify things quite a bit as we don't need to rebuild the ini file and create a temp one etc.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.