web-dev-qa-db-fra.com

comment rediriger STDOUT vers un fichier en PHP?

Le code ci-dessous fonctionne presque, mais ce n'est pas ce que je voulais vraiment dire:

ob_start();
echo 'xxx';
$contents = ob_get_contents();
ob_end_clean();
file_put_contents($file,$contents);

Existe-t-il un moyen plus naturel?

52
omg

Il est possible d'écrire STDOUT directement dans un fichier en PHP, ce qui est beaucoup plus facile et plus simple que d'utiliser la mise en mémoire tampon de sortie.

Faites-le au tout début de votre script:

fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
$STDIN = fopen('/dev/null', 'r');
$STDOUT = fopen('application.log', 'wb');
$STDERR = fopen('error.log', 'wb');

Pourquoi au tout début vous pouvez demander? Aucun descripteur de fichier ne doit encore être ouvert, car lorsque vous fermez les descripteurs de fichier d'entrée, de sortie et d'erreur standard, les trois premiers nouveaux descripteurs deviennent les NOUVEAUX descripteurs de fichier d'entrée, de sortie et d'erreur standard.

Dans mon exemple, j'ai redirigé l'entrée standard vers/dev/null et les descripteurs de fichier de sortie et d'erreur vers les fichiers journaux. C'est une pratique courante lors de la création d'un script démon en PHP.

Pour écrire dans le fichier application.log, cela suffirait:

echo "Hello world\n";

Pour écrire dans error.log, il faudrait faire:

fwrite($STDERR, "Something went wrong\n"); 

Veuillez noter que lorsque vous modifiez les descripteurs d'entrée, de sortie et d'erreur, les constantes intégrées PHP STDIN, STDOUT et STDERR seront rendues inutilisables. PHP will ne pas mettre à jour ces constantes vers les nouveaux descripteurs et il n'est pas autorisé de redéfinir ces constantes (elles sont appelées constantes pour une raison après tout).

119
Bas Peters

voici un moyen de détourner la SORTIE qui semble être le problème d'origine

$ob_file = fopen('test.txt','w');

function ob_file_callback($buffer)
{
  global $ob_file;
  fwrite($ob_file,$buffer);
}

ob_start('ob_file_callback');

plus d'infos ici:

http://my.opera.com/zomg/blog/2007/10/03/how-to-easily-redirect-php-output-to-a-file

16
user340140

Non, la mise en mémoire tampon de sortie est aussi bonne que possible. Bien qu'il soit un peu plus agréable de le faire

ob_start();
echo 'xxx';
$contents = ob_get_flush();
file_put_contents($file,$contents);
9
chaos

Aucune des réponses n'a fonctionné pour mon cas particulier où j'avais besoin d'un moyen multiplateforme de rediriger la sortie dès qu'elle était reproduite afin que je puisse suivre les journaux avec tail -f log.txt ou une autre application de visualisation des journaux. J'ai trouvé la solution suivante:

$logFp = fopen('log.txt', 'w');

ob_start(function($buffer) use($logFp){
    fwrite($logFp, $buffer);
}, 1); //notice the use of chunk_size == 1

echo "first output\n";
sleep(10)
echo "second output\n";

ob_end_clean();

Je n'ai remarqué aucun problème de performances, mais si vous le faites, vous pouvez changer chunk_size en valeurs supérieures.

Maintenant, juste -f le fichier journal:

tail -f log.txt
3
Danilo Souza Morães

L'utilisation du module eio pecl eio est très simple, vous pouvez également capturer PHP erreurs internes, var_dump, echo, etc. Dans ce code, vous pouvez trouver quelques exemples de situations différentes.

$fdout = fopen('/tmp/stdout.log', 'wb');
$fderr = fopen('/tmp/stderr.log', 'wb');

eio_dup2($fdout, STDOUT);
eio_dup2($fderr, STDERR);
eio_event_loop();

fclose($fdout);
fclose($fderr);

// output examples
echo "message to stdout\n";

$v2dump = array(10, "graphinux");
var_dump($v2dump);

// php internal error/warning
$div0 = 10/0;

// user errors messages
fwrite(STDERR, "user controlled error\n");

L'appel à eio_event_loop est utilisé pour être sûr que les demandes eio précédentes ont été traitées. Si vous avez besoin d'ajouter au journal, lors d'un appel fopen, utilisez le mode 'ab' au lieu de 'wb'.

L'installation du module eio est très simple ( http://php.net/manual/es/eio.installation.php ). J'ai testé cet exemple avec la version 1.2.6 du module eio.

2

Vous pouvez installer l'extension Eio

pecl install eio

et dupliquer un descripteur de fichier

$temp=fopen('/tmp/my_stdout','a');
$my_data='my something';
$foo=eio_dup2($temp,STDOUT,EIO_PRI_MAX,function($data,$esult,$request){
    var_dump($data,$esult,$request);
    var_dump(eio_get_last_error($request));
},$my_data);
eio_event_loop();
echo "something to stdout\n";
fclose($temp);

cela crée un nouveau descripteur de fichier et réécrit le flux cible de STDOUT

cela peut aussi être fait avec STDERR

et les constantes STD [OUT | ERR] sont toujours utilisables

1
Vaclav Krauz

Voici une solution laide qui a été utile pour un problème que j'ai eu (besoin de déboguer).

if(file_get_contents("out.txt") != "in progress")
{
    file_put_contents("out.txt","in progress");
    $content = file_get_contents('http://'.$_SERVER['HTTP_Host'].$_SERVER['REQUEST_URI']);
    file_put_contents("out.txt",$content);
}

Le principal inconvénient de cela est que vous feriez mieux de ne pas utiliser les variables $ _POST. Mais vous n'avez pas à le mettre au tout début.

1
buburs