IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
logo

FAQ DelphiConsultez toutes les FAQ

Nombre d'auteurs : 124, nombre de questions : 934, dernière mise à jour : 23 octobre 2024  Ajouter une question

 

Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums Delphi et Delphi et bases de données de www.developpez.com et de l'expérience personnelle des auteurs.

Nous tenons à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose soient correctes. Les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous souhaitez y apporter des corrections ou la compléter, contactez un responsable (lien au bas de cette page).

Nous espérons que cette FAQ saura répondre à vos attentes. Nous vous en souhaitons une bonne lecture.

L'équipe Delphi de Developpez.com.

SommaireComposants IndyIdFTP (9)
précédent sommaire suivant
 

Il y a plusieurs manières de réaliser une sorte de Fileexists() sur FTP.

La première méthode est de tenter d'exécuter la commande Size sur le serveur. Normalement, tous les serveurs devraient supporter cette commande, qui sert à renvoyer la taille en octets d'un fichier. Si le fichier n'existe pas, une exception est levée, sinon, une variable booléenne est mise à true.

Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
function FTPFileExists(AFTPClient : TIdFTP; const AFile : string) : Boolean;  
begin  
  Result := False;  
  try  
    if not AFTPClient.Connected then // Pas connecté ?  
      AFTPClient.Connect(); // On connecte  
  except  
    Exit; // Impossible de connecter !  
  end;  
  Result := AFTPClient.Size(APath)<>-1;  
end;
Exemple d'utilisation :
Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
procedure TForm1.Button1Click(Sender: TObject); 
begin 
  IdFTP1.Host := 'ftp.foo.com'; 
  IdFTP1.Username := 'anonymous'; 
  IdFTP1.Password := 'anonymous@anonymous.com'; 
  IdFTP1.Connect(); 
  if FTPFileExists(IdFTP1,'/pub.txt') then 
    MessageDlg('Le fichier existe !', mtInformation, [mbOK], 0) 
  else 
    MessageDlg('Le fichier n''existe pas.', mtInformation, [mbOK], 0); 
end;
Une autre méthode est d'utiliser List(), qui récupère le listing complet du dossier spécifié. Pour cela, la fonction a besoin du répertoire dans lequel se situe le dossier et du nom du fichier à rechercher. (On pourrait effectuer une analyse syntaxique pour séparer le fichier du dossier (en copiant le texte à partir du dernier slash), mais cela demanderait l'appel à d'autres fonctions auxiliaires.)

On procède ainsi : on tente de se positionner dans le répertoire passé en paramètre. Si celui-ci n'existe pas, une exception est levée, et on interrompt le fil d'exécution. Si le répertoire existe, on appelle List() en lui passant en paramètre une TStringList qui sera remplie avec le contenu du dossier. Le dernier paramètre de la fonction précise que nous ne voulons pas tout les détails (poids, date de modification) mais juste les noms.
L'existence du fichier est testée en cherchant (avec IndexOf()) le nom du fichier dans la liste. Le seul inconvénient de cette fonction est que si un dossier est nommé comme le fichier cherché, la fonction renverra aussi true.
Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function FTPFileExists2(AFTPClient : TIdFTP; const ADirectory, AFile : string) : Boolean; 
var 
  AOldDir : string; 
  FolderList :  TStringList; 
begin 
  Result := False; 
  try 
    if not AFTPClient.Connected then // Pas connecté ? 
      AFTPClient.Connect(); // On connecte 
  except 
    Exit; // Impossible de connecter ! 
  end; 
  try 
    FolderList := TStringList.Create; 
    AOldDir := AFTPClient.RetrieveCurrentDir; // Sauvegarder le répertoire actuel 
    try 
      AFTPClient.ChangeDir(ADirectory); // Si le dossier n'existe pas -> exception levée 
      try 
        AFTPClient.List(FolderList,'',False); // Lister les fichiers 
      finally 
        Result := FolderList.IndexOf(AFile) > 0; 
      end; 
    except 
    end; 
  finally 
    AFTPClient.ChangeDir(AOldDir); // Revient à l'ancien dossier 
    FolderList.Free; // Libère la StringList 
  end; 
end;
On pourrait appeler cette fonction ainsi :
Code Delphi : Sélectionner tout
if FTPFileExists2(IdFTP1,'/data', 'test.txt') then ...
...pour tester l'existence de /data/test.txt.

Enfin, vous pouvez aussi utiliser la liste parsée DirectoryListing après un appel à List(). La méthode est sensiblement égale à celle énoncée ci-dessus.

Mis à jour le 1er février 2014 Reisubar

Il peut arriver que vous ayez besoin d'une fonction testant si un dossier existe sur un serveur FTP : une sorte de DirectoryExists() fonctionnant sur le serveur.

La méthode à suivre est la suivante : avec un TIdFTP, se connecter au serveur, et tenter de se placer dans le répertoire dont l'existence est à tester. Si ce répertoire n'existe pas, une exception sera soulevée par Indy, dans le cas contraire rien ne se passera. On utilisera ce comportement pour mettre un variable booléenne à true si l'exception n'est pas levée.

Dans la fonction suivante, on suit cette logique en mémorisant le répertoire courant, tenter de changer de répertoire, et rétablissant l'ancien répertoire si le changement a pu se faire :

Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function FTPDirectoryExists(AFTPClient : TIdFTP; const APath : string) : Boolean; 
var 
  AOldDir : string; 
begin 
  Result := False; 
  try 
    if not AFTPClient.Connected then // Pas connecté ? 
    AFTPClient.Connect(); // On connecte 
  except 
    Exit; // Impossible de connecter ! 
  end; 
  try 
    AOldDir := AFTPClient.RetrieveCurrentDir; 
    try 
      AFTPClient.ChangeDir(APath); // Si le dossier n'existe pas -> exception levée 
      Result := True; // Si on arrive ici -> OK 
    except 
      Result := False; 
    end; 
  finally 
    AFTPClient.ChangeDir(AOldDir); // Revient à l'ancien dossier 
  end; 
end;
Voici un exemple d'exploitation de cette fonction qui teste l'existence d'un répertoire '/test' :
Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
procedure TForm1.Button1Click(Sender: TObject); 
begin 
  IdFTP1.Host := 'ftp.foo.com'; 
  IdFTP1.Username := 'anonymous'; 
  IdFTP1.Password := 'anonymous@anonymous.com'; 
  IdFTP1.Connect(); 
  if FTPDirectoryExists(IdFTP1,'/test') then 
    MessageDlg('Le dossier existe !', mtInformation, [mbOK], 0) 
  else 
    MessageDlg('Le dossier n''existe pas.', mtInformation, [mbOK], 0); 
end;

Mis à jour le 1er février 2014 Reisubar


Indy 9 permet de récupérer dans une variable de type TCollection le contenu d'un dossier. Chaque item de la collection est relatif à un fichier et contient entre autres :

  • Le type de l'élément (ItemType, qui vaut ditDirectory pour un dossier, ditFile pour un fichier, et ditSymbolicLink pour un lien symbolique)
  • La taille de l'élement (Size)
  • Le nom du fichier (FileName)
  • La date de modification (ModifiedDate)
  • Les permissions du groupe (GroupPermissions)
  • Les permissions de l'utilisateur (UserPermissions)
  • Le propriétaire (OwnerName)


Cette collection est située dans TIdFTP.DirectoryListing. Elle est remplie lors d'un appel à la méthode List(). Le texte brut renvoyé par le serveur est analysé (parsé) et les items sont ajoutés à la collection.

Précisions importantes à propos de cette propriété :
  • Les parseurs de Indy 9 sont basiques : il ne supportent que les serveurs MS-DOS ou Unix. Cependant, beaucoup de serveurs émulent le formatage Unix, comme les serveurs Macintosh et la plupart des serveurs FTP Windows distribués en freeware et shareware. La version 10 permettra l'analyse des réponses des serveurs Bull, Cisco, IBM, etc. Aussi, si vous avez besoin de parseurs sophistiqués, vous devrez certainement installer la version 10.
  • Certaines informations doivent être utilisées avec prudence : Ainsi la propriété Size contient une taille relative sous certains systèmes à des blocs d'enregistrements et pas à des octets. Utilisez plutôt la commande Size() du TidFTP.
  • Il vaut mieux utiliser la commande MDTM (Modification Time) que la propriété ModifiedDateTime. Cette commande fait partie des extensions au protocole FTP définies. Cette fonction n'est pas directement implémentée dans Indy 9, mais vous pouvez le faire vous-même. Elle est par contre implémentée par défaut dans Indy 10.


Exemple permettant de rechercher un fichier dans un répertoire passé en paramètre :

Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
List(nil); 
for i:=0 to Pred(DirectoryListing.Count) do 
  if (DirectoryListing[i].FileName=FName) and (DirectoryListing[i].ItemType=ditFile) then 
  begin 
    Result := True; 
    Exit; 
  end;

Mis à jour le 26 janvier 2014 Reisubar

Pour modifier les droits d'un fichier sur un serveur FTP il faut utiliser la commande SITE CHMOD <droits> <nomfichier>. Avec les composants Indy il faut utiliser la méthode Site :

Code Delphi : Sélectionner tout
idFTP.Site('chmod 666 MonFichier');
Cet exemple donne les droits en lecture/ecriture pour tout le monde. Ceci permet par exemple de pouvoir autoriser l'enregistrement de données dans un fichier par un script php, ou alors d'en interdire la lecture via http.

Cette fonction déclenche toujours une exception même en cas de succès. Il convient donc de la mettre dans une clause try except dans tous les cas.

Mis à jour le 1er février 2014 Nono40


Pour plus d'informations sur le sujet consultez le tutoriel indiqué dans la section Liens.

Mis à jour le 1er février 2014 Reisubar

Pour créer une arborescence sur un serveur FTP et ainsi pouvoir y déposer un fichier sans avoir à vérifier l'existence de chaque répertoire, utiliser la procédure suivante :

Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Vérifie que le répertoire existe, créé l'arborescence si nécessaire 
procedure TForm1.ForceFtpDirectories(pathToForce: string); 
var 
  FtpDirtoCreate : string; 
  i : Integer; 
begin 
  try 
    IdFTP1.ChangeDir(pathToForce); 
    // Le répertoire existe -> c'est fini! 
  except 
    // Le répertoire n'existe pas -> on vérifie et crée toute l'arborescence 
    FtpDirToCreate:= '/'; // On commence par la racine du ftp 
    repeat 
      // On prend le prochain répertoire dans l'arborescence 
      for i:= Length(FtpDirToCreate)+1 to Length(pathToForce) do begin 
        if pathToForce[i]='/' then begin 
          FtpDirToCreate:= LeftStr(pathToForce, i); 
          break; 
        end; //if 
      end; //for i 
      try 
        IdFTP1.ChangeDir(FtpDirToCreate); 
        // Le répertoire existe -> ok 
      except 
        // Le répertoire n'existe pas -> on le créé 
        IdFTP1.MakeDir(FtpDirToCreate); 
      end; //except 
      // Et on passe au suivant tant que toute l'arborescence n'est pas vérifiée 
    until FtpDirtoCreate=pathToForce; 
  end; //except 
end;
Exemple d'utilisation :
Je veux déposer un fichier 'toto.bin' dans le répertoire '/pub/driver/v2/releases/' d'un serveur FTP.
Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
procedure deposeFichier(); 
var 
  IdFTP1 : TIdFTP; 
begin 
  // On créé un objet TIdFTP 
  IdFTP1:= TIdFTP.Create; 
  // On renseigne les champs de connexion 
  IdFTP1.Host:= 'nom_du_serveur'; 
  IdFTP1.Username:= 'nom_utilisateur'; 
  IdFTP1.Password:= 'mot_de_passe'; 
  // Connexion au ftp 
  IdFTP1.Connect; 
  try 
    // Vérification de l'existence du répertoire... 
    //... Et création arborescence si nécessaire 
    ForceFTPDirectories('/pub/driver/v2/releases/'); 
    // Dépôt du fichier 
    IdFTP1.Put('C:\toto.bin', '/pub/driver/v2/releases/toto.bin'); 
  finally 
    // Déconnexion quoi qu'il arrive 
    IdFTP1.Disconnect; 
  end; 
end;
Ceci est l'équivalent de la fonction ForceDirectories de Delphi mais sur un serveur FTP.

Mis à jour le 1er février 2014 adaneels

Avec les composants Indy ? Non... TIdFTP est limité à 2 Giga-octets du fait qu'un entier de type integer est utilisé en interne pour comptabiliser le nombre d'octets reçus (valeur maxi d'un integer = 2 147 483 647, d'où la limite de 2 147 483 647 octets = 2 Go).

Voici la fonction proposée qui porte la limite de téléchargement à 4 Giga-octets (et même beaucoup plus, mais cela n'a pas encore été testé aujourd'hui) :

Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
uses Wininet; 
  
function FtpDownloadFile(strHost, strUser, strPwd: string; 
  Port: Integer; ftpDir, ftpFile, TargetFile: string; 
  ProxyUser,ProxyPassword:string; 
  ALabel:TLabel=nil;AProgressBar: TProgressBar=nil): Boolean; 
  
  function FmtFileSize(Size: Int64): string; 
  begin 
    if Size >= $E8D4A51000 then 
      Result := Format('%.2f', [Size / $3B9ACA00]) + ' To' 
    else 
    if Size >= $3B9ACA00 then 
      Result := Format('%.2f', [Size / $3B9ACA00]) + ' Go' 
    else 
    if Size >= $F4240 then 
      Result := Format('%.2f', [Size / $F4240]) + ' Mo' 
    else 
    if Size < 1000 then 
      Result := IntToStr(Size) + ' bytes' 
    else 
      Result := Format('%.2f', [Size / 1000]) + ' Ko'; 
  end; 
  
const 
  READ_BUFFERSIZE = 4096;  // ou 256, 512, ... 
var 
  hNet, hFTP, hFile: HINTERNET; 
  buffer: array[0..READ_BUFFERSIZE - 1] of Char; 
  bufsize, dwBytesRead: DWORD; 
  fileSize:Int64; 
  sRec: TWin32FindData; 
  strStatus: string; 
  LocalFile: file; 
  bSuccess: Boolean; 
  PC:integer; //Pourcentage de téléchargement 
  UnFichier:TFileStream; 
begin 
  Result := False; 
  
  { Ouvre une session internet } 
  hNet := InternetOpen('Nom du programme', // Agent 
    INTERNET_OPEN_TYPE_PRECONFIG, // AccessType 
    PChar(ProxyUser),  // Nom utilisateur pour le Proxy 
    PChar(ProxyPassword), // Mot de passe Proxy 
    0); // ou INTERNET_FLAG_ASYNC / INTERNET_FLAG_OFFLINE 
  
  { 
    l'agent contient le nom de l'application ou de 
    l'entité appelant les fonctions Internet 
  } 
  
  
  { Le Handle de connexion est-il valide?} 
  if hNet = nil then 
  begin 
    ShowMessage('Impossible d''accéder à WinInet.Dll'); 
    Exit; 
  end; 
  
  {Connexion au serveur FTP} 
  hFTP := InternetConnect(hNet, // Handle de InternetOpen 
    PChar(strHost), // serveur FTP 
    port,//ou bien (INTERNET_DEFAULT_FTP_PORT), 
    PChar(StrUser), // username 
    PChar(strPwd),  // password 
    INTERNET_SERVICE_FTP, // FTP, HTTP, ou Gopher? 
    INTERNET_FLAG_PASSIVE, // flag: 0 ou INTERNET_FLAG_PASSIVE 
    0);// Nombre défini par l'utilisateur pour un callback 
  
  if hFTP = nil then 
  begin 
    InternetCloseHandle(hNet); 
    ShowMessage(Format('L''hôte "%s" n''est pas disponible',[strHost])); 
    Exit; 
  end; 
  
  { Changer de répertoire } 
  bSuccess := FtpSetCurrentDirectory(hFTP, PChar(ftpDir)); 
  
  if not bSuccess then 
  begin 
    InternetCloseHandle(hFTP); 
    InternetCloseHandle(hNet); 
    ShowMessage(Format('Ne peut accéder au répertoire %s.',[ftpDir])); 
    Exit; 
  end; 
  
  { Lecture de la taille du fichier } 
  if FtpFindFirstFile(hFTP, PChar(ftpFile), sRec, 0, 0) <> nil then 
  begin 
    fileSize := sRec.nFileSizeLow; 
  end else 
  begin 
    InternetCloseHandle(hFTP); 
    InternetCloseHandle(hNet); 
    ShowMessage(Format('Cannot find file ',[ftpFile])); 
    Exit; 
  end; 
  
  { Ouvre le fichier } 
  hFile := FtpOpenFile(hFTP, // Handle d'une session ftp 
      PChar(ftpFile), // Nom du fichier 
      GENERIC_READ, // dwAccess 
      FTP_TRANSFER_TYPE_BINARY, // dwFlags 
      0); // Ceci est le contexte utiliser pour les Callback. 
  
  if hFile = nil then 
  begin 
    InternetCloseHandle(hFTP); 
    InternetCloseHandle(hNet); 
    Exit; 
  end; 
  
  { Créer un nouveau fichier local } 
  if FileExists(TargetFile) then DeleteFile(TargetFile); 
  UnFichier:=TFileStream.Create(TargetFile,fmCreate); 
  try 
  
  dwBytesRead := 0; 
  bufsize := READ_BUFFERSIZE; 
  
  while (bufsize > 0) do 
  begin 
    Application.ProcessMessages; 
  
    if not InternetReadFile(hFile, 
      @buffer, // addresse d'un buffer qui reçoit les données 
      READ_BUFFERSIZE, // Nombre d'octets à lire et à placer dans le buffer 
      bufsize)  // Nombre d'octets effectivement lus 
        then Break; //On a fini de recevoir quelque chose 
      if (bufsize > 0) and (bufsize <= READ_BUFFERSIZE) 
      then bufsize:=UnFichier.Write(buffer, bufsize); 
  
    dwBytesRead := dwBytesRead + bufsize; 
  
    { Montrer Progression } 
    PC:=Round(dwBytesRead * 100 / fileSize); 
    if Assigned(AProgressBar) 
    then AProgressBar.Position :=PC; 
    if Assigned(ALabel) 
    then ALabel.Caption := Format('%s of %s / %d %%',[FmtFileSize(dwBytesRead),FmtFileSize(fileSize) ,PC]); 
  end; 
    Result := True; 
  finally 
    UnFichier.Free; 
    InternetCloseHandle(hFile); 
    InternetCloseHandle(hFTP); 
    InternetCloseHandle(hNet); 
  end; 
  
end;
Et un exemple d'utilisation :
Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
procedure TForm1.Button1Click(Sender: TObject); 
var TargetFile:string; 
begin 
  TargetFile := ExtractFilePath(Application.ExeName)+'fftw-3.1.2-dll.zip'; 
  FtpDownloadFile('ftp.fftw.org','','', //Serveur ftp / Nom d'utilisateur sur le ftp / Mot de passe sur le ftp 
    21,'/pub/fftw','fftw-3.1.2-dll.zip', //Numéro de port FTP/ répertoire dans lequel se trouve le fichier / le fichier à télécharger 
    TargetFile, //La destination du fichier 
    '','', //Nom d'utilisateur et mot de passe Proxy éventuel 
    Label1,ProgressBar1); //Un Label et une ProgressBar (facultatifs) 
  ShowMessage('Téléchargement terminé'); 
end;
Vous noterez les possibilités suivantes :
  • prise en compte des paramètres de connexion proxy (si vous en avez un)
  • prise en compte des connexions ftp anonymes ou non
  • La possibilité de mettre ou non en paramètre un TLabel informatif ou une TProgressBar, tous deux dédiés à l'affichage de la progression.
  • La possibilité théorique de télécharger des fichiers de 2^63-1 octets (limite de Int64), limité toutefois au format de fichier (NTFS, FAT32) de votre disque dur.

Mis à jour le 1er février 2014 LadyWasky

L'une des solutions est d'envoyer une commande LIST et de tester les fichiers reçus. Cette méthode va retourner beaucoup d'informations pour pas grand chose au final. Pour obtenir la date de dernière modification d'un fichier on peut utiliser la commande ftp MDTM.
Cette commande a le format suivant :

Code : Sélectionner tout
MDTM NomFichier
Le retour est
Code : Sélectionner tout
213 DateFichier
si la commande réussit, sinon un code d'erreur est généré. DateFichier est au format YYYYMMDDHHNNSS.

La commande MTDM n'est pas implémentée dans IdFTP mais peut être envoyée avec la méthode SendCmd de TIdFTP.
Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Function FtpGetDate(idFtp:TIdFtp;Const NomFichier:String):TDateTime; 
Var StDate: String; 
    Y,M,D,H,N,S:Integer; 
Begin 
  IdFTP.SendCmd('MDTM '+NomFichier,[213]); 
  StDate := IdFTP.LastCmdResult.Text.Text; 
  Y := StrToIntDef(Copy(StDate, 1,4),0); 
  M := StrToIntDef(Copy(StDate, 5,2),0); 
  D := StrToIntDef(Copy(StDate, 7,2),0); 
  H := StrToIntDef(Copy(StDate, 9,2),0); 
  N := StrToIntDef(Copy(StDate,11,2),0); 
  S := StrToIntDef(Copy(StDate,13,2),0); 
  Result := EncodeDate(Y,M,D)+EncodeTime(H,N,S,0); 
End;
Note : en cas d'échec, cette fonction lèvera une exception.

Mis à jour le 1er février 2014 Nono40

La date indiquée lors d'un upload en ftp est la date de l'upload et non pas la date du fichier. Si l'on veut garder la vraie date du fichier, il faut ensuite exécuter la commande MDTM sur le fichier venant d'être uploadé.
Le format de cette commande est le suivant :

Code : Sélectionner tout
MDTM DateFichier NomFichier
Elle retourne le code 200 (OK) ou 250 suivant les serveurs. DateFichier doit être au format YYYYMMDDHHNNSS.
Cette commande n'est pas implémentée dans idFtp, par contre elle peut être envoyée directement en utilisant la méthode SendCmd de l'objet idFtp.
Code Delphi : Sélectionner tout
1
2
3
4
Procedure FtpSetDate(Const NomFichier: String; LaDate: TDateTime); 
Begin 
  idFtp.SendCmd('MDTM ' + FormatDateTime('YYYYMMDDHHNNSS', LaDate) + ' ' + NomFichier, [200, 250]); 
End;

Mis à jour le 1er février 2014 Nono40

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

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 © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.