Tips en Trucs 2021

Gegevens naar het internet sturen

Met de opdrachten wget en curl kan je gegevens van het internet downloaden. Maar gegevens naar het internet sturen, kan ook.

Gegevens worden hoofdzakelijk via POST formulieren naar een internetadres (server) gestuurd. Voor deze tip heb ik dan ook een testformulier gemaakt.
Curl Test formulier
Formulieren kunnen niet alleen manueel via een browser ingevuld worden, maar ook door curl opdrachten.

Curl is in de meeste Linux standaard geïnstalleerd. Het is bovendien een ideaal hulpmiddel om API's te testen, teruggezonden headers te bekijken en HTTP verzoeken te versturen. Vandaag versturen we gegevens via HTTP POST verzoeken naar een internetadres (server). Het internet (de server) reageert daarop met een antwoord dat we ontvangen en desnoods verder kunnen behandelen, analyseren, enz.

Een POST verzoek verzenden

Een curl opdracht om een POST verzoek naar een internetadres (URL) te versturen ziet er zo uit:

curl -X POST [opies] [URL]

De -X optie bepaalt welke HTTP verzoekmethode (POST) gebruikt wordt.

Het soort (type) gegevens wordt bepaald door de Content-Type header. Meestal wordt een POST verzoek verzonden via een HTML formulier. De verzonden gegevens zijn dan meestal van het type multipart/form-data of application/x-www-form-urlencoded.

Een POST verzoek stel je samen met behulp van de -F optie, gevold door een veld=waarde koppel. Het volgende voorbeeld stuurt een POST verzoek met de velden naam en email:

dany@main:~> curl -X POST -F 'naam=PindaNet' -F 'email=pindanet@voorbeeld.be' https://linux.pindanet.be/faq/tips21/curl/curl.php
<html>
<body>

<form method="post" enctype="multipart/form-data" action="/faq/tips21/curl/curl.php">
  Naam: <input type="text" name="naam"><br>
  E-mail: <input type="text" name="email"><br>
  Bestand: <input type="file" name="bestand"><br>
  <input type="submit" value="Verzenden">
</form>
<pre>
Je naam is PindaNet.
Jouw e-mailadres is pindanet@voorbeeld.be.
Geen JSON gegevens ontvangen.
Er werden geen bestanden ontvangen.
</pre>
</body>
</html>

De curl opdracht verstuurt met de -F optie gegevens van het type multipart/form-data. Je krijgt als antwoord van de server een HTML pagina, juist zoals met een browser.

Met de -d optie verstuurt curl de gegevens als type application/x-www-form-urlencoded:

dany@main:~> curl -X POST -d 'naam=PindaNet' -d 'email=pindanet@voorbeeld.be' https://linux.pindanet.be/faq/tips21/curl/curl.php
<html>
<body>

<form method="post" enctype="multipart/form-data" action="/faq/tips21/curl/curl.php">
  Naam: <input type="text" name="naam"><br>
  E-mail: <input type="text" name="email"><br>
  Bestand: <input type="file" name="bestand"><br>
  <input type="submit" value="Verzenden">
</form>
<pre>
Je naam is PindaNet.
Jouw e-mailadres is pindanet@voorbeeld.be.
Geen JSON gegevens ontvangen.
Er werden geen bestanden ontvangen.
</pre>
</body>
</html>

Bij het versturen van meerdere velden kan je deze in één tekenreeks plaatsen, waarbij de velden door een &-teken gescheiden worden:

dany@main:~> curl -X POST -d 'naam=PindaNet&email=pindanet@voorbeeld.be' https://linux.pindanet.be/faq/tips21/curl/curl.php
<html>
<body>

<form method="post" enctype="multipart/form-data" action="/faq/tips21/curl/curl.php">
  Naam: <input type="text" name="naam"><br>
  E-mail: <input type="text" name="email"><br>
  Bestand: <input type="file" name="bestand"><br>
  <input type="submit" value="Verzenden">
</form>
<pre>
Je naam is PindaNet.
Jouw e-mailadres is pindanet@voorbeeld.be.
Geen JSON gegevens ontvangen.
Er werden geen bestanden ontvangen.
</pre>
</body>
</html>

Het Conttent-Type zelf bepalen

Een op het internet veel gebruikte methode om gegevens uit te wisselen is met JSON. Je kunt de ontvangende server daarvan op de hoogte brengen door een header mee te sturen. Voor JSON gegevens moet je de header application/json doorgeven. Dit kan met de curl -H optie:

dany@main:~> curl -X POST -H "Content-Type: application/json" -d '{"name": "PindaNet", "email": "pindanet@voorbeeld.be"}' https://linux.pindanet.be/faq/tips21/curl/curl.php
<html>
<body>

<form method="post" enctype="multipart/form-data" action="/faq/tips21/curl/curl.php">
  Naam: <input type="text" name="naam"><br>
  E-mail: <input type="text" name="email"><br>
  Bestand: <input type="file" name="bestand"><br>
  <input type="submit" value="Verzenden">
</form>
<pre>
JSON tekenreeks: {"name": "PindaNet", "email": "pindanet@voorbeeld.be"}
Gedecodeerde JSON variabele: 
Array
(
    [name] => PindaNet
    [email] => pindanet@voorbeeld.be
)
</pre>
</body>
</html>

Bestanden uploaden

Om een bestand naar een server te sturen, voeg je een @-teken voor de bestandslocatie. Je kunt daarbij verschillende soorten bestanden (zoals archieven, afbeeldingen, documenten, enz.) verzenden:

dany@main:~> curl -X POST -F 'bestand=@/home/dany/Afbeeldingen/Achtergrond.jpg' https://linux.pindanet.be/faq/tips21/curl/curl.php
<html>
<body>

<form method="post" enctype="multipart/form-data" action="/faq/tips21/curl/curl.php">
  Naam: <input type="text" name="naam"><br>
  E-mail: <input type="text" name="email"><br>
  Bestand: <input type="file" name="bestand"><br>
  <input type="submit" value="Verzenden">
</form>
<pre>
Je gaf geen naam op.
Je gaf geen e-mailadres op.
Geen JSON gegevens ontvangen.
Het doorgezonden bestand heeft de volgende kenmerken:
Array
(
    [bestand] => Array
        (
            [name] => Achtergrond.jpg
            [type] => image/jpeg
            [tmp_name] => /run/tmp/php74U5wC
            [error] => 0
            [size] => 982061
        )

)
</pre>
</body>
</html>

De server

Vanzelfsprekend kan je niet zomaar om het even wat naar servers sturen. Je moet dus op de hoogte zijn van waarop een server kan en wil reageren. Hieronder heb ik dan ook het testformulier voor deze tip geplaatst. Om deze zo eenvoudig mogelijk te maken, zijn er geen ingebouwde filters om misbruik tegen te gaan en worden er geen gegevens en bestanden opgeslagen.

<html>
<body>
<form method="post" enctype="multipart/form-data" action="<?php echo $_SERVER['PHP_SELF'];?>">
  Naam: <input type="text" name="naam"><br>
  E-mail: <input type="text" name="email"><br>
  Bestand: <input type="file" name="bestand"><br>
  <input type="submit" value="Verzenden">
</form>
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
  echo "<pre>\n";
  $headers = getallheaders();
  if ($headers["Content-Type"] != "application/json") {
	  // Verzamel de gegevens van de invulvelden
	  $naam = $_POST['naam'];
	  if (empty($naam)) {
	    echo "Je gaf geen naam op.\n";
	  } else {
	    echo "Je naam is $naam.\n";
	  }
	  $email = $_POST['email'];
	  if (empty($email)) {
	    echo "Je gaf geen e-mailadres op.\n";
	  } else {
	    echo "Jouw e-mailadres is $email.\n";
	  }
    echo "Geen JSON gegevens ontvangen.\n";
    if (empty($_FILES)) {
	   echo "Er werden geen bestanden ontvangen.\n";
	 } else {
	   echo "Het doorgezonden bestand heeft de volgende kenmerken:\n";
	   print_r($_FILES);
	 }
  } else {
    echo "JSON tekenreeks: " . file_get_contents('php://input') . "\n";
    $data = json_decode(file_get_contents('php://input'), true);
    echo "Gedecodeerde JSON variabele: \n";
    print_r($data);
  }
  echo "</pre>\n";
}
?>
</body>
</html>