exec retourne toujours -1 (ou 127)

J’utilise php 5.2.9 sur un serveur de production, et il semble que la fonction exec () se comporte “non standard”.

Si exec("ls", $output, $return_var) alors $output contiendra la liste des fichiers dans le dossier actuel comme prévu, mais $return_var sera défini sur -1 au lieu de 0, comme prévu. J’utilise le $return_var pour déterminer où la commande s’est terminée avec succès, et sur tous les autres serveurs testés, cela fonctionne comme prévu 🙂

Quelqu’un a-t-il déjà rencontré une telle situation?


modifier:

 <?php $command = "asd"; $t1 = time(); $output = Array(); $result = -5; $r = exec($command, $output, $result); $t2 = time(); echo "
"; var_export(Array( 'command'=>$command, 'result'=>$result, 'output'=>implode("\n", $output), 'r'=>$r, 't2-t1'=>$t2-$t1, )); echo "

";

Quelle que soit la commande que je mets dans $command , $result sera toujours -1, même pour des commandes inexistantes … c’est très bizarre

En supposant que le système renvoyant $ result == -1 est basé sur Unix (je ne sais pas comment Windows se comporterait avec le même code)

La fonction PHP (5.2.9) exec () n’appelle pas la primitive C exec () qui renvoie -1 si elle ne peut pas remplacer / exécuter le processus, ce qui n’est pas le cas ici. Au lieu de cela, il appelle popen () qui crée un tube, effectue un fork () et exécute un shell avec votre commande. La valeur de retour, -1, n’est pas le résultat direct d’une primitive C, mais est construite en interne par PHP, en fonction de la manière dont votre commande a été traitée. En d’autres termes, la commande “ls” peut avoir été bien exécutée, alors que PHP, par exemple, ne peut pas fermer correctement le tube.

En regardant le code C, dans ext / standard / exec.c, il pourrait y avoir deux raisons pour lesquelles le code retour est -1, déclenché par une erreur; le 2ème arrive après l’appel popen ()

  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; 

Cependant, dans ce cas, vous ne verriez pas le résultat et le journal afficherait une erreur.

Plus tard, la valeur de retour est définie via la ligne

  pclose_return = php_stream_close(stream); 

En regardant _php_stream_free () (php_stream_close () est une macro remplacée par _php_stream_free ()), le candidat le plus susceptible de renvoyer -1 est

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

Qui à son tour appelle indirectement la primitive C pclose (). Selon le manuel

La fonction pclose () renvoie -1 si wait4 (2) renvoie une erreur ou si une autre erreur est détectée.

Il semble y avoir une erreur détectée lors de la fermeture du canal, cela n’empêche pas la définition des données résultantes. Pour trouver la raison rigoureusement, il faut vérifier la configuration du système d’exploitation et les journaux, la configuration de PHP et les parameters de compilation.

je recommanderais

  • appliquer des correctifs pour votre système d’exploitation, et éventuellement mettre à jour vers une version plus récente (le cas échéant),
  • pour mettre à jour PHP vers la version 5.3.3 (la plus récente à ce jour), car le code PHP exec () a changé de manière significative.

Sachez qu’il y a eu des changements liés au module PHP suhosin dans la version 5.3 qui améliorent par défaut la sécurité lors de l’exécution de fichiers PHP.

Assurez-vous de ne pas utiliser le mode sans échec et que exec n’est pas répertorié dans disable_functions dans php.ini.

L’une ou l’autre de ces situations entraînerait l’échec de exec() , même si je pense qu’un avis serait émis.

Pouvons-nous obtenir le résultat du traitement du processus PHP? Cela contiendra probablement la réponse que nous recherchons.

5.2.14 est également le plus récent de la série 5.2. Avez-vous eu l’occasion de l’essayer ici? Si vous êtes sur un fournisseur d’hébergement partagé, vous pouvez toujours l’exécuter localement pour voir si le comportement change.

Je l’ai essayé sur deux PC Linux différents (PHP 5.03 et PHP 5.2.10) – les deux fonctionnaient très bien.

Exemple PHP 5.2.10:

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

Je vérifie la présence de toutes les directives relatives à la sécurité dans votre fichier php.ini, vérifie les permissions des fichiers dans le répertoire que vous essayez de rechercher et vérifie si SELinux et / ou AppArmor sont en cours d’exécution.

Vous pouvez également considérer un altenratif, comme opendir () / readdir ().

IMHO .. PSM

On dirait que le problème a été résolu par l’administrateur du serveur. Je n’ai aucune idée de ce qu’il a fait, mais cela fonctionne maintenant. Le fait est que l’administrateur du serveur est plutôt “ssortingct” et peut-être qu’il est devenu un peu ressortingctif avec certaines configurations système. À partir du shell SSH, par exemple, je ne pouvais pas voir où les fichiers binarys php étaient installés. Je suis presque sûr que le shell SSH était chrooté, et aussi le serveur Web (que ce soit ou ils étaient des serveurs totalement différents, mais je ne sais pas comment cela était possible sans utiliser aucun type de assembly) …