PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/htdocs/core/modules/import/import_csv.modules.php

https://github.com/asterix14/dolibarr
PHP | 467 lines | 297 code | 62 blank | 108 comment | 42 complexity | 64cff364beae5f536d36bda65c8fd194 MD5 | raw file
Possible License(s): LGPL-2.0
  1. <?php
  2. /* Copyright (C) 2006-2009 Laurent Destailleur <eldy@users.sourceforge.net>
  3. * Copyright (C) 2009-2010 Regis Houssin <regis@dolibarr.fr>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. * or see http://www.gnu.org/
  18. */
  19. /**
  20. * \file htdocs/core/modules/import/import_csv.modules.php
  21. * \ingroup import
  22. * \brief File to load import files with CSV format
  23. * \author Laurent Destailleur
  24. */
  25. require_once(DOL_DOCUMENT_ROOT ."/core/modules/import/modules_import.php");
  26. /**
  27. * \class ImportCsv
  28. * \brief Classe permettant de lire les fichiers imports CSV
  29. */
  30. class ImportCsv extends ModeleImports
  31. {
  32. var $id;
  33. var $error;
  34. var $errors=array();
  35. var $label;
  36. var $extension;
  37. var $version;
  38. var $label_lib;
  39. var $version_lib;
  40. var $separator;
  41. var $handle; // Handle fichier
  42. var $cachefieldtable=array(); // Array to cache list of value into fields@tables
  43. /**
  44. * \brief Constructeur
  45. * \param db Handler acces base de donnee
  46. */
  47. function ImportCsv($db)
  48. {
  49. global $conf,$langs;
  50. $this->db = $db;
  51. $this->separator=','; // Change also function cleansep
  52. if (! empty($conf->global->IMPORT_CSV_SEPARATOR_TO_USE)) $this->separator=$conf->global->IMPORT_CSV_SEPARATOR_TO_USE;
  53. $this->enclosure='"';
  54. $this->escape='"';
  55. $this->id='csv'; // Same value then xxx in file name export_xxx.modules.php
  56. $this->label='Csv'; // Label of driver
  57. $this->desc=$langs->trans("CSVFormatDesc",$this->separator,$this->enclosure,$this->escape);
  58. $this->extension='csv'; // Extension for generated file by this driver
  59. $this->picto='mime/other'; // Picto
  60. $this->version='1.34'; // Driver version
  61. // If driver use an external library, put its name here
  62. $this->label_lib='Dolibarr';
  63. $this->version_lib=DOL_VERSION;
  64. }
  65. function getDriverId()
  66. {
  67. return $this->id;
  68. }
  69. function getDriverLabel()
  70. {
  71. return $this->label;
  72. }
  73. function getDriverDesc()
  74. {
  75. return $this->desc;
  76. }
  77. function getDriverExtension()
  78. {
  79. return $this->extension;
  80. }
  81. function getDriverVersion()
  82. {
  83. return $this->version;
  84. }
  85. function getLibLabel()
  86. {
  87. return $this->label_lib;
  88. }
  89. function getLibVersion()
  90. {
  91. return $this->version_lib;
  92. }
  93. /**
  94. * Output header of an example file for this format
  95. * @param outputlangs Output language
  96. */
  97. function write_header_example($outputlangs)
  98. {
  99. return '';
  100. }
  101. /**
  102. * Output title line of an example file for this format
  103. * @param outputlangs Output language
  104. */
  105. function write_title_example($outputlangs,$headerlinefields)
  106. {
  107. $s.=join($this->separator,array_map('cleansep',$headerlinefields));
  108. return $s."\n";
  109. }
  110. /**
  111. * Output record of an example file for this format
  112. * @param outputlangs Output language
  113. */
  114. function write_record_example($outputlangs,$contentlinevalues)
  115. {
  116. $s=join($this->separator,array_map('cleansep',$contentlinevalues));
  117. return $s."\n";
  118. }
  119. /**
  120. * Output footer of an example file for this format
  121. * @param outputlangs Output language
  122. */
  123. function write_footer_example($outputlangs)
  124. {
  125. return '';
  126. }
  127. /**
  128. * Open input file
  129. * @param file Path of filename
  130. * @return int <0 if KO, >=0 if OK
  131. */
  132. function import_open_file($file)
  133. {
  134. global $langs;
  135. $ret=1;
  136. dol_syslog("ImportCsv::open_file file=".$file);
  137. ini_set('auto_detect_line_endings',1); // For MAC compatibility
  138. $this->handle = fopen(dol_osencode($file), "r");
  139. if (! $this->handle)
  140. {
  141. $langs->load("errors");
  142. $this->error=$langs->trans("ErrorFailToOpenFile",$file);
  143. $ret=-1;
  144. }
  145. else
  146. {
  147. $this->file=$file;
  148. }
  149. return $ret;
  150. }
  151. /**
  152. * \brief Input header line from file
  153. */
  154. function import_read_header()
  155. {
  156. return 0;
  157. }
  158. /**
  159. * \brief Return array of next record in input file.
  160. * \return Array Array of field values. Data are UTF8 encoded.
  161. * [0] => (['val']=>val, ['type']=>-1=null,0=blank,1=string)
  162. */
  163. function import_read_record()
  164. {
  165. global $conf;
  166. $arrayres=array();
  167. if (version_compare(phpversion(), '5.3') < 0)
  168. {
  169. $arrayres=fgetcsv($this->handle,100000,$this->separator,$this->enclosure);
  170. }
  171. else
  172. {
  173. $arrayres=fgetcsv($this->handle,100000,$this->separator,$this->enclosure,$this->escape);
  174. }
  175. //var_dump($this->handle);
  176. //var_dump($arrayres);exit;
  177. $newarrayres=array();
  178. if ($arrayres && is_array($arrayres))
  179. {
  180. foreach($arrayres as $key => $val)
  181. {
  182. if (! empty($conf->global->IMPORT_CSV_FORCE_CHARSET)) // Forced charset
  183. {
  184. if (strtolower($conf->global->IMPORT_CSV_FORCE_CHARSET) == 'utf8')
  185. {
  186. $newarrayres[$key]['val']=$val;
  187. $newarrayres[$key]['type']=(dol_strlen($val)?1:-1); // If empty we considere it's null
  188. }
  189. else
  190. {
  191. $newarrayres[$key]['val']=utf8_encode($val);
  192. $newarrayres[$key]['type']=(dol_strlen($val)?1:-1); // If empty we considere it's null
  193. }
  194. }
  195. else // Autodetect format (UTF8 or ISO)
  196. {
  197. if (utf8_check($val))
  198. {
  199. $newarrayres[$key]['val']=$val;
  200. $newarrayres[$key]['type']=(dol_strlen($val)?1:-1); // If empty we considere it's null
  201. }
  202. else
  203. {
  204. $newarrayres[$key]['val']=utf8_encode($val);
  205. $newarrayres[$key]['type']=(dol_strlen($val)?1:-1); // If empty we considere it's null
  206. }
  207. }
  208. }
  209. $this->col=count($newarrayres);
  210. }
  211. return $newarrayres;
  212. }
  213. /**
  214. * \brief Close file handle
  215. */
  216. function import_close_file()
  217. {
  218. fclose($this->handle);
  219. return 0;
  220. }
  221. /**
  222. * Insert a record into database
  223. * @param arrayrecord Array of field values
  224. * @param array_match_file_to_database
  225. * @param objimport
  226. * @param maxfields Max number of fiels to use
  227. * @return int <0 if KO, >0 if OK
  228. */
  229. function import_insert($arrayrecord,$array_match_file_to_database,$objimport,$maxfields,$importid)
  230. {
  231. global $langs,$conf,$user;
  232. $error=0;
  233. $warning=0;
  234. $this->errors=array();
  235. $this->warnings=array();
  236. //dol_syslog("import_csv.modules maxfields=".$maxfields." importid=".$importid);
  237. //var_dump($array_match_file_to_database);
  238. //var_dump($arrayrecord);
  239. $array_match_database_to_file=array_flip($array_match_file_to_database);
  240. $sort_array_match_file_to_database=$array_match_file_to_database;
  241. ksort($sort_array_match_file_to_database);
  242. //var_dump($sort_array_match_file_to_database);
  243. if (count($arrayrecord) == 0 ||
  244. (count($arrayrecord) == 1 && empty($arrayrecord[0]['val'])))
  245. {
  246. //print 'W';
  247. $this->warnings[$warning]['lib']=$langs->trans('EmptyLine');
  248. $this->warnings[$warning]['type']='EMPTY';
  249. $warning++;
  250. }
  251. else
  252. {
  253. // For each table to insert, me make a separate insert
  254. foreach($objimport->array_import_tables[0] as $alias => $tablename)
  255. {
  256. // Build sql request
  257. $sql='';
  258. $listfields='';
  259. $listvalues='';
  260. $i=0;
  261. $errorforthistable=0;
  262. // Loop on each fields in the match array ($key = 1..n, $val=alias of field)
  263. foreach($sort_array_match_file_to_database as $key => $val)
  264. {
  265. if ($key <= $maxfields)
  266. {
  267. if ($listfields) { $listfields.=', '; $listvalues.=', '; }
  268. $listfields.=preg_replace('/^.*\./i','',$val);
  269. $newval='';
  270. if ($arrayrecord[($key-1)]['type'] < 0)
  271. {
  272. $listvalues.="null";
  273. }
  274. else if ($arrayrecord[($key-1)]['type'] == 0)
  275. {
  276. $listvalues.="''";
  277. }
  278. else if ($arrayrecord[($key-1)]['type'] > 0)
  279. {
  280. $newval=$arrayrecord[($key-1)]['val'];
  281. $listvalues.="'".$this->db->escape($arrayrecord[($key-1)]['val'])."'";
  282. }
  283. // Make some tests
  284. // Required field is ok
  285. if (preg_match('/\*/',$objimport->array_import_fields[0][$val]) && ($newval==''))
  286. {
  287. $this->errors[$error]['lib']=$langs->trans('ErrorMissingMandatoryValue',$key);
  288. $this->errors[$error]['type']='NOTNULL';
  289. $errorforthistable++;
  290. $error++;
  291. }
  292. // Test format only if field is not a missing mandatory field
  293. else {
  294. if (! empty($objimport->array_import_regex[0][$val]))
  295. {
  296. // If test is "Must exist in a field@table"
  297. if (preg_match('/^(.*)@(.*)$/',$objimport->array_import_regex[0][$val],$reg))
  298. {
  299. $field=$reg[1];
  300. $table=$reg[2];
  301. if (! is_array($this->cachefieldtable[$field.'@'.$table])) // If content of field@table no already loaded into cache
  302. {
  303. $sql="SELECT ".$field." as aliasfield FROM ".$table;
  304. $resql=$this->db->query($sql);
  305. if ($resql)
  306. {
  307. $num=$this->db->num_rows($resql);
  308. $i=0;
  309. while ($i < $num)
  310. {
  311. $obj=$this->db->fetch_object($resql);
  312. if ($obj) $this->cachefieldtable[$field.'@'.$table][]=$obj->aliasfield;
  313. $i++;
  314. }
  315. }
  316. else
  317. {
  318. dol_print_error($this->db);
  319. }
  320. }
  321. // Now we check cache is not empty (should not) and key is into cache
  322. if (! is_array($this->cachefieldtable[$field.'@'.$table]) || ! in_array($newval,$this->cachefieldtable[$field.'@'.$table]))
  323. {
  324. $this->errors[$error]['lib']=$langs->trans('ErrorFieldValueNotIn',$key,$newval,$field,$table);
  325. $this->errors[$error]['type']='FOREIGNKEY';
  326. $error++;
  327. }
  328. }
  329. // If test is just a static regex
  330. else if (! preg_match('/'.$objimport->array_import_regex[0][$val].'/i',$newval))
  331. {
  332. $this->errors[$error]['lib']=$langs->trans('ErrorWrongValueForField',$key,$newval,$objimport->array_import_regex[0][$val]);
  333. $this->errors[$error]['type']='REGEX';
  334. $errorforthistable++;
  335. $error++;
  336. }
  337. }
  338. // Other tests
  339. // ...
  340. }
  341. }
  342. $i++;
  343. }
  344. //print $listvalues;
  345. if (! $errorforthistable)
  346. {
  347. if ($listfields)
  348. {
  349. // If some values need to be found somewhere else than in source file: Case we need a rowid found from a fetch on a reference.
  350. // This is used when insert must be done when a parent row already exists
  351. // $objimport->array_import_convertvalue=array('s.fk_soc'=>array('rule'=>'fetchfromref',file='/societe.class.php','class'=>'Societe','method'=>'fetch'));
  352. foreach($objimport->array_import_convertvalue as $alias => $rulearray)
  353. {
  354. if (empty($rulearray['rule']) || $rulearray['rule']!='fetchfromref') continue;
  355. dol_syslog("We need to get rowid from ref=".$alias." using value found in column ".$array_match_database_to_file." in source file, so ".$arrayrecord[$array_match_database_to_file]['val']);
  356. }
  357. // If some values need to be found somewhere else than in source file: Case we need lastinsert id from previous insert
  358. // This is used when insert must be done in several tables
  359. // $objimport->array_import_convertvalue=array('s.fk_soc'=>array('rule'=>'lastrowid',table='t');
  360. // TODO
  361. // Build SQL request
  362. $sql ='INSERT INTO '.$tablename.'('.$listfields.', import_key';
  363. if (! empty($objimport->array_import_tables_creator[0][$alias])) $sql.=', '.$objimport->array_import_tables_creator[0][$alias];
  364. $sql.=') VALUES('.$listvalues.", '".$importid."'";
  365. if (! empty($objimport->array_import_tables_creator[0][$alias])) $sql.=', '.$user->id;
  366. $sql.=')';
  367. dol_syslog("import_csv.modules sql=".$sql);
  368. //print '> '.join(',',$arrayrecord);
  369. //print 'sql='.$sql;
  370. //print '<br>'."\n";
  371. // Run insert request
  372. if ($sql)
  373. {
  374. $resql=$this->db->query($sql);
  375. if ($resql)
  376. {
  377. //print '.';
  378. }
  379. else
  380. {
  381. //print 'E';
  382. $this->errors[$error]['lib']=$this->db->lasterror();
  383. $this->errors[$error]['type']='SQL';
  384. $error++;
  385. }
  386. }
  387. }
  388. else
  389. {
  390. dol_print_error('Ne doit pas arriver AAA');
  391. }
  392. }
  393. }
  394. }
  395. return 1;
  396. }
  397. }
  398. /**
  399. * Clean a string from separator
  400. */
  401. function cleansep($value)
  402. {
  403. return str_replace(',','/',$value);
  404. };
  405. ?>