8795 sujets

Développement web côté serveur, CMS

Bonjour à tous,

En ce moment je souhaite récupérer, en php, un fichier compressé par la librairie Zlib, un fichier GZ.

J'arrive très bien à récupérer l'archive par un "copy()" depuis le site externe où il se trouve, par contre, sur une archive de 13 Mo, impossible de décompresser, et de récupérér le contenu, je me retrouve avec une erreur 500.

Je vous montre le code que j'utilise.

Dans un premier temps la copie du fichier externe :

$fichier_user = "user.gz";
$dir_xml = 'xml/';
$fichier_xml = "-stats-user.xml";

//Rosetta@home
$url_rosetta = "http://boinc.bakerlab.org/rosetta/stats/".$fichier_user;
$url_dest_rosetta = $dir_xml."rosetta_".$fichier_user;

copy($url_rosetta, $url_dest_rosetta);


Jusque là, tout se passe niquel, aucun soucis, ensuite, j'essaye d'extraire le contenu de l'archive avec ceci :

decompression_xml_projet("rosetta", $url_dest_rosetta, $dir_xml);


function decompression_xml_projet($projet, $url_projet_gz, $dir_cache)
	{	
	if(${'gz'.$projet} = gzopen($url_projet_gz, "rb"))
	{
		
	while(!gzeof(${'gz'.$projet}))
			{
	        ${'text'.$projet}.= gzread(${'gz'.$projet}, 1024);
			}
		gzclose(${'gz'.$projet});
		

		${'fp'.$projet} = fopen($dir_cache.'/'.$projet.'-stats-user.xml', 'w+');
		fwrite(${'fp'.$projet}, ${'text'.$projet});
		fclose(${'fp'.$projet});
		
		echo "<p>Copie du fichier <strong>user.gz</strong> terminé</p>";
		echo "<p>Création fichier XML <strong>".$projet."</strong> terminé</p>";
		
	}
	else
		{
			echo "<p>Mise à jour <strong>".$projet."</strong> erreur</p>";
		}	
	}


Et c'est là que ça plantouille, erreur 500.

Sur une petite archive (1,7 Mo), aucun souci, j'ai bien mon fichier xml qui se crée, mais sur plus gros ça coince.

Existe t'il un moyen d'extraire le fichier en plusieurs partie ? Existe t'il un moyen de découper l'archive en plusieurs morceaux ?

Car je pense vraiment qu'il s'agisse d'un problème de taille de fichier ... Smiley decu

Merci !
Modifié par Super_baloo8 (10 Nov 2008 - 22:56)
Augmenter le temps d'exécution du script dans les settings php peut-être ?

max_execution_time (30 s par défaut)

Ou un time-out trop bas sur apache ou iis ? (300 s par défaut à priori pour les 2)
Salut PiR2,

max_execution_time 50000

Donc je pense que c'est bon, pour le Time Out, je ne sais pas ce que c'est, j'ai trouvé ceci dans la conf d'apache :

default_socket_timeout 60

?

Je ne pense pas que cela vienne d'une limite de temps, mais surement de taille (je ne peux rien gérer, je suis sur un serveur mutualisé).

Il me met erreur 500 au bout de quelques secondes

Lien de la page qui donne cette erreur :

http://www.grid-france.fr/include/membres/test.php

Code dans sa totalité :

<?php
function decompression_xml_projet($projet, $url_projet_gz, $dir_cache)
	{	
	if(${'gz'.$projet} = gzopen($url_projet_gz, "rb"))
	{
		
	while(!gzeof(${'gz'.$projet}))
			{
	        ${'text'.$projet}.= gzread(${'gz'.$projet}, 1024);
			}
		gzclose(${'gz'.$projet});
		

		${'fp'.$projet} = fopen($dir_cache.'/'.$projet.'-stats-user.xml', 'w+');
		fwrite(${'fp'.$projet}, ${'text'.$projet});
		fclose(${'fp'.$projet});
		
		echo "<p>Copie du fichier <strong>user.gz</strong> terminé</p>";
		echo "<p>Création fichier XML <strong>".$projet."</strong> terminé</p>";
		
	}
	else
		{
			echo "<p>Mise à jour <strong>".$projet."</strong> erreur</p>";
		}	
	}

$fichier_user = "user.gz";
$dir_xml = 'xml/';
$fichier_xml = "-stats-user.xml";

//Rosetta@home
$url_rosetta = "http://boinc.bakerlab.org/rosetta/stats/".$fichier_user;
$url_dest_rosetta = $dir_xml."rosetta_".$fichier_user;

copy($url_rosetta, $url_dest_rosetta);
decompression_xml_projet("rosetta", $url_dest_rosetta, $dir_xml);

//Malaria@home
$url_malaria = "http://www.malariacontrol.net/stats/".$fichier_user;
$url_dest_malaria = $dir_xml."malaria_".$fichier_user;

copy($url_malaria, $url_dest_malaria);
decompression_xml_projet("malaria", $url_dest_malaria, $dir_xml);
?>

Modifié par Super_baloo8 (10 Nov 2008 - 13:26)
As-tu accès à un journal de log des erreurs ? Voir si tu n'as pas une erreur décrite dedans.
Super_baloo8 a écrit :

Donc je pense que c'est bon, pour le Time Out, je ne sais pas ce que c'est


extrait de :
http://httpd.apache.org/docs/2.0/mod/core.html

TimeOut Directive
Description: Amount of time the server will wait for certain events before failing a request
Syntax: TimeOut seconds
Default: TimeOut 300
Context: server config, virtual host
Status: Core
Module: core

The TimeOut directive currently defines the amount of time Apache will wait for three things:

1. The total amount of time it takes to receive a GET request.
2. The amount of time between receipt of TCP packets on a POST or PUT request.
3. The amount of time between ACKs on transmissions of TCP packets in responses.

We plan on making these separately configurable at some point down the road. The timer used to default to 1200 before 1.2, but has been lowered to 300 which is still far more than necessary in most situations. It is not set any lower by default because there may still be odd places in the code where the timer is not reset when a packet is sent.
Merci ! C'est sur, ça ne viens pas du "timeout" puisque la copie se passe niquel, après je fais travailler apache en local.

En fait, je viens de voir sur la faq de l'hébergeur :

"1And1" a écrit :
Erreur 500 lors de l’appel d’un script PHP
L’erreur 500 lorsque vous appelez un script PHP peut avoir plusieurs causes.

* Dans la grande majorité des cas, elle est liée au fait que votre contrat dépasse la valeur memory_limit de PHP qui est de 32M.
Un nombre trop important de ressources sont alors exigées par votre script sur le serveur.
Ce dernier se refuse alors à satisfaire la demande en retournant une erreur 500.
* Dans un autre cas de figure plus rare, les CHMOD sur le fichier PHP ne sont pas suffisants.
Un CHMOD en 755 sur un fichier PHP est idéal afin de permettre un fonctionnement optimal de votre script.


Donc, du moment que le fichier dépasse les 32 mo, ça coince, et c'est ce qui se passe, le fichier décompresser fait 130 mo si mes souvenirs sont bons.

Donc maintenant que le problème est clair, comment faire pour découper l'archive en plusieurs petit morceau, pour pouvoir traiter des petits paquets qui ne me donneront pas d'erreur 500 ?
en fait memory_limit concerne la RAM que peut occuper un script
a écrit :
Cette option détermine la mémoire limite, en octets, qu'un script est autorisé à allouer. Cela permet de prévenir l'utilisation de toute la mémoire par un script mal codé. Notez que pour n'avoir aucune limite, vous devez définir cette directive à -1.

pas la taille que fait ton fichier ; ceci étant, la décompression de ton fichier qui fait 130 Mo au final peut fort bien saturer cette limite...
Modifié par PiR2 (10 Nov 2008 - 14:07)
Je viens d'essaye de changer la valeur de "memory_limit" en rajoutant ceci dans mon code :

ini_set('memory_limit', '360M');


Mais ça n'y fait rien Smiley decu

Tu sais comment faire une sorte de temporisation pour décompresser ?
Tente de te passer de la mise en buffer et utiliser la fonction flush() ?

Un article intéressant mais jamais testé perso :
http://muzso.hu/2008/02/19/php-output-buffering

le code suivant est extrait du lien précédent (voir aussi la directive output_buffering du php)


<?php
if (function_exists('gzencode')) {
  $zlib_compression = strtolower(ini_get('zlib.output_compression'));
  if ($zlib_compression != '' && $zlib_compression != 'off' && $zlib_compression != '0') {
    ini_set('zlib.output_compression', 'Off');
  }
}
?>
à priori tu compresses du xml non ?

en utilisant
<?php
$string = 'Some information to compress';
$gz = gzopen('somefile.gz','w9');
gzwrite($gz, $string);
gzclose($gz);
?>

Un piste de travail :
tu dois pouvoir décider où couper ton xml source, faire x fichiers zip (tu coupes toutes les 1000 lignes par exemple) et faire la manip inverse de l'autre côté ; décompresser dans l'ordre tex x fichiers et tout réagréger dans un seul fichier non compressé.
Il y avait une solution toute simple, il fallait au niveau de la boucle, écrire en direct dans le fichier, comme ça le tampon est vidé au fur et à mesure, et pas garder tout le long de la manip.

Ca fonctionne nickel maintenant !

Pour infos, voici la solution :

function decompression_xml_projet($projet, $url_projet_gz, $dir_cache)
{     
if (${'gz'.$projet} = gzopen($url_projet_gz, "rb"))
     {
     ${'fp'.$projet} = fopen($dir_cache.'/'.$projet.'-stats-user.xml','w+');
     while(!gzeof(${'gz'.$projet}))
         {
         ${'text'.$projet}= gzread(${'gz'.$projet}, 1024);
      fwrite(${'fp'.$projet}, ${'text'.$projet});
         }
     gzclose(${'gz'.$projet});
     fclose(${'fp'.$projet});
          
     echo "<p>Copie du fichier <strong>user.gz</strong> du <strong>".$projet."@home</strong> terminé<br />";
     echo "Création fichier XML<strong>".$projet."@home</strong> terminé</p>";
     }
else
     {
     echo "<p>Mise à jour <strong>".$projet."@home</strong> erreur</p>";
     }     
}


Merci pour ton aide PiR2 qui m'a mis sur la piste, et un amis m'a permis de finir la résolution ! Merci !!
Super_baloo8 a écrit :
Il y avait une solution toute simple, il fallait au niveau de la boucle, écrire en direct dans le fichier, comme ça le tampon est vidé au fur et à mesure, et pas garder tout le long de la manip.


Hé ! Hé ! Bien joué !!!! Smiley biggrin