2
0

simpleCSV.class.php 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. <?php
  2. /**
  3. * Classe simpleCSV
  4. *
  5. * Cette classe permet de manipuler des fichiers CSV, notamment pour les importer
  6. * et les exporter sous forme de tableaux associatifs.
  7. */
  8. class simpleCSV
  9. {
  10. /**
  11. * Délimiteur utilisé dans le fichier CSV.
  12. * @var string
  13. */
  14. private $_delimiter;
  15. /**
  16. * Caractère d'encadrement utilisé dans le fichier CSV.
  17. * @var string
  18. */
  19. private $_enclosure;
  20. /**
  21. * Caractère de saut de ligne utilisé dans le fichier CSV.
  22. * @var string
  23. */
  24. private $_linebreak;
  25. /**
  26. * Contenu du fichier CSV.
  27. * @var string
  28. */
  29. private $_csv = '';
  30. /**
  31. * Importe un fichier CSV ou une chaîne CSV en tableau associatif.
  32. *
  33. * @param string $filename_or_data Chemin du fichier ou contenu CSV.
  34. * @param bool $is_data Indique si l'entrée est une chaîne CSV (true) ou un fichier (false).
  35. * @param string $delimiter Délimiteur à utiliser (par défaut : auto).
  36. * @param string $enclosure Caractère d'encadrement à utiliser (par défaut : auto).
  37. * @param string $linebreak Caractère de saut de ligne à utiliser (par défaut : auto).
  38. * @return array Tableau associatif représentant le contenu du CSV.
  39. */
  40. public static function import($filename_or_data, $is_data = false, $delimiter = 'auto', $enclosure = 'auto', $linebreak = 'auto')
  41. {
  42. $csv = new static($delimiter, $enclosure, $linebreak);
  43. return $csv->toArray($filename_or_data, $is_data);
  44. }
  45. /**
  46. * Exporte un tableau associatif en chaîne CSV.
  47. *
  48. * @param array $items Tableau associatif à exporter.
  49. * @param string $delimiter Délimiteur à utiliser (par défaut : ,).
  50. * @param string $enclosure Caractère d'encadrement à utiliser (par défaut : ").
  51. * @param string $linebreak Caractère de saut de ligne à utiliser (par défaut : \r\n).
  52. * @return string Chaîne CSV générée.
  53. */
  54. public static function export($items, $delimiter = ',', $enclosure = '"', $linebreak = "\r\n")
  55. {
  56. $csv = new static($delimiter, $enclosure, $linebreak);
  57. return $csv->fromArray($items);
  58. }
  59. /**
  60. * Constructeur de la classe simpleCSV.
  61. *
  62. * @param string $delimiter Délimiteur à utiliser (par défaut : auto).
  63. * @param string $enclosure Caractère d'encadrement à utiliser (par défaut : auto).
  64. * @param string $linebreak Caractère de saut de ligne à utiliser (par défaut : auto).
  65. */
  66. public function __construct($delimiter = 'auto', $enclosure = 'auto', $linebreak = 'auto')
  67. {
  68. $this->_delimiter = $delimiter;
  69. $this->_enclosure = $enclosure;
  70. $this->_linebreak = $linebreak;
  71. }
  72. /**
  73. * Définit ou détecte automatiquement le délimiteur utilisé dans le CSV.
  74. *
  75. * @param string|bool $set Délimiteur à définir ou false pour détecter automatiquement.
  76. * @return string Délimiteur utilisé.
  77. */
  78. public function delimiter($set = false)
  79. {
  80. if ($set !== false) {
  81. return $this->_delimiter = $set;
  82. }
  83. if ($this->_delimiter === 'auto') {
  84. // detect delimiter
  85. if (strpos($this->_csv, $this->_enclosure . ',') !== false) {
  86. $this->_delimiter = ',';
  87. } else if (strpos($this->_csv, $this->_enclosure . "\t") !== false) {
  88. $this->_delimiter = "\t";
  89. } else if (strpos($this->_csv, $this->_enclosure . ';') !== false) {
  90. $this->_delimiter = ';';
  91. } else if (strpos($this->_csv, ',') !== false) {
  92. $this->_delimiter = ',';
  93. } else if (strpos($this->_csv, "\t") !== false) {
  94. $this->_delimiter = "\t";
  95. } else if (strpos($this->_csv, ';') !== false) {
  96. $this->_delimiter = ';';
  97. } else {
  98. $this->_delimiter = ',';
  99. }
  100. }
  101. return $this->_delimiter;
  102. }
  103. /**
  104. * Définit ou détecte automatiquement le caractère d'encadrement utilisé dans le CSV.
  105. *
  106. * @param string|bool $set Caractère d'encadrement à définir ou false pour détecter automatiquement.
  107. * @return string Caractère d'encadrement utilisé.
  108. */
  109. public function enclosure($set = false)
  110. {
  111. if ($set !== false) {
  112. return $this->_enclosure = $set;
  113. }
  114. if ($this->_enclosure === 'auto') {
  115. // detect quot
  116. if (strpos($this->_csv, '"') !== false) {
  117. $this->_enclosure = '"';
  118. } else if (strpos($this->_csv, "'") !== false) {
  119. $this->_enclosure = "'";
  120. } else {
  121. $this->_enclosure = '"';
  122. }
  123. }
  124. return $this->_enclosure;
  125. }
  126. /**
  127. * Définit ou détecte automatiquement le caractère de saut de ligne utilisé dans le CSV.
  128. *
  129. * @param string|bool $set Caractère de saut de ligne à définir ou false pour détecter automatiquement.
  130. * @return string Caractère de saut de ligne utilisé.
  131. */
  132. public function linebreak($set = false)
  133. {
  134. if ($set !== false) {
  135. return $this->_linebreak = $set;
  136. }
  137. if ($this->_linebreak === 'auto') {
  138. if (strpos($this->_csv, "\r\n") !== false) {
  139. $this->_linebreak = "\r\n";
  140. } else if (strpos($this->_csv, "\n") !== false) {
  141. $this->_linebreak = "\n";
  142. } else if (strpos($this->_csv, "\r") !== false) {
  143. $this->_linebreak = "\r";
  144. } else {
  145. $this->_linebreak = "\r\n";
  146. }
  147. }
  148. return $this->_linebreak;
  149. }
  150. /**
  151. * Convertit un fichier ou une chaîne CSV en tableau associatif.
  152. *
  153. * @param string $filename Chemin du fichier ou contenu CSV.
  154. * @param bool $is_csv_content Indique si l'entrée est une chaîne CSV (true) ou un fichier (false).
  155. * @return array Tableau associatif représentant le contenu du CSV.
  156. */
  157. public function toArray($filename, $is_csv_content = false)
  158. {
  159. $this->_csv = $is_csv_content ? $filename : file_get_contents($filename);
  160. $CSV_LINEBREAK = $this->linebreak();
  161. $CSV_ENCLOSURE = $this->enclosure();
  162. $CSV_DELIMITER = $this->delimiter();
  163. $r = array();
  164. $cnt = strlen($this->_csv);
  165. $esc = false;
  166. $i = $k = $n = 0;
  167. $r[$k][$n] = '';
  168. while ($i < $cnt) {
  169. $ch = $this->_csv[$i];
  170. $chch = ($i < $cnt - 1) ? $ch . $this->_csv[$i + 1] : $ch;
  171. if ($ch === $CSV_LINEBREAK) {
  172. if ($esc) {
  173. $r[$k][$n] .= $ch;
  174. } else {
  175. $k++;
  176. $n = 0;
  177. $esc = false;
  178. $r[$k][$n] = '';
  179. }
  180. } else if ($chch === $CSV_LINEBREAK) {
  181. if ($esc) {
  182. $r[$k][$n] .= $chch;
  183. } else {
  184. $k++;
  185. $n = 0;
  186. $esc = false;
  187. $r[$k][$n] = '';
  188. }
  189. $i++;
  190. } else if ($ch === $CSV_DELIMITER) {
  191. if ($esc) {
  192. $r[$k][$n] .= $ch;
  193. } else {
  194. $n++;
  195. $r[$k][$n] = '';
  196. $esc = false;
  197. }
  198. } else if ($chch === $CSV_ENCLOSURE . $CSV_ENCLOSURE && $esc) {
  199. $r[$k][$n] .= $CSV_ENCLOSURE;
  200. $i++;
  201. } elseif ($ch === $CSV_ENCLOSURE) {
  202. $esc = !$esc;
  203. } else {
  204. $r[$k][$n] .= $ch;
  205. }
  206. $i++;
  207. }
  208. return $r;
  209. }
  210. /**
  211. * Convertit un tableau associatif en chaîne CSV.
  212. *
  213. * @param array $items Tableau associatif à convertir.
  214. * @return string Chaîne CSV générée.
  215. */
  216. public function fromArray($items)
  217. {
  218. if (!is_array($items)) {
  219. trigger_error('CSV::export array required', E_USER_WARNING);
  220. return false;
  221. }
  222. $CSV_DELIMITER = $this->delimiter();
  223. $CSV_ENCLOSURE = $this->enclosure();
  224. $CSV_LINEBREAK = $this->linebreak();
  225. $result = '';
  226. foreach ($items as $i) {
  227. $line = '';
  228. foreach ($i as $v) {
  229. if (strpos($v, $CSV_ENCLOSURE) !== false) {
  230. $v = str_replace($CSV_ENCLOSURE, $CSV_ENCLOSURE . $CSV_ENCLOSURE, $v);
  231. }
  232. if ((strpos($v, $CSV_DELIMITER) !== false) || (strpos($v, $CSV_ENCLOSURE) !== false) || (strpos($v, $CSV_LINEBREAK) !== false)) {
  233. $v = $CSV_ENCLOSURE . $v . $CSV_ENCLOSURE;
  234. }
  235. $line .= $line ? $CSV_DELIMITER . $v : $v;
  236. }
  237. $result .= $result ? $CSV_LINEBREAK . $line : $line;
  238. }
  239. return $result;
  240. }
  241. }