11521 sujets

JavaScript, DOM et API Web HTML5

Bonjour à tous
Après une (très) longue discussion sur ce forum j'ai fini par comprendre comment faire de l'AJAX en ES6+
Mais je n'avais pas jusqu'alors utilisé cette méthode pour transférer un fichier.
Actuellement j'ai une balise <form> avec un <input type="file"> et mon script en est resté au bon vieux XMLHttpRequest

function uploadEnd(text) {
  ...
}

const formData = new FormData();
const filenode = document.querySelector('[type="file"]');
const fileObject = filenode.files[0];
formData.append('uploadedfile', fileObject);
formData.append(...);
...
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
  if(this.readyState == 4 && this.status == 200) {
  uploadEnd(this.responseText);
		return;
	}
}
xhr.open('post', 'uploadFile.php');
xhr.send(formData);


Je suppose qu'il doit y avoir quelque chose de mieux et de plus concis à faire ?
Modifié par PapyJP (15 Oct 2023 - 19:34)
Modérateur
Bonjour,

Il me semble qu'on n'a pas besoin d'ajax ou fetch pour ça. Un simple formulaire suffit comme par exemple :
<form action="uploadFile.php" method="post" enctype="multipart/form-data">
Sélectionnez un fichier :
<input type="file" name="fileToUpload" id="fileToUpload">
<input type="submit" value="Téléverser" name="submit">
</form>

Et dans le fichier uploadFile.php, un code minimal (à compléter par des vérifications de sécurité qui dépendent de ce qu'on téléverse) peut être :
<?php
$fileName = basename($_FILES["fileToUpload"]["name"]);
$target_dir = "uploads/";
$target_file = $target_dir.$fileName;
if(isset($_POST["submit"]))
{
	if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file))
		echo "Le fichier ".$fileName." a été téléversé.";
	else echo "Erreur !";
}
?>

Amicalement,
Merci de ta réponse
Bien entendu on n'a pas besoin d'AJAX pour téléverser un fichier, mais dans ce cas précis c'est moi qui tiens à le faire, car je ne veux pas relancer l'affichage de la page.
Je continue à utiliser le code "JS vieux style", mais je reste persuadé qu'il doit exister une syntaxe ES6+ pour une fonction asynchrone qui transfère in fichier et reçoit une réponse.
Dans mon cas la réponse n'est pas un texte, mais un objet JSON qui décrit ce que le PHP a fait du fichier,mais peu importe.
Bonsoir,

Pour les collègues, je suis en train de faire un petit programme pour les permanences, dans lequel j'intègre les jours de congés et de télétravail.

J'utilise fetch. Pour l'instant, je suis en GET ; tout est ok.

Mais par la suite, je vais devoir avoir une partie en POST (le salarié click sur un jour de congé ou télétravail, et l'info doit être passée au serveur en POST pour mettre à jour un fichier json).

Je n'ai pas encore fait cette partie POST mais j'y avais un peu réfléchi. Suite au post du forum, je me suis fait une petite ébauche.

J'ai rencontré un pble avec 'response.json' : ca me renvoie toute ma page html ! et je tombe sur un rejet "json non valide" ou quelque chose du genre. Mais pas grave, je contourne en passant par 'response.text()'.

Si ca peut aider, voila mes fichiers :

la partie JS :

// (POST)
const url = 'http://localhost:8080/receptionFetchPost'

let GS = {
    Celine: {
        gest: "Celine",
        conges: [[46, [4,5]], [48, [1,2,3,4,5] ]],
        teletravail: [[46, [1,2]], [49, [1,5]]]
    },
    Alain: {
        gest: "Alain",
        conges: [[45, [2,3,4]], [49, [1,2,3,4,5]]],
        teletravail: [[45, [1,5]]]}
}

gest = 'Celine'

fetch(url, {
        method : 'POST',
        headers: {
            "Accept": "application/json, charset=UTF-8",
            "Content-Type" : "application/json"
        },
        body: JSON.stringify(GS[gest])
})
.then( (response) => {return(response.text())})
.then( (data) => {
    console.log(data); 
})


et le fichier php pour la reception des données :

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>php reception FETCH</title>
</head>
<body>
<?php 
    if(isset($_POST)){
        // recuperation des données
        $dataFromJS = file_get_contents("php://input"); // string
        
        // transforme string en array
        $data = json_decode($dataFromJS, true); // true => return a array
        
        file_put_contents('test.json', json_encode($data));

    } else {echo 'aucun $_POST détecté';}
?>

</body>
</html>


et on obtient le fichier 'test.json' :


{"gest":"Celine","conges":[[46,[4,5]],[48,[1,2,3,4,5]]],"teletravail":[[46,[1,2]],[49,[1,5]]]}
NB :
attention en envoyant le fichier au serveur. si comme moi, il y a une structure MVC, il faudra bien sûr l'enregistrer dans une route.
Modérateur
alain_47 a écrit :
Bonsoir,

....

J'ai rencontré un pble avec 'response.json' : ca me renvoie toute ma page html ! et je tombe sur un rejet "json non valide" ou quelque chose du genre. Mais pas grave, je contourne en passant par 'response.text()'.

Si ca peut aider, voila mes fichiers :
.... et le fichier php pour la reception des données :
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>php reception FETCH</title>
</head>
<body>
<?php 
    if(isset($_POST)){
        // recuperation des données
        $dataFromJS = file_get_contents("php://input"); // string
        
        // transforme string en array
        $data = json_decode($dataFromJS, true); // true => return a array
        
        file_put_contents('test.json', json_encode($data));

    } else {echo 'aucun $_POST détecté';}
?>

</body>
</html>




C'est normal, tu renvoi une page HTML alors que tu attends un fichier json ou du moins veut le lire et éventuellement vérifier que les données envoyées y sont bien présentes.

Je pense que tu devrais renvoyé le contenu du fichier json et tester si response.text contient la ou une partie de la chaine envoyée , ou si ta clé/valeur correspond à la maj attendue.
Donc pas de HTML mais simplement ton json en echo de façon à le traiter comme tel.

Cela vaudrait d'ouvrir ton propre sujet Smiley cligne pour rester lisible et utile.
cdt
Modifié par gcyrillus (29 Oct 2023 - 13:47)
Bonjour,

Je sais mais je suis pris par le temps.

Je voulais juste montrer la possibilité d'utiliser FETCH en POST pour que le serveur reçoive des données JSON à partir de l'envoi du JS par le navigateur.

La manière n'est pas très orthodoxe, j'en conviens Smiley smile

Mais c'était la partie finale de mon travail, donc je ne travaille pas encore dessus.

Mais ça fonctionne, car j'obtiens au niveau de mon serveur, le fichier JSON pour la mise à jour. Je verrai ça plus tard (je me suis demandé si ce n'était pas dans mon 'render', qui doit envoyer une page HTML 'vide' par défaut (c'est comme ça que j'ai construit mon site).

Merci beaucoup.
Bonsoir,

Bon, j'ai repris le code. oui je sais il faudrait ouvrir un nouveau sujet mais j'ai vraiment pas le temps désolé. Juste pour te répondre gcyrillus, j'avais du HTML dans le fichier de recupération PHP car je voulais 'echo'... je l'ai enlevé :


<?php 

    if(isset($_POST)){
        
        // recuperation des données
        $dataFromJS = file_get_contents("php://input"); // string
        
        // transforme string en array
        $data = json_decode($dataFromJS, true); // true => return a array
        
        file_put_contents('test.json', json_encode($data));

    } else {echo 'aucun $_POST détecté';}


j'ai modifié le code JS pour mettre response.json à la place de response.text (je l'avais deja essayé avant) mais j'ai une erreur en console (pourtant les datas sont biens enregistrées dans le fichier test.json normalement) :

Uncaught (in promise) SyntaxError: JSON.parse: unexpected character at line 2 column 5 of the JSON data


je me suis demandé mais qui a demandé de faire 'JSON.parse' pas moi.

j'ai regardé sur stack overflow : c'est le 'response.json' du fichier JS qui fait le parse semble t il


fetch(url, {
        method : 'POST',
        headers: {
            "Accept": "application/json, charset=UTF-8",
            "Content-Type" : "application/json"
        },
        body: JSON.stringify(GS)
})
.then( (response) => {return(response.json())}) // *
.then( (data) => {
    console.log(data);
})


j'ai suivi le lien de l'erreur de la console : MDN
"
SyntaxError
Quel est le problème ?
Lorsque la méthode JSON.parse() analyse (parse) une chaîne de caractères en JSON, cette chaîne doit être du JSON valide et une exception sera levée si la syntaxe est incorrecte.
Exemples
JSON.parse() n'accepte pas les virgules en fin de tableau
....
"

donc ca viendrait de l'objet que je veux envoyer.

je l'ai remplacer par GS = { test: "test"} puis par GS={"test": "test"} en vain : tjrs la meme erreur en console.
Pourtant les datas sont bien enregistrées comme il faut dans le fichier 'test.json' à chaque fois :

{"test":"test"}


En résumé, tout fonctionne comme je le souhaite ... sauf qu'il y a une erreur en console !

C'est pour cette raison que j'avais initialement utilisé dans mon fetch 'response.text' au lieu 'response.json' car dans le premer cas, je n'ai pas d'erreur en console.

Donc ca fonctionne (euh en local tout au moins , faudra voir en reel) . je verrai le pble dans quelques semaines quand je serai à ce niveau du programme.

Merci pour tes conseils.
Modérateur
Bonjour,

PapyJP a écrit :
Merci de ta réponse
Bien entendu on n'a pas besoin d'AJAX pour téléverser un fichier, mais dans ce cas précis c'est moi qui tiens à le faire, car je ne veux pas relancer l'affichage de la page.

Soit. Voici donc un exemple minimal. J'ai supposé que le fichier uploadFile.php était dans le même répertoire que la page contenant le formulaire, et j'ai supposé qu'il existe un sous-dossier appelé "uploads" du dossier dans lequel se trouve la page contenant le formulaire. J'ai enfin supposé que la "response" est du text. Si c'est du json, il conviendra de faire quelques adaptations en conséquence (en particulier, remplacer response.text() par response.json()). Enfin, il faudrait sans doute ajouter quelques sécurités dans le code de uploadFile.php pour éviter qu'il y ait n'importe quoi de téléversé sur le serveur, mais c'est pareil quand on utilise AJAX de toute façon.

Pour vérifier que tout s'est bien passé, il faut regarder dans la console. Mais on peut bien sûr adapter le code js pour faire afficher un message pour l'utilisateur. Mais là aussi, c'est pareil quand on utilise AJAX de toute façon.

Le html :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Téléversement d'un fichier avec fetch</title>
</head>
<body>
<form><label>Sélectionnez un fichier : <input type="file"></label></form>
<script>
const fileNode = document.querySelector('[type="file"]');
fileNode.addEventListener('change', () => {
	const formData = new FormData();
	formData.append("fileToUpload", fileNode.files[0]);
	fetch('uploadFile.php',{
			method: 'POST',
			body: formData})
	.then(response => response.text())
	.then(data => console.log(data))
	.catch(error => console.error(error));
});
</script>
</body>
</html>

Le script uploadFile.php :
<?php
if(isset($_FILES["fileToUpload"]))
{
	$fileName = basename($_FILES["fileToUpload"]["name"]);
	$target_dir = "uploads/";
	$target_file = $target_dir.$fileName;
	if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file))
		echo "Le fichier ".$fileName." a été téléversé avec succès\n";
	else echo "Erreur, déplacement du fichier impossible\n";
}
else echo "Erreur, pas de 'fileToUpload' dans les données du formulaire\n";
?>

Amicalement,
Merci beaucoup
Je n’avais pas trouvé la syntaxe pour faire un fetch approprié à ce cas de figure.