Introduction par l'exemple à PHP 4


précédentsommairesuivant

IV. Exemples

IV-A. Application Impôts : Introduction

Nous introduisons ici l'application IMPOTS qui sera utilisée à de nombreuses reprises par la suite. Il s'agit d'une application permettant de calculer l'impôt d'un contribuable. On se place dans le cas simplifié d'un contribuable n'ayant que son seul salaire à déclarer :

  • on calcule le nombre de parts du salarié nbParts=nbEnfants/2 +1 s'il n'est pas marié, nbEnfants/2+2 s'il est marié, où nbEnfants est son nombre d'enfants.
  • s'il a au moins trois enfants, il a une demi-part de plus
  • on calcule son revenu imposable R=0.72*S où S est son salaire annuel
  • on calcule son coefficient familial QF=R/nbParts
  • on calcule son impôt I. Considérons le tableau suivant :
12620.0 0 0
13190 0.05 631
15640 0.1 1290.5
24740 0.15 2072.5
31810 0.2 3309.5
39970 0.25 4900
48360 0.3 6898.5
55790 0.35 9316.5
92970 0.4 12106
127860 0.45 16754.5
151250 0.50 23147.5
172040 0.55 30710
195000 0.60 39312
0 0.65 49062

Chaque ligne a 3 champs. Pour calculer l'impôt I, on recherche la première ligne où QF<=champ1. Par exemple, si QF=23000 on trouvera la ligne

247400.152072.5

L'impôt I est alors égal à 0.15*R - 2072.5*nbParts. Si QF est tel que la relation QF<=champ1 n'est jamais vérifiée, alors ce sont les coefficients de la dernière ligne qui sont utilisés. Ici :

00.6549062

ce qui donne l'impôt I=0.65*R - 49062*nbParts.

Les données définissant les différentes tranches d'impôt sont dans une base de données ODBC-MySQL. MySQL est un SGBD du domaine public utilisable sur différentes plate-formes dont Windows et Linux. Avec ce SGBD, une base de données dbimpots a été créée avec dedans une unique table appelée impots. L'accès à la base est contrôlé par un login/motdepasse ici admimpots/mdpimpots. La copie d'écran suivante montre comment utiliser la base dbimpots avec MySQL :

 
CacherSélectionnez

La base de données dbimpots est transformée en source de données ODBC de la façon suivante :

  • on lance le gestionnaire des sources de données ODBC 32 bits
Image non disponible
  • on utilise le bouton [Add] pour ajouter une nouvelle source de données ODBC
Image non disponible
  • on désigne le pilote MySQL et on fait [Terminer]
Image non disponible
  • le pilote MySQL demande un certain nombre de renseignements :
1 le nom DSN à donner à la source de données ODBC - peut-être quelconque
2 la machine sur laquelle s'exécute le SGBD MySQL - ici localhost. Il est intéressant de noter que la base de données pourrait être une base de données distante. Les applications locales utilisant la source de données ODBC ne s'en apercevraient pas. Ce serait le cas notamment de notre application PHP.
3 la base de données MySQL à utiliser. MySQL est un SGBD qui gère des bases de données relationnelles qui sont des ensembles de tables reliées entre-elles par des relations. Ici, on donne le nom de la base gérée.
4 le nom d'un utilisateur ayant un droit d'accès à cette base
5 son mot de passe

IV-B. Application Impôts : la classe ImpotsDSN

Notre application s'appuiera sur la classe PHP ImpotsDSN qui aura les attributs, constructeur et méthode suivante :

 
CacherSélectionnez
  • nous avons vu dans l'exposé du problème que nous avions besoin de trois séries de données
12620.0 0 0
13190 0.05 631
15640 0.1 1290.5
24740 0.15 2072.5
31810 0.2 3309.5
39970 0.25 4900
48360 0.3 6898.5
55790 0.35 9316.5
92970 0.4 12106
127860 0.45 16754.5
151250 0.50 23147.5
172040 0.55 30710
195000 0.60 39312
0 0.65 49062

La 1re colonne sera placée dans l'attribut $limites de la classe ImotsDSN, la seconde dans l'attribut $coeffR, la troisième dans $coeffN. Ces trois attributs sont initialisés par le constructeur de la classe. Celui-ci va chercher les données dans une source de données ODBC. Diverses erreurs peuvent se produire lors de la construction de l'objet. Ces erreurs sont rapportées dans l'attribut $erreurs sous la forme d'un tableau de messages d'erreurs.

  • le constructeur reçoit en paramètre un dictionnaire $impots avec les champs suivants :
 
CacherSélectionnez

Le paramètre du constructeur apporte toutes les informations nécessaires pour aller lire les données dans la source de données ODBC

  • une fois l'objet ImpotsDSN construit, les utilisateur de la classe pourront appeler la méthode calculerImpots de l'objet. Celui-ci reçoit en paramètre un dictionnaire $personne :
 
CacherSélectionnez

La classe complète est la suivante :

 
CacherSélectionnez

Un programme de test pourrait être le suivant :

 
CacherSélectionnez
  • le programme de test prend soin d"inclure" le fichier contenant la classe ImpotsDSN
  • puis crée un objet objImpots de la classe ImpotsDSN en passant au constructeur de l'objet les informations dont il a besoin
  • une fois cet objet créé, la méthode calculer de celui-ci va être appelée cinq fois

Les résultats obtenus sont les suivants :

 
CacherSélectionnez

Nous utiliserons désormais la classe ImpotsDSN sans en redonner la définition.

IV-C. Application Impôts : version 1

Nous présentons maintenant la version 1 de l'application IMPOTS. On se place dans le contexte d'une application web qui présenterait une interface HTML à un utilisateur afin d'obtenir les trois paramètres nécessaires au calcul de l'impôt :

  1. l'état marital (marié ou non)
  2. le nombre d'enfants
  3. le salaire annuel
Image non disponible

L'affichage du formulaire est réalisé par la page PHP suivante :

 
CacherSélectionnez

La page PHP se contente d'afficher des informations qui lui sont passées par le programme principal de l'application dans la variable $requête qui est un objet avec les champs suivants :

chkoui, chknon attributs des boutons radio oui, non - ont pour valeurs possibles "checked" ou "" afin d'allumer ou non le bouton radio correspondant
enfants le nombre d'enfants du contribuable
salaire son salaire annuel
impots le montant de l'impôt à payer
erreurs une liste éventuelle d'erreurs - peut être vide.

La page envoyée au client contient un script javascript contenant une fonction effacer associée au bouton "Effacer" dont le rôle est de remettre le formulaire dans son état initial : bouton non coché, champs de saisie vides. On notera que ce résultat ne pouvait pas être obtenu avec un bouton HTML de type "reset". En effet, lorsque ce type de bouton est utilisé, le navigateur remet le formulaire dans l'état où il l'a reçu. Or dans notre application, le navigateur reçoit des formulaires qui peuvent être non vides.

L'application qui traite le formulaire précédent est la suivante :

 
CacherSélectionnez

Commentaires :

  • tout d'abord, la classe ImpotsDSN est incluse. C'est elle qui est à la base du calcul d'impôts et qui va nous cacher l'accès à la base de données
  • un certain nombre d'initialisations sont faites visant à faciliter la maintenance de l'application. Si des paramètres changent, on changera leurs valeurs dans cette section. En général, ces valeurs de configuration sont plutôt stockées dans un fichier ou une base de données.
  • on récupère les trois paramètres du formulaire correspondant aux champs HTML optMarie, txtEnfants, txtSalaire.
  • ces paramètres peuvent être totalement ou partiellement absents. Ce sera notamment le cas lors de la demande initiale du formulaire. Dans ce cas-là, on se contente d'envoyer un formulaire vide.
  • ensuite la validité des trois paramètres récupérés est vérifiée. S'ils s'avèrent incorrects, le formulaire est renvoyé tel qu'il a été saisi mais avec de plus une liste d'erreurs.
  • une fois vérifiée la validité des trois paramètres, on peut faire le calcul de l'impôt. Celui-ci est calculé par la fonction calculerImpots. Cette fonction construit un objet de type ImpotsDSN et utilise la méthode calculer de cet objet.
  • La construction de l'objet ImpotsDSN peut échouer si la base de données est indisponible. Dans ce cas, l'application affiche une page d'erreur spécifique indiquant les erreurs qui se sont produites.
  • Si tout s'est bien passé, le formulaire est renvoyé tel qu'il a été saisi mais avec de plus le montant de l'impôt à payer.

La page d'erreurs est la suivante :

 
CacherSélectionnez

Voici quelques exemples d'erreurs. Tout d'abord on fournit un mot de passe incorrect à la base :

Image non disponible

On fournit des données incorrectes dans le formulaire :

Image non disponible

Enfin, on fournit des valeurs correctes :

Image non disponible

IV-D. Application Impôts : version 2

Dans l'exemple précédent, la validité des paramètres txtEnfants, txtSalaire du formulaire est vérifiée par le serveur. On se propose ici de la vérifier par un script Javascript inclus dans la page du formulaire. C'est alors le navigateur qui fait la vérification des paramètres. Le serveur n'est alors sollicité que si ceux-ci sont valides. On économise ainsi de la "bande passante". La page impots-form.php d'affichage devient la suivante :

 
CacherSélectionnez

On notera les changements suivants :

  • le bouton Calculer n'est plus de type submit mais de type button associé à une fonction appelée calculer. C'est celle-ci qui fera l'analyse des champs txtEnfants et txTsalaire. Si elles sont correctess, les valeurs du formulaire seront envoyées au serveur (submit) sinon un message d'erreur sera affiché.

Voici un exemple d'affichage en cas d'erreur :

Image non disponible

IV-E. Application Impôts : version 3

Nous modifions légèrement l'application pour y introduire la notion de session. Nous considérons maintenant que l'application est une application de simulation de calcul d'impôts. Un utilisateur peut alors simuler différentes "configurations" de contribuable et voir quelle serait pour chacune d'elles l'impôt à payer. La page web ci-dessous donne un exemple de ce qui pourrait être obtenu :

Image non disponible

Le programme d'affichage de la page ci-dessus est le suivant :

 
CacherSélectionnez

Le programme d'affichage présente des différences mineures avec sa version précédente :

  1. le dictionnaire reçoit un dictionnaire $requête au lieu d'un objet $requête. On écrit donc $requête[enfants] et non $requête->enfants.
  2. ce dictionnaire a un champ simulations qui est un tableau a deux dimensions. $requête[simulations][i] est la simulation n° i. Celle-ci est elle-même un tableau de quatre chaînes de caractères : statut marital, nombre d'enfants, salaire annuel, impôt à payer.

Le programme principal a lui évolué plus profondément :

 
CacherSélectionnez
  • tout d'abord, cette application gère une session. On lance donc une session en début de script :
 
CacherSélectionnez
  • la session mémorise une seule variable : le dictionnaire $session. Ce dictionnaire a deux champs :
    1. objImpots : un objet ImpotsDSN. On mémorise cet objet dans la session du client afin d'éviter des accès successifs inutiles à la base de données ODBC.
    2. simulations : le tableau des simulations pour se rappeler d'un échange à l'autre les simulations des échanges précédents.
    1. objImpots : un objet ImpotsDSN. On mémorise cet objet dans la session du client afin d'éviter des accès successifs inutiles à la base de données ODBC.
    2. simulations : le tableau des simulations pour se rappeler d'un échange à l'autre les simulations des échanges précédents.
  • une fois la session démarrée, on récupère la variable $session. Si celle-ci n'existe pas encore, c'est que la session démarre. On crée alors un objet ImpotsDSN et un tableau de simulations vide. Si besoin est, des erreurs sont signalées.
 
CacherSélectionnez
  • une fois la session correctement initialisée, les paramètres de l'échange sont récupérés. S'il n'y a pas tous les paramètres attendus, un formulaire vide est envoyé.
 
CacherSélectionnez
  • si on a bien tous les paramètres, ils sont vérifiés. S'il y a des erreurs, elles sont signalées :
     
    CacherSélectionnez
  • si les paramètres sont corrects, l'impôt est calculé :
     
    CacherSélectionnez
  • la simulation en cours est ajoutée au tableau des simulations et celui-ci envoyé au client avec le formulaire :
     
    CacherSélectionnez
  • dans tous les cas, le script se termine en enregistrant la variable $session dans la session. Ceci est fait dans la procédure terminerSession.
 
CacherSélectionnez

Terminons en présentant le programme d'affichage des erreurs d'accès à la base de données (impots-erreurs.php) :

impots-erreurs.php
CacherSélectionnez

Ici également, l'objet $requête a été remplacé par un dictionnaire $requête.

IV-F. Application Impôts : version 4

Nous allons maintenant créer une application autonome qui sera un client web de l'application web impots précédente. L'application sera une application console lancée à partir d'une fenêtre DOS :

 
CacherSélectionnez

Les paramètres du client web cltImpots sont les suivants :

 
CacherSélectionnez

Voici quelques exemples d'utilisation. Tout d'abord un premier exemple sans jeton de session.

 
CacherSélectionnez

Nous avons bien récupéré le montant de l'impôt à payer (22504 f). Nous avons également récupéré le jeton de session. Nous pouvons maintenant l'utiliser pour une seconde interrogation :

 
CacherSélectionnez

Nous obtenons bien le tableau des simulations envoyées par le serveur web. Le jeton récupéré reste bien sûr le même. Si nous interrogeons le service web alors que la base de données n'a pas été lancée, nous obtenons le résultat suivant :

 
CacherSélectionnez

Lorsqu'on écrit un client web programmé, il est nécessaire de savoir exactement ce qu'envoie le serveur en réponse aux différentes demandes possibles d'un client. Le serveur envoie un ensemble de lignes HTML comprenant des informations utiles et d'autres qui ne sont là que pour la mise en page HTML. Les expressions régulières de PHP peuvent nous aider à trouver les informations utiles dans le flot des lignes envoyées par le serveur. Pour cela, nous avons besoin de connaître le format exact des différentes réponses du serveur. Pour cela, nous pouvons interroger le service web avec un navigateur et regarder le code source qui a été envoyé. On notera que cette méthode ne permet pas de connaître les entêtes HTTP de la réponse du serveur web. Il est parfois utile de connaître ceux-ci. On peut alors utiliser l'un des deux clients web génériques vus dans le chapitre précédent.

Si nous répétons les exemples précédents, voici le code HTML reçu par le navigateur pour le tableau des simulations :

 
CacherSélectionnez

C'est une table HTML, la seule dans le document envoyé. Ainsi l'expression régulière "|<tr>\s*<td>(.+?)</td>\s*<td>(.+?)</td>\s*<td>(.+?)</td>\s*<td>(.+?)</td>\s*</tr>|" doit-elle permettre de retrouver dans le document les différentes simulations reçues. Lorsque la base de données est indisponible, on reçoit le document suivant :

 
CacherSélectionnez

Pour récupérer l'erreur, le client web devra chercher dans la réponse du serveur web les lignes correspondant au modèle : "|<li>(.+?)</li>|".

Nous avons maintenant les lignes directrices de ce qu'il faut faire lorsque l'utilisateur demande le calcul de l'impôt à partir du client console précédent :

  • vérifier que tous les paramètres sont valides et éventuellement signaler les erreurs.
  • se connecter à l'URL donnée comme premier paramètre. Pour cela on suivra le modèle du client web générique déjà présenté et étudié
  • dans le flux de la réponse du serveur, utiliser des expressions régulières pour soit :
    • trouver les messages d'erreurs
    • trouver les résultats des simulations
    • trouver les messages d'erreurs
    • trouver les résultats des simulations

Le code du client cltImpots.php est le suivant :

cltImpots.php
CacherSélectionnez

Commentaires :

  • le programme commence par vérifier la validité des paramètres qu'il a reçus. Il utilise pour ce faire deux fonctions : analyseURL qui vérifie la validité de l'URL et analyseDemande qui vérifie les autres paramètres.
  • le calcul de l'impôt est fait par la fonction getImpots :
getImpots
CacherSélectionnez
  • la fonction getImpots est déclarée comme suit :
 
CacherSélectionnez

$urlImpots est un dictionnaire contenant les champs :

host : machine où réside le service web

port : son port de service

path : le chemin de la ressource demandée

$demande est un dictionnaire contenant les champs :

marié : oui/non : état marital

enfants : nombre d'enfants

salaire : salaire annuel

$jeton est le jeton de session.

La fonction rend comme résultat un dictionnaire ayant les champs :

erreurs : tableau de messages d'erreurs

simulations : tableau de simulations, une simulation étant elle-même un tableau de quatre éléments (marié,enfants,salaire,impôt)

jeton : le jeton de session

  • une fois le résultat de getImpots obtenu, le programme affiche les résultats et se termine :
 
CacherSélectionnez
  • analysons maintenant la fonction getImpots($urlImpots,$demande,$jeton) qui doit
    • créer une connexion TCP-IP sur le port $urlImpots[port] de la machine $urlImpots[host]
    • envoyer au serveur web les entêtes HTTP qu'il attend notamment le jeton de session s'il y en a un
    • envoyer au serveur web une requête POST avec les paramètres contenus dans le dictionnaire $demande
    • analyser la réponse du serveur web pour y trouver soit une liste d'erreurs soit un tableau de simulations.
    • créer une connexion TCP-IP sur le port $urlImpots[port] de la machine $urlImpots[host]
    • envoyer au serveur web les entêtes HTTP qu'il attend notamment le jeton de session s'il y en a un
    • envoyer au serveur web une requête POST avec les paramètres contenus dans le dictionnaire $demande
    • analyser la réponse du serveur web pour y trouver soit une liste d'erreurs soit un tableau de simulations.
  • l'envoi des entêtes HTTP se fait à l'aide d'une fonction POST :
 
CacherSélectionnez
  • une fois les entêtes HTTP envoyés, la fonction getImpots lit en totalité de la réponse du serveur et la met dans $document. La réponse est lue sans être analysée sauf pour la première ligne qui nous permet de savoir si le serveur web a trouvé ou non l'URL qu'on lui a demandée. En effet si l'URL a été trouvée, le serveur web répond HTTP/1.X 200 OK où X dépend de la version de HTTP utilisée.
 
CacherSélectionnez
  • le document est analysé à l'aide de la fonction getInfos :
 
CacherSélectionnez

Le résultat rendu est un dictionnaire à deux champs :

erreurs : liste des erreurs - peut être vide

simulations : liste des simulations - peut être vide

  • ceci fait, la fonction getImpots peut rendre son résultat sous la forme d'un dictionnaire.
 
CacherSélectionnez
  • analysons maintenant la fonction POST :
 
CacherSélectionnez

Si par programme, nous avions eu l'occasion de demander une ressource web par un GET, nous n'avions pas encore eu l'occasion de le faire avec un POST. Le POST diffère du GET dans la façon d'envoyer des paramètres au serveur. Il doit envoyer les entêtes HTTP suivants :

 
Sélectionnez
1.
2.
3.
POST chemin HTTP/1.X
Content-type: application/x-www-form-urlencoded
Content-length: N

avec

    • chemin : chemin de la ressource web demandée, ici $url[path]
    • HTTP/1.X : le protocole HTTP désiré. Ici on a choisi HTTP/1.0 pour avoir la réponse en un seul bloc. HTTP/1.1 autorise l'envoi de la réponse en plusieurs blocs (chunked).
    • N désigne le nombre de caractères que le client s'apprête à envoyer au serveur

Les N caractères constituant les paramètres de la requête sont envoyés immédiatement derrière la ligne vide qui termine les entêtes HTTP envoyés au serveur. Ces paramètres sont sous la forme param1=val1&param2=val2&…parami est le nom du paramètre et vali sa valeur. Les valeurs vali peuvent contenir des caractères "gênants" tels des espaces, le caractère &, le caractère =, etc.. Ces caractères doivent être remplacés par une chaîne %XX où XX est leur code hexadécimal. La fonction PHP urlencode fait ce travail. Le travail inverse est fait par urldecode.

Enfin on notera que si on a un jeton, il est envoyé avec un entête HTTP Cookie: PHPSESSID=jeton.

  • il nous reste à étudier la fonction qui analyse la réponse du serveur :
     
    CacherSélectionnez
  • rappelons que les erreurs sont envoyées par le serveur sous la forme <li>message d'erreur</li>. L'expression régulière "|<li>(.+?)</li>|" doit permettre de récupérer ces informations. Nous avons ici utilisé le signe | pour délimiter l'expression régulière plutôt que le signe / car celui-ci existe aussi dans l'expression régulière elle-même. La fonction preg_match_all ($modèle, $document, $champs, PREG_SET_ORDER) permet de récupérer toutes les occurrences de $modèle trouvées dans $document. Celles-ci sont mises dans le tableau $champs. Ainsi $champs[i] représente l'occurrence n° i de $modèle dans $document. Dans $champs[$i][0] est placée la chaîne correspondant au modèle. Si celui-ci avait des parenthèses, la chaîne correspondant à la première parenthèse est placée dans $champs[$i][1], la seconde dans $champs[$i][2] et ainsi de suite. Le code pour récupérer les erreurs sera donc le suivant :
 
CacherSélectionnez

IV-G. Application Impôts : Conclusion

Nous avons montré différentes versions de notre application client-serveur de calcul d'impôts :

  • version 1 : le service est assuré par un ensemble de programmes PHP, le client est un navigateur. Il fait une seule simulation et n'a pas de mémoire des précédentes.
  • version 2 : on ajoute quelques capacités côté navigateur en mettant des scripts javascript dans le document HTML chargé par celui-ci. Il contrôle la validité des paramètres du formulaire.
  • version 3 : on permet au service de se souvenir des différentes simulations opérées par un client en gérant une session. L'interface HTML est modifiée en conséquence pour afficher celles-ci.
  • version 4 : le client est désormais une application console autonome. Cela nous permet de revenir sur l'écriture de clients web programmés.

A ce point, on peut faire quelques remarques :

  • les versions 1 à 3 autorisent des navigateurs sans capacité autre que celle de pouvoir exécuter des scripts javascript. On notera qu'un utilisateur a toujours la possibilité d'inhiber l'exécution de ces derniers. L'application ne fonctionnera alors que partiellement dans sa version 1 (option Effacer ne fonctionnera pas) et pas du tout dans ses versions 2 et 3 (options Effacer et Calculer ne fonctionneront pas). Il pourrait être intéressant de prévoir une version du service n'utilisant pas de scripts javascript.

Lorsqu'on écrit un service Web, il faut se demander quels types de clients on vise. Si on veut viser le plus grand nombre de clients, on écrira une application qui n'envoie aux navigateurs que du HTML (pas de javascript ni d'applet). Si on travaille au sein d'un intranet et qu'on maîtrise la configuration des postes de celui-ci on peut alors se permettre d'être plus exigeant au niveau du client.

La version 4 est un client web qui retrouve l'information dont il a besoin au sein du flux HTML envoyé par le serveur. Très souvent on ne maîtrise pas ce flux. C'est le cas lorsqu'on a écrit un client pour un service web existant sur le réseau et géré par quelqu'un d'autre. Prenon un exemple. Supposons que notre service de simulations de calcul d'impôts ait été écrit par une société X. Actuellement le service envoie les simulations dans un tableau HTML et notre client exploite ce fait pour les récupérer. Il compare ainsi chaque ligne de la réponse du serveur à l'expression régulière :

 
CacherSélectionnez

Supposons maintenant que le concepteur de l'application change l'apparence visuelle de la réponse en mettant les simulations non pas dans un tableau mais dans une liste sous la forme :

 
CacherSélectionnez

Dans ce cas, notre client web devra être réécrit. C'est là, la menace permanente pesant sur les clients web d'applications qu'on ne maîtrise pas soi-même. XML peut apporter une solution à ce problème :

  • au lieu de générer du HTML, le service de simulations va générer du XML. Dans notre exemple, cela pourrait être
 
CacherSélectionnez
  • une feuille de style pourrait être associée à cette réponse indiquant aux navigateurs la forme visuelle à donner à cette réponse XML
  • les clients web programmés ignoreraient cette feuille de style et récuperaient l'information directement dans le flux XML de la réponse

Si le concepteur du service souhaite modifier la présentation visuelle des résultats qu'il fournit, il modifiera la feuille de style et non le XML. Grâce à la feuille de style, les navigateurs afficheront la nouvelle forme visuelle et les clients web programmés n'auront pas eux à être modifiés.


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2001 Serge Tahé. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.