Pour partager cette vidéo sur les réseaux sociaux ou sur un site, voici son url :
Sujets que vous pourriez aussi aimer :
Accéder au contenu des fichiers externes
Dans cette
formation Php , nous abordons les techniques permettant d'accéder au contenu des
fichiers externes . Ces fichiers sont placés sur le serveur. Ils ont pu être uploadés automatiquement par des tâches programmées à échéances périodiques. Une
formation enseigne d'ailleurs comment réaliser une connexion FTP par le code Php , pour réaliser des mises à jour automatisées. Nous proposons ici une mise en pratique concrète. Nous réceptionnons un
fichier Csv , fruit de l'exportation de données depuis une base professionnelle. Nous devons récupérer cette information, la découper, la traiter puis l'insérer automatiquement en
base de données .
Sources et présentation de la problématique
Pour simplifier la tâche, nous débutons les travaux depuis une structure Web existante. C'est aussi l'occasion de récupérer les ressources externes.
La décompression fournit de nombreux fichiers. A la racine, nous trouvons les pages Web dont le fichier principal nommé
index.php . Les ressources nécessaires sont placées dans les sous dossiers et liées par le code.
Double cliquer sur le dossier ressources pour afficher son contenu,
Deux fichiers sont proposés. Ils sont respectivement nommés :
ideesorties.sql et
selection-id.txt . Le premier correspond à la
base de données MySql destinée à recevoir les informations récoltées et traitées par le
code Php . Il va donc s'agir d'importer cette base avec l'
interface d'administration PhpMyAdmin . Le second est un fichier texte au
format CSV .
Double cliquer sur ce fichier pour l'ouvrir dans un bloc note,
Nous y consultons les
enregistrements résultant d'une
exportation de base de données . Le
format Csv est universel. Il peut être interprété par n'importe quel
gestionnaire de bases de données . Faut-il encore lui fournir les bonnes indications.
Chaque ligne de ce fichier correspond à un
enregistrement indépendant. Chaque donnée de
champ est explicitement séparée d'une autre par un
point-virgule . C'est lui qui fait office de
séparateur de liste pour reconstituer les colonnes durant la phase d'importation. Chaque information de champ est encadrée de doubles côtes.
Nous devons construire un
code Php capable d'accéder au contenu de ce fichier. Il doit ensuite être en mesure de récupérer chaque
enregistrement ligne à ligne. Et pour chacun, il faut découper l'information champ à champ, pour finalement l'importer dans la colonne correspondante de la
table de la
base de données .
Comme nous l'avait enseigné la
formation pour débuter la programmation en Php , ce projet doit être référencé dans l'interface d'
EasyPhp . Premièrement, les deux
serveurs (http et Database) doivent être démarrés. Ensuite un nom doit lui être attribué. Et puis, l'adresse issue de l'explorateur Windows doit être renseignée.
Dès lors, l'application apparaît dans la liste des projets émulés par
EasyPhp .
Cliquer sur son lien pour accéder à sa page d'accueil,
Vous remarquez la présence d'un
contrôle Html input file . Il est destiné à sélectionner le
fichier Csv . Le
bouton Envoyer permet alors de le soumettre au serveur. Ces deux contrôles sont en effet encapsulés dans un
formulaire Html . Nous allons répliquer des techniques que nous avions apprises au travers de la
formation Php sur les dates . Le fichier doit être réceptionné par le
code Php et archivé sur le serveur. Dès lors, nous pourrons y accéder pour décortiquer son contenu. Nous simulerons ainsi l'
upload automatisé .
Importer et configurer la base de données
A l'issue, ces données récoltées et retravaillées doivent être consolidées en
base de données MySql . Quelques opérations intermédiaires sont nécessaires. Nous devons
importer la base de données . Nous devons ensuite configurer les
droits de l'utilisateur . Et enfin, nous devons paramétrer la
chaîne de connexion en Php pour autoriser le code à accéder à ses ressources. C'est aussi l'occasion de mettre en pratique les notions acquises au travers de la
formation pour importer des données MySql .
En bas de l'interface d'EasyPhp , cliquer sur le bouton Open du module MySql ,
Nous accédons ainsi à l'
interface d'administration PhpMyAdmin .
Dans le volet de gauche, cliquer sur le lien Nouvelle base de données ,
Au centre de l'écran, dans la première zone de saisie, la nommer ids par exemple,
Avec la liste déroulante, définir l'interclassement sur utf8_general_ci ,
Puis, cliquer sur le bouton Créer ,
La
base de données ids apparaît dans la liste des bases de données, sur la gauche dans le volet.
Cliquer sur le lien de cette nouvelle base de données pour la désigner,
En haut de l'interface de PhpMyAdmin , cliquer sur l'onglet Importer ,
Puis, cliquer sur le bouton Parcourir qui se propose,
Dans la boîte de dialogue qui suit, accéder au sous dossier Ressources du dossier de décompression,
Double cliquer sur le fichier ideesorties.sql pour désigner la base de données à importer,
En bas de page, cliquer sur le bouton Exécuter pour lancer le processus d'importation,
Une fois l'
importation terminée, la
table liste_id apparaît dans l'arborescence de la
base de données ids , toujours dans le volet de gauche. Elle est certes vide mais propose la structure pour recevoir les informations issues du serveur.
Dans le volet de gauche, cliquer sur le lien de la table liste_id ,
Puis, en haut de la fenêtre, cliquer sur l'onglet Structure ,
Nous constatons la présence des quatre champs pour recevoir les informations de colonne issues du
fichier Csv . La
clé primaire en entête est essentielle. Elle doit référencer chaque
enregistrement comme unique. Comme elle est
auto-incrémentée , nous ne devrons pas la renseigner par le
code PHP .
Nous dévons définir les
droits d'accès à cette
base de données , pour la
chaîne de connexion Php .
Cliquer sur l'onglet Privilèges en haut de la fenêtre PhpMyAdmin ,
Au centre de l'écran, cliquer sur le lien Ajouter un compte d'utilisateur ,
Saisir le nom d'utilisateur : codePHP , dans l'écran qui suit,
Définir l'hôte sur l'adresse locale attribuée : 127.0.0.1 , ici,
Taper le mot de passe php123bd ,
Puis, saisir de nouveau ce mot de passe dans la seconde zone de saisie,
Plus bas dans l'interface, cocher la case Tout cocher ,
Nous octroyons ainsi les privilèges administrateur à notre utilisateur.
Enfin, cliquer sur le bouton Exécuter pour créer l'utilisateur,
Dans la foulée, cliquer sur l'onglet Comptes utilisateurs en haut de la fenêtre,
Le compte que nous venons de créer se trouve listé parmi les autres utilisateurs déjà présents. Nous devons utiliser ces informations pour fabriquer la
chaîne de connexion en PHP . Il s'agit de techniques désormais bien connues. Le fichier de configuration est placé dans le
sous dossier commun du dossier de décompression. Il est bien entendu appelé par les pages du site grâce à l'
instruction Php include .
Dans l'explorateur Windows, ouvrir le sous dossier commun du dossier de décompression,
Cliquer avec le bouton droit de la souris sur le fichier connexion.php ,
Dans le menu contextuel, choisir de l'ouvrir avec un éditeur tel que le Notepad++,
En entête de la section Php existante, ajouter les instructions suivantes (notées en gras) :
<?php
/*
Section de configuration
*/
$liaison = mysqli_connect("127.0.0.1", "codePHP", "php123bd");
mysqli_select_db($liaison, "ids");
$info = $_SERVER['REQUEST_URI'];
$info = substr($info, strripos($info,"/")+1);
$info =str_replace(".php", "", str_replace("-", "", $info));
$info = strtoupper(substr($info, 0, 1)).substr($info,1);
?>
Comme nous l'avons appris, nous exploitons l'
instruction Php mysqli_connect . En paramètres, nous lui passons dans l'ordre le
nom d'hôte , le
nom d'utilisateur et le
mot de passe . Cette
chaîne de connexion est alors mémorisée dans la
variable $liaison . C'est ensuite la
fonction Php mysqli_select_db qui établit la connexion. Pour cela, nous lui passons en premier paramètre la
chaîne de connexion . De fait, elle dispose de tous les droits pour accéder à la
base de données que nous lui passons en second paramètre.
Enregistrer les modifications et fermer le fichier connexion.php ,
N'oublions pas que toute connexion ouverte doit être fermée à l'issue des traitements. C'est pourquoi il existe le
fichier pied-page.php dans le
sous dossier commun . Il est lui aussi imbriqué dans la construction.
L'ouvrir dans le Notepad,
Puis ajouter la section Php entre la balise fermante du script et la balise html fermante :
...
</script>
<?php
mysqli_close($liaison);
?>
</html>
Si vous rafraîchissez la page Web, vous obtenez strictement le même résultat que précédemment. Pourtant la
connexion est désormais établie. Si vous changez le mot de passe dans la
chaîne de connexion et que vous rafraîchissez le navigateur, une erreur survient. Tout cela prouve que la
liaison est fonctionnelle et prête à être exploitée.
Upload d'un fichier sur le serveur
L'internaute est invité à désigner le
fichier Csv grâce au
bouton Parcourir proposé sur la page Web. Il clique alors sur le
bouton Envoyer pour le soumettre au serveur. Et c'est un
code Php , que nous allons répliquer selon les techniques apprises, qui doit se charger de le réceptionner pour en faire une copie, précisément sur le serveur.
A la racine du dossier de décompression, cliquer droit sur le fichier index.php ,
Dans le menu contextuel, choisir de l'ouvrir dans un éditeur tel que le Notepad ++,
A partir de la ligne 30 pour un éditeur Notepad, vous notez la présence du
formulaire Html :
...
<div class="centre">
<div class="titre_centre">
<form id="formulaire" name="formulaire" enctype="multipart/form-data" method="post" action="index.php">
<input type="hidden" name="MAX_FILE_SIZE" value="<?php echo $max_file_size ?>">
<input name="fichier" type="file" id="fichier" size="200" class="liste">
<div class="liste_div" style="float:right;">
<input type="button" id="envoyer" name="envoyer" class="liste" style="width:100px;" value="Envoyer" onClick="document.getElementById('formulaire').submit();" />
</div>
</form>
</div>
</div>
...
Vous constatez la présence essentielle de son
attribut enctype . Il permet le transport d'informations sous forme de fichier. Sa méthode est réglée sur
Post . Nous transmettrons donc les informations par PostBack (Aller-retour serveur). Ce dernier a pour effet de recharger et réinitialiser la page au retour. La page appelante est le fichier sur lequel nous allons coder, soit la page d'accueil elle-même (
action="index.php" ). Ce formulaire encapsule le
contrôle input de
type file ainsi que le
bouton Envoyer . Ce dernier soumet les informations du formulaire au clic. Le
contrôle input file est nommé
fichier . C'est ainsi que nous le piloterons par le
code Php . Souvenez-vous, les informations transmises par un
contrôle file consistent en un
tableau de variables . Nous devons récupérer le nom temporaire attribué au fichier. Pour cela, nous répliquons un code que nous avions mis en oeuvre lors d'une formation :
Dans le calque d'identifiant colonne_gauche , à partir de la ligne 40 pour un éditeur Notepad, ajouter les instructions Php suivantes :
...
<div class="colonne" id="colonne_gauche">
<?php
if(isset($_FILES["fichier"]["tmp_name"]))
{
$nom_fichier_tmp = $_FILES["fichier"]["tmp_name"];
copy($nom_fichier_tmp, "ressources/pour_import.txt");
echo "Le fichier a correctement été transféré";
}
?>
</div>
<div class="colonne" id="colonne_droite">
...
Nous l'avions vu, c'est l'instruction
Php $_Files qui permet d'atteindre un
contrôle File Html par son nom. Ce dernier stocke les éléments sous forme de tableau. C'est pourquoi, nous accédons au nom temporaire attribué au fichier grâce à l'
argument tmp_name . La
fonction isset permet de tester son existence. En effet, au premier chargement de la page, le transfert n'ayant pas encore eu lieu, la variable n'existe pas. De fait, il est nulle question d'enclencher le moindre traitement, sous peine de générer des erreurs. Lorsque la valeur existe en revanche, nous la stockons dans une variable. Puis, nous exploitons la
fonction Php copy pour réaliser le transfert sur le serveur. Elle requiert le chemin source en premier argument et le chemin de destination en second argument.
Nous désignons exactement le même dossier que celui du
fichier Csv . En effet, en phase de développement,
EasyPhp émule le
serveur . Et il est placé sur la même machine. Mais ne vous y trompez pas, en production, le
fichier Csv est le fichier client. Le fichier résultant de la copie est forcément placé sur le
serveur distant , détaché du fichier d'origine.
Enregistrer les modifications (CTRL + S) et basculer sur le navigateur Web,
Rafraîchir la page et cliquer sur le bouton Parcourir ,
Dans la fenêtre qui suit, double cliquer sur le fichier selection-id.txt , situé dans le sous dossier ressources du dossier de décompression,
Puis, cliquer sur le bouton Envoyer pour le transmettre au serveur.
Comme vous le remarquez, le message de confirmation retourné par la
fonction Php echo indique que le transfert s'est déroulé avec succès. D'ailleurs, si vous ouvrez le
sous dossier ressources , vous y notez la copie du
fichier Csv , nommée
pour_import.txt .
Accéder aux contenus de fichiers
Il est désormais temps d'enclencher le
code Php pour accéder au fichier en lecture.
A la suite du code Php précédent, à la place de l'instruction echo, ajouter les lignes suivantes :
...
<div class="colonne" id="colonne_gauche">
<?php
if(isset($_FILES["fichier"]["tmp_name"]))
{
$nom_fichier_tmp = $_FILES["fichier"]["tmp_name"];
copy($nom_fichier_tmp, "ressources/pour_import.txt");
$fichier_a_lire = fopen("ressources/pour_import.txt","r");
$taille = strlen(file_get_contents("ressources/pour_import.txt"));
$lecture = fread($fichier_a_lire, $taille);
$lignes = explode("\n",$lecture);
$compteur=0;
?>
</div>
<div class="colonne" id="colonne_droite">
...
C'est la
fonction Php fopen qui permet de charger en mémoire un fichier dont le chemin lui est passé en premier paramètre. Notez l'
attribut r pour
Read passé en second paramètre. Il indique que nous accédons au fichier en
lecture et non en écriture. L'objet résultant est stocké dans la
variable $fichier_a_lire , pour exploitation ultérieure.
Pour parcourir le fichier intégralement, nous devons connaître sa taille en octets. La
fonction Php file_get_contents permet de récupérer ce contenu, sous forme de caractères. Dès lors, la
fonction Php strlen les compte et renvoie la taille en octets. Cette dernière est stockée dans la
variable $taille .
La
fonction fread permet alors d'initier la lecture en mémoire. Pour ce faire, elle requiert l'objet désignant le fichier en premier paramètre. En second paramètre, nous lui passons l'information sur la taille pour permettre l'allocation mémoire. Le contenu ainsi récupéré est le fichier complet. Il est stocké dans la
variable $lecture .
Mais nous souhaitons récupérer les informations ligne à ligne. C'est pourquoi nous exploitons la
fonction Php explode . Comme nous l'avions appris, elle découpe une chaîne de texte, le fichier passé en second paramètre, sur le caractère passé en premier paramètre. Cette séquence (\n) représente le saut de ligne. Ainsi, nous stockons chaque ligne, dans le
tableau de variables $lignes créé à la volée.
Nous aurons besoin de parcourir chacune de ces lignes. A l'issue, souvenez-vous, nous souhaitons archiver ces données en
base de données . C'est pourquoi, nous initialisons une
variable $compteur à 0. Nous l'incrémenterons dans une boucle que nous devons coder pour récupérer chaque
enregistrement . Nous l'utiliserons comme limite supérieure à ne pas dépasser afin de ne restituer que les premiers d'entre eux, à titre d'essai.
A la suite de ce code, ajouter la boucle foreach suivante :
...
if(isset($_FILES["fichier"]["tmp_name"]))
{
$nom_fichier_tmp = $_FILES["fichier"]["tmp_name"];
copy($nom_fichier_tmp, "ressources/pour_import.txt");
$fichier_a_lire = fopen("ressources/pour_import.txt", "r");
$taille = strlen(file_get_contents("ressources/pour_import.txt"));
$lecture = fread($fichier_a_lire,$taille);
$lignes = explode("\n",$lecture);
$compteur=0;
foreach($lignes as $ligne)
{
echo utf8_encode($ligne)."<br />";
$compteur++;
if($compteur>2)
break;
}
fclose($fichier_a_lire);
}
?>
...
Nous avions abordé les
traitements récursifs en Php , mais pas la
boucle foreach . Cette
boucle particulière a en revanche été traitée en VBA Excel notamment . Elle permet de passer en revue chaque élément contenu dans le
tableau de variables $lignes , les uns après les autres. Chacun de ces éléments est reconnu sous le nom de
variable $ligne déclarée à la volée. Nous l'exploitons à chaque passage pour l'afficher en lieu et place, grâce à la
fonction Php echo . Nous traitons les caractères latins pour les encoder selon le système en vigueur dans la page Web, grâce à la
fonction utf8_encode . Nous sommes ainsi en conformité. Nous concaténons le tout avec une
balise Html <br /> pour réaliser un saut de ligne. Nous incrémentons la
variable $compteur à chaque passage et mettons fin au traitement à partir de la troisième ligne (if($compteur>2)), grâce à l'
instruction break . Après la boucle, nous n'oublions pas de libérer la mémoire en fermant le fichier désigné en paramètre de la
fonction php fclose .
Enregistrer les modifications et basculer sur le navigateur internet,
Recharger la page en validant sa barre d'adresse,
Cliquer sur le bouton Parcourir et désigner le fichier Csv ,
Cliquer ensuite sur le bouton Envoyer pour le transférer vers le serveur,
Comme vous le remarquez, les trois enregistrements sont en effet restitués sur la page Web. Il est intéressant de constater que le fichier copié, s'il existe, est écrasé automatiquement.
Insérer les données externes en base de données
Nous avons donc été en mesure d'accéder au contenu d'un fichier externe pour en récupérer la substance. Nous devons désormais exploiter ces informations, pour les insérer en
base de données . Il s'agit de techniques que nous avons déjà mises en oeuvre, notamment au travers de la
formation Php pour construire un formulaire d'inscription . C'est une
requête Sql Insert Into qui doit être exécutée par le
code Php . Mais chaque information de colonne doit être insérée dans le champ de la table qui lui correspond. Or à ce stade, nous avons bien réceptionné les enregistrements indépendamment mais pas les champs. Pour chaque ligne, nous devons donc découper l'information sur le
séparateur de liste . Il s'agit du point-virgule, typique d'un
fichier Csv .
Revenir dans le code de la boucle foreach ,
Remplacer l'instruction echo de test par les lignes suivantes :
...
foreach($lignes as $ligne)
{
$champs=explode(";",$ligne);
$le_nom = utf8_encode(str_replace("\"", "", $champs[0]));
$lactivite = utf8_encode(str_replace("\"", "", $champs[1]));
$le_dep = utf8_encode(str_replace("\"", "", $champs[2]));
$la_ville = utf8_encode(str_replace("\"", "", $champs[3]));
echo $le_nom." - ".$lactivite." - ".$le_dep." - ".$la_ville."<br/>";
$compteur++;
if($compteur>2)
break;
}
fclose($fichier_a_lire);
}
...
Pour chaque enregistrement ($ligne), nous découpons l'information sur le séparateur de liste (;) grâce à la
fonction Php explode . L'affectation produit un
tableau de variables à la volée, mémorisé sous le nom
$champs . Dès lors, nous n'avons plus qu'à accéder aux différents éléments dans l'ordre, en partant de l'indice 0.
Nous exploitons la
fonction Php utf8_encode pour gérer les accents en conformité avec le système d'encodage de la page Web. Cet encodage est défini dans une
balise meta spécifique en entête des imbrications. Nous utilisons ensuite la
fonction str_replace pour supprimer les doubles côtes dans chacun des champs. Et puis, nous effectuons un test avec la
fonction echo , en concaténant toutes ces données récupérées.
Enregistrer les modifications et basculer sur le navigateur Web,
Recharger la page en validant sa barre d'adresse avec la touche Entrée,
Cliquer sur le bouton Parcourir du formulaire,
Dans la boîte de dialogue, désigner le fichier Csv : selection-id.txt ,
Puis, cliquer sur le bouton Envoyer pour le transmettre au serveur,
A l'affichage, nous restituons toujours les trois premiers enregistrements seulement. Mais cette fois, les champs sont effectivement séparés par un tiret. Nous confirmons ainsi que nous avons isolé l'information. Et nous devons exploiter ces variables dans une
requête Sql Insert Into pour mettre à jour la
base de données ids . Là encore, il s'agit de répliquer des techniques que nous avons apprises.
Revenir dans l'éditeur de code de la page Web,
Supprimer l'instruction echo,
De même supprimer l'incrémentation du compteur,
Et enfin, supprimer le test sur la valeur du compteur (Sans oublier le break),
Remplacer la fonction utf8_encode par la fonction addslashes pour ses quatre appels,
Le système d'encodage définit dans la base de données permet de gérer les accents. Nous éliminons la
fonction utf8_encode qui servait à la restitution, à titre de test. Souvenez-vous, la
fonction Php addslashes échappe chaque caractère problématique pour une insertion en
base de données . Il s'agit notamment de l'apostrophe.
Des erreurs peuvent survenir si un enregistrement vide est trouvé. La
fonction explode sera dès lors incapable de découper l'information sur le point-virgule. En retour elle le mentionnera. Nous devons donc tester si la
variable $ligne est vide.
Englober ces lignes dans l'instruction conditionnelle suivante :
...
if($ligne<>"")
{
$champs=explode(";",$ligne);
$le_nom = addslashes (str_replace("\"", "", $champs[0]));
$lactivite = addslashes (str_replace("\"", "", $champs[1]));
$le_dep = addslashes (str_replace("\"", "", $champs[2]));
$la_ville = addslashes (str_replace("\"", "", $champs[3]));
}
...
Il ne reste plus qu'à ajouter ces données dans la base. Pour cela, comme nous l'avons appris, nous devons exécuter une
requête Sql Insert Into .
A la fin de l'instruction conditionnelle, ajouter les lignes Php suivantes :
...
<div class="colonne" id="colonne_gauche">
<?php
if(isset($_FILES["fichier"]["tmp_name"]))
{
$nom_fichier_tmp = $_FILES["fichier"]["tmp_name"];
copy($nom_fichier_tmp, "ressources/pour_import.txt");
$fichier_a_lire = fopen("ressources/pour_import.txt", "r");
$taille = strlen(file_get_contents("ressources/pour_import.txt"));
$lecture = fread($fichier_a_lire, $taille);
$lignes = explode("\n",$lecture);
$compteur=0;
foreach($lignes as $ligne)
{
if($ligne<>"")
{
$champs = explode(";",$ligne);
$le_nom = addslashes(str_replace("\"", "", $champs[0]));
$lactivite = addslashes(str_replace("\"", "", $champs[1]));
$le_dep = addslashes(str_replace("\"", "", $champs[2]));
$la_ville = addslashes(str_replace("\"", "", $champs[3]));
$requete = "INSERT INTO liste_id(liste_nom, liste_activite, liste_dep, liste_ville) VALUES
('".$le_nom."', '".$lactivite."', '".$le_dep."', '".$la_ville."')";
if(mysqli_query($liaison, $requete) or die ("Problème avec la requête"))
$compteur++;
}
}
fclose($fichier_a_lire);
if($compteur>0)
echo $compteur." enregistrements ont été ajoutés dans la base de données";
}
?>
</div>
<div class="colonne" id="colonne_droite">
...
La syntaxe est bien connue désormais. La
clause Insert Into est suivie du nom de la table dans laquelle doivent être insérées les données. Puis, entre parenthèses, sont énumérés les champs de destination. Après la
clause VALUES sont énumérées les variables à y insérer respectivement. Prenez soin de bien les encadrer de simples côtes. Il s'agit d'informations textuelles. C'est la
fonction Php mysqli_query qui permet d'exécuter cette requête passée en second paramètre. En premier paramètre, nous lui passons la
chaîne de connexion désignant la
base de données et offrant les
droits administrateurs . Cette fonction est booléenne. Nous la testons et à chaque succès nous incrémentons la
variable $compteur . Et puis, nous l'exploitons en dehors de la boucle pour retourner l'information à l'utilisateur.
Enregistrer les modifications et basculer sur le navigateur Web,
Recharger la page en validant sa barre d'adresse,
Désigner le fichier CSV avec la liste déroulante puis soumettre le formulaire,
Comme vous le constatez, l'opération semble s'être déroulée avec succès. Pour le vérifier, nous proposons d'accéder à l'interface de
PhpMyAdmin .
Dans PhpMyAdmin , afficher le contenu de la table liste_id ,
En effet, nous avons parfaitement simulé l'insertion automatique d'enregistrements, issus d'une
source externe Csv .