Les bases de la manipulation de fichiers CSV en PHP
Le format CSV (Comma-Separated Values) est un standard incontournable pour l’échange de données. Que ce soit pour migrer une base de données, synchroniser un catalogue de produits ou générer des rapports pour des clients, la gestion données CSV fait partie du quotidien des développeurs.
PHP propose des fonctions natives extrêmement performantes pour traiter ces fichiers sans avoir besoin de charger des bibliothèques externes lourdes. Le secret d’une bonne manipulation réside dans l’utilisation des pointeurs de fichiers (fopen) associés aux fonctions dédiées fgetcsv et fputcsv, qui gèrent automatiquement les complexités liées aux guillemets et aux retours à la ligne présents dans les données.
Lire et réaliser un import CSV PHP
Pour lire un fichier CSV, la pire approche consisterait à charger tout le fichier en mémoire avec file_get_contents puis à utiliser explode. Cette méthode est non seulement gourmande en mémoire, mais elle échouera dès qu’une cellule contiendra le caractère délimiteur.
La bonne pratique consiste à lire le fichier ligne par ligne à l’aide de fgetcsv().
Utiliser la fonction fgetcsv
La fonction fgetcsv lit une ligne depuis le pointeur de fichier, l’analyse selon le format CSV, et retourne un tableau contenant les champs lus. Voici comment mettre en place un script d’importation robuste.
<?php
$fichier = 'utilisateurs.csv';
// Ouverture du fichier en mode lecture ('r')
if (($handle = fopen($fichier, 'r')) !== false) {
// Lecture ligne par ligne jusqu'à la fin du fichier
// fgetcsv retourne un tableau, ou false à la fin du fichier
while (($donnees = fgetcsv($handle, 1000, ',')) !== false) {
// $donnees est un tableau numérique représentant une ligne
$nom = $donnees[0];
$email = $donnees[1];
$role = $donnees[2];
// Exemple d'insertion en base de données ou de traitement
echo "Importation de : $nom ($email)n";
}
// Toujours fermer le pointeur de fichier pour libérer les ressources
fclose($handle);
} else {
echo "Erreur : Impossible d'ouvrir le fichier CSV.";
}
?>
Dans cet exemple, le deuxième paramètre (1000) correspond à la longueur maximale attendue d’une ligne. Définir cette limite (bien qu’optionnelle depuis PHP 5.1) permet d’optimiser légèrement les performances. Le troisième paramètre (',') est le délimiteur.
Créer et gérer un export CSV PHP
L’opération inverse, la création d’un fichier CSV, suit la même logique de flux. Nous ouvrons un fichier en mode écriture (w) et nous utilisons fputcsv() pour formater automatiquement un tableau PHP en ligne CSV.
Écrire des données dans un fichier physique
Voici comment générer un fichier sur le serveur à partir d’un tableau multidimensionnel.
<?php
$utilisateurs = [
['Nom', 'Email', 'Rôle'], // En-têtes du CSV
['Jean Dupont', 'jean@example.com', 'Admin'],
['Marie Curie', 'marie@example.com', 'Utilisateur'],
['Alan Turing', 'alan@example.com', 'Utilisateur']
];
$nomFichier = 'export_utilisateurs.csv';
// Ouverture en mode écriture ('w')
if (($handle = fopen($nomFichier, 'w')) !== false) {
foreach ($utilisateurs as $ligne) {
// fputcsv formate le tableau et l'écrit dans le fichier
fputcsv($handle, $ligne, ',');
}
fclose($handle);
echo "Fichier exporté avec succès.";
}
?>
Générer un téléchargement direct (sans sauvegarde sur le serveur)
Il est très fréquent de vouloir proposer un export CSV PHP directement en téléchargement au clic d’un bouton, sans encombrer l’espace disque du serveur. Pour cela, nous combinons la modification des en-têtes HTTP avec le flux de sortie standard de PHP : php://output.
<?php
// Forcer le téléchargement via les headers HTTP
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="rapport.csv"');
// Ouvrir le flux de sortie direct
$output = fopen('php://output', 'w');
// Écrire les en-têtes de colonnes
fputcsv($output, ['ID', 'Produit', 'Prix']);
// Récupération des données (ex: depuis une BDD)
$produits = [
[1, 'Clavier mécanique', '89.99'],
[2, 'Souris sans fil', '45.50']
];
// Écrire les données
foreach ($produits as $produit) {
fputcsv($output, $produit, ';'); // Utilisation du point-virgule pour Excel
}
fclose($output);
exit; // Terminer le script proprement
?>
Gérer les spécificités et les erreurs fréquentes
Manipuler des fichiers CSV PHP semble simple, mais la réalité des données utilisateurs impose de gérer quelques cas particuliers fréquents.
Le problème du délimiteur (Virgule vs Point-virgule)
Par défaut, le standard CSV utilise la virgule (,). Cependant, des logiciels comme Microsoft Excel en version française utilisent le point-virgule (;) pour éviter les conflits avec la virgule des nombres décimaux. Il est crucial d’adapter le troisième paramètre de fgetcsv ou fputcsv selon la source ou la destination de votre fichier.
Gérer l’encodage et le BOM UTF-8
Un problème classique lors d’un parser CSV PHP est l’apparition de caractères étranges (comme ) au début de la première cellule lue. Il s’agit du BOM (Byte Order Mark) d’un fichier enregistré en UTF-8 avec BOM.
Pour nettoyer cette première cellule lors de la lecture, vous pouvez utiliser une simple substitution de chaîne :
<?php
$premiereLigne = fgetcsv($handle, 1000, ';');
// Supprimer le BOM UTF-8 invisible de la première colonne
if (isset($premiereLigne[0])) {
$premiereLigne[0] = preg_replace('/x{FEFF}/u', '', $premiereLigne[0]);
}
?>
Optimiser le traitement des gros fichiers avec les Générateurs
Si vous devez traiter un fichier CSV contenant des centaines de milliers de lignes, stocker les résultats dans un tableau intermédiaire provoquera une erreur fatale liée à la limite de mémoire (Allowed memory size of X bytes exhausted).
La solution moderne consiste à utiliser les Générateurs PHP (le mot-clé yield). Cela permet d’itérer sur le fichier tout en ne conservant qu’une seule ligne en mémoire à la fois.
<?php
function lireGrosFichierCsv($chemin) {
if (($handle = fopen($chemin, 'r')) !== false) {
while (($ligne = fgetcsv($handle, 0, ';')) !== false) {
yield $ligne; // Retourne la ligne et met la fonction en pause
}
fclose($handle);
}
}
// Utilisation
foreach (lireGrosFichierCsv('gros_fichier_catalogue.csv') as $index => $donnees) {
// Traitement ligne par ligne (ex: appel API, insert DB)
// La mémoire reste stable peu importe la taille du fichier
}
?>
Cette approche garantit des scripts d’importation stables, prévisibles et hautement performants, même sur des serveurs disposant de ressources limitées.


