dolibarr 18.0.6
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
41 public $datatoimport;
42
46 public $error = '';
47
51 public $errors = array();
52
56 public $id;
57
61 public $label;
62
63 public $extension; // Extension of files imported by driver
64
69 public $version = 'dolibarr';
70
71 public $label_lib; // Label of external lib used by driver
72
73 public $version_lib; // Version of external lib used by driver
74
75 public $separator;
76
77 public $file; // Path of file
78
79 public $handle; // Handle fichier
80
81 public $cacheconvert = array(); // Array to cache list of value found after a convertion
82
83 public $cachefieldtable = array(); // Array to cache list of value found into fields@tables
84
85 public $nbinsert = 0; // # of insert done during the import
86
87 public $nbupdate = 0; // # of update done during the import
88
89 public $charset = '';
90
91
98 public function __construct($db, $datatoimport)
99 {
100 global $conf, $langs;
101
102 parent::__construct();
103 $this->db = $db;
104
105 $this->separator = (GETPOST('separator') ?GETPOST('separator') : (empty($conf->global->IMPORT_CSV_SEPARATOR_TO_USE) ? ',' : $conf->global->IMPORT_CSV_SEPARATOR_TO_USE));
106 $this->enclosure = '"';
107 $this->escape = '"';
108
109 $this->id = 'csv'; // Same value then xxx in file name export_xxx.modules.php
110 $this->label = 'Csv'; // Label of driver
111 $this->desc = $langs->trans("CSVFormatDesc", $this->separator, $this->enclosure, $this->escape);
112 $this->extension = 'csv'; // Extension for generated file by this driver
113 $this->picto = 'mime/other'; // Picto
114 $this->version = '1.34'; // Driver version
115
116 // If driver use an external library, put its name here
117 $this->label_lib = 'Dolibarr';
118 $this->version_lib = DOL_VERSION;
119
120 $this->datatoimport = $datatoimport;
121 if (preg_match('/^societe_/', $datatoimport)) {
122 $this->thirdpartyobject = new Societe($this->db);
123 }
124 }
125
126
127 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
134 public function write_header_example($outputlangs)
135 {
136 // phpcs:enable
137 return '';
138 }
139
140 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
148 public function write_title_example($outputlangs, $headerlinefields)
149 {
150 // phpcs:enable
151 $s = join($this->separator, array_map('cleansep', $headerlinefields));
152 return $s."\n";
153 }
154
155 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
163 public function write_record_example($outputlangs, $contentlinevalues)
164 {
165 // phpcs:enable
166 $s = join($this->separator, array_map('cleansep', $contentlinevalues));
167 return $s."\n";
168 }
169
170 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
177 public function write_footer_example($outputlangs)
178 {
179 // phpcs:enable
180 return '';
181 }
182
183
184 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
191 public function import_open_file($file)
192 {
193 // phpcs:enable
194 global $langs;
195 $ret = 1;
196
197 dol_syslog(get_class($this)."::open_file file=".$file);
198
199 ini_set('auto_detect_line_endings', 1); // For MAC compatibility
200
201 $this->handle = fopen(dol_osencode($file), "r");
202 if (!$this->handle) {
203 $langs->load("errors");
204 $this->error = $langs->trans("ErrorFailToOpenFile", $file);
205 $ret = -1;
206 } else {
207 $this->file = $file;
208 }
209
210 return $ret;
211 }
212
213
214 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
221 public function import_get_nb_of_lines($file)
222 {
223 // phpcs:enable
224 return dol_count_nb_of_line($file);
225 }
226
227
228 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
234 public function import_read_header()
235 {
236 // phpcs:enable
237 return 0;
238 }
239
240
241 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
247 public function import_read_record()
248 {
249 // phpcs:enable
250 global $conf;
251
252 $arrayres = fgetcsv($this->handle, 100000, $this->separator, $this->enclosure, $this->escape);
253
254 // End of file
255 if ($arrayres === false) {
256 return false;
257 }
258
259 //var_dump($this->handle);
260 //var_dump($arrayres);exit;
261 $newarrayres = array();
262 if ($arrayres && is_array($arrayres)) {
263 foreach ($arrayres as $key => $val) {
264 if (!empty($conf->global->IMPORT_CSV_FORCE_CHARSET)) { // Forced charset
265 if (strtolower($conf->global->IMPORT_CSV_FORCE_CHARSET) == 'utf8') {
266 $newarrayres[$key]['val'] = $val;
267 $newarrayres[$key]['type'] = (dol_strlen($val) ? 1 : -1); // If empty we considere it's null
268 } else {
269 $newarrayres[$key]['val'] = utf8_encode($val);
270 $newarrayres[$key]['type'] = (dol_strlen($val) ? 1 : -1); // If empty we considere it's null
271 }
272 } else // Autodetect format (UTF8 or ISO)
273 {
274 if (utf8_check($val)) {
275 $newarrayres[$key]['val'] = $val;
276 $newarrayres[$key]['type'] = (dol_strlen($val) ? 1 : -1); // If empty we considere it's null
277 } else {
278 $newarrayres[$key]['val'] = utf8_encode($val);
279 $newarrayres[$key]['type'] = (dol_strlen($val) ? 1 : -1); // If empty we considere it's null
280 }
281 }
282 }
283
284 $this->col = count($newarrayres);
285 }
286
287 return $newarrayres;
288 }
289
290 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
296 public function import_close_file()
297 {
298 // phpcs:enable
299 fclose($this->handle);
300 return 0;
301 }
302
303
304 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
316 public function import_insert($arrayrecord, $array_match_file_to_database, $objimport, $maxfields, $importid, $updatekeys)
317 {
318 // phpcs:enable
319 global $langs, $conf, $user;
320 global $thirdparty_static; // Specific to thirdparty import
321 global $tablewithentity_cache; // Cache to avoid to call desc at each rows on tables
322
323 $error = 0;
324 $warning = 0;
325 $this->errors = array();
326 $this->warnings = array();
327
328 //dol_syslog("import_csv.modules maxfields=".$maxfields." importid=".$importid);
329
330 //var_dump($array_match_file_to_database);
331 //var_dump($arrayrecord); exit;
332
333 $array_match_database_to_file = array_flip($array_match_file_to_database);
334 $sort_array_match_file_to_database = $array_match_file_to_database;
335 ksort($sort_array_match_file_to_database);
336
337 //var_dump($sort_array_match_file_to_database);
338
339 if (count($arrayrecord) == 0 || (count($arrayrecord) == 1 && empty($arrayrecord[0]['val']))) {
340 //print 'W';
341 $this->warnings[$warning]['lib'] = $langs->trans('EmptyLine');
342 $this->warnings[$warning]['type'] = 'EMPTY';
343 $warning++;
344 } else {
345 $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)
346 $updatedone = false;
347 $insertdone = false;
348 // For each table to insert, me make a separate insert
349 foreach ($objimport->array_import_tables[0] as $alias => $tablename) {
350 // Build sql request
351 $sql = '';
352 $listfields = array();
353 $listvalues = array();
354 $i = 0;
355 $errorforthistable = 0;
356
357 // Define $tablewithentity_cache[$tablename] if not already defined
358 if (!isset($tablewithentity_cache[$tablename])) { // keep this test with "isset"
359 dol_syslog("Check if table ".$tablename." has an entity field");
360 $resql = $this->db->DDLDescTable($tablename, 'entity');
361 if ($resql) {
362 $obj = $this->db->fetch_object($resql);
363 if ($obj) {
364 $tablewithentity_cache[$tablename] = 1; // table contains entity field
365 } else {
366 $tablewithentity_cache[$tablename] = 0; // table does not contain entity field
367 }
368 } else {
369 dol_print_error($this->db);
370 }
371 } else {
372 //dol_syslog("Table ".$tablename." check for entity into cache is ".$tablewithentity_cache[$tablename]);
373 }
374
375 // Define array to convert fields ('c.ref', ...) into column index (1, ...)
376 $arrayfield = array();
377 foreach ($sort_array_match_file_to_database as $key => $val) {
378 $arrayfield[$val] = ($key - 1);
379 }
380
381 // $arrayrecord start at key 0
382 // $sort_array_match_file_to_database start at key 1
383
384 // Loop on each fields in the match array: $key = 1..n, $val=alias of field (s.nom)
385 foreach ($sort_array_match_file_to_database as $key => $val) {
386 $fieldalias = preg_replace('/\..*$/i', '', $val);
387 $fieldname = preg_replace('/^.*\./i', '', $val);
388
389 if ($alias != $fieldalias) {
390 continue; // Not a field of current table
391 }
392
393 if ($key <= $maxfields) {
394 // Set $newval with value to insert and set $listvalues with sql request part for insert
395 $newval = '';
396 if ($arrayrecord[($key - 1)]['type'] > 0) {
397 $newval = $arrayrecord[($key - 1)]['val']; // If type of field into input file is not empty string (so defined into input file), we get value
398 }
399
400 //var_dump($newval);var_dump($val);
401 //var_dump($objimport->array_import_convertvalue[0][$val]);
402
403 // Make some tests on $newval
404
405 // Is it a required field ?
406 if (preg_match('/\*/', $objimport->array_import_fields[0][$val]) && ((string) $newval == '')) {
407 $this->errors[$error]['lib'] = $langs->trans('ErrorMissingMandatoryValue', $key);
408 $this->errors[$error]['type'] = 'NOTNULL';
409 $errorforthistable++;
410 $error++;
411 } else {
412 // Test format only if field is not a missing mandatory field (field may be a value or empty but not mandatory)
413 // We convert field if required
414 if (!empty($objimport->array_import_convertvalue[0][$val])) {
415 //print 'Must convert '.$newval.' with rule '.join(',',$objimport->array_import_convertvalue[0][$val]).'. ';
416 if ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeid'
417 || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromref'
418 || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeorlabel'
419 ) {
420 // 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.
421 $isidorref = 'id';
422 if (!is_numeric($newval) && $newval != '' && !preg_match('/^id:/i', $newval)) {
423 $isidorref = 'ref';
424 }
425
426 $newval = preg_replace('/^(id|ref):/i', '', $newval); // Remove id: or ref: that was used to force if field is id or ref
427 //print 'Newval is now "'.$newval.'" and is type '.$isidorref."<br>\n";
428
429 if ($isidorref == 'ref') { // If value into input import file is a ref, we apply the function defined into descriptor
430 $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
431 $class = $objimport->array_import_convertvalue[0][$val]['class'];
432 $method = $objimport->array_import_convertvalue[0][$val]['method'];
433 if ($this->cacheconvert[$file.'_'.$class.'_'.$method.'_'][$newval] != '') {
434 $newval = $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'][$newval];
435 } else {
436 $resultload = dol_include_once($file);
437 if (empty($resultload)) {
438 dol_print_error('', 'Error trying to call file='.$file.', class='.$class.', method='.$method);
439 break;
440 }
441 $classinstance = new $class($this->db);
442 if ($class == 'CGenericDic') {
443 $classinstance->element = $objimport->array_import_convertvalue[0][$val]['element'];
444 $classinstance->table_element = $objimport->array_import_convertvalue[0][$val]['table_element'];
445 }
446
447 // Try the fetch from code or ref
448 $param_array = array('', $newval);
449 if ($class == 'AccountingAccount') {
450 //var_dump($arrayrecord[0]['val']);
451 /*include_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountancysystem.class.php';
452 $tmpchartofaccount = new AccountancySystem($this->db);
453 $tmpchartofaccount->fetch(getDolGlobalInt('CHARTOFACCOUNTS'));
454 //var_dump($tmpchartofaccount->ref.' - '.$arrayrecord[0]['val']);
455 if ((! (getDolGlobalInt('CHARTOFACCOUNTS') > 0)) || $tmpchartofaccount->ref != $arrayrecord[0]['val'])
456 {
457 $this->errors[$error]['lib']=$langs->trans('ErrorImportOfChartLimitedToCurrentChart', $tmpchartofaccount->ref);
458 $this->errors[$error]['type']='RESTRICTONCURRENCTCHART';
459 $errorforthistable++;
460 $error++;
461 }*/
462 $param_array = array('', $newval, 0, $arrayrecord[0]['val']); // Param to fetch parent from account, in chart.
463 }
464
465 $result = call_user_func_array(array($classinstance, $method), $param_array);
466
467 // If duplicate record found
468 if (!($classinstance->id != '') && $result == -2) {
469 $this->errors[$error]['lib'] = $langs->trans('ErrorMultipleRecordFoundFromRef', $newval);
470 $this->errors[$error]['type'] = 'FOREIGNKEY';
471 $errorforthistable++;
472 $error++;
473 }
474
475 // If not found, try the fetch from label
476 if (!($classinstance->id != '') && $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeorlabel') {
477 $param_array = array('', '', $newval);
478 call_user_func_array(array($classinstance, $method), $param_array);
479 }
480 $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'][$newval] = $classinstance->id;
481
482 //print 'We have made a '.$class.'->'.$method.' to get id from code '.$newval.'. ';
483 if ($classinstance->id != '') { // id may be 0, it is a found value
484 $newval = $classinstance->id;
485 } elseif (! $error) {
486 if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
487 $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, 'code', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
488 } elseif (!empty($objimport->array_import_convertvalue[0][$val]['element'])) {
489 $this->errors[$error]['lib'] = $langs->trans('ErrorFieldRefNotIn', num2Alpha($key - 1), $newval, $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['element']));
490 } else {
491 $this->errors[$error]['lib'] = 'ErrorBadDefinitionOfImportProfile';
492 }
493 $this->errors[$error]['type'] = 'FOREIGNKEY';
494 $errorforthistable++;
495 $error++;
496 }
497 }
498 }
499 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeandlabel') {
500 $isidorref = 'id';
501 if (!is_numeric($newval) && $newval != '' && !preg_match('/^id:/i', $newval)) {
502 $isidorref = 'ref';
503 }
504 $newval = preg_replace('/^(id|ref):/i', '', $newval);
505
506 if ($isidorref == 'ref') {
507 $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
508 $class = $objimport->array_import_convertvalue[0][$val]['class'];
509 $method = $objimport->array_import_convertvalue[0][$val]['method'];
510 $codefromfield = $objimport->array_import_convertvalue[0][$val]['codefromfield'];
511 $code = $arrayrecord[$arrayfield[$codefromfield]]['val'];
512 if ($this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$code][$newval] != '') {
513 $newval = $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$code][$newval];
514 } else {
515 $resultload = dol_include_once($file);
516 if (empty($resultload)) {
517 dol_print_error('', 'Error trying to call file='.$file.', class='.$class.', method='.$method.', code='.$code);
518 break;
519 }
520 $classinstance = new $class($this->db);
521 // Try the fetch from code and ref
522 $param_array = array('', $newval, $code);
523 call_user_func_array(array($classinstance, $method), $param_array);
524 $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$code][$newval] = $classinstance->id;
525 if ($classinstance->id > 0) { // we found record
526 $newval = $classinstance->id;
527 } else {
528 if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
529 $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, 'scale', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
530 } else {
531 $this->errors[$error]['lib'] = 'ErrorFieldValueNotIn';
532 }
533 $this->errors[$error]['type'] = 'FOREIGNKEY';
534 $errorforthistable++;
535 $error++;
536 }
537 }
538 }
539 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'zeroifnull') {
540 if (empty($newval)) {
541 $newval = '0';
542 }
543 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeunits' || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchscalefromcodeunits') {
544 $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
545 $class = $objimport->array_import_convertvalue[0][$val]['class'];
546 $method = $objimport->array_import_convertvalue[0][$val]['method'];
547 $units = $objimport->array_import_convertvalue[0][$val]['units'];
548 if ($this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$units][$newval] != '') {
549 $newval = $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$units][$newval];
550 } else {
551 $resultload = dol_include_once($file);
552 if (empty($resultload)) {
553 dol_print_error('', 'Error trying to call file='.$file.', class='.$class.', method='.$method.', units='.$units);
554 break;
555 }
556 $classinstance = new $class($this->db);
557 // Try the fetch from code or ref
558 call_user_func_array(array($classinstance, $method), array('', '', $newval, $units));
559 $scaleorid = (($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeunits') ? $classinstance->id : $classinstance->scale);
560 $this->cacheconvert[$file.'_'.$class.'_'.$method.'_'.$units][$newval] = $scaleorid;
561 //print 'We have made a '.$class.'->'.$method." to get a value from key '".$newval."' and we got '".$scaleorid."'.";exit;
562 if ($classinstance->id > 0) { // we found record
563 $newval = $scaleorid ? $scaleorid : 0;
564 } else {
565 if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
566 $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, 'scale', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
567 } else {
568 $this->errors[$error]['lib'] = 'ErrorFieldValueNotIn';
569 }
570 $this->errors[$error]['type'] = 'FOREIGNKEY';
571 $errorforthistable++;
572 $error++;
573 }
574 }
575 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getcustomercodeifauto') {
576 if (strtolower($newval) == 'auto') {
577 $this->thirdpartyobject->get_codeclient(0, 0);
578 $newval = $this->thirdpartyobject->code_client;
579 //print 'code_client='.$newval;
580 }
581 if (empty($newval)) {
582 $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
583 }
584 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getsuppliercodeifauto') {
585 if (strtolower($newval) == 'auto') {
586 $this->thirdpartyobject->get_codefournisseur(0, 1);
587 $newval = $this->thirdpartyobject->code_fournisseur;
588 //print 'code_fournisseur='.$newval;
589 }
590 if (empty($newval)) {
591 $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
592 }
593 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getcustomeraccountancycodeifauto') {
594 if (strtolower($newval) == 'auto') {
595 $this->thirdpartyobject->get_codecompta('customer');
596 $newval = $this->thirdpartyobject->code_compta;
597 //print 'code_compta='.$newval;
598 }
599 if (empty($newval)) {
600 $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
601 }
602 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getsupplieraccountancycodeifauto') {
603 if (strtolower($newval) == 'auto') {
604 $this->thirdpartyobject->get_codecompta('supplier');
605 $newval = $this->thirdpartyobject->code_compta_fournisseur;
606 if (empty($newval)) {
607 $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
608 }
609 //print 'code_compta_fournisseur='.$newval;
610 }
611 if (empty($newval)) {
612 $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
613 }
614 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getrefifauto') {
615 if (strtolower($newval) == 'auto') {
616 $defaultref = '';
617
618 $classModForNumber = $objimport->array_import_convertvalue[0][$val]['class'];
619 $pathModForNumber = $objimport->array_import_convertvalue[0][$val]['path'];
620
621 if (!empty($classModForNumber) && !empty($pathModForNumber) && is_readable(DOL_DOCUMENT_ROOT.$pathModForNumber)) {
622 require_once DOL_DOCUMENT_ROOT.$pathModForNumber;
623 $modForNumber = new $classModForNumber;
624
625 $tmpobject = null;
626 // Set the object with the date property when we can
627 if (!empty($objimport->array_import_convertvalue[0][$val]['classobject'])) {
628 $pathForObject = $objimport->array_import_convertvalue[0][$val]['pathobject'];
629 require_once DOL_DOCUMENT_ROOT.$pathForObject;
630 $tmpclassobject = $objimport->array_import_convertvalue[0][$val]['classobject'];
631 $tmpobject = new $tmpclassobject($this->db);
632 foreach ($arrayfield as $tmpkey => $tmpval) { // $arrayfield is array('c.ref'=>0, ...)
633 if (in_array($tmpkey, array('t.date', 'c.date_commande'))) {
634 $tmpobject->date = dol_stringtotime($arrayrecord[$arrayfield[$tmpkey]]['val'], 1);
635 }
636 }
637 }
638
639 $defaultref = $modForNumber->getNextValue(null, $tmpobject);
640 }
641 if (is_numeric($defaultref) && $defaultref <= 0) { // If error
642 $defaultref = '';
643 }
644 $newval = $defaultref;
645 }
646 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'compute') {
647 $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
648 $class = $objimport->array_import_convertvalue[0][$val]['class'];
649 $method = $objimport->array_import_convertvalue[0][$val]['method'];
650 $resultload = dol_include_once($file);
651 if (empty($resultload)) {
652 dol_print_error('', 'Error trying to call file='.$file.', class='.$class.', method='.$method);
653 break;
654 }
655 $classinstance = new $class($this->db);
656 $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $arrayfield, ($key - 1)));
657 if (empty($classinstance->error) && empty($classinstance->errors)) {
658 $newval = $res; // We get new value computed.
659 } else {
660 $this->errors[$error]['type'] = 'CLASSERROR';
661 $this->errors[$error]['lib'] = implode(
662 "\n",
663 array_merge([$classinstance->error], $classinstance->errors)
664 );
665 $errorforthistable++;
666 $error++;
667 }
668 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'numeric') {
669 $newval = price2num($newval);
670 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'accountingaccount') {
671 if (empty($conf->global->ACCOUNTING_MANAGE_ZERO)) {
672 $newval = rtrim(trim($newval), "0");
673 } else {
674 $newval = trim($newval);
675 }
676 }
677
678 //print 'Val to use as insert is '.$newval.'<br>';
679 }
680
681 // Test regexp
682 if (!empty($objimport->array_import_regex[0][$val]) && ($newval != '')) {
683 // If test is "Must exist in a field@table or field@table:..."
684 $reg = array();
685 if (preg_match('/^(.+)@([^:]+)(:.+)?$/', $objimport->array_import_regex[0][$val], $reg)) {
686 $field = $reg[1];
687 $table = $reg[2];
688 $filter = !empty($reg[3]) ?substr($reg[3], 1) : '';
689
690 $cachekey = $field.'@'.$table;
691 if (!empty($filter)) {
692 $cachekey .= ':'.$filter;
693 }
694
695 // Load content of field@table into cache array
696 if (!is_array($this->cachefieldtable[$cachekey])) { // If content of field@table not already loaded into cache
697 $sql = "SELECT ".$field." as aliasfield FROM ".$table;
698 if (!empty($filter)) {
699 $sql .= ' WHERE '.$filter;
700 }
701
702 $resql = $this->db->query($sql);
703 if ($resql) {
704 $num = $this->db->num_rows($resql);
705 $i = 0;
706 while ($i < $num) {
707 $obj = $this->db->fetch_object($resql);
708 if ($obj) {
709 $this->cachefieldtable[$cachekey][] = $obj->aliasfield;
710 }
711 $i++;
712 }
713 } else {
714 dol_print_error($this->db);
715 }
716 }
717
718 // Now we check cache is not empty (should not) and key is into cache
719 if (!is_array($this->cachefieldtable[$cachekey]) || !in_array($newval, $this->cachefieldtable[$cachekey])) {
720 $tableforerror = $table;
721 if (!empty($filter)) {
722 $tableforerror .= ':'.$filter;
723 }
724 $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, $field, $tableforerror);
725 $this->errors[$error]['type'] = 'FOREIGNKEY';
726 $errorforthistable++;
727 $error++;
728 }
729 } elseif (!preg_match('/'.$objimport->array_import_regex[0][$val].'/i', $newval)) {
730 // If test is just a static regex
731 //if ($key == 19) print "xxx".$newval."zzz".$objimport->array_import_regex[0][$val]."<br>";
732 $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorWrongValueForField', num2Alpha($key - 1), $newval, $objimport->array_import_regex[0][$val]);
733 $this->errors[$error]['type'] = 'REGEX';
734 $errorforthistable++;
735 $error++;
736 }
737 }
738
739 // Check HTML injection
740 $inj = testSqlAndScriptInject($newval, 0);
741 if ($inj) {
742 $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorHtmlInjectionForField', num2Alpha($key - 1), dol_trunc($newval, 100));
743 $this->errors[$error]['type'] = 'HTMLINJECTION';
744 $errorforthistable++;
745 $error++;
746 }
747
748 // Other tests
749 // ...
750 }
751
752 // Define $listfields and $listvalues to build SQL request
753 if (isModEnabled("socialnetworks") && strpos($fieldname, "socialnetworks") !== false) {
754 if (!in_array("socialnetworks", $listfields)) {
755 $listfields[] = "socialnetworks";
756 $socialkey = array_search("socialnetworks", $listfields); // Return position of 'socialnetworks' key in array
757 $listvalues[$socialkey] = '';
758 }
759 //var_dump($newval); var_dump($arrayrecord[($key - 1)]['type']);
760 if (!empty($newval) && $arrayrecord[($key - 1)]['type'] > 0) {
761 $socialkey = array_search("socialnetworks", $listfields); // Return position of 'socialnetworks' key in array
762 //var_dump('sk='.$socialkey); // socialkey=19
763 $socialnetwork = explode("_", $fieldname)[1];
764 if (empty($listvalues[$socialkey]) || $listvalues[$socialkey] == "null") {
765 $json = new stdClass();
766 $json->$socialnetwork = $newval;
767 $listvalues[$socialkey] = json_encode($json);
768 } else {
769 $jsondata = $listvalues[$socialkey];
770 $json = json_decode($jsondata);
771 $json->$socialnetwork = $newval;
772 $listvalues[$socialkey] = json_encode($json);
773 }
774 }
775 } else {
776 $listfields[] = $fieldname;
777 // Note: arrayrecord (and 'type') is filled with ->import_read_record called by import.php page before calling import_insert
778 if (empty($newval) && $arrayrecord[($key - 1)]['type'] < 0) {
779 $listvalues[] = ($newval == '0' ? $newval : "null");
780 } elseif (empty($newval) && $arrayrecord[($key - 1)]['type'] == 0) {
781 $listvalues[] = "''";
782 } else {
783 $listvalues[] = "'".$this->db->escape($newval)."'";
784 }
785 }
786 }
787 $i++;
788 }
789
790 // We add hidden fields (but only if there is at least one field to add into table)
791 // We process here all the fields that were declared into the array $this->import_fieldshidden_array of the descriptor file.
792 // Previously we processed the ->import_fields_array.
793 if (!empty($listfields) && is_array($objimport->array_import_fieldshidden[0])) {
794 // Loop on each hidden fields to add them into listfields/listvalues
795 foreach ($objimport->array_import_fieldshidden[0] as $tmpkey => $tmpval) {
796 if (!preg_match('/^'.preg_quote($alias, '/').'\./', $tmpkey)) {
797 continue; // Not a field of current table
798 }
799 if ($tmpval == 'user->id') {
800 $listfields[] = preg_replace('/^'.preg_quote($alias, '/').'\./', '', $tmpkey);
801 $listvalues[] = ((int) $user->id);
802 } elseif (preg_match('/^lastrowid-/', $tmpval)) {
803 $tmp = explode('-', $tmpval);
804 $lastinsertid = (isset($last_insert_id_array[$tmp[1]])) ? $last_insert_id_array[$tmp[1]] : 0;
805 $keyfield = preg_replace('/^'.preg_quote($alias, '/').'\./', '', $tmpkey);
806 $listfields[] = $keyfield;
807 $listvalues[] = $lastinsertid;
808 //print $tmpkey."-".$tmpval."-".$listfields."-".$listvalues."<br>";exit;
809 } elseif (preg_match('/^const-/', $tmpval)) {
810 $tmp = explode('-', $tmpval, 2);
811 $listfields[] = preg_replace('/^'.preg_quote($alias, '/').'\./', '', $tmpkey);
812 $listvalues[] = "'".$this->db->escape($tmp[1])."'";
813 } elseif (preg_match('/^rule-/', $tmpval)) {
814 $fieldname = $tmpkey;
815 if (!empty($objimport->array_import_convertvalue[0][$fieldname])) {
816 if ($objimport->array_import_convertvalue[0][$fieldname]['rule'] == 'compute') {
817 $file = (empty($objimport->array_import_convertvalue[0][$fieldname]['classfile']) ? $objimport->array_import_convertvalue[0][$fieldname]['file'] : $objimport->array_import_convertvalue[0][$fieldname]['classfile']);
818 $class = $objimport->array_import_convertvalue[0][$fieldname]['class'];
819 $method = $objimport->array_import_convertvalue[0][$fieldname]['method'];
820 $resultload = dol_include_once($file);
821 if (empty($resultload)) {
822 dol_print_error('', 'Error trying to call file=' . $file . ', class=' . $class . ', method=' . $method);
823 break;
824 }
825 $classinstance = new $class($this->db);
826 $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $arrayfield, ($key - 1)));
827 if (empty($classinstance->error) && empty($classinstance->errors)) {
828 $fieldArr = explode('.', $fieldname);
829 if (count($fieldArr) > 0) {
830 $fieldname = $fieldArr[1];
831 }
832 $listfields[] = $fieldname;
833 $listvalues[] = $res;
834 } else {
835 $this->errors[$error]['type'] = 'CLASSERROR';
836 $this->errors[$error]['lib'] = implode(
837 "\n",
838 array_merge([$classinstance->error], $classinstance->errors)
839 );
840 $errorforthistable++;
841 $error++;
842 }
843 }
844 }
845 } else {
846 $this->errors[$error]['lib'] = 'Bad value of profile setup '.$tmpval.' for array_import_fieldshidden';
847 $this->errors[$error]['type'] = 'Import profile setup';
848 $error++;
849 }
850 }
851 }
852 //print 'listfields='.$listfields.'<br>listvalues='.$listvalues.'<br>';
853
854 // If no error for this $alias/$tablename, we have a complete $listfields and $listvalues that are defined
855 // so we can try to make the insert or update now.
856 if (!$errorforthistable) {
857 //print "$alias/$tablename/$listfields/$listvalues<br>";
858 if (!empty($listfields)) {
859 $updatedone = false;
860 $insertdone = false;
861
862 $is_table_category_link = false;
863 $fname = 'rowid';
864 if (strpos($tablename, '_categorie_') !== false) {
865 $is_table_category_link = true;
866 $fname='*';
867 }
868
869 if (!empty($updatekeys)) {
870 // We do SELECT to get the rowid, if we already have the rowid, it's to be used below for related tables (extrafields)
871
872 if (empty($lastinsertid)) { // No insert done yet for a parent table
873 $sqlSelect = "SELECT ".$fname." FROM ".$tablename;
874 $data = array_combine($listfields, $listvalues);
875 $where = array(); // filters to forge SQL request
876 $filters = array(); // filters to forge output error message
877 foreach ($updatekeys as $key) {
878 $col = $objimport->array_import_updatekeys[0][$key];
879 $key = preg_replace('/^.*\./i', '', $key);
880 if (isModEnabled("socialnetworks") && strpos($key, "socialnetworks") !== false) {
881 $tmp = explode("_", $key);
882 $key = $tmp[0];
883 $socialnetwork = $tmp[1];
884 $jsondata = $data[$key];
885 $json = json_decode($jsondata);
886 $stringtosearch = json_encode($socialnetwork).':'.json_encode($json->$socialnetwork);
887 //var_dump($stringtosearch);
888 //var_dump($this->db->escape($stringtosearch)); // This provide a value for sql string (but not for a like)
889 $where[] = $key." LIKE '%".$this->db->escape($this->db->escapeforlike($stringtosearch))."%'";
890 $filters[] = $col." LIKE '%".$this->db->escape($this->db->escapeforlike($stringtosearch))."%'";
891 //var_dump($where[1]); // This provide a value for sql string inside a like
892 } else {
893 $where[] = $key.' = '.$data[$key];
894 $filters[] = $col.' = '.$data[$key];
895 }
896 }
897 if (!empty($tablewithentity_cache[$tablename])) {
898 $where[] = "entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")";
899 $filters[] = "entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")";
900 }
901 $sqlSelect .= " WHERE ".implode(' AND ', $where);
902
903 $resql = $this->db->query($sqlSelect);
904 if ($resql) {
905 $num_rows = $this->db->num_rows($resql);
906 if ($num_rows == 1) {
907 $res = $this->db->fetch_object($resql);
908 $lastinsertid = $res->rowid;
909 if ($is_table_category_link) $lastinsertid = 'linktable'; // 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;
974 }
975 $sqlstart .= " SET ".implode(', ', $set);
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:409
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.
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