php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #25361 Program Execution Functions fail in certain cases
Submitted: 2003-09-02 11:07 UTC Modified: 2008-06-06 09:36 UTC
Votes:2
Avg. Score:4.0 ± 1.0
Reproduced:2 of 2 (100.0%)
Same Version:1 (50.0%)
Same OS:2 (100.0%)
From: sam at freepeers dot com Assigned:
Status: Closed Package: Program Execution
PHP Version: 4.3.2 OS: Windows 2000
Private report: No CVE-ID: None
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: sam at freepeers dot com
New email:
PHP Version: OS:

 

 [2003-09-02 11:07 UTC] sam at freepeers dot com
Description:
------------
Running PHP on Windows 2000 with IIS 5.

Basic program executation does not work in certain cases. 

This is ok:

$output = `C:\executable.exe C:\\file1.txt`;

Now, lets suppose that both the filename and the executable names contain spaces, and therefore each are to be enclosed in quotes.  Then it fails:

This is not ok:

$output = `"C:\executable.exe" "C:\\file1.txt"`;

This is ok again:

$output = `C:\executable.exe "C:\\file1.txt"`;

This is also ok:

$output = `"C:\executable.exe" C:\\file1.txt`;

So, the problem arises when BOTH the command and the file are enclosed in quotes.  In some cases you do need to enclose both the command and the file in quotes. You will not be able to.

This affects all forms of command execution (exec, system, backticks...)
  

Reproduce code:
---------------
1.  Create file called "Test.txt" and put it into C: drive.    Put some random text in it.

2.  Try this code:

<?php

$output = "";
$output = `more C:\\Test.txt`;
echo "Test.txt contains $output.  This works<br><br>";

$output = "";
$output = `"more" C:\\Test.txt`;
echo "Test.txt contains $output.  This works<br><br>";

$output = "";
$output = `more "C:\\Test.txt"`;
echo "Test.txt contains $output.  This works<br><br>";

$output = "";
$output = `"more" "C:\\Test.txt"`;
echo "Test.txt contains $output.  This does not works<br><br>";

?>

Expected result:
----------------
Test.txt contains Contents of file. . This works

Test.txt contains Contents of file. . This works

Test.txt contains Contents of file. . This works

Test.txt contains Contents of file. . This does not works

Actual result:
--------------
Test.txt contains Contents of file. . This works

Test.txt contains Contents of file. . This works

Test.txt contains Contents of file. . This works

Test.txt contains . This does not works

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2003-09-02 18:08 UTC] sniper@php.net
PHP uses "cmd.exe /c" for executing programs under windows.
You can try your examples on command line:

cmd.exe /c "your long command" "another file"

And you'll see it does not work. This is not PHP problem but yet another windows problem. 

You must always use the '8.3' format of the paths/filenames.


 [2007-08-02 09:22 UTC] rquadling@php.net
For Windows NT+ (i.e. not win98-), this SEEMS to work.

cmd /s /c ""your long command" "another file""

Compare this against ...

cmd /c "your long command" "another file"

which doesn't work.

The /S option basically treats the rest of the string in quotes as a command line.

This is slightly different behaviour.


%COMPSPEC% /S /C ""C:\Program Files\Internet Explorer\IEXPLORE.EXE" "http://www.php.net""


This is a patch to proc_open.c which I think should deal with the issue. It may need to be optimized.

Index: proc_open.c
===================================================================
RCS file: /repository/php-src/ext/standard/proc_open.c,v
retrieving revision 1.57
diff -u -r1.57 proc_open.c
--- proc_open.c	28 May 2007 23:00:25 -0000	1.57
+++ proc_open.c	2 Aug 2007 09:21:02 -0000
@@ -740,7 +740,12 @@
 	if (bypass_shell) {
 		newprocok = CreateProcess(NULL, command, &security, &security, TRUE, NORMAL_PRIORITY_CLASS|CREATE_NO_WINDOW, env.envp, cwd, &si, &pi);
 	} else {
-		spprintf(&command_with_cmd, 0, "%s /c %s", GetVersion() < 0x80000000 ? COMSPEC_NT : COMSPEC_9X, command);
+		if (GetVersion() < 0x80000000) {
+			/* Wrap command in quotes and use the /s parameter to pass quotes to the command line. */
+			spprintf(&command_with_cmd, 0, "%s /s /c \"%s\"", COMSPEC_NT, command);
+		} else {
+			spprintf(&command_with_cmd, 0, "%s /c %s", COMSPEC_9X, command);
+		}
 
 		newprocok = CreateProcess(NULL, command_with_cmd, &security, &security, TRUE, NORMAL_PRIORITY_CLASS|CREATE_NO_WINDOW, env.envp, cwd, &si, &pi);
 
http://pastie.caboo.se/84303
 [2007-08-02 09:28 UTC] rquadling@php.net
And thanks to Ashar Lohmar <asharlohmar@yahoo.com>, as he put me onto this fix. He had a similar issue with wscript.
 [2007-08-02 09:33 UTC] rquadling@php.net
It may be that the /S is not required.

http://pastie.caboo.se/84306
 [2007-08-03 09:04 UTC] rquadling@php.net
Index: proc_open.c
===================================================================
RCS file: /repository/php-src/ext/standard/proc_open.c,v
retrieving revision 1.57
diff -u -r1.57 proc_open.c
--- proc_open.c	28 May 2007 23:00:25 -0000	1.57
+++ proc_open.c	2 Aug 2007 09:30:57 -0000
@@ -740,7 +740,7 @@
 	if (bypass_shell) {
 		newprocok = CreateProcess(NULL, command, &security, &security, TRUE, NORMAL_PRIORITY_CLASS|CREATE_NO_WINDOW, env.envp, cwd, &si, &pi);
 	} else {
-		spprintf(&command_with_cmd, 0, "%s /c %s", GetVersion() < 0x80000000 ? COMSPEC_NT : COMSPEC_9X, command);
+		spprintf(&command_with_cmd, 0, "%s /c \"%s\"", GetVersion() < 0x80000000 ? COMSPEC_NT : COMSPEC_9X, command);
 
 		newprocok = CreateProcess(NULL, command_with_cmd, &security, &security, TRUE, NORMAL_PRIORITY_CLASS|CREATE_NO_WINDOW, env.envp, cwd, &si, &pi);
 

 [2007-08-03 09:10 UTC] rquadling@php.net
Non volatile link (Sorry Pierre) : http://rquadling.php1h.com/proc_open.c.diff2
 [2007-08-03 09:26 UTC] rquadling@php.net
From the cmd.exe /? help

If /C or /K is specified, then the remainder of the command line after
the switch is processed as a command line, where the following logic is
used to process quote (") characters:

1. If all of the following conditions are met, then quote characters
on the command line are preserved:

- no /S switch
- exactly two quote characters
- no special characters between the two quote characters,
where special is one of: &<>()@^|
- there are one or more whitespace characters between the
the two quote characters
- the string between the two quote characters is the name
of an executable file.

2. Otherwise, old behavior is to see if the first character is
a quote character and if so, strip the leading character and
remove the last quote character on the command line, preserving
any text after the last quote character.

My intent is to force the command line supplied by exec() et. al. to be wrapped in a pair of quotes, thus forcing option 2 to be used.

For older windows (9x), using command.com, the help is ...

/C string       Carries out the command specified by string, and then stops.

If 9x is not a concern (I'm getting it tested next week as I don't have a 9x machine at hand), then the first patch could be used which only wraps "" around NT+.


 [2007-08-11 01:00 UTC] php-bugs at lists dot php dot net
No feedback was provided for this bug for over a week, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".
 [2008-01-26 13:09 UTC] t03 at springtimesoftware dot com
Under Windows, here is a workaround to the bugs in PHP and Windows:

1. Copy cmd.exe into the main PHP folder (usually C:\php or C:\Program Files\php). This gives PHP authorization to run it.

2. In your PHP code, execute the command "Exec.cmd <command> <args>". Each arg can be quoted. Consider calling escapeshellcmd or escapeshellarg.

3. Create a file Exec.cmd where your PHP code can find it. It should contain the following:

rem @echo off
rem echo Args: %1 %2 %3 %4 %5 %6 %7 %8 %9
start "Exec.cmd Is Running" /b %1 %2 %3 %4 %5 %6 %7 %8 %9
exit

4. Change the /b to /w for synchronous execution.

5. This is rough. It should be changed to return the command's error code (errorlevel), etc.

David Spector
 [2008-05-30 10:04 UTC] scottmac@php.net
This bug has been fixed in CVS.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.

Fixed in 5.2, 5.3 and 6.0
 [2008-06-06 09:36 UTC] rquadling@php.net
This was fixed.

HEAD : http://cvs.php.net/viewvc.cgi/TSRM/tsrm_win32.c?r1=1.34&r2=1.35
5.2x :
http://cvs.php.net/viewvc.cgi/TSRM/tsrm_win32.c?r1=1.27.2.1.2.8&r2=1.27.2.1.2.9
5.3x :
http://cvs.php.net/viewvc.cgi/TSRM/tsrm_win32.c?r1=1.27.2.1.2.7.2.1&r2=1.27.2.1.2.7.2.2

Can the 5.2x commit be reversed?

This caused a minor issue with phd for 5.2. Whilst it is easily fixed it
is a BC mid version (5.2.6 vs 5.2.7-dev).

Having it at 5.3+ allows the BC to be documented as part of the changes
to 5.3.

Thank you.

Richard Quadling.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Oct 31 23:01:28 2024 UTC