2010-11-19 16 views
6

Tengo que solucionar este pequeño error. En primer lugar, vamos a hablar de un pequeño hecho: En CLI en Windows, no se puede ejecutar un programa con un espacio en su camino, a menos que se escapó:Error extraño en PHP, espacios en las rutas y Windows

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:\> 

estoy usando proc_open ... proc_close en PHP para ejecutar un proceso (programa), ejemplo:

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'); 

ejemplo 1

  • RESULTADO: 1
  • STDERR: 'C: \ a' no se reconoce como un comando interno o externo, programa operable o archivo por lotes.
  • STDOUT:

Ejemplo 2

  • RESULTADO: 1
  • STDERR: 'C: \ a' no se reconoce como un comando interno o externo, programa operable o lote archivo.
  • STDOUT:

Ejemplo 3

  • RESULTADO: 1
  • STDERR: La sintaxis de etiqueta de nombre de archivo, nombre de directorio, o el volumen es incorrecta.
  • STDOUT:

Como puede ver, cualquiera de los casos (entre comillas dobles o no) el código falla. ¿Soy yo o me estoy perdiendo algo?

+0

tiro en la oscuridad, pero puede que trate de cambiar los tipos de cotización? ('" 'to' '') –

+0

No tengo experiencia en esto, pero en el símbolo del sistema ejecutas" ab/c.bat "y en PHP llamas" C: \ ab \ c.bat "incluyendo el camino dentro las citas. ¿Tal vez llamar a C: \ "ab \ c.bat" funciona? –

+0

@Pekka, me sale igual que el Ejemplo 3, parece que las comillas simples no son caracteres de contenedor como comillas dobles. – Christian

Respuesta

3

lo más lamentable, la solución no funciona como se espera, sin embargo primera sugerencia de Pekka me dio una 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); 

Esto es específico de la plataforma, y ​​espero que no tenga que arreglar esto también en Linux. ¡Hasta ahora funciona bien!

+0

hola, tratando de usar la solución en mi código, y descubrí que hay un error de sintaxis. Tienes un problema) en al final de la línea 5. Lo arreglaría, pero hay un límite de caracteres mínimo en las ediciones. aplausos –

+1

@ ted.strauss ¡Gracias! Arreglado. – Christian

+1

Esta es una buena solución. No veo ninguna razón por la cual esto fallaría en Linux. – Aust

0

This is strage.

las ideas de solución no probados:

  • utilizar una variable de entorno temporal:

    exec('SET ENVPATH="C:\a b"'); 
    proc_open('%ENVPATH%\c.bat' .... 
    

    (ni idea de si esto funcionará para proc_open)

  • Uso del 8.3 nombre del archivo si que de alguna manera se pueden recuperar en PHP - sin duda sería factible utilizando otro exec()

  • proc_open() tiene una opción para omitir cmd.exe - podría valer la pena probar si el sistema de archivos de alguna manera se encarga de las cotizaciones de manera diferente

  • Trate de escapar de las cotizaciones \"

+0

El bypass cmd.exe me dio una idea:' cmd "C: \\ ab \\ c.bat" ' – Christian

+0

proc_open tiene un argumento para pasar en las variables de env mejor para usar eso. –

+0

@Christian ah, interesante. Podría funcionar. Quizás intente también 'call' @Viper buen punto! –

1

Otra forma de resolver esto es poniendo comillas dobles adicionales al principio y al final 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); 

he encontrado esta solución en https://bugs.php.net/bug.php?id=49139
Parece raro, pero bueno - es de Windows ...: D

+0

Esa solución es extraña, pero funciona y es más sensato que copiar en el directorio solo para ejecutar un comando. –

+0

Tenga en cuenta que is_executable no funciona para rutas dentro de comillas. – SWilk