Strano bug in PHP, spazi nei percorsi e Windows
-
26-09-2019 - |
Domanda
Devo risolvere questo piccolo bug.Innanzitutto parliamo di un piccolo fatto:Nella CLI su Windows, non puoi eseguire un programma con uno spazio nel suo percorso, a meno che non sia eseguito l'escape:
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:\>
Sto usando proc_open...proc_close in PHP per eseguire un processo (programma), esempio:
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');
Esempio 1
- RISULTATO:1
- STDER:'C: A' non è riconosciuto come comando interno o esterno, programma operabile o file batch.
- STUDIO:
Esempio 2
- RISULTATO:1
- STDER:'C: A' non è riconosciuto come comando interno o esterno, programma operabile o file batch.
- STUDIO:
Esempio 3
- RISULTATO:1
- STDER:La sintassi del nome file, del nome della directory o dell'etichetta del volume non è corretta.
- STUDIO:
Quindi vedi, in entrambi i casi (virgolette doppie o meno) il codice fallisce.Sono io o mi sono perso qualcosa?
Soluzione
Sfortunatamente, la soluzione non funziona come previsto, tuttavia il primo suggerimento di Pekka mi ha dato un'idea:
$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);
Questo è specifico della piattaforma e spero di non doverlo risolvere anche su Linux.Finora funziona bene!
Altri suggerimenti
Un altro modo per risolvere questo problema è inserire virgolette doppie aggiuntive all'inizio e alla fine del comando.
$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);
Ho trovato questa soluzione su https://bugs.php.net/bug.php?id=49139
Sembra strano, ma ehi, è Windows...:D
Questo è strano.
Idee alternative non testate:
Utilizza una variabile d'ambiente temporanea:
exec('SET ENVPATH="C:\a b"'); proc_open('%ENVPATH%\c.bat' ....
(non ho idea se funzionerà per proc_open)
Usa il nome file 8.3 se in qualche modo può essere recuperato in PHP: sarebbe sicuramente fattibile usandone un altro
exec()
proc_open()
ha un'opzione per bypassarecmd.exe
- potrebbe valere la pena provare nel caso in cui il filesystem gestisca in qualche modo le virgolette in modo diversoProva a sfuggire alle virgolette
\"