[SPIP] v3.2.1-->v3.2.2
[lhc/web/www.git] / www / ecrire / inc / csv.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2019 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
8 * *
9 * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
10 * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
11 \***************************************************************************/
12
13 /**
14 * Analyse de fichiers CSV
15 *
16 * @package SPIP\Core\CSV
17 */
18
19 if (!defined('_ECRIRE_INC_VERSION')) {
20 return;
21 }
22
23 /**
24 * Retourne les données d'un texte au format CSV
25 *
26 * @param string $t
27 * Contenu du CSV
28 * @return array
29 * Tableau des données en 3 index :
30 * - Liste des noms des colonnes
31 * - Liste des valeurs de chaque ligne et chaque colonne
32 * - Titre du tableau (si une seule colonne)
33 **/
34 function analyse_csv($t) {
35
36 // Quel est le séparateur ?
37 $virg = substr_count($t, ',');
38 $pvirg = substr_count($t, ';');
39 $tab = substr_count($t, "\t");
40 if ($virg > $pvirg) {
41 $sep = ',';
42 $hs = '&#44;';
43 } else {
44 $sep = ';';
45 $hs = '&#59;';
46 $virg = $pvirg;
47 }
48 // un certain nombre de tab => le séparateur est tab
49 if ($tab > $virg / 10) {
50 $sep = "\t";
51 $hs = "\t";
52 }
53
54 // un separateur suivi de 3 guillemets attention !
55 // attention au ; ou , suceptible d'etre confondu avec un separateur
56 // on substitue un # et on remplacera a la fin
57 $t = preg_replace("/([\n$sep])\"\"\"/", '\\1"&#34#', $t);
58 $t = str_replace('""', '&#34#', $t);
59 preg_match_all('/"[^"]*"/', $t, $r);
60 foreach ($r[0] as $cell) {
61 $t = str_replace($cell,
62 str_replace($sep, $hs,
63 str_replace("\n", "``**``", // échapper les saut de lignes, on les remettra après.
64 substr($cell, 1, -1))),
65 $t);
66 }
67
68 $t = preg_replace('/\r?\n/', "\n",
69 preg_replace('/[\r\n]+/', "\n", $t));
70
71 list($entete, $corps) = explode("\n", $t, 2);
72 $caption = '';
73 // sauter la ligne de tete formee seulement de separateurs
74 if (substr_count($entete, $sep) == strlen($entete)) {
75 list($entete, $corps) = explode("\n", $corps, 2);
76 }
77 // si une seule colonne, en faire le titre
78 if (preg_match("/^([^$sep]+)$sep+\$/", $entete, $l)) {
79 $caption = "\n||" . $l[1] . "|";
80 list($entete, $corps) = explode("\n", $corps, 2);
81 }
82 // si premiere colonne vide, le raccourci doit quand meme produire <th...
83 if ($entete[0] == $sep) {
84 $entete = ' ' . $entete;
85 }
86
87 $lignes = explode("\n", $corps);
88
89 // retrait des lignes vides finales
90 while (count($lignes) > 0
91 and preg_match("/^$sep*$/", $lignes[count($lignes) - 1])) {
92 unset($lignes[count($lignes) - 1]);
93 }
94 // calcul du nombre de colonne a chaque ligne
95 $nbcols = array();
96 $max = $mil = substr_count($entete, $sep);
97 foreach ($lignes as $k => $v) {
98 if ($max <> ($nbcols[$k] = substr_count($v, $sep))) {
99 if ($max > $nbcols[$k]) {
100 $mil = $nbcols[$k];
101 } else {
102 $mil = $max;
103 $max = $nbcols[$k];
104 }
105 }
106 }
107 // Si pas le meme nombre, cadrer au nombre max
108 if ($mil <> $max) {
109 foreach ($nbcols as $k => $v) {
110 if ($v < $max) {
111 $lignes[$k] .= str_repeat($sep, $max - $v);
112 }
113 }
114 }
115 // et retirer les colonnes integralement vides
116 while (true) {
117 $nbcols = ($entete[strlen($entete) - 1] === $sep);
118 foreach ($lignes as $v) {
119 $nbcols &= ($v[strlen($v) - 1] === $sep);
120 }
121 if (!$nbcols) {
122 break;
123 }
124 $entete = substr($entete, 0, -1);
125 foreach ($lignes as $k => $v) {
126 $lignes[$k] = substr($v, 0, -1);
127 }
128 }
129
130 foreach ($lignes as &$l) {
131 $l = str_replace('&#34#','"',$l);
132 $l = str_replace('``**``',"\n",$l);
133 $l = explode($sep, $l);
134 }
135
136 return array(explode($sep, $entete), $lignes, $caption);
137 }