0

I am migrating a web function from a to-be-decommissioned Windows 2003 server running PHP 5.2.6 to a Windows 2012 server running PHP 7.3.9.

On the original server, the following PHP code would execute:

$WshShell = new COM("WScript.Shell");
$oExec = $WshShell->Exec("cmd /c ".$filePath);
$sStdOut = $oExec->StdOut->ReadAll;

$sStdOut would then be parsed to inform the user of the outcome of the batch file (absolutely path'd in $filePath). The batch file itself would run an rsync.

On the new server, this code will not execute, even though I turned on COM / .NET by adding [COM_DOT_NET] extension=php_com_dotnet.dll into the end of php.ini. $sStdOut would simply be an empty string, although $WshShell var_dumps as an object(com) and $oExec var_dumps as an object(variant).

I have also tried the numerous exec, shell_exec, etc. functions available in PHP. None of them execute the batch file that executes the rsync. As to specific functions and return values:

exec($filePath, $sStdOut) -> empty array for $sStdOut

exec("C:\WINDOWS\system32\cmd.exe cmd /c START " . $filePath, $sStdOut); -> waiting, then 500 error

exec('start /B / C ' . $filePath, $sStdOut); -> empty array for $sStdOut

exec("powershell -Command '[batch file name]'", $sStdOut); -> empty array for $sStdOut [I placed the batch file in the same directory as the PHP file to see if a relative file path would work]

$sStdOut = shell_exec($filePath) -> null for $sStdOut

$sStdOut = passthru($filePath); -> null for $sStdOut

$sStdOut = popen($filePath, 'r');
$read = fread($sStdOut, 2096);
pclose($sStdOut); -> stream resource for $sStdOut, empty string for $read

$r = pclose(popen($filePath, 'r')); -> int 1 for $r

$sStdOut = system("cmd.exe /c " . $filePath); -> empty string for $sStdOut

Essentially I have reviewed the answers to these three questions (among many other sources), and tried everything suggested in those three questions. No luck.

I also replaced spaces with underscores in the directory names leading up to the batch file, and added Everyone with execute access to the directories and the batch file itself. Again, no luck.

Oddly, I can execute "dir" as the $filePath in several of the examples listed above (I haven't re-tried them all), and get directory-related information back! Based upon that, I added the batch file's location to the Windows Path and tried to run it with just the batch file's name, but still no luck.

Neil Wehneman
  • 154
  • 1
  • 12
  • Best bet would be to replicate the config on the new system from the old. It is difficult to help here as it is not programming/scripting related. – Gerhard Oct 07 '21 at 08:15

1 Answers1

0

I figured this one out (at least as to a work-around), using largely my initial setup from the top of the question.

The first step was adding 2>&1 to the end of the PHP execution command. This routed error messages (normally sent to stderr) to stdout. I also found a source that indicated that StdOut and ReadAll should have parentheses after them, so I added those.

Once I did that, I was able to see an error message that rsync was not a recognized command. This error message only triggered on exec-like commands, and only when PHP executes the batch file (not when I manually ran it).

I still don't know why that error arose. I placed rsync's location within the Windows System Path, but that didn't change anything.

Ultimately, I ended up replacing rsync.exe in the batch file with C:\"Program Files"\CWRSYNC\bin\rsync.exe. I was surprised to have to use a Windows-centric path instead of a Cygwin-centric path (e.g. /cygdrive/c/path), especially given the rsync command itself used Cygwin-centric paths to identify file locations, but that's what it took to work.

Neil Wehneman
  • 154
  • 1
  • 12