csvparser.class.inc.php 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. <?php
  2. /**
  3. * CSVParser
  4. * CSV interpreter helper, optionaly tries to guess column mapping and the separator, check the consistency
  5. *
  6. * @package iTopORM
  7. * @author Romain Quetiez <romainquetiez@yahoo.fr>
  8. * @author Denis Flaven <denisflave@free.fr>
  9. * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
  10. * @link www.itop.com
  11. * @since 1.0
  12. * @version 1.1.1.1 $
  13. */
  14. class CSVParserException extends CoreException
  15. {
  16. }
  17. /**
  18. * CSVParser
  19. *
  20. * @package iTopORM
  21. * @author Romain Quetiez <romainquetiez@yahoo.fr>
  22. * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
  23. * @link www.itop.com
  24. * @since 1.0
  25. * @version $itopversion$
  26. */
  27. class CSVParser
  28. {
  29. private $m_sCSVData;
  30. private $m_sSep;
  31. private $m_iSkip;
  32. public function __construct($sTxt)
  33. {
  34. $this->m_sCSVData = $sTxt;
  35. }
  36. public function SetSeparator($sSep)
  37. {
  38. $this->m_sSep = $sSep;
  39. }
  40. public function GetSeparator()
  41. {
  42. return $this->m_sSep;
  43. }
  44. public function SetSkipLines($iSkip)
  45. {
  46. $this->m_iSkip = $iSkip;
  47. }
  48. public function GetSkipLines()
  49. {
  50. return $this->m_iSkip;
  51. }
  52. public function GuessSeparator()
  53. {
  54. // Note: skip the first line anyway
  55. $aKnownSeps = array(';', ',', "\t"); // Use double quote for special chars!!!
  56. $aStatsBySeparator = array();
  57. foreach ($aKnownSeps as $sSep)
  58. {
  59. $aStatsBySeparator[$sSep] = array();
  60. }
  61. foreach(split("\n", $this->m_sCSVData) as $sLine)
  62. {
  63. $sLine = trim($sLine);
  64. if (substr($sLine, 0, 1) == '#') continue;
  65. if (empty($sLine)) continue;
  66. $aLineCharsCount = count_chars($sLine, 0);
  67. foreach ($aKnownSeps as $sSep)
  68. {
  69. $aStatsBySeparator[$sSep][] = $aLineCharsCount[ord($sSep)];
  70. }
  71. }
  72. // Default to ','
  73. $this->SetSeparator(",");
  74. foreach ($aKnownSeps as $sSep)
  75. {
  76. // Note: this function is NOT available :-(
  77. // stats_variance($aStatsBySeparator[$sSep]);
  78. $iMin = min($aStatsBySeparator[$sSep]);
  79. $iMax = max($aStatsBySeparator[$sSep]);
  80. if (($iMin == $iMax) && ($iMax > 0))
  81. {
  82. $this->SetSeparator($sSep);
  83. break;
  84. }
  85. }
  86. return $this->GetSeparator();
  87. }
  88. public function GuessSkipLines()
  89. {
  90. // Take the FIRST -valuable- LINE ONLY
  91. // If there is a number, then for sure this is not a header line
  92. // Otherwise, we may consider that there is one line to skip
  93. foreach(split("\n", $this->m_sCSVData) as $sLine)
  94. {
  95. $sLine = trim($sLine);
  96. if (substr($sLine, 0, 1) == '#') continue;
  97. if (empty($sLine)) continue;
  98. foreach (split($this->m_sSep, $sLine) as $value)
  99. {
  100. if (is_numeric($value))
  101. {
  102. $this->SetSkipLines(0);
  103. return 0;
  104. }
  105. }
  106. $this->SetSkipLines(1);
  107. return 1;
  108. }
  109. }
  110. function ToArray($aFieldMap = null, $iMax = 0)
  111. {
  112. // $aFieldMap is an array of col_index=>col_name
  113. // $iMax is to limit the count of rows computed
  114. $aRes = array();
  115. $iCount = 0;
  116. $iSkipped = 0;
  117. foreach(split("\n", $this->m_sCSVData) as $sLine)
  118. {
  119. $sLine = trim($sLine);
  120. if (substr($sLine, 0, 1) == '#') continue;
  121. if (empty($sLine)) continue;
  122. if ($iSkipped < $this->m_iSkip)
  123. {
  124. $iSkipped++;
  125. continue;
  126. }
  127. foreach (split($this->m_sSep, $sLine) as $iCol=>$sValue)
  128. {
  129. if (is_array($aFieldMap)) $sColRef = $aFieldMap[$iCol];
  130. else $sColRef = $iCol;
  131. $aRes[$iCount][$sColRef] = $sValue;
  132. }
  133. $iCount++;
  134. if (($iMax > 0) && ($iCount >= $iMax)) break;
  135. }
  136. return $aRes;
  137. }
  138. public function ListFields()
  139. {
  140. // Take the first valuable line
  141. foreach(explode("\n", $this->m_sCSVData) as $sLine)
  142. {
  143. $sLine = trim($sLine);
  144. if (substr($sLine, 0, 1) == '#') continue;
  145. if (empty($sLine)) continue;
  146. // We've got the first valuable line, that's it!
  147. break;
  148. }
  149. $aRet = array();
  150. foreach (explode($this->m_sSep, $sLine) as $iCol=>$value)
  151. {
  152. if ($this->m_iSkip == 0)
  153. {
  154. // No header to help us
  155. $sLabel = "field $iCol";
  156. }
  157. else
  158. {
  159. $sLabel = "$value";
  160. }
  161. $aRet[] = $sLabel;
  162. }
  163. return $aRet;
  164. }
  165. }
  166. ?>