[résolu] Fichier corrompu au dl après achat

  • Posts: 6
  • Thank you received: 0
12 years 9 months ago #36668

Bonjour,

Je me permet de solliciter votre soutien concernant un problème majeur dans la boutique joomla via Hikashop que je tente de mettre en place.

Qu'il s'agisse de fichiers rar, zip, xlsm, ods, rien a faire, ils sont toujours corrompus. Par exemple les fichier zip ont un CRC32 avec une valeur 0000000 alors que l'original a un CRC32 avec des chiffres et lettres. Si je télécharge les fichiers directement sur le FTP, pas de soucis, de même si je retire le .htaccess du dossier media/com_hikashop/upload/safe et que je lance un téléchargement direct sur l'url d'un fichier, tout est parfait. Mais cela fait sauter la sécurité, et permet aux utilisateur n'ayant pas réglé leur achat de télécharger quand même, donc cette solution n'est pas viable bien-sur.

Malgré les modifications de paramètre apache afin d’empêcher le gzip et les mime type du header pour HTTP responses, rien a faire les fichiers sont corrompus à tous les coups.

J'ai testé de remplacer ( dans le fichier .htaccess rangé dans media/com_hikashop/upload/safe/ ):

deny from all

par

deny from all
<IfModule mod_gzip.c>
mod_gzip_on No
</IfModule>

Afin de retirer un éventuel Gzip qui aurait survécu dans la config apache, mais rien a faire, même problème. (j'ai aussi tester cette methode dans le htaccess a la racine de joomla)

Un autre indice peut être qui pourrait aider:
J'ai remarquer que si je force un download moi même (en ayant retiré ou non le htaccess dans le dossier safe), j’obtiens aussi un corruption de fichier, avec ce code:

$fichier = 'media/com_hikashop/upload/safe/xxx.zip';
header("Content-disposition:attachment; filename=$fichier");
header("Content-Type:application/force-download");
readfile($fichier);

Et il me semble que les fonction Hikashop utilise cette fonction:

Par exemple :
- la fonction csv du fichier view.html.php ===> dans administrator/components/com_hikashop/views/dashboard/
- dans le fichier export.php ===> ligne 150 dans administrator/components/com_hikashop/views/order/tmpl
- dans le fichier export.php ===> ligne 351 dans administrator/components/com_hikashop/views/product/tmpl

Autre chose qui peut être peut aider à trouver la raison:
Mon lien de téléchargement ce présente sous cette forme:
lenomdemonsite.com/index.php?option=com_..._id=134&order_id=150

Et afin de m'asssurer que mon thème personnalisé ne soit pas en cause, j'ai testé avec le thème de base joomla sans aucun modifes, et même histoire. Le serveur d'hébergement est OVH. J'ai migré le site chez Host papa pour testé mais toujours pareil, ensuite j'ai testé sur un serveur NAS personnel en local, ou j'ai modifié les paramètres httpd.conf et apache.conf à l'aide de WinSCP en SFTP. Mais rien a faire, les paramêtres apache ne sont pas en cause.


Je vous avoue que je suis un peu a court d'idée pour résoudre ce problème, et légèrement désespéré. Merci de m'aider. Si vous avez besoin de précision, n'hésitez pas, je reste a l'affu de ce post.

Cordialement

Steeve

Last edit: 12 years 9 months ago by Steeve.C.

Please Log in or Create an account to join the conversation.

  • Posts: 82863
  • Thank you received: 13372
  • MODERATOR
12 years 9 months ago #36709

Bonjour,

Un CRC de 000000 signifie que le fichier téléchargé est vide.
En cherchant sur google j'ai trouvé ces deux messages:
stackoverflow.com/questions/6978870/down...ty-php-what-is-wrong
stackoverflow.com/questions/3563769/forc...hp-giving-empty-file

Le premier indique que le problème pourrait venir de l'option EnableSendfile de apache donc vérifiez bien que cette option soit activée et qu'elle ne soit pas désactivée par un htaccess.

Le second indique que le problème pourrait venir d'un chemin de fichier erroné. Avez vous changé le chemin d'upload sécurisé dans la configuration d'hikashop après avoir uploadé vos fichiers ?
cela pourrait expliqué pourquoi la taille des fichiers est de 0: Le fichier n'existe tout simplement pas dans le nouveau dossier d'upload sécurisé.

Cela pourrait peut être également venir de votre logiciel de téléchargement ? Essayez voir de télécharger avec un autre logiciel.

Je n'ai pas trouvé d'autre piste intéressante.
Si cela ne résoud toujours pas votre problème. Il faudra éditer le fichier administrator/components/com_hikashop/classes/file.php et ajouter des informations de débug dans la fonction qui envoi le fichier au navigateur pour espérer y trouver quelque chose d'intéressant.

Please Log in or Create an account to join the conversation.

  • Posts: 6
  • Thank you received: 0
12 years 9 months ago #36742

Bonjour,

Merci beaucoup pour votre, réponse, j'ai étudié vos différentes pistes.

Concernant le EnableSendfile, la configuration apache ainsi que les fichiers .htaccess ne semble pas être désactivé. Dans le doute j'ai même ajouté "EnableSendfile On".


#
# EnableMMAP and EnableSendfile: On systems that support it,
# memory-mapping or the sendfile syscall is used to deliver
# files. This usually improves server performance, but must
# be turned off when serving from networked-mounted
# filesystems or if support for these functions is otherwise
# broken on your system.
#
#EnableMMAP off
#EnableSendfile off




Concernant le chemin du fichier de téléchargement, jen 'ai jamais modifié le parametre par default:



Par contre, il arrive parfois que le fichier soit tros gros pour être importé dans le backoffice de Hikashop, donc on y envoit un fichier légé de quelques kilo avec le même nom, puis on le remplace directement dans le FTP, à la main.

Sinon les fichiers téléchargés pèsent le même nombre de kilo que l'original non corrompu mais c'est vrai qu'ils semblent vide dans le contenu même de chaque élément du zip impossible a extraire. Les fichier Ods de Openoffices, s'ouvre mais le contenu est absolument vide, meme pas la page blanche de base, et Openoffice affiche un message de contenu illisible.



Concernant le logiciel de téléchargement:
Avec le navigateur Chrome ,Firefox, Internet Explorer 9.0 64bit, on obtient le même résultat.


J'ai commencé a éplucher le fichier administrator/components/com_hikashop/classes/file.php

Je ne suis pas sûr d'avoir bien compris le fonctionnement du système, pourriez-vous m'indiquer si je me trompe ?
Le script consisterait à dupliquer le fichier se trouvant dans le dossier media/com_hikashop/upload/safe (le dossier contenant le htaccess avec "deny from all"), de placer cette copie de fichier dans un autre dossier dont j'ignore le nom.
Ensuite il vérifi si la session utilisateur actuel à l'auttorisation de télécharger, nombre de telechargement, date d'expiration du droit, le statu de la commande, etc..)
Et pour finir il utiliserait la fonction sendFile (ligne 487), en construisant le Header http avec des paramêtres du type, nom du fichier, son poids ...


J'ai l'impression que la fonction qui détermine le dossier de déstination pour la duplication du fichier provisoir, se nomme function storeFiles($type,$pkey,$var_name = 'files') ===> ligne 93, et que la variable $uploadPath détermine le chemin du dossier. J'ai rpesque envie de forcer la valeur de ce dossier de déstination, pour attribuer avec filezilla les droits d'acces public a ce dossier. Qu'en pensez vous?

Je me demande aussi si le programme ne supprimerait pas trop vite le fichier dupliqué, genre il le duplique, le supprime et l'envois. Mais le je pense que je m'écarte de la solution car je suppose que d'autre utilisateur Hikashop n'ont pas eu ce probleme, et je possède le fichier par default comme tout el monde.

Pour finir, auriez-vous un indice pour tester l'éxistence du fichier provisoir dupliqué ?

Merci beaucoup pour votre soutien. Si vous le souhaitez je peux vous PM mon mail, skype...

Steeve

Please Log in or Create an account to join the conversation.

  • Posts: 230
  • Thank you received: 6
12 years 9 months ago #36746

Une piste ... je l'espère

Les paramètres de php.ini suivant pourraient être vérifiés

Selon la grosseur du fichier: (exemple 10 megs)

upload_max_filesize = 10M
post_max_size = 10M

valider les paramètres de PHP effectifs à partir du menu "Information système" - "Informations PHP" de Joomla avant et après les modifications


si votre serveur permet de modififier le PHP.INI

1- placer un fichier php.ini à la racine de votre site contenant les lignes précédentes

2- Placer au début du fichier .htaccess la ligne suivante en ajustant bien le chemin ou se trouve votre fichier

suPHP_ConfigPath /home/repertoire_site_serveur/public_html/ (bien inscrire le chemin)

Cela devrait en même temps corriger le problème pour le upload des fichiers qui coupe.

Si après les modifications votre site affiche "Internal error ..." soit il y a une erreur dans le fichier ou bien ce n'est pas supporté par le serveur. Modifier de nouveau le fichier .HTACCESS sans la modifications pour corriger.

En passant les fichiers on quelle grosseur ?

Last edit: 12 years 9 months ago by greniers.

Please Log in or Create an account to join the conversation.

  • Posts: 6
  • Thank you received: 0
12 years 9 months ago #36764

Merci Greniers pour cette réponse, mais malheureusement, cette modification engendre une erreure 500 Internal Server Error.

Sinon sur le serveur officiel mutualisé, je ne peux pas modifier le php.ini, mais sur mon serveur NAS local, modifier la valeur du fichier max me permet d'envoyer un plus gros fichier mais l'utilisateur récupère quand même un fichier corrompu.

De plus, si je comprend bien le script d'envois de fichier Hikashop, l'utilisateur ne télécharge pas le fichier lui même mais une copie provisoire qui va je ne sais pas ou. Et je pense que c'est le coeur du problème, car les fichiers reçus ont la bonne info dans le header, pour le nom, le poids, etc.. mais le contenu est absent.

Merci quand même d'avoir essayer.

Nicolas, auriez vous une indication sur la modification php des fonction d'envois permettant de m'assurer de la duplication du fichier ?

Please Log in or Create an account to join the conversation.

  • Posts: 82863
  • Thank you received: 13372
  • MODERATOR
12 years 9 months ago #36783

Il n'y a pas de copie de fichier. Vous devez seulement regarder la fonction sendFile qui devrait récupérer le chemin du fichier à envoyer et l'envoyer directement. C'est tout.
La fonction storeFiles est seulement utilisée lors de l'upload des fichiers pour enregistrer les fichiers dans le dossier d'upload d'hikashop.

Si le chemin du fichier dans sendFile est correct, cela veut dire qu'il y a un problème entre l'affichage des données par hikashop via la ligne:
print(fread($fp, 8192));

et l'arrivée dans votre fichier sur votre disque dur.

Pourriez vous essayer de télécharger via une autre connexion internet/un autre ordinateur. On ne sait jamais, il y a peut être quelque chose qui cause le problème sur votre ordinateur.

Please Log in or Create an account to join the conversation.

  • Posts: 6
  • Thank you received: 0
12 years 9 months ago #36794

Merci Nicolas pour cette réponse,


Donc afin de vérifier la valeur des variables j'ai inséré dans la fonction sendFile quelques ligne de code pour envoyer dans une bdd leur valeur

Au final:

$filename correspond bien au nom du fichier cible, avec son extension
$fileinfo ===> qui d’ailleurs n'est pas utilisé sous cette forme en tout cas, mais il correspond bien au chemin (media/com_hikashop/upload/safe)
$fp = Resource id #94 ==> ça je ne comprend pas trop ce que c'est.

J'ai tenté de remplacer:

print(fread($fp, 8192)); par readfile($filename); ==> le fichier télécharger ne s'ouvre même plus.


J'ai aussi tenté de remplacer : $fp = fopen($file, 'rb'); par $fp = fopen($file, 'r'); ===> le résultat est le même


Dans la function getPath($type) ===> j'ai exporté la valeur de $uploadFolder qui correspond au bon chemin du fichier (media/com_hikashop/upload/safe/)
!! A noté que $uploadFolder me calle bien le slash final / , alors que dans la function sendFile ==> $fileinfo me donn le meme chemin sans le slash final


Je sens que je m'approche de la solution la non?

Encore Merci pour ce soutien :)

Please Log in or Create an account to join the conversation.

  • Posts: 6
  • Thank you received: 0
12 years 9 months ago #36795

Ha oui j'oubliais, au passage,
$seek_start me renvois la valeur 0
$seek_end me renvois la valeur 5147725

Et si je remplace:

print(fread($fp, 8192));

par

print(fread($fp, filesize($filename)));

Le fichier télécharger ne peut plus s'ouvrir

Au fait, le téléchargement corrompu arrive depuis Reims, Bordeaux, Bayonne. Partout la même histoire

Last edit: 12 years 9 months ago by Steeve.C.

Please Log in or Create an account to join the conversation.

  • Posts: 6
  • Thank you received: 0
12 years 9 months ago #36874

Bonsoir,

J'ai finalement résolu le probleme en codant a ma sauce un script permettant ce ttéléchargement.

Que voici:(j'ai volontairement changer le nom des table de la bdd par sécurité)

Les function:

function verif_statu_order($id_order)
{

$query_chope_le_text = "SELECT * FROMhikashop_order WHERE order_id = $id_order AND order_status = 'confirmed' OR order_id = $id_order AND order_status = 'shipped' LIMIT 0, 1";
$chope_le_text = mysql_query($query_chope_le_text) or die(mysql_error());
$row_chope_le_text = mysql_fetch_assoc($chope_le_text);

$id_order = $row_chope_le_text;

if($id_order > 0)
{
return 1;
} else {
return 0;
}

}



function order_time($order_id)
{
$dateA = date("Y-m-d");
$heureA = date("H:i:s");
$date_du_jour = $dateA." ".$heureA;
$date_du_jour = str_replace("-","/",$date_du_jour);

//je commence par vérifier si l'order existe dans la table
$query_existence_order = "SELECT * FROM order_time WHERE id_order = $order_id LIMIT 1";
$existence_order = mysql_query($query_existence_order) or die(mysql_error());
$row_existence_order = mysql_fetch_assoc($existence_order);

//s'il existe
if($row_existence_order > 0)
{
//donc il existe, je verifie si le temps est bon
//je commence par aller chercher le temps autoriser en minute
$temp_autorise = nombre_minute_autorise_telechargement();

$date_deb = $row_existence_order;
$date_fin = ajout_minute_a_date($date_deb, $temp_autorise);

//je verifie si la date du jour est comprise entre les deux date
if($date_du_jour >= $date_deb and $date_du_jour <= $date_fin)
{
return 1;
} else {
return 0;
}

} else {
//donc il n'existe pas, je commence par aller chercher les infos sur cette order
$query_order_info = "SELECT * FROM hikashop_order WHERE order_id = $order_id LIMIT 1";
$order_info = mysql_query($query_order_info) or die(mysql_error());
$row_order_info = mysql_fetch_assoc($order_info);

$order_user_id = $row_order_info;



//Je cré l'order dans la table order time
$sql_post_order_time = "INSERT INTO order_time (id_order, date, order_user_id) VALUES ( $order_id, '$date_du_jour', $order_user_id)";
$req_post_order_time = mysql_query($sql_post_order_time) or die('Erreur SQL ! '.$sql_post_order_time.' '.mysql_error());

return 1;
}

}

function check_download_number_limit()
{

$query_chope_le_text = "SELECT * FROM hikashop_config WHERE config_namekey = 'download_number_limit' LIMIT 0, 1";
$chope_le_text = mysql_query($query_chope_le_text) or die(mysql_error());
$row_chope_le_text = mysql_fetch_assoc($chope_le_text);

$nbr_dl = $row_chope_le_text;


return $nbr_dl;

}


function check_download_number_file_id_order_id($file_id, $order_id)
{

$query_chope_le_text = "SELECT * FROM hikashop_download WHERE file_id = $file_id AND order_id = $order_id LIMIT 0, 1";
$chope_le_text = mysql_query($query_chope_le_text) or die(mysql_error());
$row_chope_le_text = mysql_fetch_assoc($chope_le_text);

$nbr_dl = $row_chope_le_text;

if($nbr_dl > 0)
{
return $nbr_dl;
} else {
return 0;
}

}

function check_nom_file($file_id)
{

$query_chope_le_text = "SELECT * FROM hikashop_file WHERE file_id = $file_id LIMIT 0, 1";
$chope_le_text = mysql_query($query_chope_le_text) or die(mysql_error());
$row_chope_le_text = mysql_fetch_assoc($chope_le_text);

$nom_fichier = $row_chope_le_text;

if($nom_fichier != "")
{
return $nom_fichier;
}

}

function ajout_un_nbr_telechargement_id_file_id_order($file_id, $order_id)
{

$query_chope_le_text = "SELECT * FROM hikashop_download WHERE file_id = $file_id AND order_id = $order_id LIMIT 0, 1";
$chope_le_text = mysql_query($query_chope_le_text) or die(mysql_error());
$row_chope_le_text = mysql_fetch_assoc($chope_le_text);

$nbr_dl = $row_chope_le_text;

if($nbr_dl > 0)
{
$new_nbr = $nbr_dl + 1;
$sql_base = "UPDATE hikashop_download SET download_number = $new_nbr WHERE file_id = $file_id AND order_id = $order_id";
$req_base = mysql_query($sql_base) or die('Erreur SQL ! '.$sql_base.' '.mysql_error());

} else {
$sql_base = "INSERT INTO hikashop_download (file_id, order_id, download_number) VALUES ( $file_id, $order_id, 1)";
$req_base = mysql_query($sql_base) or die('Erreur SQL ! '.$sql_base.' '.mysql_error());
}

}



Le script final:


//Avant tout si pas log, je le renvois ailleur
if($id_utilisateur > 0)
{
$order_id_traitement = $_GET;
$file_id_traitement = $_GET;

//je verifie si order statu valide
if(verif_statu_order($order_id_traitement) == 1)
{
//Si l'order est toujours dans le bon timing
if(order_time($order_id_traitement) == 1)
{
//je verifi si le fichier n'a pas depasser le nombre maxi de telechargement
$nbr_maxi_dl = check_download_number_limit();
$nbr_deja_dl = check_download_number_file_id_order_id($file_id_traitement, $order_id_traitement);

if($nbr_deja_dl < $nbr_maxi_dl)
{
//je verifie si le fichier existe, si oui j'en ressort son nom
$nom_fichier = check_nom_file($file_id_traitement);
//echo "nom_fichier = ".$nom_fichier;
if($nom_fichier != "")
{
$nom_chemin_fichier = 'media/com_hikashop/upload/safe/'.$nom_fichier;
//Donc tout est bon je commence a filer le fichier a l'utilisateur
if (file_exists($nom_chemin_fichier)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($nom_chemin_fichier));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($nom_chemin_fichier));
ob_clean();
flush();
readfile($nom_chemin_fichier);
exit;
}


//j ajoute 1 au nbr de telechargement
ajout_un_nbr_telechargement_id_file_id_order($file_id_traitement, $order_id_traitement);


} else {
//sinon je renvois sur la page profil
header ("Location: index.php?page=profil&message=4");
}


} else {
//sinon je renvois sur la page profil
header ("Location: index.php?page=profil&message=3");
}


} else {
//sinon je renvois sur la page profil
header ("Location: index.php?page=profil&message=2");
}
} else {
//sinon je renvois vers la page panier, car order non validé
header ("Location: index.php?option=com_hikashop&ctrl=checkout&voir=panier&eta=1");
}



} else {
//sinon je renvois sur la page enregistrement
header ("Location: index.php?page=enregistrement&message=1");
}



Voila, un grand merci au soutien malgré tout qui ma orienté dans le bon sens

Longue vie a Hikashop

Please Log in or Create an account to join the conversation.

  • Posts: 82863
  • Thank you received: 13372
  • MODERATOR
12 years 9 months ago #36984

Je vois que vous utilisez readfile pour envoyer le fichier.
C'est très certainement ça qui à résolu votre problème.

En remplaçant juste

//open the file
		$fp = fopen($file, 'rb');
		//seek to start of missing part
		fseek($fp, $seek_start);
	//reset time limit for big files
		set_time_limit(0);
		//start buffered download
		while(!feof($fp))
		{
			 print(fread($fp, 8192));
				flush();
				ob_flush();
		}

		fclose($fp);
par
readfile($file);
dans le fichier original cela devrait donc fonctionner également.

Ce qui signifie qu'il doit y avoir quelque chose sur votre serveur qui empêche l'éxecution d'une des fonctions PHP utilisées par le code original:
fopen fseek set_time_limit feof fread flush ob_flush fclose

Donc il faudrait vérifier la configuration PHP/apache pour voir s'il n'y a pas quelque chose qui pourrait bloquer l'une de ces fonctions tel que l'option "disable_functions" de PHP.

Please Log in or Create an account to join the conversation.

Time to create page: 0.086 seconds
Powered by Kunena Forum