Problem/Motivation

I'm not able to press the scan button (deactivated) because this error appears on the top of the page:
The PHP binary was not found. Scanning is not possible until this is resolved.

Steps to reproduce

I've installed correctly all requested modules on a 8.9.19 legacy Drupal site: core_dev:8.9.19, upgrade_status, composer_deploy.

Set up PHP with open_basedir restrictions

Proposed resolution

Make the PHP binary configurable since we may not be able to scan for it.

Remaining tasks

n.a.

User interface changes

n.a.

API changes

n.a.

Data model changes

n.a.

CommentFileSizeAuthor
error_php_binary.jpeg199.67 KBcharly71
Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

charly71 created an issue. See original summary.

gábor hojtsy’s picture

Do you have a PHP command line executable file on the system?

charly71’s picture

Yes but I found the bug in file /src/DeprecationAnalyzer.php:

Row 265, I've rewrited the protected function findPhpPath():

/**
   * Finds the PHP path.
   *
   * This ensures we execute PHPStan with the same PHP binary that is used by
   * the web server.
   *
   * @return string
   *   PHP path if found.
   *
   * @throws \Exception
   */
  protected function findPhpPath() {
    $finder = new PhpExecutableFinder();
    $binary = $finder->find();
    if ($binary === FALSE) {
      if (PHP_BINDIR === NULL){  // Checks if PHP constant is avaiable
        throw new \Exception('The PHP binary was not found.');
      } else {
        $binary = PHP_BINDIR;
      }
    }
    return $binary;
  }

mglaman’s picture

Status: Active » Postponed (maintainer needs more info)

#3 That's weird you needed to hardcode in PHP_BINDIR. The Syfmony PHP exectuable finder relies on that, too.

The PHP_BINDIR is a last report that the class uses:

        if (@is_executable($php = \PHP_BINDIR.('\\' === \DIRECTORY_SEPARATOR ? '\\php.exe' : '/php'))) {
            return $php;
        }

        $dirs = [\PHP_BINDIR];
        if ('\\' === \DIRECTORY_SEPARATOR) {
            $dirs[] = 'C:\xampp\php\\';
        }

What kind of setup do you have? Are you on Windows or macOS or Linux? Is your Drupal site running on your host or in a local development stack? I'm not sure how or why this would have been missed.

Can you try this command and post the output:

composer show symfony/process

I checked and Symfony 3.4 to 4.x looks to be the same code, so I do not think it's something in the libary.

Feel free to ping me in #d9readiness slack channel to walk through this. As it looks to be really edge case.

What's more odd is that PHP_BINDIR is a directory, so even though you may scan the scans should be failing.

simgui8’s picture

Same thing here on linux, on production host.

Here is the output of

composer show symfony/process
name     : symfony/process
descrip. : Symfony Process Component
keywords : 
versions : * v3.4.47
type     : library
license  : MIT License (MIT) (OSI approved) https://spdx.org/licenses/MIT.html#licenseText
source   : [git] https://github.com/symfony/process.git b8648cf1d5af12a44a51d07ef9bf980921f15fca
dist     : [zip] https://api.github.com/repos/symfony/process/zipball/b8648cf1d5af12a44a51d07ef9bf980921f15fca b8648cf1d5af12a44a51d07ef9bf980921f15fca
path     : /web/vendor/symfony/process
names    : symfony/process

autoload
psr-4
Symfony\Component\Process\ => .
exclude-from-classmap

requires
php ^5.5.9|>=7.0.8

#3 fixes this

simgui8’s picture

@Gábor Hojtsy

If it helps, I have a jailed php cli

simgui8’s picture

On the same host, another D8-D9 migration done in early September didn't have this.

I have just tested 3.10 and, everything when smooth, so this was introduced in 3.11

charly71’s picture

@mglaman

Hi,I'm on a Virtualbox VM configured with Ansible on a MacOS machine:

Linux lcl-webfarm-php-comm01-portali 3.10.0-1160.45.1.el7.x86_64 #1 SMP Wed Oct 13 17:20:51 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"

PHP 7.3.31 (cli) (built: Sep 21 2021 10:24:03) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.31, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.3.31, Copyright (c) 1999-2018, by Zend Technologies
    with Xdebug v2.9.8, Copyright (c) 2002-2020, by Derick Rethans

Here is the output of your command:

name     : symfony/process
descrip. : Executes commands in sub-processes
keywords : 
versions : * v4.4.25
type     : library
license  : MIT License (MIT) (OSI approved) https://spdx.org/licenses/MIT.html#licenseText
homepage : https://symfony.com
source   : [git] https://github.com/symfony/process.git cd61e6dd273975c6625316de9d141ebd197f93c9
dist     : [zip] https://api.github.com/repos/symfony/process/zipball/cd61e6dd273975c6625316de9d141ebd197f93c9 cd61e6dd273975c6625316de9d141ebd197f93c9
path     : /var/www/lcl-www-mysite.portali.csi.it/app/deploy/main/aslto5/vendor/symfony/process
names    : symfony/process

autoload
psr-4
Symfony\Component\Process\ => .
exclude-from-classmap

requires
php >=7.1.3
mglaman’s picture

Is open_basedir restriction in effect on your servers? See https://www.php.net/manual/en/ini.core.php#ini.open-basedir

Are you able to inspect what directories are being searched by the PhpExecutable finder? See https://github.com/symfony/symfony/blob/5.4/src/Symfony/Component/Proces...

Are there any warnings generated in PHP when trying to process?

The PhpExecutableFinder tries to discover in PHP_BINDIR, I don't know why defaulting to that would "just work."

gábor hojtsy’s picture

@mglaman suggested to add an option to specify the PHP path which we can use in case people need it set differently. That could be a solution to help people fix it for themselves without a requirement of a code change.

ajay gadhavana’s picture

#3 working fine for me. I just wanted a report and I got that by adding the code that was suggested on #3.

Anonymous’s picture

I am only able to fix this when I change:

// PHP_BINARY return the current sapi executable 
if (PHP_BINARY && \in_array(\PHP_SAPI, ['cli', 'cli-server', 'phpdbg', 'cgi-fcgi'], true)) { 
           return PHP_BINARY.$args; 
}

In /vendor/symfony/process/PhpExecutableFinder.php

I'm using ISPConfig and php7.4 via fastcgi (php from Debian SURY repos).

etron770’s picture

#12 working at debian buster
Thank`s a lot

lhugg’s picture

#3 fixed this issue for me as well. Running on Windows 10 based system.

kristen pol’s picture

Maybe this needs to go back to Active based on the various comments?

joachim namyslo’s picture

for sure, I've got the same error on plesk 18.4 so that error is still an issue. So maybe there is a problem on installations delivering more than one PHP handler. I am not sure how to help out debugging that. But sadly many customers are interested in Drupal using things like plesk, icp and other stuff. That's always a bit tricky. But perhaps worth digging.

joachim namyslo’s picture

Status: Postponed (maintainer needs more info) » Active
superlolo95’s picture

#3
Does not work for me on a Linux plesk hosting
I have Command error:
sh: /opt/plesk/php/7.4/bin: Is a directory sh: line 0: exec: /opt/plesk/php/7.4/bin: cannot execute: Is a directory

I had to add .'/php' to the returned value to make it work properly

gábor hojtsy’s picture

@superlolo95, @Joachim Namyslo: your specific problem is at #3245521: PHP directory attempted to be used to run PHP, instead of the binary I think.

There is a related problem for Windows users at #3265479: PHPStan is a shell script on windows, not a PHP script, should not be run through PHP which seems to be different though.

mglaman’s picture

#12 is the main difference removing the \ backslash?

I guess we need to make this a setting.

I cannot fathom why the following would work, given it should be constant set at compile which is a directory not a binary path

   if ($binary === FALSE) {
      if (PHP_BINDIR === NULL){  // Checks if PHP constant is avaiable
        throw new \Exception('The PHP binary was not found.');
      } else {
        $binary = PHP_BINDIR;
      }
    }

I think the next step is to tackle #3245521: PHP directory attempted to be used to run PHP, instead of the binary, because I'm not sure what's going on here, exactly. I don't understand how #3 or #12 could work.

mglaman’s picture

If you were experiencing problems of the PHP binary coming back as a directory, please test the MR/proposed fix in #3245521: PHP directory attempted to be used to run PHP, instead of the binary

If you are on Windows and having issues, can you try the MR/proposed fix in #3265479: PHPStan is a shell script on windows, not a PHP script, should not be run through PHP to execute the phar directly versus wrapping script.

mglaman’s picture

Status: Active » Postponed (maintainer needs more info)

We still need more info. Such as if there are errors due to open_basedir. Especially if the two previously issues do not resolve your problems.

quimic’s picture

@superlolo95 @joachim-namyslo

Trying to use the is_dir() funtion like in the #3245521: PHP directory attempted to be used to run PHP, instead of the binary proposed MR does not work here: 'Warning: is_dir(): open_basedir restriction in effect. File(/opt/plesk/php/7.4/bin) is not within the allowed path(s)".

Like @mlgaman originally suggested, If using a Plesk environment, it looks like the whole problem is due to open_basedir. If you add "/opt/plesk/php" to your open_basedir (in your domain PHP settings), the problem goes away without any code change.

mglaman’s picture

Title: Unable to scan: PHP binary not found » open_basedir restrictions prevent scanning to find PHP binary
Priority: Normal » Major
Issue summary: View changes
Status: Postponed (maintainer needs more info) » Active
Issue tags: -PHP

@quimic thank you for reporting back feedback! This is great to know and pushes the case for making the PHP binary a configured path to work around open_basedir restrictions.

I bumped this to Major since it's a problem on shared/managed hosting.

mglaman’s picture

@quimic can you try the fix proposed in https://www.drupal.org/project/upgrade_status/issues/3245521?

quimic’s picture

@mglman
I did try it, and this is what allowed me to find the open_basedir issue.
The is_dir() function returns an open_basedir warning (basically it refuses to execute because of the open_basedir restriction).
Adding the php binary path fixed the warning. But then I realized I did not even need the fix. The original code works fine as soon as one add the php binary path to open_basedir.

mglaman’s picture

Adding the php binary path fixed the warning. But then I realized I did not even need the fix. The original code works fine as soon as one add the php binary path to open_basedir.

My concern is that some folks won't be able to change this, or we may not be able to surface the documentation for the fix easily.

So the fix in #3245521: PHP directory attempted to be used to run PHP, instead of the binary made it run even if the open_basedir wasn't fixed? I don't want us to blindly commit code, but I want us to try and work as much out of the box without end-users needing to modify things.

quimic’s picture

Priority: Major » Normal
Status: Active » Postponed (maintainer needs more info)

So the fix in #3245521: PHP directory attempted to be used to run PHP, instead of the binary made it run even if the open_basedir wasn't fixed?

No, it did not fix the original issue. But it allowed me to better understand what was going on.
It looks like in some environments (and definitely in a Plesk environment), the code cannot access the php binary if it is not explicitly allowed in the open_basedir config. And it looks like when this happens, symphony PhpExecutableFinder returns the directory instead of the actual php executable file (like you identified). This is why appending ‘/php' manually like @superlolo95 suggests in #18 does fix the problem, but it is not the original cause.
Adding the php executable directory to the open_basedir config (which in Plesk is easily done through GUI as part of the domain hosting php configuration) resolves everything.

It is not clear to me if this happens in any other environment than Plesk. If not, then this might not be a major issue, since there is an easy fix. It should probably be mentioned somewhere in the doc.
If code needs to be changed to really fix this, it should probably be in Symphony, not in the module.

mglaman’s picture

Someone proposed a fix: https://github.com/symfony/symfony/pull/45676. The problem is that folks may not get that version of Symfony :/

Plesk is popular enough that maybe we can add a detection for it and prompt that /opt/plesk/php should be added to open_basedir so that the appropriate PHP binary is used to scan code?

quimic’s picture

Someone proposed a fix: https://github.com/symfony/symfony/pull/45676. The problem is that folks may not get that version of Symfony :/

I doubt that the proposed fix will work. When base_dir restriction is enabled, the is_dir() function fails when used on a restricted path. See the message I got in Drupal when I tried the code in #3245521: PHP directory attempted to be used to run PHP, instead of the binary, which uses is_dir():

Warning : is_dir(): open_basedir restriction in effect. File(/opt/plesk/php/7.4/bin) is not within the allowed path(s)

When I saw that message, I added /opt/plesk/php to my open_basedir config. This fixed the message. But I also realized that with that setting, I no longer needed any patch, and that the original code worked as is…

Regarding Plesk detection (or more generally base_dir restriction detection?), if it can be done, that would be great.

gábor hojtsy’s picture

@quimic: hm, https://github.com/symfony/symfony/pull/45676/files uses @is_dir() so that should silently swallow the open basedir error. And return probably false. The later would be the problem for open_basedir indeed. For that I think a combination of @is_readable() and @is_dir() could be used? We can do that in our consuming code.

gábor hojtsy’s picture

Added that to the existing MR in #3245521: PHP directory attempted to be used to run PHP, instead of the binary, I think that would be best to test first still and then see if there is more to fix here.

fgm’s picture

FWIW, I had the same issue on a vanilla composer install on macOS. The issue turned out to be I had not restarted the PHP services after upgrading, so PHP was 8.1.9 on CLI and 8.1.8 on Web, and I had that error.

After restarting so Web was also on 8.1.9, the error went away.

umac_de’s picture

For Plesk on Linux you have to set open_basedir in PHP settings to
{WEBSPACEROOT}{/}{:}{TMP}{/}{:}{/}opt{/}plesk{/}php{/}8.1{/}bin{/}

The php main version number must be the same as for hosting.