dolibarr 19.0.3
import_csv.modules.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2006-2012 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2009-2012 Regis Houssin <regis.houssin@inodbox.com>
4 * Copyright (C) 2012 Christophe Battarel <christophe.battarel@altairis.fr>
5 * Copyright (C) 2012-2016 Juanjo Menent <jmenent@2byte.es>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 * or see https://www.gnu.org/
20 */
21
28require_once DOL_DOCUMENT_ROOT.'/core/modules/import/modules_import.php';
29
30
35{
39 public $db;
40
44 public $id;
45
49 public $label;
50
51 public $extension; // Extension of files imported by driver
52
57 public $version = 'dolibarr';
58
59 public $label_lib; // Label of external lib used by driver
60
61 public $version_lib; // Version of external lib used by driver
62
63 public $separator;
64
65 public $file; // Path of file
66
67 public $handle; // Handle fichier
68
69 public $cacheconvert = array(); // Array to cache list of value found after a convertion
70
71 public $cachefieldtable = array(); // Array to cache list of value found into fields@tables
72
73 public $nbinsert = 0; // # of insert done during the import
74
75 public $nbupdate = 0; // # of update done during the import
76
77 public $charset = '';
78
79 public $col;
80
81
88 public function __construct($db, $datatoimport)
89 {
90 global $conf, $langs;
91
92 parent::__construct();
93 $this->db = $db;
94
95 $this->separator = (GETPOST('separator') ? GETPOST('separator') : (!getDolGlobalString('IMPORT_CSV_SEPARATOR_TO_USE') ? ',' : $conf->global->IMPORT_CSV_SEPARATOR_TO_USE));
96 $this->enclosure = '"';
97 $this->escape = '"';
98
99 $this->id = 'csv'; // Same value then xxx in file name export_xxx.modules.php
100 $this->label = 'Csv'; // Label of driver
101 $this->desc = $langs->trans("CSVFormatDesc", $this->separator, $this->enclosure, $this->escape);
102 $this->extension = 'csv'; // Extension for generated file by this driver
103 $this->picto = 'mime/other'; // Picto
104 $this->version = '1.34'; // Driver version
105
106 // If driver use an external library, put its name here
107 $this->label_lib = 'Dolibarr';
108 $this->version_lib = DOL_VERSION;
109
110 $this->datatoimport = $datatoimport;
111 if (preg_match('/^societe_/', $datatoimport)) {
112 $this->thirdpartyobject = new Societe($this->db);
113 }
114 }
115
116
117 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
124 public function write_header_example($outputlangs)
125 {
126 // phpcs:enable
127 return '';
128 }
129
130 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
138 public function write_title_example($outputlangs, $headerlinefields)
139 {
140 // phpcs:enable
141 $s = join($this->separator, array_map('cleansep', $headerlinefields));
142 return $s."\n";
143 }
144
145 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
153 public function write_record_example($outputlangs, $contentlinevalues)
154 {
155 // phpcs:enable
156 $s = join($this->separator, array_map('cleansep', $contentlinevalues));
157 return $s."\n";
158 }
159
160 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
167 public function write_footer_example($outputlangs)
168 {
169 // phpcs:enable
170 return '';
171 }
172
173
174 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
181 public function import_open_file($file)
182 {
183 // phpcs:enable
184 global $langs;
185 $ret = 1;
186
187 dol_syslog(get_class($this)."::open_file file=".$file);
188
189 ini_set('auto_detect_line_endings', 1); // For MAC compatibility
190
191 $this->handle = fopen(dol_osencode($file), "r");
192 if (!$this->handle) {
193 $langs->load("errors");
194 $this->error = $langs->trans("ErrorFailToOpenFile", $file);
195 $ret = -1;
196 } else {
197 $this->file = $file;
198 }
199
200 return $ret;
201 }
202
203
204 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
211 public function import_get_nb_of_lines($file)
212 {
213 // phpcs:enable
214 return dol_count_nb_of_line($file);
215 }
216
217
218 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
224 public function import_read_header()
225 {
226 // phpcs:enable
227 return 0;
228 }
229
230
231 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
237 public function import_read_record()
238 {
239 // phpcs:enable
240 global $conf;
241
242 $arrayres = fgetcsv($this->handle, 100000, $this->separator, $this->enclosure, $this->escape);
243
244 // End of file
245 if ($arrayres === false) {
246 return false;
247 }
248
249 //var_dump($this->handle);
250 //var_dump($arrayres);exit;
251 $newarrayres = array();
252 if ($arrayres && is_array($arrayres)) {
253 foreach ($arrayres as $key => $val) {
254 if (getDolGlobalString('IMPORT_CSV_FORCE_CHARSET')) { // Forced charset
255 if (strtolower($conf->global->IMPORT_CSV_FORCE_CHARSET) == 'utf8') {
256 $newarrayres[$key]['val'] = $val;
257 $newarrayres[$key]['type'] = (dol_strlen($val) ? 1 : -1); // If empty we considere it's null
258 } else {
259 $newarrayres[$key]['val'] = mb_convert_encoding($val, 'UTF-8', 'ISO-8859-1');
260 $newarrayres[$key]['type'] = (dol_strlen($val) ? 1 : -1); // If empty we considere it's null
261 }
262 } else { // Autodetect format (UTF8 or ISO)
263 if (utf8_check($val)) {
264 $newarrayres[$key]['val'] = $val;
265 $newarrayres[$key]['type'] = (dol_strlen($val) ? 1 : -1); // If empty we considere it's null
266 } else {
267 $newarrayres[$key]['val'] = mb_convert_encoding($val, 'UTF-8', 'ISO-8859-1');
268 $newarrayres[$key]['type'] = (dol_strlen($val) ? 1 : -1); // If empty we considere it's null
269 }
270 }
271 }
272
273 $this->col = count($newarrayres);
274 }
275
276 return $newarrayres;
277 }
278
279 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
285 public function import_close_file()
286 {
287 // phpcs:enable
288 fclose($this->handle);
289 return 0;
290 }
291
292
293 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
305 public function import_insert($arrayrecord, $array_match_file_to_database, $objimport, $maxfields, $importid, $updatekeys)
306 {
307 // phpcs:enable
308 global $langs, $conf, $user;
309 global $thirdparty_static; // Specific to thirdparty import
310 global $tablewithentity_cache; // Cache to avoid to call desc at each rows on tables
311
312 $error = 0;
313 $warning = 0;
314 $this->errors = array();
315 $this->warnings = array();
316
317 //dol_syslog("import_csv.modules maxfields=".$maxfields." importid=".$importid);
318
319 //var_dump($array_match_file_to_database);
320 //var_dump($arrayrecord); exit;
321
322 $array_match_database_to_file = array_flip($array_match_file_to_database);
323 $sort_array_match_file_to_database = $array_match_file_to_database;
324 ksort($sort_array_match_file_to_database);
325
326 //var_dump($sort_array_match_file_to_database);
327
328 if (count($arrayrecord) == 0 || (count($arrayrecord) == 1 && empty($arrayrecord[0]['val']))) {
329 //print 'W';
330 $this->warnings[$warning]['lib'] = $langs->trans('EmptyLine');
331 $this->warnings[$warning]['type'] = 'EMPTY';
332 $warning++;
333 } else {
334 $last_insert_id_array = array(); // store the last inserted auto_increment id for each table, so that dependent tables can be inserted with the appropriate id (eg: extrafields fk_object will be set with the last inserted object's id)
335 $updatedone = false;
336 $insertdone = false;
337 // For each table to insert, me make a separate insert
338 foreach ($objimport->array_import_tables[0] as $alias => $tablename) {
339 // Build sql request
340 $sql = '';
341 $listfields = array();
342 $listvalues = array();
343 $i = 0;
344 $errorforthistable = 0;
345
346 // Define $tablewithentity_cache[$tablename] if not already defined
347 if (!isset($tablewithentity_cache[$tablename])) { // keep this test with "isset"
348 dol_syslog("Check if table ".$tablename." has an entity field");
349 $resql = $this->db->DDLDescTable($tablename, 'entity');
350 if ($resql) {
351 $obj = $this->db->fetch_object($resql);
352 if ($obj) {
353 $tablewithentity_cache[$tablename] = 1; // table contains entity field
354 } else {
355 $tablewithentity_cache[$tablename] = 0; // table does not contain entity field
356 }
357 } else {
358 dol_print_error($this->db);
359 }
360 } else {
361 //dol_syslog("Table ".$tablename." check for entity into cache is ".$tablewithentity_cache[$tablename]);
362 }
363
364 // Define array to convert fields ('c.ref', ...) into column index (1, ...)
365 $arrayfield = array();
366 foreach ($sort_array_match_file_to_database as $key => $val) {
367 $arrayfield[$val] = ($key - 1);
368 }
369
370 // $arrayrecord start at key 0
371 // $sort_array_match_file_to_database start at key 1
372
373 // Loop on each fields in the match array: $key = 1..n, $val=alias of field (s.nom)
374 foreach ($sort_array_match_file_to_database as $key => $val) {
375 $fieldalias = preg_replace('/\..*$/i', '', $val);
376 $fieldname = preg_replace('/^.*\./i', '', $val);
377
378 if ($alias != $fieldalias) {
379 continue; // Not a field of current table
380 }
381
382 if ($key <= $maxfields) {
383 // Set $newval with value to insert and set $listvalues with sql request part for insert
384 $newval = '';
385 if ($arrayrecord[($key - 1)]['type'] > 0) {
386 $newval = $arrayrecord[($key - 1)]['val']; // If type of field into input file is not empty string (so defined into input file), we get value
387 }
388
389 //var_dump($newval);var_dump($val);
390 //var_dump($objimport->array_import_convertvalue[0][$val]);
391
392 // Make some tests on $newval
393
394 // Is it a required field ?
395 if (preg_match('/\*/', $objimport->array_import_fields[0][$val]) && ((string) $newval == '')) {
396 $this->errors[$error]['lib'] = $langs->trans('ErrorMissingMandatoryValue', $key);
397 $this->errors[$error]['type'] = 'NOTNULL';
398 $errorforthistable++;
399 $error++;
400 } else {
401 // Test format only if field is not a missing mandatory field (field may be a value or empty but not mandatory)
402 // We convert field if required
403 if (!empty($objimport->array_import_convertvalue[0][$val])) {
404 //print 'Must convert '.$newval.' with rule '.join(',',$objimport->array_import_convertvalue[0][$val]).'. ';
405 if ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeid'
406 || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromref'
407 || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeorlabel'
408 ) {
409 // New val can be an id or ref. If it start with id: it is forced to id, if it start with ref: it is forced to ref. It not, we try to guess.
410 $isidorref = 'id';
411 if (!is_numeric($newval) && $newval != '' && !preg_match('/^id:/i', $newval)) {
412 $isidorref = 'ref';
413 }
414
415 $newval = preg_replace('/^(id|ref):/i', '', $newval); // Remove id: or ref: that was used to force if field is id or ref
416 //print 'Newval is now "'.$newval.'" and is type '.$isidorref."<br>\n";
417
418 if ($isidorref == 'ref') { // If value into input import file is a ref, we apply the function defined into descriptor
419 $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
420 $class = $objimport->array_import_convertvalue[0][$val]['class'];
421 $method = $objimport->array_import_convertvalue[0][$val]['method'];
422 if ($this->cacheconvert[$file.'_'.$class.'_'.$method.'_'][$newval] != '') {
423 $newval = $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'][$newval];
424 } else {
425 $resultload = dol_include_once($file);
426 if (empty($resultload)) {
427 dol_print_error('', 'Error trying to call file='.$file.', class='.$class.', method='.$method);
428 break;
429 }
430 $classinstance = new $class($this->db);
431 if ($class == 'CGenericDic') {
432 $classinstance->element = $objimport->array_import_convertvalue[0][$val]['element'];
433 $classinstance->table_element = $objimport->array_import_convertvalue[0][$val]['table_element'];
434 }
435
436 // Try the fetch from code or ref
437 $param_array = array('', $newval);
438 if ($class == 'AccountingAccount') {
439 //var_dump($arrayrecord[0]['val']);
440 /*include_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountancysystem.class.php';
441 $tmpchartofaccount = new AccountancySystem($this->db);
442 $tmpchartofaccount->fetch(getDolGlobalInt('CHARTOFACCOUNTS'));
443 //var_dump($tmpchartofaccount->ref.' - '.$arrayrecord[0]['val']);
444 if ((! (getDolGlobalInt('CHARTOFACCOUNTS') > 0)) || $tmpchartofaccount->ref != $arrayrecord[0]['val'])
445 {
446 $this->errors[$error]['lib']=$langs->trans('ErrorImportOfChartLimitedToCurrentChart', $tmpchartofaccount->ref);
447 $this->errors[$error]['type']='RESTRICTONCURRENCTCHART';
448 $errorforthistable++;
449 $error++;
450 }*/
451 $param_array = array('', $newval, 0, $arrayrecord[0]['val']); // Param to fetch parent from account, in chart.
452 }
453
454 $result = call_user_func_array(array($classinstance, $method), $param_array);
455
456 // If duplicate record found
457 if (!($classinstance->id != '') && $result == -2) {
458 $this->errors[$error]['lib'] = $langs->trans('ErrorMultipleRecordFoundFromRef', $newval);
459 $this->errors[$error]['type'] = 'FOREIGNKEY';
460 $errorforthistable++;
461 $error++;
462 }
463
464 // If not found, try the fetch from label
465 if (!($classinstance->id != '') && $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeorlabel') {
466 $param_array = array('', '', $newval);
467 call_user_func_array(array($classinstance, $method), $param_array);
468 }
469 $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'][$newval] = $classinstance->id;
470
471 //print 'We have made a '.$class.'->'.$method.' to get id from code '.$newval.'. ';
472 if ($classinstance->id != '') { // id may be 0, it is a found value
473 $newval = $classinstance->id;
474 } elseif (! $error) {
475 if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
476 $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, 'code', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
477 } elseif (!empty($objimport->array_import_convertvalue[0][$val]['element'])) {
478 $this->errors[$error]['lib'] = $langs->trans('ErrorFieldRefNotIn', num2Alpha($key - 1), $newval, $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['element']));
479 } else {
480 $this->errors[$error]['lib'] = 'ErrorBadDefinitionOfImportProfile';
481 }
482 $this->errors[$error]['type'] = 'FOREIGNKEY';
483 $errorforthistable++;
484 $error++;
485 }
486 }
487 }
488 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeandlabel') {
489 $isidorref = 'id';
490 if (!is_numeric($newval) && $newval != '' && !preg_match('/^id:/i', $newval)) {
491 $isidorref = 'ref';
492 }
493 $newval = preg_replace('/^(id|ref):/i', '', $newval);
494
495 if ($isidorref == 'ref') {
496 $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
497 $class = $objimport->array_import_convertvalue[0][$val]['class'];
498 $method = $objimport->array_import_convertvalue[0][$val]['method'];
499 $codefromfield = $objimport->array_import_convertvalue[0][$val]['codefromfield'];
500 $code = $arrayrecord[$arrayfield[$codefromfield]]['val'];
501 if ($this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$code][$newval] != '') {
502 $newval = $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$code][$newval];
503 } else {
504 $resultload = dol_include_once($file);
505 if (empty($resultload)) {
506 dol_print_error('', 'Error trying to call file='.$file.', class='.$class.', method='.$method.', code='.$code);
507 break;
508 }
509 $classinstance = new $class($this->db);
510 // Try the fetch from code and ref
511 $param_array = array('', $newval, $code);
512 call_user_func_array(array($classinstance, $method), $param_array);
513 $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$code][$newval] = $classinstance->id;
514 if ($classinstance->id > 0) { // we found record
515 $newval = $classinstance->id;
516 } else {
517 if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
518 $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, 'scale', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
519 } else {
520 $this->errors[$error]['lib'] = 'ErrorFieldValueNotIn';
521 }
522 $this->errors[$error]['type'] = 'FOREIGNKEY';
523 $errorforthistable++;
524 $error++;
525 }
526 }
527 }
528 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'zeroifnull') {
529 if (empty($newval)) {
530 $newval = '0';
531 }
532 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeunits' || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchscalefromcodeunits') {
533 $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
534 $class = $objimport->array_import_convertvalue[0][$val]['class'];
535 $method = $objimport->array_import_convertvalue[0][$val]['method'];
536 $units = $objimport->array_import_convertvalue[0][$val]['units'];
537 if ($this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$units][$newval] != '') {
538 $newval = $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$units][$newval];
539 } else {
540 $resultload = dol_include_once($file);
541 if (empty($resultload)) {
542 dol_print_error('', 'Error trying to call file='.$file.', class='.$class.', method='.$method.', units='.$units);
543 break;
544 }
545 $classinstance = new $class($this->db);
546 // Try the fetch from code or ref
547 call_user_func_array(array($classinstance, $method), array('', '', $newval, $units));
548 $scaleorid = (($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeunits') ? $classinstance->id : $classinstance->scale);
549 $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$units][$newval] = $scaleorid;
550 //print 'We have made a '.$class.'->'.$method." to get a value from key '".$newval."' and we got '".$scaleorid."'.";exit;
551 if ($classinstance->id > 0) { // we found record
552 $newval = $scaleorid ? $scaleorid : 0;
553 } else {
554 if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
555 $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, 'scale', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
556 } else {
557 $this->errors[$error]['lib'] = 'ErrorFieldValueNotIn';
558 }
559 $this->errors[$error]['type'] = 'FOREIGNKEY';
560 $errorforthistable++;
561 $error++;
562 }
563 }
564 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getcustomercodeifauto') {
565 if (strtolower($newval) == 'auto') {
566 $this->thirdpartyobject->get_codeclient(0, 0);
567 $newval = $this->thirdpartyobject->code_client;
568 //print 'code_client='.$newval;
569 }
570 if (empty($newval)) {
571 $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
572 }
573 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getsuppliercodeifauto') {
574 if (strtolower($newval) == 'auto') {
575 $this->thirdpartyobject->get_codefournisseur(0, 1);
576 $newval = $this->thirdpartyobject->code_fournisseur;
577 //print 'code_fournisseur='.$newval;
578 }
579 if (empty($newval)) {
580 $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
581 }
582 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getcustomeraccountancycodeifauto') {
583 if (strtolower($newval) == 'auto') {
584 $this->thirdpartyobject->get_codecompta('customer');
585 $newval = $this->thirdpartyobject->code_compta;
586 //print 'code_compta='.$newval;
587 }
588 if (empty($newval)) {
589 $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
590 }
591 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getsupplieraccountancycodeifauto') {
592 if (strtolower($newval) == 'auto') {
593 $this->thirdpartyobject->get_codecompta('supplier');
594 $newval = $this->thirdpartyobject->code_compta_fournisseur;
595 if (empty($newval)) {
596 $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
597 }
598 //print 'code_compta_fournisseur='.$newval;
599 }
600 if (empty($newval)) {
601 $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
602 }
603 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getrefifauto') {
604 if (strtolower($newval) == 'auto') {
605 $defaultref = '';
606
607 $classModForNumber = $objimport->array_import_convertvalue[0][$val]['class'];
608 $pathModForNumber = $objimport->array_import_convertvalue[0][$val]['path'];
609
610 if (!empty($classModForNumber) && !empty($pathModForNumber) && is_readable(DOL_DOCUMENT_ROOT.$pathModForNumber)) {
611 require_once DOL_DOCUMENT_ROOT.$pathModForNumber;
612 $modForNumber = new $classModForNumber();
613
614 $tmpobject = null;
615 // Set the object with the date property when we can
616 if (!empty($objimport->array_import_convertvalue[0][$val]['classobject'])) {
617 $pathForObject = $objimport->array_import_convertvalue[0][$val]['pathobject'];
618 require_once DOL_DOCUMENT_ROOT.$pathForObject;
619 $tmpclassobject = $objimport->array_import_convertvalue[0][$val]['classobject'];
620 $tmpobject = new $tmpclassobject($this->db);
621 foreach ($arrayfield as $tmpkey => $tmpval) { // $arrayfield is array('c.ref'=>0, ...)
622 if (in_array($tmpkey, array('t.date', 'c.date_commande'))) {
623 $tmpobject->date = dol_stringtotime($arrayrecord[$arrayfield[$tmpkey]]['val'], 1);
624 }
625 }
626 }
627
628 $defaultref = $modForNumber->getNextValue(null, $tmpobject);
629 }
630 if (is_numeric($defaultref) && $defaultref <= 0) { // If error
631 $defaultref = '';
632 }
633 $newval = $defaultref;
634 }
635 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'compute') {
636 $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
637 $class = $objimport->array_import_convertvalue[0][$val]['class'];
638 $method = $objimport->array_import_convertvalue[0][$val]['method'];
639 $resultload = dol_include_once($file);
640 if (empty($resultload)) {
641 dol_print_error('', 'Error trying to call file='.$file.', class='.$class.', method='.$method);
642 break;
643 }
644 $classinstance = new $class($this->db);
645 $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $arrayfield, ($key - 1)));
646 if (empty($classinstance->error) && empty($classinstance->errors)) {
647 $newval = $res; // We get new value computed.
648 } else {
649 $this->errors[$error]['type'] = 'CLASSERROR';
650 $this->errors[$error]['lib'] = implode(
651 "\n",
652 array_merge([$classinstance->error], $classinstance->errors)
653 );
654 $errorforthistable++;
655 $error++;
656 }
657 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'numeric') {
658 $newval = price2num($newval);
659 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'accountingaccount') {
660 if (!getDolGlobalString('ACCOUNTING_MANAGE_ZERO')) {
661 $newval = rtrim(trim($newval), "0");
662 } else {
663 $newval = trim($newval);
664 }
665 }
666
667 //print 'Val to use as insert is '.$newval.'<br>';
668 }
669
670 // Test regexp
671 if (!empty($objimport->array_import_regex[0][$val]) && ($newval != '')) {
672 // If test is "Must exist in a field@table or field@table:..."
673 $reg = array();
674 if (preg_match('/^(.+)@([^:]+)(:.+)?$/', $objimport->array_import_regex[0][$val], $reg)) {
675 $field = $reg[1];
676 $table = $reg[2];
677 $filter = !empty($reg[3]) ? substr($reg[3], 1) : '';
678
679 $cachekey = $field.'@'.$table;
680 if (!empty($filter)) {
681 $cachekey .= ':'.$filter;
682 }
683
684 // Load content of field@table into cache array
685 if (!is_array($this->cachefieldtable[$cachekey])) { // If content of field@table not already loaded into cache
686 $sql = "SELECT ".$field." as aliasfield FROM ".$table;
687 if (!empty($filter)) {
688 $sql .= ' WHERE '.$filter;
689 }
690
691 $resql = $this->db->query($sql);
692 if ($resql) {
693 $num = $this->db->num_rows($resql);
694 $i = 0;
695 while ($i < $num) {
696 $obj = $this->db->fetch_object($resql);
697 if ($obj) {
698 $this->cachefieldtable[$cachekey][] = $obj->aliasfield;
699 }
700 $i++;
701 }
702 } else {
703 dol_print_error($this->db);
704 }
705 }
706
707 // Now we check cache is not empty (should not) and key is into cache
708 if (!is_array($this->cachefieldtable[$cachekey]) || !in_array($newval, $this->cachefieldtable[$cachekey])) {
709 $tableforerror = $table;
710 if (!empty($filter)) {
711 $tableforerror .= ':'.$filter;
712 }
713 $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, $field, $tableforerror);
714 $this->errors[$error]['type'] = 'FOREIGNKEY';
715 $errorforthistable++;
716 $error++;
717 }
718 } elseif (!preg_match('/'.$objimport->array_import_regex[0][$val].'/i', $newval)) {
719 // If test is just a static regex
720 //if ($key == 19) print "xxx".$newval."zzz".$objimport->array_import_regex[0][$val]."<br>";
721 $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorWrongValueForField', num2Alpha($key - 1), $newval, $objimport->array_import_regex[0][$val]);
722 $this->errors[$error]['type'] = 'REGEX';
723 $errorforthistable++;
724 $error++;
725 }
726 }
727
728 // Check HTML injection
729 $inj = testSqlAndScriptInject($newval, 0);
730 if ($inj) {
731 $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorHtmlInjectionForField', num2Alpha($key - 1), dol_trunc($newval, 100));
732 $this->errors[$error]['type'] = 'HTMLINJECTION';
733 $errorforthistable++;
734 $error++;
735 }
736
737 // Other tests
738 // ...
739 }
740
741 // Define $listfields and $listvalues to build the SQL request
742 if (isModEnabled("socialnetworks") && strpos($fieldname, "socialnetworks") !== false) {
743 if (!in_array("socialnetworks", $listfields)) {
744 $listfields[] = "socialnetworks";
745 $socialkey = array_search("socialnetworks", $listfields); // Return position of 'socialnetworks' key in array
746 $listvalues[$socialkey] = '';
747 }
748 //var_dump($newval); var_dump($arrayrecord[($key - 1)]['type']);
749 if (!empty($newval) && $arrayrecord[($key - 1)]['type'] > 0) {
750 $socialkey = array_search("socialnetworks", $listfields); // Return position of 'socialnetworks' key in array
751 //var_dump('sk='.$socialkey); // socialkey=19
752 $socialnetwork = explode("_", $fieldname)[1];
753 if (empty($listvalues[$socialkey]) || $listvalues[$socialkey] == "null") {
754 $json = new stdClass();
755 $json->$socialnetwork = $newval;
756 $listvalues[$socialkey] = json_encode($json);
757 } else {
758 $jsondata = $listvalues[$socialkey];
759 $json = json_decode($jsondata);
760 $json->$socialnetwork = $newval;
761 $listvalues[$socialkey] = json_encode($json);
762 }
763 }
764 } else {
765 $listfields[] = $fieldname;
766 // Note: arrayrecord (and 'type') is filled with ->import_read_record called by import.php page before calling import_insert
767 if (empty($newval) && $arrayrecord[($key - 1)]['type'] < 0) {
768 $listvalues[] = ($newval == '0' ? (int) $newval : "null");
769 } elseif (empty($newval) && $arrayrecord[($key - 1)]['type'] == 0) {
770 $listvalues[] = "''";
771 } else {
772 $listvalues[] = "'".$this->db->escape($newval)."'";
773 }
774 }
775 }
776 $i++;
777 }
778
779 // We add hidden fields (but only if there is at least one field to add into table)
780 // We process here all the fields that were declared into the array $this->import_fieldshidden_array of the descriptor file.
781 // Previously we processed the ->import_fields_array.
782 if (!empty($listfields) && is_array($objimport->array_import_fieldshidden[0])) {
783 // Loop on each hidden fields to add them into listfields/listvalues
784 foreach ($objimport->array_import_fieldshidden[0] as $tmpkey => $tmpval) {
785 if (!preg_match('/^'.preg_quote($alias, '/').'\./', $tmpkey)) {
786 continue; // Not a field of current table
787 }
788 if ($tmpval == 'user->id') {
789 $listfields[] = preg_replace('/^'.preg_quote($alias, '/').'\./', '', $tmpkey);
790 $listvalues[] = ((int) $user->id);
791 } elseif (preg_match('/^lastrowid-/', $tmpval)) {
792 $tmp = explode('-', $tmpval);
793 $lastinsertid = (isset($last_insert_id_array[$tmp[1]])) ? $last_insert_id_array[$tmp[1]] : 0;
794 $keyfield = preg_replace('/^'.preg_quote($alias, '/').'\./', '', $tmpkey);
795 $listfields[] = $keyfield;
796 $listvalues[] = (int) $lastinsertid;
797 //print $tmpkey."-".$tmpval."-".$listfields."-".$listvalues."<br>";exit;
798 } elseif (preg_match('/^const-/', $tmpval)) {
799 $tmp = explode('-', $tmpval, 2);
800 $listfields[] = preg_replace('/^'.preg_quote($alias, '/').'\./', '', $tmpkey);
801 $listvalues[] = "'".$this->db->escape($tmp[1])."'";
802 } elseif (preg_match('/^rule-/', $tmpval)) {
803 $fieldname = $tmpkey;
804 if (!empty($objimport->array_import_convertvalue[0][$fieldname])) {
805 if ($objimport->array_import_convertvalue[0][$fieldname]['rule'] == 'compute') {
806 $file = (empty($objimport->array_import_convertvalue[0][$fieldname]['classfile']) ? $objimport->array_import_convertvalue[0][$fieldname]['file'] : $objimport->array_import_convertvalue[0][$fieldname]['classfile']);
807 $class = $objimport->array_import_convertvalue[0][$fieldname]['class'];
808 $method = $objimport->array_import_convertvalue[0][$fieldname]['method'];
809 $type = $objimport->array_import_convertvalue[0][$fieldname]['type'];
810 $resultload = dol_include_once($file);
811 if (empty($resultload)) {
812 dol_print_error('', 'Error trying to call file=' . $file . ', class=' . $class . ', method=' . $method);
813 break;
814 }
815 $classinstance = new $class($this->db);
816 $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $arrayfield, ($key - 1)));
817 if (empty($classinstance->error) && empty($classinstance->errors)) {
818 $fieldArr = explode('.', $fieldname);
819 if (count($fieldArr) > 0) {
820 $fieldname = $fieldArr[1];
821 }
822
823 // Set $listfields and $listvalues
824 $listfields[] = $fieldname;
825 if ($type == 'int') {
826 $listvalues[] = (int) $res;
827 } elseif ($type == 'double') {
828 $listvalues[] = (float) $res;
829 } else {
830 $listvalues[] = "'".$this->db->escape($res)."'";
831 }
832 } else {
833 $this->errors[$error]['type'] = 'CLASSERROR';
834 $this->errors[$error]['lib'] = implode(
835 "\n",
836 array_merge([$classinstance->error], $classinstance->errors)
837 );
838 $errorforthistable++;
839 $error++;
840 }
841 }
842 }
843 } else {
844 $this->errors[$error]['lib'] = 'Bad value of profile setup '.$tmpval.' for array_import_fieldshidden';
845 $this->errors[$error]['type'] = 'Import profile setup';
846 $error++;
847 }
848 }
849 }
850 //print 'listfields='.$listfields.'<br>listvalues='.$listvalues.'<br>';
851
852 // If no error for this $alias/$tablename, we have a complete $listfields and $listvalues that are defined
853 // so we can try to make the insert or update now.
854 if (!$errorforthistable) {
855 //print "$alias/$tablename/$listfields/$listvalues<br>";
856 if (!empty($listfields)) {
857 $updatedone = false;
858 $insertdone = false;
859
860 $is_table_category_link = false;
861 $fname = 'rowid';
862 if (strpos($tablename, '_categorie_') !== false) {
863 $is_table_category_link = true;
864 $fname='*';
865 }
866
867 if (!empty($updatekeys)) {
868 // We do SELECT to get the rowid, if we already have the rowid, it's to be used below for related tables (extrafields)
869
870 if (empty($lastinsertid)) { // No insert done yet for a parent table
871 $sqlSelect = "SELECT ".$fname." FROM ".$tablename;
872 $data = array_combine($listfields, $listvalues);
873 $where = array(); // filters to forge SQL request
874 $filters = array(); // filters to forge output error message
875 foreach ($updatekeys as $key) {
876 $col = $objimport->array_import_updatekeys[0][$key];
877 $key = preg_replace('/^.*\./i', '', $key);
878 if (isModEnabled("socialnetworks") && strpos($key, "socialnetworks") !== false) {
879 $tmp = explode("_", $key);
880 $key = $tmp[0];
881 $socialnetwork = $tmp[1];
882 $jsondata = $data[$key];
883 $json = json_decode($jsondata);
884 $stringtosearch = json_encode($socialnetwork).':'.json_encode($json->$socialnetwork);
885 //var_dump($stringtosearch);
886 //var_dump($this->db->escape($stringtosearch)); // This provide a value for sql string (but not for a like)
887 $where[] = $key." LIKE '%".$this->db->escape($this->db->escapeforlike($stringtosearch))."%'";
888 $filters[] = $col." LIKE '%".$this->db->escape($this->db->escapeforlike($stringtosearch))."%'";
889 //var_dump($where[1]); // This provide a value for sql string inside a like
890 } else {
891 $where[] = $key.' = '.$data[$key];
892 $filters[] = $col.' = '.$data[$key];
893 }
894 }
895 if (!empty($tablewithentity_cache[$tablename])) {
896 $where[] = "entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")";
897 $filters[] = "entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")";
898 }
899 $sqlSelect .= " WHERE ".implode(' AND ', $where);
900
901 $resql = $this->db->query($sqlSelect);
902 if ($resql) {
903 $num_rows = $this->db->num_rows($resql);
904 if ($num_rows == 1) {
905 $res = $this->db->fetch_object($resql);
906 $lastinsertid = $res->rowid;
907 if ($is_table_category_link) {
908 $lastinsertid = 'linktable';
909 } // used to apply update on tables like llx_categorie_product and avoid being blocked for all file content if at least one entry already exists
910 $last_insert_id_array[$tablename] = $lastinsertid;
911 } elseif ($num_rows > 1) {
912 $this->errors[$error]['lib'] = $langs->trans('MultipleRecordFoundWithTheseFilters', implode(', ', $filters));
913 $this->errors[$error]['type'] = 'SQL';
914 $error++;
915 } else {
916 // No record found with filters, insert will be tried below
917 }
918 } else {
919 //print 'E';
920 $this->errors[$error]['lib'] = $this->db->lasterror();
921 $this->errors[$error]['type'] = 'SQL';
922 $error++;
923 }
924 } else {
925 // We have a last INSERT ID (got by previous pass), so we check if we have a row referencing this foreign key.
926 // This is required when updating table with some extrafields. When inserting a record in parent table, we can make
927 // a direct insert into subtable extrafields, but when me wake an update, the insertid is defined and the child record
928 // may already exists. So we rescan the extrafield table to know if record exists or not for the rowid.
929 // Note: For extrafield tablename, we have in importfieldshidden_array an enty 'extra.fk_object'=>'lastrowid-tableparent' so $keyfield is 'fk_object'
930 $sqlSelect = "SELECT rowid FROM ".$tablename;
931
932 if (empty($keyfield)) {
933 $keyfield = 'rowid';
934 }
935 $sqlSelect .= " WHERE ".$keyfield." = ".((int) $lastinsertid);
936
937 if (!empty($tablewithentity_cache[$tablename])) {
938 $sqlSelect .= " AND entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")";
939 }
940
941 $resql = $this->db->query($sqlSelect);
942 if ($resql) {
943 $res = $this->db->fetch_object($resql);
944 if ($this->db->num_rows($resql) == 1) {
945 // We have a row referencing this last foreign key, continue with UPDATE.
946 } else {
947 // No record found referencing this last foreign key,
948 // force $lastinsertid to 0 so we INSERT below.
949 $lastinsertid = 0;
950 }
951 } else {
952 //print 'E';
953 $this->errors[$error]['lib'] = $this->db->lasterror();
954 $this->errors[$error]['type'] = 'SQL';
955 $error++;
956 }
957 }
958
959 if (!empty($lastinsertid)) {
960 // We db escape social network field because he isn't in field creation
961 if (in_array("socialnetworks", $listfields)) {
962 $socialkey = array_search("socialnetworks", $listfields);
963 $tmpsql = $listvalues[$socialkey];
964 $listvalues[$socialkey] = "'".$this->db->escape($tmpsql)."'";
965 }
966
967 // Build SQL UPDATE request
968 $sqlstart = "UPDATE ".$tablename;
969
970 $data = array_combine($listfields, $listvalues);
971 $set = array();
972 foreach ($data as $key => $val) {
973 $set[] = $key." = ".$val; // $val was escaped/sanitized previously
974 }
975 $sqlstart .= " SET ".implode(', ', $set).", import_key = '".$this->db->escape($importid)."'";
976
977 if (empty($keyfield)) {
978 $keyfield = 'rowid';
979 }
980 $sqlend = " WHERE ".$keyfield." = ".((int) $lastinsertid);
981
982 if ($is_table_category_link) {
983 $sqlend = " WHERE " . implode(' AND ', $where);
984 }
985
986 if (!empty($tablewithentity_cache[$tablename])) {
987 $sqlend .= " AND entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")";
988 }
989
990 $sql = $sqlstart.$sqlend;
991
992 // Run update request
993 $resql = $this->db->query($sql);
994 if ($resql) {
995 // No error, update has been done. $this->db->db->affected_rows can be 0 if data hasn't changed
996 $updatedone = true;
997 } else {
998 //print 'E';
999 $this->errors[$error]['lib'] = $this->db->lasterror();
1000 $this->errors[$error]['type'] = 'SQL';
1001 $error++;
1002 }
1003 }
1004 }
1005
1006 // Update not done, we do insert
1007 if (!$error && !$updatedone) {
1008 // We db escape social network field because he isn't in field creation
1009 if (in_array("socialnetworks", $listfields)) {
1010 $socialkey = array_search("socialnetworks", $listfields);
1011 $tmpsql = $listvalues[$socialkey];
1012 $listvalues[$socialkey] = "'".$this->db->escape($tmpsql)."'";
1013 }
1014
1015 // Build SQL INSERT request
1016 $sqlstart = "INSERT INTO ".$tablename."(".implode(", ", $listfields).", import_key";
1017 $sqlend = ") VALUES(".implode(', ', $listvalues).", '".$this->db->escape($importid)."'";
1018 if (!empty($tablewithentity_cache[$tablename])) {
1019 $sqlstart .= ", entity";
1020 $sqlend .= ", ".$conf->entity;
1021 }
1022 if (!empty($objimport->array_import_tables_creator[0][$alias])) {
1023 $sqlstart .= ", ".$objimport->array_import_tables_creator[0][$alias];
1024 $sqlend .= ", ".$user->id;
1025 }
1026 $sql = $sqlstart.$sqlend.")";
1027 //dol_syslog("import_csv.modules", LOG_DEBUG);
1028
1029 // Run insert request
1030 if ($sql) {
1031 $resql = $this->db->query($sql);
1032 if ($resql) {
1033 if (!$is_table_category_link) {
1034 $last_insert_id_array[$tablename] = $this->db->last_insert_id($tablename); // store the last inserted auto_increment id for each table, so that child tables can be inserted with the appropriate id. This must be done just after the INSERT request, else we risk losing the id (because another sql query will be issued somewhere in Dolibarr).
1035 }
1036 $insertdone = true;
1037 } else {
1038 //print 'E';
1039 $this->errors[$error]['lib'] = $this->db->lasterror();
1040 $this->errors[$error]['type'] = 'SQL';
1041 $error++;
1042 }
1043 }
1044 }
1045 }
1046 /*else
1047 {
1048 dol_print_error('','ErrorFieldListEmptyFor '.$alias."/".$tablename);
1049 }*/
1050 }
1051
1052 if ($error) {
1053 break;
1054 }
1055 }
1056
1057 if ($updatedone) {
1058 $this->nbupdate++;
1059 }
1060 if ($insertdone) {
1061 $this->nbinsert++;
1062 }
1063 }
1064
1065 return 1;
1066 }
1067}
1068
1075function cleansep($value)
1076{
1077 return str_replace(array(',', ';'), '/', $value);
1078}
Class to import CSV files.
write_header_example($outputlangs)
Output header of an example file for this format.
import_get_nb_of_lines($file)
Return nb of records.
import_insert($arrayrecord, $array_match_file_to_database, $objimport, $maxfields, $importid, $updatekeys)
Insert a record into database.
__construct($db, $datatoimport)
Constructor.
import_read_record()
Return array of next record in input file.
write_record_example($outputlangs, $contentlinevalues)
Output record of an example file for this format.
write_footer_example($outputlangs)
Output footer of an example file for this format.
import_close_file()
Close file handle.
import_read_header()
Input header line from file.
write_title_example($outputlangs, $headerlinefields)
Output title line of an example file for this format.
import_open_file($file)
Open input file.
Parent class for import file readers.
getElementFromTableWithPrefix($tableNameWithPrefix)
Get element from table name with prefix.
Class to manage third parties objects (customers, suppliers, prospects...)
dol_stringtotime($string, $gm=1)
Convert a string date into a GM Timestamps date Warning: YYYY-MM-DDTHH:MM:SS+02:00 (RFC3339) is not s...
Definition date.lib.php:426
dol_count_nb_of_line($file)
Count number of lines in a file.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
num2Alpha($n)
Return a numeric value into an Excel like column number.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
utf8_check($str)
Check if a string is in UTF8.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
cleansep($value)
Clean a string from separator.
testSqlAndScriptInject($val, $type)
Security: WAF layer for SQL Injection and XSS Injection (scripts) protection (Filters on GET,...
Definition main.inc.php:89