[RESOLU] Upload sans rechargement de page

Eléphanteau du PHP | 29 Messages

20 janv. 2015, 13:34

Bonjour, j'aimerais créer de la manière la plus simple possible un formulaire qui permet d'uploader un fichier sans rechargement de la page. J'ai regardé plusieurs tutoriels sur internet et maintenant je suis un peu perdu car les méthodes utilisées sont différentes :
- AjaxUpload (http://www.commentcamarche.net/faq/2438 ... d-multiple)
- Upload avec extension APC (http://openclassrooms.com/courses/ajax- ... apc-de-php)
- XMLHttpRequests (http://blog.teamtreehouse.com/uploading-files-ajax)
- ...
Pouvez-vous m'éclairer sur les principales méthodes qui existent actuellement et quelle est la meilleure à votre avis (ou la plus simple pour un débutant) ?
Merci d'avance !

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 9782 Messages

20 janv. 2015, 13:54

Bonjour,

En fait, les 3 liens que tu indiques reposent sur le même procédé à savoir un envoi via XMLHttpRequest (qui est pour faire simple, le nom technique d'ajax).

Ton 3ème lien présente comment mettre en œuvre de façon la plus simple/rudimentaire le procédé d'upload avec XMLHttpRequest .

Ton 1er lien, préconise d'utiliser une librairie javascript appelée "ajaxupload.js" qui est sensé simplifier l'utilisation de la fonction XMLHttpRequest. Mais visiblement cette librairie javascript n'existe plus donc ce tutoriel ne pourra pas fonctionner.

Et le 2ème lien utilise XMLHttpRequest (sous l'appelation xhr) et l'extension APC pour pouvoir afficher une barre de progression d'upload.

Mon conseil : vériffie déjà si ton hébergeur dispose d'APC, si ce n'est pas le cas tu peux oublier cette approche. Si tes fichiers ne sont pas très volumineux et que tu veux faire un upload tout simple, le 3ème tuto est suffisant.

Si tu veux des choses plus évoluées il y a pas mal de librairies javascript qui pourraient te simplifier la vie :
http://www.dropzonejs.com
http://www.queness.com/post/11434/7-jav ... ad-plugins
Quand tout le reste a échoué, lisez le mode d'emploi...

Eléphanteau du PHP | 29 Messages

20 janv. 2015, 13:59

Merci beaucoup pour ta réponse ! Tout est bien plus clair maintenant.

Eléphanteau du PHP | 29 Messages

24 janv. 2015, 20:43

J'ai essayé avec ce tutoriel : http://www.journaldunet.com/developpeur ... -ajax.html
Donc j'ai ce code HTML :
<form action="upload.php" method="post" enctype="multipart/form-data">
    Select image to upload:
    <input type="file" name="fileToUpload" id="fileToUpload">
    <input type="submit" value="Upload Image" name="submit">
</form>
<progress></progress>
Ce code PHP (http://www.w3schools.com/php/php_file_upload.asp) :
<?php
$target_dir = "uploads/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
$uploadOk = 1;
$imageFileType = pathinfo($target_file,PATHINFO_EXTENSION);
// Check if image file is a actual image or fake image
if(isset($_POST["submit"])) {
    $check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
    if($check !== false) {
        echo "File is an image - " . $check["mime"] . ".";
        $uploadOk = 1;
    } else {
        echo "File is not an image.";
        $uploadOk = 0;
    }
}
// Check if file already exists
if (file_exists($target_file)) {
    echo "Sorry, file already exists.";
    $uploadOk = 0;
}
// Check file size
if ($_FILES["fileToUpload"]["size"] > 500000) {
    echo "Sorry, your file is too large.";
    $uploadOk = 0;
}
// Allow certain file formats
if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg"
&& $imageFileType != "gif" ) {
    echo "Sorry, only JPG, JPEG, PNG & GIF files are allowed.";
    $uploadOk = 0;
}
// Check if $uploadOk is set to 0 by an error
if ($uploadOk == 0) {
    echo "Sorry, your file was not uploaded.";
// if everything is ok, try to upload file
} else {
    if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
        echo "The file ". basename( $_FILES["fileToUpload"]["name"]). " has been uploaded.";
    } else {
        echo "Sorry, there was an error uploading your file.";
    }
}
?>
Et ce code JS :
[javascript]
$(':button').click(function(){
var formulaire = new FormData($('form')[0]);
$.ajax({
url: 'upload.php', //script qui traitera l'envoi du fichier
type: 'POST',
xhr: function() { // xhr qui traite la barre de progression
myXhr = $.ajaxSettings.xhr();
if(myXhr.upload){ // vérifie si l'upload existe
myXhr.upload.addEventListener('progress',afficherAvancement, false); // Pour ajouter l'évènement progress sur l'upload de fichier
}
return myXhr;
},
//Traitements AJAX
beforeSend: traitementAvantEnvois,
success: traitementSiReussite,
error: taitementSiEchec,
//Données du formulaire envoyé
data: formData,
//Options signifiant à jQuery de ne pas s'occuper du type de données
cache: false,
contentType: false,
processData: false
});
});
function afficherAvancement(e){
if(e.lengthComputable){
$('progress').attr({value:e.loaded,max:e.total});
}
}
[/javascript]
Finalement l'upload de fichier fonctionne parfaitement bien mais cela me redirige vers la page "upload.php" donc AJAX ne fonctionne pas correctement. Des idées ? Merci d'avance !

Nestecha
Invité n'ayant pas de compte PHPfrance

27 janv. 2015, 00:47

Remplace :

[javascript]$(':button').click(function(){[/javascript]

Par :

[javascript]$('form').on('submit', function(event) {[/javascript]

Et écrit :

[javascript]$('form').on('submit', function(event) {
event.preventDefault(event);
var formulaire = new FormData($('form')[0]);[/javascript]

Et y'aura pas de redirection !

Eléphanteau du PHP | 29 Messages

28 janv. 2015, 17:38

Merci pour la réponse, c'est parfait la page "upload.php" ne s'affiche plus mais malheureusement aucun fichier n'est uploadé...

ViPHP
AB
ViPHP | 5818 Messages

29 janv. 2015, 06:13

Salut,

Mais tu tiens absolument à le faire toi-même ?

Parce que avec ajax on commence par une barre de progression... puis on se dit qu'il serait bien d'afficher les vignettes des images avant l'upload... puis d'afficher aussi le temps restant... puis un système de queuing pour les téléchargements multiples.

...et puis autant en profiter pour pouvoir annuler certains fichiers avant ou pendant l'upload.

...et puis pourquoi être limité par la configuration serveur puisqu'on pourrait découper les fichiers en morceaux. Donc possible aussi d'uploader des fichiers de plusieurs centaines de méga ou même plusieurs giga avec une "malheureuse" config php mutualisée dont les paramètres "post_max_size" ou "upload_max_filesize" sont limités à 8 Mo ou parfois moins.

... puis tant qu'à faire, comme une connexion internet peut être interrompue volontairement ou pas, on se dit qu'il serait bien de pouvoir sauvegarder les fichiers partiellement uploadés pour pouvoir reprendre le téléchargement ultérieurement (très utile pour les gros fichiers).

... j'allais oublier des styles évènementiels pour une meilleure maîtrise de l'affichage durant l'upload.

Y'a finalement que le drag and drop qui est facile puisque c'est maintenant intégré dans tous les navigateurs modernes.

Au final pour avoir un script assez universel possédant toutes les fonctionnalités que j'ai énoncées on arrive à une solution d'upload comme celle-ci.

L'avantage c'est qu'elle est fournie dans un dossier de test prêt à l'emploi et fonctionnelle dès le départ sans aucune configuration, mais avec beaucoup d'options configurables si besoin. Pour le téléchargement (si cela t'intéresse) faudra t'inscrire mais c'est gratuit. Le site phpfrance ne dispose pas d'un module équivalent c'est pour cette raison que je ne le propose pas dans ce forum.

Si tu tiens absolument à le faire toi-même, je te conseille d'attendre d'avoir un peu plus d'expérience. L'upload de fichier est un sujet très spécifique et je ne pense pas que ce soit un bon exercice pour progresser au départ, d'autant que les phases de tests sont laborieuses comme tu as pu t'en rendre compte. Ou tu arriveras à un résultat tellement minimaliste que tu auras besoin de le faire évoluer à la moindre occasion.
Après je dis ça, c'est comme tu veux, dans le dossier de téléchargement en plus du fichier javascript minifié il y a aussi la version de développement si tu veux jeter un oeil, mais c'est pas vraiment à la portée d'un débutant.

Eléphanteau du PHP | 29 Messages

29 janv. 2015, 12:01

PROBLÈME RÉSOLU

Effectivement c'est une très bonne solution celle que tu me propose, mais selon mes besoins il me faut quelque chose très léger, je viens de trouver la solution :

étape 1 : créer un fichier index.html
<form id="uploadimage" action="upload.php" method="post" enctype="multipart/form-data">
<input type="file" name="file" id="file" required />
<input id="sub" type="submit" value="Upload" class="submit" />
</form>
étape 2 : ajouter bibliothèque jquery
étape 3 : ajouter ce code js au fichier html
[javascript]
$("#uploadimage").on('submit',(function(e) {
e.preventDefault();
$.ajax({
url: "upload.php",
type: "POST",
data: new FormData(this),
contentType: false,
cache: false,
processData: false,
});
}));
[/javascript]
étape 4 : créer un fichier upload.php
$sourcePath = $_FILES['file']['tmp_name']; 
$targetPath = "upload/".$_FILES['file']['name']; 
move_uploaded_file($sourcePath,$targetPath); 
étape 5 : créer un dossier "upload"

Voilà la manière la plus simple et légère de faire un système d'upload sans rechargement de page sur son site :)

ViPHP
AB
ViPHP | 5818 Messages

29 janv. 2015, 21:28

Simple oui, mais légère non, étant donné que tu utilises jquery qui fait dans les 90ko de code... Faudrait faire du code javascript vanilla (sans lib) pour pouvoir dire que c'est vraiment léger.

Après si tu fais pas mal de développement javascript il est probable que tu sois amené à utilisé jquery par facilité. Donc au final tu peux le garder pour tous tes scripts.

Mais en l'état comme mon script fait dans les 20ko, ton code n'est finalement plus léger que d'environ 20/90 = 22% ... :wink:

Cela dit, effectivement tu as mis le minimum du minimum pour que ça fonctionne. C'est un bon départ mais cela ne fonctionnera que dans des circonstances favorables. Tu n'es pas à l'abri d'un dépassement d'un timeout du serveur ou d'un dépassement des config "post_max_size" ou "upload_max_filesize".

Mais sans même parler de gérer ou de surpasser ces erreurs, le code minimal devrait au moins faire un retour de php vers javascript pour pouvoir indiquer que le fichier a été correctement téléchargé. Dans ton code ont fait un upload et on n'a aucun retour sur le résultat des opérations. On peut pas dire que c'est le minimum fonctionnel si on se met à la place du visiteur : ... attendre ? ... encore ? ou plus attendre ? ... on fait quoi maintenant #-o
Modifié en dernier par AB le 30 janv. 2015, 05:04, modifié 3 fois.

Mammouth du PHP | 2278 Messages

29 janv. 2015, 22:18

Si on utilise du préparé comme @rthur t'indiquait, on est prêt pour l'avenir, sinon :
Demain, je m'apercevrai que le fichier estb trop gros: ajout de quoi à mon truc minimaliste? (la limite de php est basse, par exemple pour du son, même mono et échantillonné àcomme du téléphone, par exemple...)
Puis je pesterai parce que je ne sais pas combien de temps ça prend, ou parce que le serveur m'a renvoyé un time out...
Vanitas vanitatum et omnia vanitas
Mes derniers livres :
Sauvez les Mots chez BoD,
Tous les chemins mènent à ROM chez BoD

Eléphanteau du PHP | 29 Messages

30 janv. 2015, 01:46

Merci pour vos réponses. C'est clair que la solution que j'ai posté est très minimaliste, néanmoins c'était ce dont j'avais besoin, le but étant de pouvoir customiser comme on le souhaite. Légère n'était effectivement pas le bon mot.

AB tu parles de timeout du serveur, qu'est-ce que c'est ? Est-ce en lien avec une erreur 500 ?

ViPHP
AB
ViPHP | 5818 Messages

30 janv. 2015, 03:57

Salut,

Une erreur timeout se produit suivant les réglages du serveur qui alloue un certain temps pour traiter une requête. Si le post est gros et la connexion internet pas rapide, le temps peut être dépassé même si le fichier est moins gros que les directives "post_max_size" ou "upload_max_filesize". Et cela renvoie en effet une erreur de type 500. Si l'on ne peut pas modifier la configuration serveur, la solution est la fragmentation des fichiers.

C'est bien pour cette raison d'ailleurs que j'ai fait cette classe d'upload pour éviter ce problème. En effet sur les mutualisés ovh entrée de gamme que j'utilise, la directive "upload_max_filesize" est actuellement réglée sur 64 Mo ce qui est assez confortable si l'on ne charge que quelques images à la fois. Mais suivant le lieu ou l'on se trouve pour faire les tests - plus exactement suivant la rapidité de la liaison internet - on est loin de pouvoir atteindre cette limite qui peut être divisée par 2 ou plus à cause du timeout. En coupant les fichiers en morceaux on évite ce problème.

Sinon je comprend pas le lien entre faire un code minimaliste et pouvoir customiser comme on veut... Tu pourrais tout à fait avoir un formulaire aussi minimaliste que celui que tu donne en exemple et utiliser la solution d'upload que j'ai donné en lien dans mon premier message. Elle n'impose absolument rien au niveau de la mise en page et tu peux customiser comme tu veux.
Elle est conçue pour permettre un maximum de possibilités pour la mise en forme des retours d'information grâce à des styles évènementiels. Mais tu utilise ces évènements comme tu veux. Par exemple en cas de succès du téléchargement d'un fichier, pour afficher un message "ok" mais tu pourrais tout aussi bien faire afficher "toto a bien reçu votre fichier", ou pourquoi pas un rond ou un carré vert ou bleu ou ce que tu veux, tu fais bien ce que tu veux et sur les éléments html que tu veux et comme tout est optionnel tu n'es pas obligé de les utiliser. Il y a 4 exemples de configuration différentes dans mon fichier de test pour illustrer les possibilités mais on pourrait en faire à l'infini.

De même on peut activer la visualisation des vignettes des fichiers image, ou ne pas l'activer. Et dans le cas où on l'active on peut aussi paramétrer une taille maximale par image et/ou un poids total maximum du formulaire au delà duquel la visualisation ne se fait pas car c'est trop gourmand en ressources pour l'ordinateur du client. Comme se sont des options facilement configurables on peut aussi imaginer faire une détection du périphérique client et faire le paramétrage de la fonction à la volée suivant qu'il s'agit d'un portable ou d'un pc.

Pour dire que y'a absolument rien d'obligatoire, rien n'est imposé, ce sont toutes des options/possibilités que tu utilises ou pas et que tu customise comme tu veux. Mais d'office et sans n'avoir rien à paramétrer on est au moins certain de pouvoir se prévenir au mieux contre les limitations serveur. Et au pire si le serveur plante, tout n'est pas perdu puisque qu'on pourra réutiliser la partie du fichier déjà uploadée pour simplement la compléter lors d'une prochaine session de téléchargement.

Après si tu veux en savoir plus, il te faudra pas plus de cinq minutes pour faire les premiers tests puisqu'il s'agit juste de télécharger ce dossier, le décompresser puis le copier sur ton serveur. Et simplement tester le fichier qui se trouve à la racine du dossier. On peut pas faire plus simple :)
Pour ceux qui veulent aller plus loin que les exemples de base déjà fournis, il y a aussi un mode d'emploi et les exemples de code sont commentés... je peux difficilement être plus complet :wink:

Eléphanteau du PHP | 29 Messages

30 janv. 2015, 11:42

Un grand merci pour ta réponse ! Alors quand je disais customiser, c'est peut-être pas le bon mot ici non plus :lol: mais je pensais dans le sens ajouter des fonctions soi-même et ne pas passer par une solution toute faite, par exemple limiter soi-même la taille, les formats (dans mon cas il me faut du SVG) etc. etc. etc. et surtout bien comprendre le code que j'utilise. En général avec les solutions toutes faites on ose pas trop toucher au code (moi en tout cas je n'ose pas). Voilà, en tout cas ta solution est très bien je l'ai un peu regardé et j'ai regardé les commentaires des gens, mais ce n'était pas ce que je recherchais. Merci encore !

ViPHP
AB
ViPHP | 5818 Messages

31 janv. 2015, 05:01

... je pensais dans le sens ajouter des fonctions soi-même et ne pas passer par une solution toute faite, par exemple limiter soi-même la taille, les formats (dans mon cas il me faut du SVG) etc. etc. etc. et surtout bien comprendre le code que j'utilise. En général avec les solutions toutes faites on ose pas trop toucher au code (moi en tout cas je n'ose pas).
Il faut bien distinguer deux choses, le code côté javascript et le code côté serveur (dans notre cas php).

C'est côté serveur que tout se décide et que tu dois faire les contrôles, traitements spécifiques etc. Pour reprendre l'exemple de mon script (je peux en parler plus facilement), une classe php est également fournie pour aider les débutants et avoir une solution fonctionnelle dès le départ mais tu pourrais la modifier ou faire ton propre code. Au passage, les exemples d'utilisation de la classe php donnent des exemples pour les contrôles élémentaires que tu as cités (taille, extension) mais aussi pour des redimensionnements d'images, renommage des fichiers en cas de doublons sur le serveur (mode incrémentiel ou suffixe unique), etc. Mais pour parler du principe, une variable javascript est envoyée à php dès que le fichier est entièrement téléchargé, à partir de là tu peux bien faire le code et les contrôles php que tu veux derrière.

Je comprend que tu sois réticent à utiliser quelque chose que tu ne maîtrise pas, mais tu apprendras vite à distinguer les choses importantes qu'on doit absolument maîtriser, de celles que l'on peut déléguer. Et en gros on peut déléguer le code javascript, d'ailleurs c'est bien ce que tu as fait en incluant la librairie jquery sans chercher à comprendre ce qu'elle contient :wink:

Ensuite si on te demande par exemple un slide-show, ou d'autres fonctionnalités javascript un peu sophistiquées et que tu veux tout programmer toi-même cela va te prendre un temps infini. Le client va te demander des explications sur tes délais et le prix facturé comparé à d'autres qui auront tout fini en une journée avec beaucoup plus de fonctionnalités disponibles. La plupart du temps on ne fait donc que le strict nécessaire en javascript tant qu'on peut trouver des solutions toutes prêtes. Ce qu'on demande à un code javascript est qu'il soit fonctionnel et suffisamment modulable pour qu'on puisse l'adapter à ses besoins. Si je te demandais des explications sur le code jquey que tu utilises tu me répondrais "je m'en tape mais ça marche et avec ça je peux simplifier des fonctionnalités qui auraient nécessité beaucoup plus de lignes et de temps avec du javascript vanilla". Pour des solutions d'upload toutes prêtes comme celle que je propose ou celles que t'a proposé @rthur, c'est le même principe. Sauf qu'à la place d'être une couche qui permet d'écrire plus facilement du javascript c'est une couche plus spécifique qui permet d'écrire plus facilement un upload de fichiers. A terme le boulot d'un développeur est donc de pouvoir se servir de ce type de solutions, de même que les API que fournissent certains sites pour exploiter leurs fonctionnalités (et dans ce dernier cas on ne peut pas faire autrement que s'adapter à ce qui est proposé).

D'un autre côté, il est tout à ton honneur de vouloir apprendre... Ce que je disais simplement plus haut c'est que l'upload de fichiers est très spécifique et qu'il serait très casse gueule de vouloir s'initier à jquery ou à javascript avec cet exercice surtout si tu veux avoir des fonctionnalités un peu évoluées et un code qui tient la route (sans besoin de tout changer si tu veux permettre l'upload multiple par exemple).

Par contre concernant ton code, ce que tu pourrais faire et qui est à la portée d'un débutant, est d'avoir au moins un retour d'information pour dire que le fichier est bien téléchargé. C'est le béaba d'ajax de pouvoir fournir un retour d'information sinon ça perd pratiquement tout son intérêt. Mets-toi à la place de l'utilisateur, il envoie un fichier et puis... rien, toujours rien, jamais rien ne se passe. Peut-il ou non quitter la page ? Il ne le saura jamais. Ne me dis pas que cela correspond à tes besoins, personne ne pourra te croire :shock:
Enfin bon c'est pas la mer à boire, une dizaine de lignes tout au plus en comptant le php, le javascript et une zone d'insertion html. En plus cela fait partie de l'apprentissage normal d'un débutant, cela te servira tous les jours, et à la fin tu pourras dire que tu as une solution minimaliste et fonctionnelle pour télécharger un petit fichier. Pour l'upload multiple ou les gros fichiers et des fonctionnalités plus évoluées les prérequis sont au delà du niveau débutant, c'est pour cela que je te disais d'attendre d'être plus expérimenté ou sinon d'utiliser un code tout fait. Mais le retour ajax, c'est indispensable dès le départ, c'est la base. Allez au boulot :)

Eléphanteau du PHP | 29 Messages

31 janv. 2015, 18:28

Ta réponse est une mine d'informations, merci pour cela. C'est clair que j'ai encore beaucoup de choses à apprendre mais je verrais plus tard ce que je ferais du côté serveur car actuellement j'ai un autre problème. Puis-je te demander d'y jeter un coup d'oeil ? (même si c'est du jQuery :D) javascript-ajax/slider-avec-jquery-mobile-t272968.html
Si tu as la réponse merci d'avance !