Module GSM - Requête POST quasi-fonctionnelle

Bonjour,

Me voila face à une nouvelle difficulté.
J’essaye de transmettre des données sur un serveur web (j’ai pris un domaine chez OVH) via mon module GSM. Pour cela je fais une requête POST.

J’utilise donc les commandes suivantes :

AT+CPIN=xxxx

+CPIN: READY
AT+CREG=1
+CREG: 1
AT+SAPBR=3,1,“APN”,“sl2sfr”
OK
AT+SAPBR=1,1
OK
AT+HTTPINIT
OK
AT+HTTPPARA=“CID”,1
OK
AT+HTTPPARA=“URL”,“http://mon-truc.php
OK
AT+HTTPPARA=“CONTENT”,“application/json” <== ici Je ne sais pas quoi mettre en 2e paramètre
OK
AT+HTTPDATA=192,10000
DOWNLOAD
{“commande”:“testarduino”, “details”:“desdetails”}\n
{“commande”:“testarduino”, “details”:“desdetails”}
AT+HTTPACTION=1
OK
+HTTPACTION: 1,200,723
//(ma page fait 723 caractères).
AT+HTTPREAD
+HTTPREAD: 723

Id Commande Details</T- Mumble 2017-06-04 16:26:38
2< etc...

AT+HTTPTERM

OK

Bizarre que HTTPACTION=1 me retourne un statut 200 puis le nombre de caractères de ma page, c’est pas sensé être le nombre de caractères de ma donnée ?

côté serveur j’utilise du PHP pour la “réception” de la requête :

<?php
	error_reporting(E_ALL);
	ini_set('display_errors','1');
	require_once 'db.php';

	$db = new Database();
//	$db->createTable();


	if(isset($_POST['commande']) && !empty($_POST['commande']) && isset($_POST['details']) && !empty($_POST['details'])) {
		$db->insertData($_POST['commande'],$_POST['details']);
	}

	
	$db->printTableContent();
?>

Je regarde si j’ai un champ commande et un champ details, puis j’affiche la table sur ma page http://mon-truc//traitementPostDb..php (je précise qu’elle s’affiche bien…)

J’ai des logs au niveau du serveur qui me permettent de voir les requêtes entrantes et je vois la requête de mon module GSM avec le statut 200 (un super statut normalement…) mais ça ne change rien à la table de ma base de données.

Je pense que mon problème c’est ma façon d’écrire les données dans mes commandes :
{“commande”:“testarduino”, “details”:“desdetails”}\n

C’est au format json ça non ?
Du coup j’ai mis “application/json” en 2e paramètre de AT+HTTPPARA=“CONTENT”,“application/json”.
C’est calqué sur un exemple d’internet.
C’est une mauvaise façon de faire ?

Je peux aussi montrer ça mais franchement c’est sensé bien fonctionner :

	class Database {
		private $servername	= "xxxxxxx.mysql.db";
		private $username	= "xxxxxxx";
		private $password	= "xxxxxxx";
		private $database	= "xxxxxxx";

		public $mysql;

		public function __construct() {
			// Create connection
			$this->mysql = new mysqli($this->servername, $this->username, $this->password, $this->database);

			// Check connection
			if ($this->mysql->connect_error) {
			    die("Database connection failed: " . $this->mysql->connect_error);
			}
			$this->mysql->set_charset("utf8");
		}

		public function insertData($cmd, $details) {
			$sql = "INSERT INTO rawData (`commande`,`details`) VALUES (?,?)";
			if (!$stmt = $this->mysql->prepare($sql)) {
				die($this->mysql->error);
			}
			$stmt->bind_param('ss',$cmd,$details);
			$stmt->execute();
		}

		public function createTable() {
			$sql = "CREATE TABLE IF NOT EXISTS rawData (
				id INTEGER(50) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
				commande VARCHAR(50),
				details VARCHAR(500),
				timestamp TIMESTAMP DEFAULT current_timestamp())";
			if (!$stmt = $this->mysql->prepare($sql)) {
				die($this->mysql->error);
			}
			$stmt->execute();
			echo 'DB-KUTGW!\n';
		}

		public function dropTable() {
			$sql = "DROP TABLE rawData";
			if (!$stmt = $this->mysql->prepare($sql)) {
				die($this->mysql->error);
			}
			$stmt->execute();
			echo 'DB-DROPPED!\n';
		}

		public function printTableContent() {
			$sql = "SELECT * FROM rawData ORDER BY `timestamp` DESC";
			if (!$stmt = $this->mysql->prepare($sql)) {
				die($this->mysql->error);
			}
			$stmt->execute();
			$stmt->bind_result($id,$commande,$details,$timestamp);
			echo '<TABLE border="1"><THEAD><TR><TD>Id</TD><TD>Commande</TD><TD>Details</TD><TD>Timestamp</TD></TR></THEAD><TBODY>';
			while ($stmt->fetch()) {
				echo "<TR><TD>".$id."</TD><TD>".$commande."</TD><TD>".$details."</TD><TD>".$timestamp."</TD></TR>";
			}
			echo '</TBODY></TABLE>';
		}
	}

Si vous avez une idée de ce qui cloche je serais heureux de l’entendre :grinning:
J’ai l’impression qu’il y a à peine 3 personnes sur internet qui se sont penchés sur les requêtes POST avec ce module…

bonjour,

Bizarre que HTTPACTION=1 me retourne un statut 200 puis le nombre de caractères de ma page, c'est pas sensé être le nombre de caractères de ma donnée ?

0= GET
1 = POST
200 = Requête traitée avec succès
723 = payload

Bonjour,

Euh, c’est un peu expédié votre histoire :smiley:

Je suis au courant qu’on met 0 pour GET et 1 pour POST c’est précisément une requête POST que je suis entrain d’essayer de faire (titre du topic).

Je ne suis pas bloqué par mon statut 200 et j’ai lu la documentation des commandes AT…

Je vais citer cette dernière : "+HTTPACTION: ,, ".

Si par payload vous entendez (la taille de) la donnée transmise je pense qu’il y a erreur. 723 est sensé être la . Mais ce n’est apparemment pas la taille de la donnée, mais plutôt la taille du fichier .php ciblé par l’URL ce qui en soit, ne me sert à rien.

Mon soucis est ailleurs, ma table ne se met pas à jour. :’(

Merci pour votre aide.

puis le nombre de caractères de ma page, c’est pas sensé être le nombre de caractères de ma donnée ?

723 est ce que retourne la requête
maintenant, que ca te serve ou pas, c’est a toi de le juger

A part dire que c’est vite expédié la réponse…
Regardes dans les logs apache.

Je peux aussi montrer ça mais franchement c’est sensé bien fonctionner :

c’est bien, mais as tu testé le code dans un navigateur?

Mets le code entier entre balise code aussi </> à coté du B

Bonjour,

J’ignorais que payload signifiait “ce que retourne la requête”. Et “expédié” c’est l’impression que ça me donne lorsque vous ne fournissez pas d’explications. Je ne suis pas irréprochable et je disais ça sur le ton de la rigolade, vous en revanche, vous n’avez pas l’air de rigoler beaucoup :stuck_out_tongue:

Oui, j’ai testé le code dans un navigateur,
Voici l’affichage de ma table réalisé par afficherDb.php (des données test).

I | dCommande | Details | Timestamp
2 | TEST_CMD | This is an exemple of speech… - Mumble | 2017-06-04 16:26:37
1 | TEST_CMD | This is an exemple of speech… - Mumble | 2017-06-04 16:26:33

Le code associé de afficherDb.php:

<?php
 error_reporting(E_ALL);
 ini_set('display_errors','1');
 require_once 'db.php';

 $db = new Database();

 $db->printTableContent();

?>

Voici le formulaire de test que j’ai utilisé pour remplir ma table:

<HTML>
 <HEAD>
 <TITLE>Test de formulaire Post</TITLE>
 </HEAD>
 <BODY>
 <FORM action="./traitementPostDb.php" method="POST">
 <INPUT type="text" name="commande" placeholder="Nom de la commande" />

 <TEXTAREA name="details" placeholder="Bla Bla Bla"></TEXTAREA>

 <INPUT type="submit" value="Valider" />
 </FORM>
 </BODY>
</HTML>

Et voici les fonctions BDD dans mon fichier db.php :

<?php

 class Database {
 private $servername = "xxxxxxx.mysql.db";
 private $username = "xxxxxxx";
 private $password = "xxxxxxx";
 private $database = "xxxxxxx";

 public $mysql;

 public function __construct() {
 // Create connection
 $this->mysql = new mysqli($this->servername, $this->username, $this->password, $this->database);

 // Check connection
 if ($this->mysql->connect_error) {
    die("Database connection failed: " . $this->mysql->connect_error);
 }
 $this->mysql->set_charset("utf8");
 }

 public function insertData($cmd, $details) {
 $sql = "INSERT INTO rawData (`commande`,`details`) VALUES (?,?)";
 if (!$stmt = $this->mysql->prepare($sql)) {
 die($this->mysql->error);
 }
 $stmt->bind_param('ss',$cmd,$details);
 $stmt->execute();
 }

 public function deleteData($id) {
 $sql = "DELETE FROM rawData WHERE id=?";
 if (!$stmt = $this->mysql->prepare($sql)) {
 die($this->mysql->error);
 }
 $stmt->bind_param('i',$id);
 $stmt->execute();
 }

 public function createTable() {
 $sql = "CREATE TABLE IF NOT EXISTS rawData (
 id INTEGER(50) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
 commande VARCHAR(50),
 details VARCHAR(500),
 timestamp TIMESTAMP DEFAULT current_timestamp())";
 if (!$stmt = $this->mysql->prepare($sql)) {
 die($this->mysql->error);
 }
 $stmt->execute();
 echo 'DB-KUTGW!\n';
 }

 public function dropTable() {
 $sql = "DROP TABLE rawData";
 if (!$stmt = $this->mysql->prepare($sql)) {
 die($this->mysql->error);
 }
 $stmt->execute();
 echo 'DB-DROPPED!\n';
 }

 public function printTableContent() {
 $sql = "SELECT * FROM rawData ORDER BY `timestamp` DESC";
 if (!$stmt = $this->mysql->prepare($sql)) {
 die($this->mysql->error);
 }
 $stmt->execute();
 $stmt->bind_result($id,$commande,$details,$timestamp);
 echo '<TABLE border="1"><THEAD><TR><TD>Id</TD><TD>Commande</TD><TD>Details</TD><TD>Timestamp</TD></TR></THEAD><TBODY>';
 while ($stmt->fetch()) {
 echo "<TR><TD>".$id."</TD><TD>".$commande."</TD><TD>".$details."</TD><TD>".$timestamp."</TD></TR>";
 }
 echo '</TBODY></TABLE>';
 }
 }
?>

D’autres fichiers que j’utilise :

Pour traiter ma requête POST, traitementPostDb.php :

<?php
 error_reporting(E_ALL);
 ini_set('display_errors','1');
 require_once 'db.php';

 $db = new Database();
// $db->createTable();


 if(isset($_POST['commande']) && !empty($_POST['commande']) && isset($_POST['details']) && !empty($_POST['details'])) {
 $db->insertData($_POST['commande'],$_POST['details']);
 }

 
 $db->printTableContent();
?>

Pour supprimer un élément deleteInDb.php :

<?php
 error_reporting(E_ALL);
 ini_set('display_errors','1');
 require_once 'db.php';

 $db = new Database();
// $db->createTable();

 $db->deleteData(5);


 $db->printTableContent();
?>

La suite au post d’après…

…Suite

Voici mon la partie utile de mon code Arduino, pour effectuer une requête POST :

const int INIT_GSM = 2;
static int state = INIT_GSM;

//expected answers
const char * NETWORK_REGISTRATION_STR = "AT+CREG=1\r\r\nOK\r\n";
const char * TEXT_MODE_STR = "AT+CMGF=1\r\r\nOK\r\n";
const char * INIT_HTTP_STR = "AT+HTTPINIT\r\r\nOK\r\n";
const char * HTTP_SESSION_STR ="AT+HTTPPARA=\"CID\",1\r\r\nOK\r\n";
// When didn't added other expected answers yet
const char * TEST ="\n";

// --------------------------------------
// waitForString wait max for duration ms
// while checking if endMarker string is received
// on the GSM Serial port
// returns a boolean stating if the marker
// was found
// --------------------------------------

boolean waitForString(const char * endMarker, unsigned long duration)
{
  //It varies when we check componants answer by comparing the received string to an expected answer.
  boolean endMarkerFound = false;
  int localBufferSize = strlen(endMarker); // we won't need an \0 at the end
  char localBuffer[localBufferSize];
  int index = 0;
  unsigned long currentTime;

  memset(localBuffer, '\0', localBufferSize); // clear buffer

  currentTime = millis();
  while (millis() - currentTime <= duration) {
    if (Serial1.available() > 0) {
      if (index == localBufferSize) index = 0;
      localBuffer[index] = (uint8_t) Serial1.read();
      Serial.print(localBuffer[index]);
      endMarkerFound = true;
      for (int i = 0; i < localBufferSize; i++) {
        if (localBuffer[(index + 1 + i) % localBufferSize] != endMarker[i]) {
          endMarkerFound = false;
          break;
        }
      }
      index++;
    }
    if (endMarkerFound) break;
  }
  return endMarkerFound;
}


// --------------------------------------
// espATCommand executes an AT commmand
// checks if endMarker string is received
// on the GSM Serial port for max duration ms
// returns a boolean stating if the marker
// was found
// --------------------------------------

boolean gsmATCommand(const char * command, const char * endMarker, unsigned long duration)
{
  Serial1.println(command);
  return waitForString(endMarker, duration);
}


void setup() {
  Serial.begin(115200); while (!Serial);

  //__________________________________________GSM setup
  Serial1.begin(9600); while (!Serial1);
  pinMode(SIM800_RESET_PIN, OUTPUT);
  pinMode(PWKEY, OUTPUT);
  digitalWrite(PWKEY, HIGH);
  delay(1000);
  digitalWrite(SIM800_RESET_PIN, LOW);
  delay(100);
  digitalWrite(SIM800_RESET_PIN, HIGH);
  delay(2000);

}

void loop() {

//Let it chill a bit 
  delay(500);
  //______________________________switch (state)
  switch (state) {
    //_____________________________case INIT_GSM
    case INIT_GSM :
delay(1000);
      // Enter pin code
      Serial.println("Sending AT+CPIN=2407");
      if(gsmATCommand("AT+CPIN=2407",TEST, 1000)){
      }else {
        ERROR_TRACKER = BAD_GSM_ANSWER;
        state = RETRY_ON_ERROR;
        break;
      }

      //Waiting 10 sec to be sure that internal initialization process is over (I add trouble with a lower value).
      delay(3000);
      // Network registration
      Serial.println("Sending AT+CREG=1...");
      if(gsmATCommand("AT+CREG=1", NETWORK_REGISTRATION_STR, 1000)){
      }else{
        ERROR_TRACKER = BAD_GSM_ANSWER;
        state = RETRY_ON_ERROR;
        break;
      }
      
      delay(3000);
      // Network registration
      Serial.println("Sending AT+CREG=1...");
      if(gsmATCommand("AT+CREG=1", NETWORK_REGISTRATION_STR, 1000)){
      }else{
        ERROR_TRACKER = BAD_GSM_ANSWER;
        state = RETRY_ON_ERROR;
        break;
      }
      delay(3000);
      // apn SET
      Serial.println("AT+SAPBR=3,1,\"APN\",\"sl2sfr\"...");
      if(gsmATCommand("AT+SAPBR=3,1,\"APN\",\"sl2sfr\"", TEST, 1000)){
      }else{
        ERROR_TRACKER = BAD_GSM_ANSWER;
        state = RETRY_ON_ERROR;
        break;
      }

      delay(10000);
      Serial.println("AT+SAPBR=1,1...");
      if(gsmATCommand("AT+SAPBR=1,1", TEST, 1000)){
      }else{
        ERROR_TRACKER = BAD_GSM_ANSWER;
        state = RETRY_ON_ERROR;
        break;
      }    

      delay(3000);
      // enabling the HTTP mode
      Serial.println("Sending AT+HTTPINIT...");      
      if(gsmATCommand("AT+HTTPINIT",INIT_HTTP_STR, 1000)){
      }else{
        ERROR_TRACKER = BAD_GSM_ANSWER;
        state = RETRY_ON_ERROR;
        break;        
      }
      delay(3000);
      // Start by setting up the HTTP bearer profile identifier
      Serial.println("Sending AT+HTTPPARA=\"CID\",1...");
      if(gsmATCommand("AT+HTTPPARA=\"CID\",1",HTTP_SESSION_STR, 1000)){
      }else{
        ERROR_TRACKER = BAD_GSM_ANSWER;
        state = RETRY_ON_ERROR;
        break;        
      }
      delay(3000);
      // Set the url  to the address of the webpage you want to post to
      Serial.println("Sending AT+HTTPPARA=\"URL\",\"http://http://demo.operator-bean.ovh/traitementPostDb.php\"");
      if(gsmATCommand("AT+HTTPPARA=\"URL\",\"http://demo.operator-bean.ovh/traitementPostDb.php\"",TEST, 1000)){
      }else {
        ERROR_TRACKER = BAD_GSM_ANSWER;
        state = RETRY_ON_ERROR;
        break;
      }
      
      delay(3000);
      // Set the Content as application/json type of HTTP POST and also set the boundary value
      Serial.println("AT+HTTPPARA=\"CONTENT\",\"application/json\"");
      if(gsmATCommand("AT+HTTPPARA=\"CONTENT\",\"application/json\"",TEST, 1000)){
      }else {
        ERROR_TRACKER = BAD_GSM_ANSWER;
        state = RETRY_ON_ERROR;
        break;
      }
      
      delay(3000);
      // After this command you get the DOWNLOAD URC
      Serial.println("Sending AT+HTTPDATA=192,10000");
      if(gsmATCommand("AT+HTTPDATA=192,10000",TEST, 1000)){
      }else {
        ERROR_TRACKER = BAD_GSM_ANSWER;
        state = RETRY_ON_ERROR;
        break;
      }

      delay(3000);
      Serial.println("Sending data..");
      //Printing stuff
      if(gsmATCommand("{\"commande\":22, \"details\":33}OK\r\n",TEST, 1000)){
      }else {
        ERROR_TRACKER = BAD_GSM_ANSWER;
        state = RETRY_ON_ERROR;
        break;
      }

      delay(3000);
      // Execute the HTTP POST command so that the buffer contents are POST to the server
      Serial.println("Sending AT+HTTPACTION=1");
      if(gsmATCommand("AT+HTTPACTION=1",TEST, 1000)){
      }else {
        ERROR_TRACKER = BAD_GSM_ANSWER;
        state = RETRY_ON_ERROR;
        break;
      }


      delay(3000);
      // The below command tells the module that we want to read the received data
      Serial.println("Sending AT+HTTPREAD");
      if(gsmATCommand("AT+HTTPREAD",TEST, 1000)){
      }else {
        ERROR_TRACKER = BAD_GSM_ANSWER;
        state = RETRY_ON_ERROR;
        break;
      }

      delay(3000);
      // Terminate the request
      Serial.println("Sending AT+HTTPTERM");
      if(gsmATCommand("AT+HTTPTERM",TEST, 1000)){
      }else {
        ERROR_TRACKER = BAD_GSM_ANSWER;
        state = RETRY_ON_ERROR;
        break;
      }

Au niveau des logs web d’OVH j’ai ceci :

77.136.41.5 xxxxxxxxxx.ovh - [06/Jun/2017:10:55:01 +0200] “POST /traitementPostDb.php HTTP/1.1” 200 433 “-” “SIMCOM_MODULE”
77.136.41.5 xxxxxxxxxx.ovh - [06/Jun/2017:10:55:47 +0200] “POST /traitementPostDb.php HTTP/1.1” 200 433 “-” “SIMCOM_MODULE”
92.90.21.43 xxxxxxxxxx.ovh - [06/Jun/2017:10:57:10 +0200] “POST /traitementPostDb.php HTTP/1.1” 200 433 “-” “SIMCOM_MODULE”
92.90.21.43 xxxxxxxxxx.ovh - [06/Jun/2017:10:57:56 +0200] “POST /traitementPostDb.php HTTP/1.1” 200 433 “-” “SIMCOM_MODULE”

Cela peut aider ?

J’ai encore bien creusé, mais ça bloque encore.

Si ma requête parvient au serveur avec le statut 200 j’en déduit qu’elle est convenablement effectuée. Le problème serait donc plutôt le format que je donne à mes données dans les commandes AT ?

Si j’arrive à remplir ma base de donnée avec un formulaire POST en HTML je suppose que j’ai juste à comprendre le format d’une requête POST pour le reproduire au niveau de mon module GSM ?

Si je reproduit le format :

POST /fichier.ext HTTP/1.1
Host: www.site.com
Connection: Close
Content-type: application/x-www-form-urlencoded
Content-Length: 33

variable=valeur&variable2=valeur2

ça marchera peut-être, mais comment faire cela ?

Dans un formulaire HTML simple, comment sont traités les données avant d’être mises dans un paquet POST ? Je veux dire, AVANT d’être acheminées vers un serveur… Elle sont bien formatées non ?

vu que tu as repris la source d'openclassroom, tu as du lire cette ligne

Ce dernier est un chouïa plus complexe. Il a le même effet que GET sauf que, lui, envoie des données via le corps de la requête.

if(gsmATCommand("AT+HTTPPARA=\"CONTENT\",\"application/x-www-form-urlencoded\"",TEST, 1000)){
..
..
..
//pas testé mais ca doit ressembler a quelque chose comme ca
if(gsmATCommand("{\"commande=\"22, \"&details=\"33}OK\r\n",TEST, 1000)){

Merci pour ces indications,

Je n'ai toujours pas de donnée dans ma table, cela signifie que quelque part ma requête POST diffère de celle que j'ai effectué avec mon formulaire HTML de test.

Sur quels points peut-elle encore différer ?

Par ailleurs je me demandais pourquoi vous aviez mis une virgule ici :

"{"commande="22, "&details="33}OK\r\n"

C'est plutôt data1=valeur1&data2=valeur2 non ?
Dans tout les cas j'ai essayé, ça n'a pas fonctionné (mais j'ai toujours le statut 200).

J'ai aussi essayé sans virgule comme ceci :

"{"commande="22"&details="33}OK\r\n"

Mais rien dans ma table (toujours le statut 200).

J'ai aussi essayé en mettant uniquement les mots "commande" et "details" entre guillemets, j'ignore si c'est judicieux :

"{"commande"=22&"details"=33}OK\r\n"

Mais ça n'a pas fonctionné non plus (statut 200, rien dans la base)
Mon soucis c'est que je sais pas comment savoir quel format il faut effectivement adopter.

Par ailleurs, que signifie "-" dans mes logs ?

"POST /traitementPostDb.php HTTP/1.1" 200 433 "-" "SIMCOM_MODULE"

Pour comparer voici le message de log lorsque j'utilise mon formulaire HTML de test:

"POST /traitementPostDb.php HTTP/1.1" 200 258 "http://monsite.ovh/testFormulaire.html" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"

C'est l'adresse de la source c'est bien ça ?
On ne peut rien déduire du fait que la source ne s'affiche pas ("-") lorsque j'essaye avec mon module GSM ?

Par ailleurs je me demandais pourquoi vous aviez mis une virgule ici :

"{"commande="22, "&details="33}OK\r\n"

C'est plutôt data1=valeur1&data2=valeur2 non ?
Dans tout les cas j'ai essayé, ça n'a pas fonctionné (mais j'ai toujours le statut 200).

simplement que c'est toi qui l'avais mis au début :wink:
200 = requête effectuée sur le server, donc non rejetée

teste en GET pour voir si ca vient de la requête ou du server qui pourrait bloquer les entrées par un proxi

Vous voulez dire une requête GET vers mon site ?

car j'ai déjà essayé une requête GET vers ce site : http://arduinodev.com/datetime.php
Et j'ai reçu la donnée sur mon module GSM sans problèmes.

Niconnexion:
Vous voulez dire une requête GET vers mon site ?

car j'ai déjà essayé une requête GET vers ce site : http://arduinodev.com/datetime.php
Et j'ai reçu la donnée sur mon module GSM sans problèmes.

pourquoi tu parle d'un autre site?

le tiens est bien trucmuchemachinchose/traitementPostDb.php
je te demande de faire le test sur TON server, pas sur un autre, à moins que arduinodev.com soit à toi et sur celui que tu veuilles transférer des datas.

J'ai beau essayer de faire des efforts, à vous lire, j'ai l'impression de vous énerver avec mes questions. Inutile de mettre les choses en gras quand elles sont déjà en majuscule. Je sais lire, et je sais à peu près réfléchir.

Pourquoi autant d'amertume.

Je fais le test et je reviens vers vous.

Ce n'est pas une question d'amertume ou d'énervement.
Je pose des questions et tu réponds à coté, donc il faut insister en mettant en majuscule et gras pour avoir des réponses.

Je n'ai toujours pas de donnée dans ma table, cela signifie que quelque part ma requête POST diffère de celle que j'ai effectué avec mon formulaire HTML de test.

Ou que le server rejète la requête malgré un 200, car peut être trop de requêtes en peu de temps.

Il serait bon de donner les caractéristiques du server.
htaccess?
mod evasive?

c'est toi qui a monté le système du server?