2010-08-11 18 views
12

Estoy usando php 5.2.9 en un servidor de producción, y parece que la función exec() se comporta como "no estándar".exec siempre devuelve -1 (o 127)

Si corro exec("ls", $output, $return_var) continuación $output contendrá la lista de archivos en la carpeta actual como se esperaba, pero $return_var se establece en -1 en lugar de 0, como se esperaba. Estoy usando el $return_var para determinar donde el comando terminó con éxito, y en cada otro servidor probado esto funciona como se esperaba :)

¿Alguien alguna vez ha llegado a una situación como esta?


edición:

<?php 
$command = "asd"; 

$t1 = time(); 

$output = Array(); 
$result = -5; 
$r = exec($command, $output, $result); 
$t2 = time(); 

echo "<pre>"; 
var_export(Array(
    'command'=>$command, 
    'result'=>$result, 
    'output'=>implode("\n", $output), 
    'r'=>$r, 
    't2-t1'=>$t2-$t1, 
)); 
echo "</pre>"; 

Cualquiera que sea comando i poner en $command, $result siempre será -1, incluso para los comandos inexistentes ... esto es muy raro

+2

What si su variable '$ command' es una cadena vacía para que' exec() 'no proporcione argumentos a' ls'? ¿El código de salida sigue siendo '-1'? Si es así, ¿ha comprobado la implementación de 'ls' para su sistema actual con' man ls' para ver si se define el código de salida '-1'? ¿Es esto cierto con otros comandos (tal vez un 'du -h index.html')? – sleepynate

+0

Parece que no puedo llamar a 'exec (" ")'. Imprime una advertencia. Cualquier otro comando se comporta de la misma manera. 'sleep 5' regresa con -1,' lsmod' devuelve -1, etc ... – Quamis

+1

Lo único que puedo ver es esto [publicar en la página del manual de php del ejecutor] (http://www.php.net/manual) /en/function.exec.php#76687) pero dado que está funcionando en otros servidores, no es obvio por qué sería esto. – Troubadour

Respuesta

1

Suponiendo que el sistema de devolver $ resultado == -1 es similar a Unix basado (no sé cómo se comportarían de Windows con el mismo código)

función

El PHP (5.2.9) exec() hace no llame a la primitiva C exec() (que devuelve -1 si no pudo reemplazar/ejecutar el proceso, que no es el caso aquí). En su lugar, llama a popen() que crea un conducto, realiza un fork() y ejecuta un shell con su comando. return_value, -1, no es el resultado directo de una primitiva C, sino que está construido internamente por PHP, según la forma en que se procesó su comando. En otros términos, el comando "ls" puede haber sido bien ejecutado, mientras que, por ejemplo, PHP no pudo cerrar correctamente el conducto.

Mirando el código C, en ext/standard/exec.c, puede haber dos razones por las cuales el código de retorno es -1, desencadenado por un error; el segundo uno pasa después de la popen() llaman

fp = VCWD_POPEN(cmd_p, "r"); 

    if (!fp) { 
     php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to fork [%s]", cmd); 
     goto err; 
    } 
    // ... 
    err: 

    pclose_return = -1; 
    goto done; 

Sin embargo, en este caso, sería no ver el resultado, y el registro mostraría un error.

Más tarde, el valor_devuelto se establece a través de la línea

pclose_return = php_stream_close(stream); 

En cuanto a _php_stream_free() (php_stream_close() es una macro sustituido por _php_stream_free()), el candidato más probable que podría devolver -1 es

ret = stream->ops->close(stream, preserve_handle ? 0 : 1 TSRMLS_CC); 

Que a su vez llama indirectamente a la C primitiva pclose(). De acuerdo con el manual

La función pclose() devuelve -1 si wait4 (2) devuelve un error o se detecta algún otro error.

Parece haber un error detectado durante el cierre de la tubería, que no impide que se establezcan los datos resultantes.Para encontrar el motivo de forma rigurosa, es necesario verificar la configuración y los registros del sistema operativo, la configuración de PHP y los parámetros de compilación.

recomendaría

  • para aplicar los parches para su sistema operativo, y tal vez actualizar a una versión más reciente (si es aplicable),
  • para actualizar a PHP 5.3.3 (la última a partir de ahora), ya el código PHP exec() cambió significativamente.

Tenga en cuenta que hubo cambios relacionados con el módulo PHP suhosin en la versión 5.3 que mejoran de forma predeterminada la seguridad al ejecutar archivos PHP.

+0

Sí, era "unix-like" (sinceramente, no tengo ideea si era Linux o un sabor de Unix). buena respuesta. El administrador del servidor solucionó el problema, pero no sé qué hizo para romperlo o arreglarlo ... El problema es que el servidor se configuró de una manera muy restrictiva. Tuve acceso a muy pocos comandos (por ejemplo, php-cli no estaba disponible a través de SSH, y muchos otros comandos. – Quamis

+0

Estoy aceptando su respuesta ya que es la más completa y supongo que el administrador del servidor ejecutó el sistema operativo. – Quamis

0

Asegúrese de que está no se ejecuta en safe mode y ese ejecutivo no aparece en disable_functions en php.ini.

Cualquiera de estas situaciones causaría la falla de exec(), aunque creo que se generaría una notificación.

+0

no me estoy ejecutando en modo seguro (no puedes usar exec en modo seguro) y no hay función deshabilitada. – Quamis

+0

@Quamis - No creo que se aplique en su caso, pero puede usar el ejecutor en modo seguro. Lo que sucede entonces es que con el modo seguro habilitado, la cadena de comando se escapa con escapeshellcmd(). - http://php.net/manual/en/function.exec.php –

0

¿Podemos obtener la salida de strace'ing el proceso de PHP? Es probable que contenga la respuesta que estamos buscando.

También 5.2.14 es el más nuevo de la serie 5.2. ¿Alguna posibilidad de que puedas probarlo allí? Si tienes un proveedor de alojamiento compartido, es probable que puedas ejecutarlo localmente para ver si el comportamiento cambia.

0

Lo probé en dos PC Linux distintas (PHP 5.03 y PHP 5.2.10) - ambas funcionaron bien.

PHP 5.2.10 ejemplo:

array (
    'command' => 'ls', 
    'result' => 0, 
    'output' => 'atmail 
... 
vhosts', 
    'r' => 'vhosts', 
    't2-t1' => 0, 
) 

Me doble comprobar que no existen directivas relacionadas con la seguridad en su archivo php.ini, comprobar los permisos de archivos en el directorio que está tratando de buscar, y ver si ejecuta SELinux y/o AppArmor.

También podría considerar una alternativa, como opendir()/readdir().

mi humilde opinión .. PSM

0

Parece que el problema fue resuelto por el administrador del servidor. No tengo idea de lo que hizo, pero ahora funciona. El caso es que el administrador del servidor es bastante "estricto" y tal vez se puso un poco restrictivo con algunas configuraciones del sistema. Desde el shell SSH, por ejemplo, no pude ver dónde se instalaron los binarios de php. Estoy bastante seguro de que el shell SSH fue chrooted, y también el servidor web (o eso o eran servidores totalmente diferentes, pero no sé cómo era posible sin usar ningún tipo de montaje) ...

Cuestiones relacionadas