Aller au contenu

Exemple d'utilisation d'un serveur Flask⚓︎

Réalisation d'une interface homme-machine pour utiliser l'algorithme de César⚓︎

Vous avez travaillé au début de l'année sur cet algorithme et l'avez implémenté en Python (la fonction est rappelée ci-dessous), nous allons voir comment réaliser une interface, pour utiliser cette fonction, dans un navigateur internet en lien avec un serveur accessible depuis un réseau local ou depuis le Web.

L'algorithme de César⚓︎

On rappelle la fonction cesar mettant en œuvre la méthode de César pour crypter un texte :

🐍 Script Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
def cesar(phrase : str, cle : int) -> str:
    """ 
    Cette fonction retourne la chaîne de caractères obtenue par la 
    méthode de César appliquée sur la chaîne phrase avec la clé cle
    param phrase (str) : chaîne de caractères à crypter, sans 
                         caractères spéciaux, ni ponctuation 
                         ou accents, les espaces sont conservés
    param cle (int) : clé utilisée par la méthode de César
    return (str) : chaîne de caractères résultat du codage
    """
    phrase_crypte = ""
    for caractere in phrase:
        valeur_caractere = ord(caractere)
        if valeur_caractere != 32: # Espace
            # Il y a 58 caractères de A à z dans la table ASCII
            valeur_crypte = (valeur_caractere + cle - 65) % 58 + 65
        else:
            valeur_crypte = 32
        phrase_crypte = phrase_crypte + chr(valeur_crypte)
    return phrase_crypte

Voici deux exemples d'appels de cette fonction :

📋 Texte
>>> cesar("Bonjour tout le monde", 10)
LyxtyEB DyED vo wyxno
>>> cesar("LyxtyEB DyED vo wyxno", -10)
Bonjour tout le monde

Création de la page HTML et du formulaire⚓︎

On crée le répertoire Serveur avec l'arborescence suivante :

arborescence

Le fichier formulaire.html est le suivant :

HTML
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html>
    <head>
        <title>Ma première page dynamique avec Flask</title>
        <link rel = "stylesheet" href = "/static/style.css"/>
        <meta charset=UTF-8">
    </head>
    <body>
        <div style="text-align: center;"><b><i><h1>Codage avec la méthode de César</h1></i></b></div>
        <form>
            <p>Saisir ci-dessous le texte à crypter : </p>
            <textarea name="texte" rows=4 cols=40>Le texte n a ni caractere de ponctuation ni caractere speciaux mais eventuellement des espaces et des MAJUSCULES </textarea><br>
            <p>Choisir une clé (un entier compris entre 1 et 26) : </p>
            <input type = "text" value="15" maxlength="2"><br>
            <button>Crypter</button>
        </form>
    </body>
</html>

Voici le rendu :

Rendu

Mise en route du serveur Flask⚓︎

Pour permettre la communication entre la page HTML (formulaire.html) et la fonction Python (cesar), nous allons mettre en route un serveur Flask. Flask est un framework de développement web en Python.

  • Dans le répertoire Serveur, créer le fichier index.py suivant :
🐍 Script Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from flask import Flask, render_template

# On crée une instance de la classe Flask : un serveur web
app = Flask(__name__)

# On décrit la route par défaut du serveur (racine du serveur)
@app.route("/")
def index():
    return render_template("formulaire.html")

if __name__ == "__main__":
     # Lancement du serveur
     app.run(debug = True, host = "serveur-pgdg.net", port = "5000")  # Mode debug pour commencer
    # host = "localhost" en local
    # votre port personnel vous sera précisé
  • Exécuter ce fichier à partir d'un terminal :

lancement du serveur

  • Saisir l'adresse suivante dans votre navigateur : http://serveur-pgdg.net:5000/ pour un premier aperçu (vous indiquerez le numéro du port qui vous a été attribué).

Interaction Formulaire - Serveur⚓︎

Nous allons utiliser un formulaire de type POST pour transmettre les données du formulaire au serveur.

  • Ajouter le paramètre method = "POST à la balise form du fichier formulaire.html.

Ajouter également l'adresse du serveur à suivre pour traiter ce formulaire à l'aide du paramètre action = "/crypter/" (cette adresse sera définie par la suite dans le fichier index.py) :

HTML
13
14
15
<form action = "/crypter/" method = "POST">
...
</form>
- Ajouter également respectivement aux balises textarea et input les paramètres name = "texte" et name = "cle". Le type de la balise button est type = "submit".

Le serveur est maintenant prêt à recevoir les données du formulaire. Il reste à mettre en place la "route" vers l'adresse "/crypter/" du serveur.

Traitement des données du formulaire⚓︎

On suppose maintenant que la fonction cesar est codée dans un fichier nommé fonctions.py qui se trouve dans à la racine du répertoire Serveur.

  • Ajouter ou modifier les lignes suivantes au fichier index.py déjà créé :
🐍 Script Python
# On ajoute l'import de la méthode request
from flask import Flask, render_template, request
from fonctions import cesar

...

@app.route("/crypter/", methods = ['POST'])
def crypter():
    texte = request.form['texte']
    cle = int(request.form['cle'])
    return cesar(texte, cle)

...
  • Arrêter le serveur lancé précédemment par Ctrl+C (dans le terminal) puis le redémarrer. Après avoir rechargé la page et cliqué sur le bouton, on constate le fonctionnement et l'affichage du résultat dans une page vide comme ci-dessous :

Affichage du résultat dans une page HTML⚓︎

  • On crée une page affichage.html, dans le répertoire templates sur le modèle de la page formulaire.html.

  • On modifie la fonction crypter dans le fichier index.py ainsi :

    🐍 Script Python
    def crypter():
        texte = request.form['texte']
        cle = int(request.form['cle'])
        return render_template("affichage.html", texte = cesar(texte, cle))
    

  • On intègre ce qui est envoyé par le codage {{ texte }}. Ici on aura le texte crypté dans une balise <h2>

    HTML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    <!DOCTYPE html>
    <html>
        <head>
            <title>Ma première page dynamique avec Flask</title>
            <meta charset = UTF-8"/>
            <link rel = "stylesheet" href = "/static/style.css"/>
        </head>
        <body style = "background-color:lightgray ;">
            <h1>Codage avec la méthode de César</h1>
            <h2>{{ texte }}</h2><br>
            <input type = "button" onclick = "javascript:location.href = '/'" value = "Retour"/>
        </body>
    </html>
    

Intégration de CSS et Javascript⚓︎

On peut intégrer des feuilles style CSS et des scripts Javascript. Les fichiers contenant le code doivent se trouver dans un répertoire nommé static :

Ces deux fichiers seront incorporés de la manière suivante dans la balise <head> du code HTML :
HTML
...
<head>
    <link rel = "stylesheet" href = "/static/style.css"/>
    <script src = "/static/scripts.js"></script>
</head>
...

Compléments⚓︎

Afficher le résultats dans la même page⚓︎

On peut vouloir ajouter un bouton radio à la page formulaire.html afin de choisir de crypter ou de décrypter votre message.

  • On ajoute (ou modifie) les lignes suivantes au fichier formulaire.html :
HTML
20
21
22
23
<input type = "text" name = "cle" value = "15" maxlength = "2"><br>
<input type = "radio" name = "bouton" value="crypter" checked> Crypter<br>
<input type = "radio" name = "bouton" value="decrypter"> Décrypter<br>
<button name = "valider" type = "submit">Valider</button>
  • Il faut maintenant modifier le fichier index.py et la route /crypter/ afin de tenir compte de ce nouveau paramètre :
🐍 Script Python
17
18
    if request.form['bouton'] == "decrypter":
        cle = - cle

On peut également afficher le résultat dans la page formulaire.html et ne plus avoir recours à la page affichage.html et donc à la route /cryper/ :

  • Modification du fichier index.py :
🐍 Script Python
 9
10
11
12
13
14
15
16
17
18
19
20
21
@app.route("/", methods = ['POST', 'GET'])
def index():
    if request.method == 'POST':
        return render_template("formulaire.html", phrase_crypte = crypter())
    else:
        return render_template("formulaire.html")

def crypter():
    texte = request.form['texte']
    cle = int(request.form['cle'])
    if request.form['bouton'] == "decrypter":
        cle = - cle
    return cesar(texte, cle)
  • Modification du formulaire pour intégrer le message crypté :
HTML
<form action = "/" method = "POST">
...
<br><br>
<h2>Message codé : </h2>{{ phrase_crypte }} 

Ajouter de l'interaction dynamique avec Javascript⚓︎

On voudrait maintenant que le codage se fasse "à la volée", sans avoir à cliquer sur le bouton pour voir apparaître le message crypté. Il faudra ajouter un script Javascript qui va en temps réel analyser les contenus du formulaire et interroger le serveur Flask pour calculer le message à afficher. Nous allons commencer par créer le fichier static/scripts.js :

HTML
...
<head>
    <link href = "/static/style.css" rel = "stylesheet" type = "text/css" />
    <script src = "/static/scripts.js"></script>
</head>
...
En ajoutant id = "texte" et id = "texte_crypte", respectivement, aux balises dans laquelle le texte est saisie et dans laquelle le texte est affiché, le code suivant, permet d'afficher de l'afficher à la volée :

JavaScript
// On déclenche un événement si on relâche une touche du clavier
document.addEventListener("keyup", cryptage);

// On déclenche un événement si on clique quelque part
document.addEventListener("click", cryptage);

// Fonction appelée lorsqu'un événement est détecté sur la page 
function cryptage() {

    // on définit les valeurs des paramètres à envoyer au serveur et la méthode GET ou POST
    const data = {
        method: "POST",
        // Les données sont récupérées dans la page 
        body: new URLSearchParams({
                    texte: document.getElementById('texte').value,
                    cle: document.getElementById('cle').value,
                    mode: document.querySelector('input[name = bouton]:checked').value,
                })
    };

    // Voici la méthode permettant l'échange de données avec le serveur (allé et retour)
    // data est défini juste au dessus et contient notamment "texte" "cle" et "mode"       
    fetch("/", data)
        .then(
            // Attente d'une réponse du serveur sous forme d'un object JSON (équivalent du dictionnaire en python)
            // le nom de la variable "promesse" n'a pas d'importance
            promesse => promesse.json()
        )
        .then( 
            // Traitement de la réponse du serveur
            // le nom de la variable "reponse" n'a pas d'importance
            reponse => document.getElementById('texte_crypte').textContent = reponse["texte_crypte"]
        )
        .catch(
            // On peut gérer l'erreur si tel est le cas (par exemple si le champs clé est vide)
            error => alert("Erreur : " + error)
        );
}
Le code Python associé :
🐍 Script Python
# On ajoute l'import de la méthode request
from flask import Flask, render_template, request, jsonify
from fonctions import cesar

# On cré une instance de la classe Flask : un serveur web
app = Flask(__name__)

# On décrit la route par défaut du serveur (racine du serveur)
@app.route("/", methods = ['POST', 'GET'])
def index():
    if request.method == 'POST':
        return jsonify({"texte_crypte" : crypter()})
    else:
        return render_template("formulaire.html")

def crypter():
    texte = request.form['texte']
    cle = int(request.form['cle'])
    if request.form['mode'] == 'decrypter':
        cle = - cle
    return cesar(texte, cle)

if __name__ == "__main__":
     # Lancement du serveur
     app.run(debug = True)  # Mode debug pour commencer

Et le code HTML :

HTML
<!DOCTYPE html>
<html lang="fr">
    <head>
        <title>Ma première page dynamique avec Flask</title>
        <meta charset = "UTF-8"/>
        <link rel="stylesheet" href="/static/style.css"/>
        <script src = "/static/scripts.js"></script>
    </head>
    <body>
        <h1>Codage avec la méthode de César</h1>
        <h2>Saisir ci-dessous le texte à crypter : </h2>
        <textarea rows = 4 cols = 60 id = "texte">Le texte n a ni caractere de ponctuation ni caractere speciaux mais eventuellement des espaces et des MAJUSCULES</textarea> <br>
        <p>Choisir une clé de cryptage : </p>
        <input type = "number" id = "cle" value="15" min="0" max="26">
        <p> 
            <input type = "radio" name = "bouton" value = "crypter" checked> Crypter<br>
            <input type = "radio" name = "bouton" value = "decrypter"> Décrypter
        </p>
        <br><br>
        <h2>Texte crypté : </h2>
        <h3 id = "texte_crypte"></h3>
    </body>
</html>