Maîtriser la programmation Web C++ avec CGI
Qu'est-ce que le CGI ?
L'Interface de passerelle commune (CGI) est un ensemble de normes définissant l'échange d'informations entre le serveur web et un script personnalisé. Les spécifications CGI sont maintenues par le NCSA.
Le CGI permet à des programmes externes (scripts CGI) d'interagir avec les serveurs d'information comme les serveurs HTTP. Ces programmes peuvent être écrits en Python, Perl, Shell, C, C++, etc. La version actuelle est CGI/1.1.
Navigation web et CGI
Lorsqu'on clique sur un lien :
- Le navigateur contacte le serveur HTTP et demande l'URL (nom de fichier).
- Le serveur analyse l'URL, cherche le fichier. S'il le trouve, il l'envoie ; sinon, il renvoie une erreur.
- Le navigateur affiche le fichier reçu ou le message d'erreur.
On peut configurer le serveur pour qu'au lieu d'envoyer un fichier, il l'exécute comme un programme et renvoie sa sortie au navigateur. C'est le principe du CGI.
Architecture CGI

Configuration du serveur web
Avant de programmer en CGI, vérifiez que votre serveur le supporte et est configuré pour exécuter les programmes CGI. Par convention, les programmes CGI résident dans /var/www/cgi-bin et portent l'extension .cgi (même s'il s'agit d'exécutables C++).
Pour Apache, la configuration typique dans httpd.conf :
<Directory "/var/www/cgi-bin">
AllowOverride None
Options ExecCGI
Order allow,deny
Allow from all
</Directory>
<Directory "/var/www/cgi-bin">
Options All
</Directory>
Premier programme CGI en C++
#include <iostream>
using namespace std;
int main() {
cout << "Content-type:text/html\r\n\r\n";
cout << "<html>\n";
cout << "<head>\n";
cout << "<title>Hello World - Premier programme CGI</title>\n";
cout << "</head>\n";
cout << "<body>\n";
cout << "<h2>Hello World! Ceci est mon premier programme CGI</h2>\n";
cout << "</body>\n";
cout << "</html>\n";
return 0;
}
Compilez et nommez l'exécutable cplusplus.cgi. Placez-le dans /var/www/cgi-bin et rendez-le exécutable :
chmod 755 cplusplus.cgi
Point crucial : l'en-tête HTTP
La première ligne Content-type:text/html\r\n\r\n est obligatoire. Elle indique au navigateur le type de contenu (MIME). Sans elle, le navigateur ne saura pas comment afficher la sortie.
En-têtes HTTP courants
| En-tête | Description |
|---|---|
Content-type | Type MIME du contenu (ex: text/html). |
Expires | Date d'expiration du contenu (format: 01 Jan 1998 12:00:00 GMT). |
Location | URL de redirection. |
Last-modified | Date de dernière modification de la ressource. |
Content-length | Taille en octets des données renvoyées. |
Set-Cookie | Définit un cookie. |
Variables d'environnement CGI
Les programmes CGI accèdent à de nombreuses variables d'environnement :
| Variable | Description |
|---|---|
CONTENT_TYPE | Type de données envoyées par le client (ex: upload de fichier). |
CONTENT_LENGTH | Longueur des données (requêtes POST). |
HTTP_COOKIE | Cookies envoyés par le client. |
HTTP_USER_AGENT | Navigateur/client utilisé. |
PATH_INFO | Chemin du script CGI. |
QUERY_STRING | Données encodées en URL (méthode GET). |
REMOTE_ADDR | Adresse IP du client. |
REMOTE_HOST | Nom d'hôte du client. |
REQUEST_METHOD | Méthode HTTP (GET, POST, etc.). |
SCRIPT_FILENAME | Chemin complet du script CGI. |
SCRIPT_NAME | Nom du script CGI. |
SERVER_NAME | Nom d'hôte ou IP du serveur. |
SERVER_SOFTWARE | Logiciel serveur et version. |
Exemple : lister toutes les variables d'environnement
#include <iostream>
#include <stdlib.h>
#include <string>
#include <vector>
using namespace std;
const string ENV[24] = {
"COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE",
"HTTP_ACCEPT", "HTTP_ACCEPT_ENCODING", "HTTP_ACCEPT_LANGUAGE",
"HTTP_CONNECTION", "HTTP_HOST", "HTTP_USER_AGENT",
"PATH", "QUERY_STRING", "REMOTE_ADDR", "REMOTE_PORT",
"REQUEST_METHOD", "REQUEST_URI", "SCRIPT_FILENAME",
"SCRIPT_NAME", "SERVER_ADDR", "SERVER_ADMIN",
"SERVER_NAME", "SERVER_PORT", "SERVER_PROTOCOL",
"SERVER_SIGNATURE", "SERVER_SOFTWARE"
};
int main() {
cout << "Content-type:text/html\r\n\r\n";
cout << "<html><head><title>Variables d'environnement CGI</title></head><body>";
cout << "<table border=\"0\" cellspacing=\"2\">";
for (int i = 0; i < 24; i++) {
cout << "<tr><td>" << ENV[i] << "</td><td>";
char *value = getenv(ENV[i].c_str());
if (value) cout << value;
else cout << "Variable d'environnement inexistante.";
cout << "</td></tr>\n";
}
cout << "</table></body></html>";
return 0;
}
Bibliothèque CGI pour C++ (cgicc)
Pour des applications réelles, utilisez la bibliothèque cgicc (GNU) :
$ tar xzf cgicc-X.X.X.tar.gz
$ cd cgicc-X.X.X/
$ ./configure --prefix=/usr
$ make
$ make install
Documentation : C++ CGI Lib Documentation.
Méthodes GET et POST
Deux méthodes principales pour transmettre des données du navigateur au serveur :
Méthode GET
Les données sont ajoutées à l'URL après ? :
https://www.test.com/cgi-bin/cpp.cgi?key1=value1&key2=value2
- Méthode par défaut.
- Visible dans la barre d'adresse.
- Limite de ~1024 caractères.
- Ne pas utiliser pour les mots de passe ou données sensibles.
- Accessible via la variable d'environnement
QUERY_STRING.
Exemple GET avec cgicc
URL : /cgi-bin/cpp_get.cgi?first_name=ZARA&last_name=ALI
#include <iostream>
#include <vector>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <cgicc/CgiDefs.h>
#include <cgicc/Cgicc.h>
#include <cgicc/HTTPHTMLHeader.h>
#include <cgicc/HTMLClasses.h>
using namespace std;
using namespace cgicc;
int main() {
Cgicc formData;
cout << HTTPHTMLHeader() << endl;
cout << "<html><head><title>Méthodes GET et POST</title></head><body>";
form_iterator fi = formData.getElement("first_name");
if (!fi->isEmpty() && fi != (*formData).end()) {
cout << "Prénom : " << **fi << "<br/>";
} else {
cout << "Aucun prénom saisi<br/>";
}
fi = formData.getElement("last_name");
if (!fi->isEmpty() && fi != (*formData).end()) {
cout << "Nom : " << **fi << "<br/>";
} else {
cout << "Aucun nom saisi<br/>";
}
cout << "</body></html>";
return 0;
}
Compilation : g++ -o cpp_get.cgi cpp_get.cpp -lcgicc
Exemple formulaire HTML GET
<form action="/cgi-bin/cpp_get.cgi" method="get">
Prénom: <input type="text" name="first_name"><br/>
Nom: <input type="text" name="last_name" />
<input type="submit" value="Soumettre" />
</form>
Méthode POST
Plus fiable : les données sont envoyées dans le corps de la requête (entrée standard), pas dans l'URL. Pas de limite de taille pratique. Le même script CGI gère GET et POST avec cgicc.
Exemple formulaire HTML POST
<form action="/cgi-bin/cpp_get.cgi" method="post">
Prénom: <input type="text" name="first_name"><br/>
Nom: <input type="text" name="last_name" />
<input type="submit" value="Soumettre" />
</form>
Cas particuliers de formulaires
Cases à cocher (checkboxes)
Permettent de sélectionner plusieurs options.
<form action="/cgi-bin/cpp_checkbox.cgi" method="POST">
<input type="checkbox" name="maths" value="on" /> Maths
<input type="checkbox" name="physics" value="on" /> Physique
<input type="submit" value="Sélectionner" />
</form>
Traitement avec formData.queryCheckbox("nom").
Boutons radio
Un seul choix possible.
<form action="/cgi-bin/cpp_radiobutton.cgi" method="post">
<input type="radio" name="subject" value="maths" checked="checked"/> Maths
<input type="radio" name="subject" value="physics" /> Physique
<input type="submit" value="Sélectionner" />
</form>
Traitement avec formData.getElement("subject").
Zone de texte (textarea)
Pour du texte multiligne.
<form action="/cgi-bin/cpp_textarea.cgi" method="post">
<textarea name="textcontent" cols="40" rows="4">Votre texte...</textarea>
<input type="submit" value="Soumettre" />
</form>
Liste déroulante (dropdown)
<form action="/cgi-bin/cpp_dropdown.cgi" method="post">
<select name="dropdown">
<option value="Maths" selected>Maths</option>
<option value="Physique">Physique</option>
</select>
<input type="submit" value="Soumettre"/>
</form>
Utilisation des cookies en CGI
HTTP est sans état. Les cookies permettent de maintenir des informations de session entre les pages.
Fonctionnement
Le serveur envoie un cookie au navigateur. S'il l'accepte, il le stocke localement. À la prochaine visite, le cookie est renvoyé au serveur.
Un cookie comporte 5 champs : Expires, Domain, Path, Secure, Name=Value.
Définir des cookies
Les cookies sont envoyés avant la ligne Content-type via l'en-tête Set-Cookie :
#include <iostream>
using namespace std;
int main() {
cout << "Set-Cookie:UserID=XYZ;\r\n";
cout << "Set-Cookie:Password=XYZ123;\r\n";
cout << "Set-Cookie:Domain=www.exemple.com;\r\n";
cout << "Set-Cookie:Path=/cgi;\n";
cout << "Content-type:text/html\r\n\r\n";
cout << "<html><head><title>Cookies en CGI</title></head><body>";
cout << "Cookies définis<br/></body></html>";
return 0;
}
Récupérer les cookies
Ils sont dans la variable d'environnement HTTP_COOKIE sous forme clé1=valeur1; clé2=valeur2; .... Avec cgicc :
#include <iostream>
#include <vector>
#include <string>
#include <cgicc/CgiDefs.h>
#include <cgicc/Cgicc.h>
#include <cgicc/HTTPHTMLHeader.h>
#include <cgicc/HTMLClasses.h>
using namespace std;
using namespace cgicc;
int main() {
Cgicc cgi;
const CgiEnvironment& env = cgi.getEnvironment();
cout << HTTPHTMLHeader() << "<html><head><title>Cookies</title></head><body>";
cout << "<table border=\"0\" cellspacing=\"2\">";
for (const_cookie_iterator cci = env.getCookieList().begin();
cci != env.getCookieList().end(); ++cci) {
cout << "<tr><td>" << cci->getName() << "</td><td>";
cout << cci->getValue() << "</td></tr>\n";
}
cout << "</table></body></html>";
return 0;
}
Upload de fichiers
Le formulaire doit avoir enctype="multipart/form-data" :
<form enctype="multipart/form-data" action="/cgi-bin/cpp_uploadfile.cgi" method="post">
<p>Fichier: <input type="file" name="userfile" /></p>
<p><input type="submit" value="Téléverser" /></p>
</form>
Script de traitement :
#include <iostream>
#include <vector>
#include <string>
#include <cgicc/CgiDefs.h>
#include <cgicc/Cgicc.h>
#include <cgicc/HTTPHTMLHeader.h>
#include <cgicc/HTMLClasses.h>
using namespace std;
using namespace cgicc;
int main() {
Cgicc cgi;
cout << HTTPHTMLHeader() << "<html><head><title>Upload de fichier</title></head><body>";
const_file_iterator file = cgi.getFile("userfile");
if (file != cgi.getFiles().end()) {
cout << HTTPContentHeader(file->getDataType());
file->writeToStream(cout);
}
cout << "<p>Fichier téléversé avec succès</p>";
cout << "</body></html>";
return 0;
}
Vous pouvez rediriger le flux vers un fichier pour sauvegarder l'upload.
Langue C
- Maîtriser les espaces de noms en C# : Organisation, portée et bonnes pratiques
- Maîtriser les opérateurs C++ : Guide complet avec exemples pratiques
- Commentaires C++ : Bonnes pratiques pour un code lisible et maintenable
- Comment passer des tableaux aux fonctions en C++ : Guide pratique
- Maîtriser la programmation C : Tutoriel complet pour débutants
- Langage C++ : Vue d'ensemble et caractéristiques clés
- Constantes et littéraux en C++ : Types, syntaxe et bonnes pratiques
- Guide complet des opérateurs C++ : Types, utilisation et bonnes pratiques
- Maîtriser les types numériques en C++ : Guide pratique