bug étrange en PHP, espaces dans les chemins et fenêtres
-
26-09-2019 - |
Question
Je dois corriger ce petit bug. Tout d'abord, nous allons parler d'un petit fait: Dans CLI sous Windows, vous ne pouvez pas exécuter un programme avec un espace dans son chemin, à moins échappé:
C:\>a b/c.bat
'a' is not recognized as an internal or external command,
operable program or batch file.
C:\>"a b/c.bat"
C:\>
J'utilise proc_open ... proc_close en PHP pour exécuter un processus (programme), par exemple:
function _pipeExec($cmd,$input=''){
$proc=proc_open($cmd,array(0=>array('pipe','r'),
1=>array('pipe','w'),2=>array('pipe','w')),$pipes);
fwrite($pipes[0],$input);
fclose($pipes[0]);
$stdout=stream_get_contents($pipes[1]); // max execusion time exceeded ssue
fclose($pipes[1]);
$stderr=stream_get_contents($pipes[2]);
fclose($pipes[2]);
$rtn=proc_close($proc);
return array(
'stdout'=>$stdout,
'stderr'=>$stderr,
'return'=>(int)$rtn
);
}
// example 1
_pipeExec('C:\\a b\\c.bat -switch');
// example 2
_pipeExec('"C:\\a b\\c.bat" -switch');
// example 3 (sounds stupid but I had to try)
_pipeExec('""C:\\a b\\c.bat"" -switch');
Exemple 1
- : 1
- STDERR: 'C: \ a' est pas reconnu comme une commande interne ou externe, fichier de programme ou d'un lot utilisable.
- STDOUT:
Exemple 2
- : 1
- STDERR: 'C: \ a' est pas reconnu comme une commande interne ou externe, fichier de programme ou d'un lot utilisable.
- STDOUT:
Exemple 3
- : 1
- STDERR:. Le nom de fichier, nom de répertoire ou la syntaxe étiquette de volume est incorrect
- STDOUT:
Donc, vous voyez, que ce soit le cas (guillemets doubles ou non) le code échoue. Est-ce moi ou suis-je manque quelque chose?
La solution
La plupart malheureusement, le correctif ne fonctionne pas comme prévu, mais la première suggestion de Pekka m'a donné une idée:
$file='C:\a b\c';
$cmdl='/d /b /g';
if(strtolower(substr(PHP_OS,0,3))=='win') // if windows...
$file='cd '.escapeshellarg(dirname($file)).' && '.basename($file);
_pipeExec($file.' '.$cmdl);
Ceci est la plate-forme spécifique, et j'espère ne pas avoir à résoudre ce problème sur Linux. Jusqu'à présent, il fonctionne bien!
Autres conseils
Une autre façon de résoudre c'est en mettant des guillemets doubles supplémentaires au début et à la fin de la commande.
$process = 'C:\\Program Files\\nodejs\\node.exe';
$arg1 = 'C:\\Path to File\\foo.js';
$cmd = sprintf('"%s" %s', $process, escapeshellarg($arg1));
if (strtolower(substr(PHP_OS, 0, 3)) === 'win') {
$cmd = '"'.$cmd.'"';
}
_pipeExec($cmd);
J'ai trouvé cette solution sur https://bugs.php.net/bug. php? id = 49139
Il fait un peu bizarre, mais bon - il est de Windows ...: D
Ceci est strage.
Idées de contournement non testées:
-
Utilisez une variable d'environnement temporaire:
exec('SET ENVPATH="C:\a b"'); proc_open('%ENVPATH%\c.bat' ....
(aucune idée si cela fonctionnera pour proc_open)
-
Utilisez le nom de fichier 8.3 si cela peut en quelque sorte tiré par les cheveux en PHP - serait certainement faisable d'utiliser un autre
exec()
-
proc_open()
a une option pour contournercmd.exe
- peut-être la peine d'essayer dans le cas où le système de fichiers gère en quelque sorte les citations différemment -
Essayez d'échapper aux citations
\"