dolibarr 25.0.0-alpha
modules_import.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2005-2012 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
4 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
5 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
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
27require_once DOL_DOCUMENT_ROOT.'/core/lib/functions.lib.php';
28
29
34{
38 public $db;
39
43 public $datatoimport;
44
48 public $error = '';
49
53 public $errors = array();
54
58 public $warnings = array();
59
63 public $id;
64
68 public $label;
69
73 public $extension;
74
79 public $version = 'dolibarr';
80
85 public $phpmin = array(7, 0);
86
91 public $label_lib;
92
97 public $version_lib;
98
99 // Array of all drivers
103 public $driverlabel = array();
104
108 public $driverdesc = array();
109
113 public $driverversion = array();
114
118 public $drivererror = array();
119
123 public $liblabel = array();
124
128 public $libversion = array();
129
133 public $charset;
134
138 public $picto;
139
143 public $desc;
144
148 public $escape;
149
153 public $enclosure;
154
158 public $thirdpartyobject;
159
167 public $importtriggermode = '';
168
176 public $importissimulation = 0;
177
183 public $importtriggerinterface;
184
190 public $importbulkstats = array();
191
197 public $importtriggerobjectprototypes = array();
198
204 public $importtriggeractionshookcache = array();
205
211 public $cacheconvert = array();
212
218 public $cachefieldtable = array();
219
225 public $nbinsert = 0;
226
232 public $nbupdate = 0;
233
237 public static $mapTableToElement = MODULE_MAPPING;
238
242 public function __construct()
243 {
244 global $hookmanager;
245
246 if (is_object($hookmanager)) {
247 $hookmanager->initHooks(array('import'));
248 $parameters = array();
249 $reshook = $hookmanager->executeHooks('constructModeleImports', $parameters, $this);
250 if ($reshook >= 0 && !empty($hookmanager->resArray)) {
251 foreach ($hookmanager->resArray as $mapList) {
252 self::$mapTableToElement[$mapList['table']] = $mapList['element'];
253 }
254 }
255 }
256 }
257
263 public function getDriverId()
264 {
265 return $this->id;
266 }
267
273 public function getDriverLabel()
274 {
275 return $this->label;
276 }
277
283 public function getDriverDesc()
284 {
285 return $this->desc;
286 }
287
293 public function getDriverExtension()
294 {
295 return $this->extension;
296 }
297
303 public function getDriverVersion()
304 {
305 return $this->version;
306 }
307
313 public function getLibLabel()
314 {
315 return $this->label_lib;
316 }
317
323 public function getLibVersion()
324 {
325 return $this->version_lib;
326 }
327
328
336 public function listOfAvailableImportFormat($db, $maxfilenamelength = 0)
337 {
338 dol_syslog(get_class($this)."::listOfAvailableImportFormat");
339
340 $dir = DOL_DOCUMENT_ROOT."/core/modules/import/";
341 $handle = opendir($dir);
342
343 // Search list ov drivers available and qualified
344 if (is_resource($handle)) {
345 while (($file = readdir($handle)) !== false) {
346 $reg = array();
347 if (preg_match("/^import_(.*)\.modules\.php/i", $file, $reg)) {
348 $moduleid = $reg[1];
349
350 // Loading Class
351 $file = $dir."/import_".$moduleid.".modules.php";
352 $classname = "Import".ucfirst($moduleid);
353
354 require_once $file;
355 $module = new $classname($db, '');
356 '@phan-var-force ModeleImports $module';
357
358 // Picto
359 $this->picto[$module->id] = $module->picto;
360 // Driver properties
361 $this->driverlabel[$module->id] = $module->getDriverLabel();
362 $this->driverdesc[$module->id] = $module->getDriverDesc();
363 $this->driverversion[$module->id] = $module->getDriverVersion();
364 $this->drivererror[$module->id] = $module->error ? $module->error : '';
365 // If use an external lib
366 $this->liblabel[$module->id] = ($module->error ? '<span class="error">'.$module->error.'</span>' : $module->getLibLabel());
367 $this->libversion[$module->id] = $module->getLibVersion();
368 }
369 }
370 }
371
372 return array_keys($this->driverlabel);
373 }
374
375
382 public function getPictoForKey($key)
383 {
384 return $this->picto[$key];
385 }
386
393 public function getDriverLabelForKey($key)
394 {
395 return $this->driverlabel[$key];
396 }
397
404 public function getDriverDescForKey($key)
405 {
406 return $this->driverdesc[$key];
407 }
408
415 public function getDriverVersionForKey($key)
416 {
417 return $this->driverversion[$key];
418 }
419
426 public function getLibLabelForKey($key)
427 {
428 return $this->liblabel[$key];
429 }
430
437 public function getLibVersionForKey($key)
438 {
439 return $this->libversion[$key];
440 }
441
448 public function getElementFromTableWithPrefix($tableNameWithPrefix)
449 {
450 $tableElement = preg_replace('/^'.preg_quote($this->db->prefix(), '/').'/', '', $tableNameWithPrefix);
451 $element = $tableElement;
452
453 if (isset(self::$mapTableToElement[$tableElement])) {
454 $element = self::$mapTableToElement[$tableElement];
455 }
456
457 return $element;
458 }
459
465 protected function getImportTriggerMode()
466 {
467 $mode = trim((string) $this->importtriggermode);
468 if ($mode === '') {
469 $mode = (string) getDolGlobalString('IMPORT_TRIGGER_MODE_DEFAULT', 'strict_line');
470 }
471 if (!in_array($mode, array('strict_line', 'fast_bulk'), true)) {
472 $mode = 'strict_line';
473 }
474 return $mode;
475 }
476
484 protected function registerImportBulkEvent($tablename, $operation)
485 {
486 if (empty($this->importbulkstats)) {
487 $this->importbulkstats = array(
488 'insert' => 0,
489 'update' => 0,
490 'tables' => array(),
491 );
492 }
493
494 $operation = strtolower((string) $operation);
495 if (!isset($this->importbulkstats[$operation])) {
496 $this->importbulkstats[$operation] = 0;
497 }
498 $this->importbulkstats[$operation]++;
499
500 $tableElement = preg_replace('/^'.preg_quote($this->db->prefix(), '/').'/', '', (string) $tablename);
501 if (!isset($this->importbulkstats['tables'][$tableElement])) {
502 $this->importbulkstats['tables'][$tableElement] = array('insert' => 0, 'update' => 0);
503 }
504 if (!isset($this->importbulkstats['tables'][$tableElement][$operation])) {
505 $this->importbulkstats['tables'][$tableElement][$operation] = 0;
506 }
507 $this->importbulkstats['tables'][$tableElement][$operation]++;
508 }
509
519 public function runImportBulkTrigger($importid, $user, $langs, $conf)
520 {
521 require_once DOL_DOCUMENT_ROOT.'/core/class/interfaces.class.php';
522
523 if (!($this->importtriggerinterface instanceof Interfaces)) {
524 $this->importtriggerinterface = new Interfaces($this->db);
525 }
526
527 $object = new stdClass();
528 $object->db = $this->db;
529 $object->id = 0;
530 $object->rowid = 0;
531 $object->import_key = $importid;
532 $object->context = array(
533 'import' => 1,
534 'operation' => 'bulk',
535 'importtriggermode' => $this->getImportTriggerMode(),
536 );
537 $object->bulk_stats = (empty($this->importbulkstats) ? array('insert' => 0, 'update' => 0, 'tables' => array()) : $this->importbulkstats);
538
539 try {
540 $result = $this->importtriggerinterface->run_triggers('IMPORT_BULK_DONE', $object, $user, $langs, $conf);
541 } catch (Throwable $e) {
542 $this->errors[] = array('lib' => $e->getMessage(), 'type' => 'TRIGGER');
543 $this->error = 'ErrorFailedTriggerCall';
544 return -1;
545 }
546
547 if ($result < 0) {
548 if (!empty($this->importtriggerinterface->errors)) {
549 foreach ($this->importtriggerinterface->errors as $errormsg) {
550 $this->errors[] = array('lib' => $errormsg, 'type' => 'TRIGGER');
551 }
552 }
553 $this->error = 'ErrorFailedTriggerCall';
554 return -1;
555 }
556
557 return 1;
558 }
559
569 protected function getImportTriggerActions($tableElement, $operation, $element, $object = null)
570 {
571 $operation = strtolower((string) $operation);
572
573 $actionMap = array(
574 'societe' => array('insert' => 'COMPANY_CREATE', 'update' => 'COMPANY_MODIFY'),
575 'product' => array('insert' => 'PRODUCT_CREATE', 'update' => 'PRODUCT_MODIFY'),
576 'socpeople' => array('insert' => 'CONTACT_CREATE', 'update' => 'CONTACT_MODIFY'),
577 'commande' => array('insert' => 'ORDER_CREATE', 'update' => 'ORDER_MODIFY'),
578 'commandedet' => array('insert' => 'LINEORDER_INSERT', 'update' => 'LINEORDER_MODIFY'),
579 'propal' => array('insert' => 'PROPAL_CREATE', 'update' => 'PROPAL_MODIFY'),
580 'propaldet' => array('insert' => 'LINEPROPAL_INSERT', 'update' => 'LINEPROPAL_MODIFY'),
581 'facture' => array('insert' => 'BILL_CREATE', 'update' => 'BILL_MODIFY'),
582 'facturedet' => array('insert' => 'LINEBILL_INSERT', 'update' => 'LINEBILL_MODIFY'),
583 'facture_fourn' => array('insert' => 'BILL_SUPPLIER_CREATE', 'update' => 'BILL_SUPPLIER_MODIFY'),
584 'facture_fourn_det' => array('insert' => 'LINEBILL_SUPPLIER_CREATE', 'update' => 'LINEBILL_SUPPLIER_MODIFY'),
585 'commande_fournisseur' => array('insert' => 'ORDER_SUPPLIER_CREATE', 'update' => 'ORDER_SUPPLIER_MODIFY'),
586 'commande_fournisseurdet' => array('insert' => 'LINEORDER_SUPPLIER_CREATE', 'update' => 'LINEORDER_SUPPLIER_MODIFY'),
587 'contrat' => array('insert' => 'CONTRACT_CREATE', 'update' => 'CONTRACT_MODIFY'),
588 'contratdet' => array('insert' => 'LINECONTRACT_INSERT', 'update' => 'LINECONTRACT_MODIFY'),
589 'fichinter' => array('insert' => 'FICHINTER_CREATE', 'update' => 'FICHINTER_MODIFY'),
590 'fichinterdet' => array('insert' => 'LINEFICHINTER_CREATE', 'update' => 'LINEFICHINTER_MODIFY'),
591 'expedition' => array('insert' => 'SHIPPING_CREATE', 'update' => 'SHIPPING_MODIFY'),
592 'expeditiondet' => array('insert' => 'LINESHIPPING_INSERT', 'update' => 'LINESHIPPING_MODIFY'),
593 'supplier_proposal' => array('insert' => 'SUPPLIER_PROPOSAL_CREATE', 'update' => 'SUPPLIER_PROPOSAL_MODIFY'),
594 'supplier_proposaldet' => array('insert' => 'LINESUPPLIER_PROPOSAL_INSERT', 'update' => 'LINESUPPLIER_PROPOSAL_MODIFY'),
595 );
596
597 $actions = array();
598 if (!empty($actionMap[$tableElement][$operation])) {
599 $actions[] = $actionMap[$tableElement][$operation];
600 }
601
602 // Let external modules add explicit import trigger actions.
603 // We merge with core mapping when present.
604 $hookactions = $this->getImportTriggerActionsFromHooks($tableElement, $operation, $element, $object);
605 if (!empty($hookactions)) {
606 $actions = array_merge($actions, $hookactions);
607 }
608
609 // Dynamic fallback only for real business objects and only when
610 // no explicit mapping/hook action exists.
611 // Avoid generating trigger names from stdClass (legacy SQL context).
612 if (empty($actions) && is_object($object) && method_exists($object, 'call_trigger')) {
613 $triggerprefix = $this->getImportTriggerPrefixFromObject($object);
614 $action = $this->buildImportTriggerActionFromPrefix($triggerprefix, $operation);
615 if (!empty($action)) {
616 $actions[] = $action;
617 }
618 }
619
620 // Generic fallback for external/custom objects imported through legacy SQL path:
621 // derive a deterministic trigger prefix from element/table when no explicit mapping exists.
622 if (empty($actions)) {
623 $triggerprefix = $this->getImportGenericTriggerPrefix($element, $tableElement);
624 $action = $this->buildImportTriggerActionFromPrefix($triggerprefix, $operation);
625 if (!empty($action)) {
626 $actions[] = $action;
627 }
628 }
629
630 return array_values(array_unique(array_filter($actions)));
631 }
632
640 protected function buildImportTriggerActionFromPrefix($triggerprefix, $operation)
641 {
642 $triggerprefix = strtoupper(trim((string) $triggerprefix));
643 $operation = strtolower((string) $operation);
644 if ($triggerprefix === '') {
645 return '';
646 }
647
648 if ($operation === 'update') {
649 return $triggerprefix.'_MODIFY';
650 }
651 if ($operation === 'insert') {
652 return preg_match('/^LINE/', $triggerprefix) ? $triggerprefix.'_INSERT' : $triggerprefix.'_CREATE';
653 }
654
655 return '';
656 }
657
665 {
666 if (!empty($object->TRIGGER_PREFIX)) {
667 return (string) $object->TRIGGER_PREFIX;
668 }
669 if (!empty($object->element)) {
670 return (string) $object->element;
671 }
672 return get_class($object);
673 }
674
682 protected function getImportGenericTriggerPrefix($element, $tableElement)
683 {
684 $rawprefix = '';
685 if (!empty($element)) {
686 $rawprefix = (string) $element;
687 } elseif (!empty($tableElement)) {
688 $rawprefix = (string) $tableElement;
689 }
690
691 return trim((string) preg_replace('/[^A-Za-z0-9]+/', '_', strtoupper($rawprefix)), '_');
692 }
693
711 protected function getImportTriggerActionsFromHooks($tableElement, $operation, $element, $object = null)
712 {
713 global $hookmanager;
714
715 $actions = array();
716 $objectclass = (is_object($object) ? get_class($object) : 'none');
717 $cachekey = $tableElement.'|'.$operation.'|'.$element.'|'.$objectclass;
718 if (isset($this->importtriggeractionshookcache[$cachekey])) {
719 return $this->importtriggeractionshookcache[$cachekey];
720 }
721
722 if (!is_object($hookmanager)) {
723 $this->importtriggeractionshookcache[$cachekey] = $actions;
724 return $actions;
725 }
726
727 $hookmanager->initHooks(array('import'));
728 $parameters = array(
729 'tableelement' => (string) $tableElement,
730 'operation' => (string) $operation,
731 'element' => (string) $element,
732 );
733 $action = '';
734 $hookmanager->executeHooks('getImportTriggerActions', $parameters, $object, $action);
735
736 if (!empty($hookmanager->resArray['actions'])) {
737 if (is_array($hookmanager->resArray['actions'])) {
738 $actions = array_merge($actions, $hookmanager->resArray['actions']);
739 } else {
740 $actions = array_merge($actions, preg_split('/[\s,;|]+/', (string) $hookmanager->resArray['actions']));
741 }
742 }
743 if (!empty($hookmanager->resArray['action'])) {
744 $actions[] = (string) $hookmanager->resArray['action'];
745 }
746
747 $cleaned = array();
748 foreach ($actions as $oneaction) {
749 $oneaction = strtoupper(trim((string) $oneaction));
750 if ($oneaction !== '') {
751 $cleaned[] = $oneaction;
752 }
753 }
754
755 $cleaned = array_values(array_unique($cleaned));
756 $this->importtriggeractionshookcache[$cachekey] = $cleaned;
757 return $cleaned;
758 }
759
772 protected function triggerImportSqlOperation($tablename, $operation, $rowid, $importid, $user, $langs, $conf)
773 {
774 require_once DOL_DOCUMENT_ROOT.'/core/class/interfaces.class.php';
775
776 $tableElement = preg_replace('/^'.preg_quote($this->db->prefix(), '/').'/', '', $tablename);
777 $element = $this->getElementFromTableWithPrefix($tablename);
778 $object = null;
779 $needenrichobject = (bool) getDolGlobalInt('IMPORT_TRIGGER_ENRICH_OBJECT');
780
781 // Fast-path: for mapped tables, get action list without loading business object.
782 $actions = $this->getImportTriggerActions($tableElement, $operation, $element, null);
783
784 // Resolve business object only when needed:
785 // - dynamic action fallback requires real object,
786 // - optional richer trigger context can be enabled with IMPORT_TRIGGER_ENRICH_OBJECT.
787 if (empty($actions) || $needenrichobject) {
788 // Try to resolve a real business object for full trigger compatibility.
789 // - with rowid when available (best case),
790 // - otherwise as a prototype object based on element/table.
791 if ((int) $rowid > 0) {
792 $objecttmp = fetchObjectByElement((int) $rowid, $tableElement);
793 if (is_object($objecttmp)) {
794 $object = $objecttmp;
795 }
796 }
797 if (!is_object($object)) {
798 $objecttmp = fetchObjectByElement(0, $tableElement);
799 if (is_object($objecttmp)) {
800 $object = $objecttmp;
801 if ((int) $rowid > 0) {
802 if (method_exists($object, 'fetch')) {
803 $fetchres = $object->fetch((int) $rowid);
804 if ($fetchres <= 0) {
805 $object->id = (int) $rowid;
806 $object->rowid = (int) $rowid;
807 }
808 } else {
809 $object->id = (int) $rowid;
810 $object->rowid = (int) $rowid;
811 }
812 }
813 }
814 }
815 }
816
817 // Compatibility path for strict_line mode:
818 // for mapped actions, provide at least a business object prototype (not stdClass)
819 // so custom triggers can call object methods safely.
820 if (!is_object($object) && !empty($actions) && $this->getImportTriggerMode() === 'strict_line') {
821 if (!isset($this->importtriggerobjectprototypes[$tableElement])) {
822 $prototype = fetchObjectByElement(0, $tableElement);
823 if (is_object($prototype)) {
824 $this->importtriggerobjectprototypes[$tableElement] = $prototype;
825 }
826 }
827 if (isset($this->importtriggerobjectprototypes[$tableElement])) {
828 $object = clone $this->importtriggerobjectprototypes[$tableElement];
829 $object->id = (int) $rowid;
830 $object->rowid = (int) $rowid;
831 if ((int) $rowid > 0 && method_exists($object, 'fetch')) {
832 $fetchres = $object->fetch((int) $rowid);
833 if ($fetchres <= 0) {
834 $object->id = (int) $rowid;
835 $object->rowid = (int) $rowid;
836 }
837 }
838 }
839 }
840
841 if (!is_object($object)) {
842 $object = new stdClass();
843 $object->db = $this->db;
844 $object->id = (int) $rowid;
845 $object->rowid = (int) $rowid;
846 $object->table_element = $tableElement;
847 $object->element = $element;
848 }
849 $object->import_key = $importid;
850 $object->context = array('import' => 1, 'operation' => $operation);
851
852 if (empty($actions)) {
853 $actions = $this->getImportTriggerActions($tableElement, $operation, $element, $object);
854 }
855
856 if (empty($actions)) {
857 dol_syslog(get_class($this)."::triggerImportSqlOperation no trigger mapping for table=".$tableElement." operation=".$operation, LOG_DEBUG);
858 return 1;
859 }
860
861 // Optional enrichment: provides full row payload for stdClass context.
862 // Disabled by default for performance.
863 if ($needenrichobject && $rowid > 0 && $object instanceof stdClass) {
864 $sql = "SELECT * FROM ".$tablename." WHERE rowid = ".((int) $rowid);
865 $resql = $this->db->query($sql);
866 if ($resql) {
867 $objrow = $this->db->fetch_object($resql);
868 if ($objrow) {
869 foreach (get_object_vars($objrow) as $key => $value) {
870 $object->$key = $value;
871 }
872 if (!isset($object->id) && isset($object->rowid)) {
873 $object->id = (int) $object->rowid;
874 }
875 }
876 }
877 }
878
879 if (!($this->importtriggerinterface instanceof Interfaces)) {
880 $this->importtriggerinterface = new Interfaces($this->db);
881 }
882 $interface = $this->importtriggerinterface;
883 foreach ($actions as $action) {
884 try {
885 $result = $interface->run_triggers($action, $object, $user, $langs, $conf);
886 } catch (Throwable $e) {
887 $this->errors[] = array('lib' => $e->getMessage(), 'type' => 'TRIGGER');
888 $this->error = 'ErrorFailedTriggerCall';
889 return -1;
890 }
891 if ($result < 0) {
892 if (!empty($interface->errors)) {
893 foreach ($interface->errors as $errormsg) {
894 $this->errors[] = array('lib' => $errormsg, 'type' => 'TRIGGER');
895 }
896 }
897 $this->error = 'ErrorFailedTriggerCall';
898 return -1;
899 }
900 }
901
902 return 1;
903 }
904
905 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
912 public function import_open_file($file)
913 {
914 // phpcs:enable
915 $msg = get_class($this)."::".__FUNCTION__." not implemented";
916 dol_syslog($msg, LOG_ERR);
917 $this->errors[] = $msg;
918 $this->error = $msg;
919 return -1;
920 }
921
922
923 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
930 public function import_get_nb_of_lines($file)
931 {
932 // phpcs:enable
933 $msg = get_class($this)."::".__FUNCTION__." not implemented";
934 dol_syslog($msg, LOG_ERR);
935 $this->errors[] = $msg;
936 $this->error = $msg;
937 return -1;
938 }
939
940 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
946 public function import_read_header()
947 {
948 // phpcs:enable
949 $msg = get_class($this)."::".__FUNCTION__." not implemented";
950 dol_syslog($msg, LOG_ERR);
951 $this->errors[] = $msg;
952 $this->error = $msg;
953 return -1;
954 }
955
956
957 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
963 public function import_read_record()
964 {
965 // phpcs:enable
966 $msg = get_class($this)."::".__FUNCTION__." not implemented";
967 dol_syslog($msg, LOG_ERR);
968 $this->errors[] = $msg;
969 $this->error = $msg;
970 return array();
971 }
972
973
974 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
980 public function import_close_file()
981 {
982 // phpcs:enable
983 $msg = get_class($this)."::".__FUNCTION__." not implemented";
984 dol_syslog($msg, LOG_ERR);
985 $this->errors[] = $msg;
986 $this->error = $msg;
987 return -1;
988 }
989
1002 protected function commonImportInsert($arrayrecord, $array_match_file_to_database, $objimport, $maxfields, $importid, $updatekeys, $recordpositionbase = 0)
1003 {
1004 global $langs, $conf, $user;
1005 global $thirdparty_static; // Specific to thirdparty import
1006 global $tablewithentity_cache; // Cache to avoid to call entity desc at each rows on tables
1007
1008 if (is_array($arrayrecord) && !empty($recordpositionbase)) {
1009 $arrayrecord = array_values($arrayrecord);
1010 }
1011
1012 $error = 0;
1013 $warning = 0;
1014 $importtriggermode = $this->getImportTriggerMode();
1015 $importissimulation = !empty($this->importissimulation);
1016 $this->errors = array();
1017 $this->warnings = array();
1018
1019 //dol_syslog("import_csv.modules maxfields=".$maxfields." importid=".$importid);
1020
1021 //var_dump($array_match_file_to_database);
1022 //var_dump($arrayrecord); exit;
1023 $array_match_database_to_file = array_flip($array_match_file_to_database);
1024 $sort_array_match_file_to_database = $array_match_file_to_database;
1025 ksort($sort_array_match_file_to_database);
1026
1027 //var_dump($sort_array_match_file_to_database);
1028
1029 if (count($arrayrecord) == 0 || (count($arrayrecord) == 1 && empty($arrayrecord[0]['val']))) {
1030 //print 'W';
1031 $this->warnings[$warning]['lib'] = $langs->trans('EmptyLine');
1032 $this->warnings[$warning]['type'] = 'EMPTY';
1033 $warning++;
1034 } else {
1035 $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)
1036 $updatedone = false;
1037 $insertdone = false;
1038 // For each table to insert, me make a separate insert
1039 foreach ($objimport->array_import_tables[0] as $alias => $tablename) {
1040 // Build sql request
1041 $sql = '';
1042 $sql_listfields = array();
1043 $sql_listvalues = array();
1044 $i = 0;
1045 $errorforthistable = 0;
1046
1047 // Define $tablewithentity_cache[$tablename] if not already defined
1048 if (!isset($tablewithentity_cache[$tablename])) { // keep this test with "isset"
1049 dol_syslog("Check if table ".$tablename." has an entity field");
1050 $resql = $this->db->DDLDescTable($tablename, 'entity');
1051 if ($resql) {
1052 $obj = $this->db->fetch_object($resql);
1053 if ($obj) {
1054 $tablewithentity_cache[$tablename] = 1; // table contains entity field
1055 } else {
1056 $tablewithentity_cache[$tablename] = 0; // table does not contain entity field
1057 }
1058 } else {
1059 dol_print_error($this->db);
1060 }
1061 } else {
1062 //dol_syslog("Table ".$tablename." check for entity into cache is ".$tablewithentity_cache[$tablename]);
1063 }
1064
1065 // Define an array to convert fields ('c.ref', ...) into column index (1, ...)
1066 $arrayfield = array();
1067 foreach ($sort_array_match_file_to_database as $key => $val) {
1068 $arrayfield[$val] = ($key - 1);
1069 }
1070
1071 // $arrayrecord start at key 0
1072 // $sort_array_match_file_to_database start at key 1
1073
1074 // Loop on each fields in the match array: $key = 1..n, $val=alias of field (s.nom)
1075 foreach ($sort_array_match_file_to_database as $key => $val) {
1076 $fieldalias = preg_replace('/\..*$/i', '', $val);
1077 $fieldname = preg_replace('/^.*\./i', '', $val);
1078
1079 if ($alias != $fieldalias) {
1080 continue; // Not a field of current table
1081 }
1082
1083 if ($key <= $maxfields) {
1084 // Set $newval with value to insert and set $sql_listvalues with sql request part for insert
1085 $newval = '';
1086 if ($arrayrecord[($key - 1)]['type'] > 0) {
1087 $newval = $arrayrecord[($key - 1)]['val']; // If type of field into input file is not empty string (so defined into input file), we get value
1088 }
1089
1090 //var_dump($newval);var_dump($val);
1091 //var_dump($objimport->array_import_convertvalue[0][$val]);
1092
1093 // Make some tests on $newval
1094
1095 // Is it a required field ?
1096 if (preg_match('/\*/', $objimport->array_import_fields[0][$val]) && ((string) $newval == '')) {
1097 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
1098 $this->errors[$error]['lib'] = $langs->trans('ErrorMissingMandatoryValue', $key);
1099 $this->errors[$error]['type'] = 'NOTNULL';
1100 $errorforthistable++;
1101 $error++;
1102 } else {
1103 // Test format only if field is not a missing mandatory field (field may be a value or empty but not mandatory)
1104 // We convert field if required
1105 if (!empty($objimport->array_import_convertvalue[0][$val])) {
1106 //print 'Must convert '.$newval.' with rule '.join(',',$objimport->array_import_convertvalue[0][$val]).'. ';
1107 if ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeid'
1108 || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromref'
1109 || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeorlabel'
1110 ) {
1111 // 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.
1112 $isidorref = 'id';
1113 if (!is_numeric($newval) && $newval != '' && !preg_match('/^id:/i', $newval)) {
1114 $isidorref = 'ref';
1115 }
1116
1117 $newval = preg_replace('/^(id|ref):/i', '', $newval); // Remove id: or ref: that was used to force if field is id or ref
1118 //print 'Newval is now "'.$newval.'" and is type '.$isidorref."<br>\n";
1119
1120 if ($isidorref == 'ref') { // If value into input import file is a ref, we apply the function defined into descriptor
1121 $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
1122 $class = $objimport->array_import_convertvalue[0][$val]['class'];
1123 $method = $objimport->array_import_convertvalue[0][$val]['method'];
1124 $cachekey = $file.'_'.$class.'_'.$method.'_';
1125 if (isset($this->cacheconvert[$cachekey][$newval]) && $this->cacheconvert[$cachekey][$newval] != '') {
1126 $newval = $this->cacheconvert[$cachekey][$newval];
1127 } else {
1128 $resultload = dol_include_once($file);
1129 if (empty($resultload)) {
1130 dol_print_error(null, 'Error trying to call file='.$file.', class='.$class.', method='.$method);
1131 break;
1132 }
1133 $classinstance = new $class($this->db);
1134 if ($class == 'CGenericDic') {
1135 $classinstance->element = $objimport->array_import_convertvalue[0][$val]['element'];
1136 $classinstance->table_element = $objimport->array_import_convertvalue[0][$val]['table_element'];
1137 }
1138
1139 // Try the fetch from code or ref
1140 $param_array = array('', $newval);
1141 if ($class == 'AccountingAccount') {
1142 //var_dump($arrayrecord[0]['val']);
1143 /*include_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountancysystem.class.php';
1144 $tmpchartofaccount = new AccountancySystem($this->db);
1145 $tmpchartofaccount->fetch(getDolGlobalInt('CHARTOFACCOUNTS'));
1146 //var_dump($tmpchartofaccount->ref.' - '.$arrayrecord[0]['val']);
1147 if ((! (getDolGlobalInt('CHARTOFACCOUNTS') > 0)) || $tmpchartofaccount->ref != $arrayrecord[0]['val'])
1148 {
1149 $this->errors[$error]['lib']=$langs->trans('ErrorImportOfChartLimitedToCurrentChart', $tmpchartofaccount->ref);
1150 $this->errors[$error]['type']='RESTRICTONCURRENCTCHART';
1151 $errorforthistable++;
1152 $error++;
1153 }*/
1154 $param_array = array('', $newval, 0, $arrayrecord[0]['val']); // Param to fetch parent from account, in chart.
1155 }
1156 if ($class == 'CActionComm') {
1157 $param_array = array($newval); // CActionComm fetch method have same parameter for id and code
1158 }
1159 $result = call_user_func_array(array($classinstance, $method), $param_array);
1160
1161 // If duplicate record found
1162 if (!($classinstance->id != '') && $result == -2) {
1163 $this->errors[$error]['lib'] = $langs->trans('ErrorMultipleRecordFoundFromRef', $newval);
1164 $this->errors[$error]['type'] = 'FOREIGNKEY';
1165 $errorforthistable++;
1166 $error++;
1167 }
1168
1169 // If not found, try the fetch from label
1170 if (!($classinstance->id != '') && $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeorlabel') {
1171 $param_array = array('', '', $newval);
1172 call_user_func_array(array($classinstance, $method), $param_array);
1173 }
1174 $this->cacheconvert[$cachekey][$newval] = $classinstance->id;
1175
1176 //print 'We have made a '.$class.'->'.$method.' to get id from code '.$newval.'. ';
1177 if ($classinstance->id != '') { // id may be 0, it is a found value
1178 $newval = $classinstance->id;
1179 } elseif (! $error) {
1180 if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
1181 $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, 'code', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
1182 } elseif (!empty($objimport->array_import_convertvalue[0][$val]['element'])) {
1183 $this->errors[$error]['lib'] = $langs->trans('ErrorFieldRefNotIn', num2Alpha($key - 1), $newval, $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['element']));
1184 } else {
1185 $this->errors[$error]['lib'] = 'ErrorBadDefinitionOfImportProfile';
1186 }
1187 $this->errors[$error]['type'] = 'FOREIGNKEY';
1188 $errorforthistable++;
1189 $error++;
1190 }
1191 }
1192 }
1193 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeandlabel') {
1194 $isidorref = 'id';
1195 if (!is_numeric($newval) && $newval != '' && !preg_match('/^id:/i', $newval)) {
1196 $isidorref = 'ref';
1197 }
1198 $newval = preg_replace('/^(id|ref):/i', '', $newval);
1199
1200 if ($isidorref == 'ref') {
1201 $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
1202 $class = $objimport->array_import_convertvalue[0][$val]['class'];
1203 $method = $objimport->array_import_convertvalue[0][$val]['method'];
1204 $codefromfield = $objimport->array_import_convertvalue[0][$val]['codefromfield'];
1205 $code = $arrayrecord[$arrayfield[$codefromfield]]['val'];
1206 $cachekey = $file.'_'.$class.'_'.$method.'_'.$code;
1207 if (isset($this->cacheconvert[$cachekey][$newval]) && $this->cacheconvert[$cachekey][$newval] != '') {
1208 $newval = $this->cacheconvert[$cachekey][$newval];
1209 } else {
1210 $resultload = dol_include_once($file);
1211 if (empty($resultload)) {
1212 dol_print_error(null, 'Error trying to call file='.$file.', class='.$class.', method='.$method.', code='.$code);
1213 break;
1214 }
1215 $classinstance = new $class($this->db);
1216 // Try the fetch from code and ref
1217 $param_array = array('', $newval, $code);
1218 call_user_func_array(array($classinstance, $method), $param_array);
1219 $this->cacheconvert[$cachekey][$newval] = $classinstance->id;
1220 if ($classinstance->id > 0) { // we found record
1221 $newval = $classinstance->id;
1222 } else {
1223 if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
1224 $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, 'scale', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
1225 } else {
1226 $this->errors[$error]['lib'] = 'ErrorFieldValueNotIn';
1227 }
1228 $this->errors[$error]['type'] = 'FOREIGNKEY';
1229 $errorforthistable++;
1230 $error++;
1231 }
1232 }
1233 }
1234 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'zeroifnull') {
1235 if (empty($newval)) {
1236 $newval = '0';
1237 }
1238 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeunits' || $objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchscalefromcodeunits') {
1239 $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
1240 $class = $objimport->array_import_convertvalue[0][$val]['class'];
1241 $method = $objimport->array_import_convertvalue[0][$val]['method'];
1242 $units = $objimport->array_import_convertvalue[0][$val]['units'];
1243 $cachekey = $file.'_'.$class.'_'.$method.'_'.$units;
1244 if (isset($this->cacheconvert[$cachekey][$newval]) && $this->cacheconvert[$cachekey][$newval] != '') {
1245 $newval = $this->cacheconvert[$cachekey][$newval];
1246 } else {
1247 $resultload = dol_include_once($file);
1248 if (empty($resultload)) {
1249 dol_print_error(null, 'Error trying to call file='.$file.', class='.$class.', method='.$method.', units='.$units);
1250 break;
1251 }
1252 $classinstance = new $class($this->db);
1253 // Try the fetch from code or ref
1254 call_user_func_array(array($classinstance, $method), array('', '', $newval, $units));
1255 $scaleorid = (($objimport->array_import_convertvalue[0][$val]['rule'] == 'fetchidfromcodeunits') ? $classinstance->id : $classinstance->scale);
1256 $this->cacheconvert[$cachekey][$newval] = $scaleorid;
1257 //print 'We have made a '.$class.'->'.$method." to get a value from key '".$newval."' and we got '".$scaleorid."'.";exit;
1258 if ($classinstance->id > 0) { // we found record
1259 $newval = $scaleorid ? $scaleorid : 0;
1260 } else {
1261 if (!empty($objimport->array_import_convertvalue[0][$val]['dict'])) {
1262 $this->errors[$error]['lib'] = $langs->trans('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, 'scale', $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$val]['dict']));
1263 } else {
1264 $this->errors[$error]['lib'] = 'ErrorFieldValueNotIn';
1265 }
1266 $this->errors[$error]['type'] = 'FOREIGNKEY';
1267 $errorforthistable++;
1268 $error++;
1269 }
1270 }
1271 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getcustomercodeifauto') {
1272 if (strtolower($newval) == 'auto') {
1273 $this->thirdpartyobject->get_codeclient(null, 0);
1274 $newval = $this->thirdpartyobject->code_client;
1275 //print 'code_client='.$newval;
1276 }
1277 if (empty($newval)) {
1278 $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
1279 }
1280 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getsuppliercodeifauto') {
1281 if (strtolower($newval) == 'auto') {
1282 $this->thirdpartyobject->get_codefournisseur(null, 1);
1283 $newval = $this->thirdpartyobject->code_fournisseur;
1284 //print 'code_fournisseur='.$newval;
1285 }
1286 if (empty($newval)) {
1287 $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
1288 }
1289 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getcustomeraccountancycodeifauto') {
1290 if (strtolower($newval) == 'auto') {
1291 $this->thirdpartyobject->get_codecompta('customer');
1292 $newval = $this->thirdpartyobject->code_compta_client;
1293 //print 'code_compta='.$newval;
1294 }
1295 if (empty($newval)) {
1296 $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
1297 }
1298 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getsupplieraccountancycodeifauto') {
1299 if (strtolower($newval) == 'auto') {
1300 $this->thirdpartyobject->get_codecompta('supplier');
1301 $newval = $this->thirdpartyobject->code_compta_fournisseur;
1302 if (empty($newval)) {
1303 $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
1304 }
1305 //print 'code_compta_fournisseur='.$newval;
1306 }
1307 if (empty($newval)) {
1308 $arrayrecord[($key - 1)]['type'] = -1; // If we get empty value, we will use "null"
1309 }
1310 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'getrefifauto') {
1311 if (strtolower($newval) == 'auto') {
1312 $defaultref = '';
1313
1314 $classModForNumber = $objimport->array_import_convertvalue[0][$val]['class'];
1315 $pathModForNumber = $objimport->array_import_convertvalue[0][$val]['path'];
1316
1317 if (!empty($classModForNumber) && !empty($pathModForNumber) && is_readable(DOL_DOCUMENT_ROOT.$pathModForNumber)) {
1318 require_once DOL_DOCUMENT_ROOT.$pathModForNumber;
1319 $modForNumber = new $classModForNumber();
1320 '@phan-var-force ModeleNumRefMembers|ModeleNumRefCommandes|ModeleNumRefSuppliersInvoices|ModeleNumRefSuppliersOrders|ModeleNumRefProjects|ModeleNumRefTask|ModeleNumRefPropales $modForNumber';
1321
1322 $tmpobject = null;
1323 // Set the object with the date property when we can
1324 if (!empty($objimport->array_import_convertvalue[0][$val]['classobject'])) {
1325 $pathForObject = $objimport->array_import_convertvalue[0][$val]['pathobject'];
1326 require_once DOL_DOCUMENT_ROOT.$pathForObject;
1327 $tmpclassobject = $objimport->array_import_convertvalue[0][$val]['classobject'];
1328 $tmpobject = new $tmpclassobject($this->db);
1329 foreach ($arrayfield as $tmpkey => $tmpval) { // $arrayfield is array('c.ref'=>0, ...)
1330 if (in_array($tmpkey, array('t.date', 'c.date_commande'))) {
1331 $tmpobject->date = dol_stringtotime($arrayrecord[$arrayfield[$tmpkey]]['val'], 1);
1332 }
1333 }
1334 }
1335
1336 $defaultref = $modForNumber->getNextValue(null, $tmpobject);
1337 }
1338 if (is_numeric($defaultref) && $defaultref <= 0) { // If error
1339 $defaultref = '';
1340 }
1341 $newval = $defaultref;
1342 }
1343 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'compute') {
1344 $file = (empty($objimport->array_import_convertvalue[0][$val]['classfile']) ? $objimport->array_import_convertvalue[0][$val]['file'] : $objimport->array_import_convertvalue[0][$val]['classfile']);
1345 $class = $objimport->array_import_convertvalue[0][$val]['class'];
1346 $method = $objimport->array_import_convertvalue[0][$val]['method'];
1347 $resultload = dol_include_once($file);
1348 if (empty($resultload)) {
1349 dol_print_error(null, 'Error trying to call file='.$file.', class='.$class.', method='.$method);
1350 break;
1351 }
1352 $classinstance = new $class($this->db);
1353 $computedFieldPos = isset($arrayfield[$val]) ? ((int) $arrayfield[$val]) : 0;
1354 $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $arrayfield, $computedFieldPos));
1355 if (empty($classinstance->error) && empty($classinstance->errors)) {
1356 $newval = $res; // We get new value computed.
1357 } else {
1358 $this->errors[$error]['type'] = 'CLASSERROR';
1359 $this->errors[$error]['lib'] = implode(
1360 "\n",
1361 array_merge([$classinstance->error], $classinstance->errors)
1362 );
1363 $errorforthistable++;
1364 $error++;
1365 }
1366 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'numeric') {
1367 $newval = price2num($newval);
1368 } elseif ($objimport->array_import_convertvalue[0][$val]['rule'] == 'accountingaccount') {
1369 if (!getDolGlobalString('ACCOUNTING_MANAGE_ZERO')) {
1370 $newval = rtrim(trim($newval), "0");
1371 } else {
1372 $newval = trim($newval);
1373 }
1374 }
1375
1376 //print 'Val to use as insert is '.$newval.'<br>';
1377 }
1378
1379 // Test regexp
1380 if (!empty($objimport->array_import_regex[0][$val]) && ($newval != '')) {
1381 // If test regex string is "field@table" or "field@table:..." (means must exists into table ...)
1382 $reg = array();
1383 if (preg_match('/^(.+)@([^:]+)(:.+)?$/', $objimport->array_import_regex[0][$val], $reg)) {
1384 $field = $reg[1];
1385 $table = $reg[2];
1386 $filter = !empty($reg[3]) ? substr($reg[3], 1) : '';
1387
1388 $cachekey = $field.'@'.$table;
1389 if (!empty($filter)) {
1390 $cachekey .= ':'.$filter;
1391 }
1392
1393 // Load content of field@table into cache array
1394 if (!is_array($this->cachefieldtable[$cachekey])) { // If content of field@table not already loaded into cache
1395 $sql = "SELECT ".$this->db->sanitize($field)." as aliasfield FROM ".$this->db->sanitize($table);
1396 if (!empty($filter)) {
1397 $sql .= forgeSQLFromUniversalSearchCriteria($filter);
1398 }
1399
1400 $resql = $this->db->query($sql);
1401 if ($resql) {
1402 $num = $this->db->num_rows($resql);
1403 $i = 0;
1404 while ($i < $num) {
1405 $obj = $this->db->fetch_object($resql);
1406 if ($obj) {
1407 $this->cachefieldtable[$cachekey][] = $obj->aliasfield;
1408 }
1409 $i++;
1410 }
1411 } else {
1412 dol_print_error($this->db);
1413 }
1414 }
1415
1416 // Now we check cache is not empty (should not) and key is in cache
1417 if (!is_array($this->cachefieldtable[$cachekey]) || !in_array($newval, $this->cachefieldtable[$cachekey])) {
1418 $tableforerror = $table;
1419 if (!empty($filter)) {
1420 $tableforerror .= ':'.$filter;
1421 }
1422 $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorFieldValueNotIn', num2Alpha($key - 1), $newval, $field, $tableforerror);
1423 $this->errors[$error]['type'] = 'FOREIGNKEY';
1424 $errorforthistable++;
1425 $error++;
1426 }
1427 } elseif (!preg_match('/'.$objimport->array_import_regex[0][$val].'/i', $newval)) {
1428 // If test is just a static regex
1429 //if ($key == 19) print "xxx".$newval."zzz".$objimport->array_import_regex[0][$val]."<br>";
1430 $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorWrongValueForField', num2Alpha($key - 1), $newval, $objimport->array_import_regex[0][$val]);
1431 $this->errors[$error]['type'] = 'REGEX';
1432 $errorforthistable++;
1433 $error++;
1434 }
1435 }
1436
1437 // Check HTML injection
1438 $inj = testSqlAndScriptInject($newval, 0);
1439 if ($inj) {
1440 $this->errors[$error]['lib'] = $langs->transnoentitiesnoconv('ErrorHtmlInjectionForField', num2Alpha($key - 1), dol_trunc($newval, 100));
1441 $this->errors[$error]['type'] = 'HTMLINJECTION';
1442 $errorforthistable++;
1443 $error++;
1444 }
1445
1446 // Other tests
1447 // ...
1448 }
1449
1450 // Define $sql_listfields and $sql_listvalues to build the SQL request
1451 if (isModEnabled("socialnetworks") && strpos($fieldname, "socialnetworks") !== false) {
1452 if (!in_array("socialnetworks", $sql_listfields)) {
1453 $sql_listfields[] = "socialnetworks";
1454 $socialkey = array_search("socialnetworks", $sql_listfields); // Return position of 'socialnetworks' key in array
1455 $sql_listvalues[$socialkey] = '';
1456 }
1457 //var_dump($newval); var_dump($arrayrecord[($key - 1)]['type']);
1458 if (!empty($newval) && $arrayrecord[($key - 1)]['type'] > 0) {
1459 $socialkey = array_search("socialnetworks", $sql_listfields); // Return position of 'socialnetworks' key in array
1460 //var_dump('sk='.$socialkey); // socialkey=19
1461 $socialnetwork = explode("_", $fieldname)[1];
1462 if (empty($sql_listvalues[$socialkey]) || $sql_listvalues[$socialkey] == "null") {
1463 $json = new stdClass();
1464 $json->$socialnetwork = $newval;
1465 $sql_listvalues[$socialkey] = json_encode($json);
1466 } else {
1467 $jsondata = $sql_listvalues[$socialkey];
1468 $json = json_decode($jsondata);
1469 $json->$socialnetwork = $newval;
1470 $sql_listvalues[$socialkey] = json_encode($json);
1471 }
1472 }
1473 } else {
1474 $sql_listfields[] = $this->db->sanitize($fieldname);
1475 // Note: arrayrecord (and 'type') is filled with ->import_read_record called by import.php page before calling import_insert
1476 if (empty($newval) && $arrayrecord[($key - 1)]['type'] < 0) {
1477 $sql_listvalues[] = ($newval == '0' ? (int) $newval : "null");
1478 } elseif (empty($newval) && $arrayrecord[($key - 1)]['type'] == 0) {
1479 $sql_listvalues[] = "''";
1480 } else {
1481 $sql_listvalues[] = "'".$this->db->escape($newval)."'";
1482 }
1483 }
1484 }
1485 $i++;
1486 }
1487
1488 // We add hidden fields (but only if there is at least one field to add into table)
1489 // We process here all the fields that were declared into the array $this->import_fieldshidden_array of the descriptor file.
1490 // Previously we processed the ->import_fields_array.
1491 if (!empty($sql_listfields) && is_array($objimport->array_import_fieldshidden[0])) {
1492 // Loop on each hidden fields to add them into listfields/listvalues
1493 foreach ($objimport->array_import_fieldshidden[0] as $tmpkey => $tmpval) {
1494 if (!preg_match('/^' . preg_quote($alias, '/') . '\./', $tmpkey)) {
1495 continue; // Not a field of current table
1496 }
1497 $keyfieldcache = preg_replace('/^' . preg_quote($alias, '/') . '\./', '', $tmpkey);
1498
1499 if (in_array($keyfieldcache, $sql_listfields)) { // avoid duplicates in insert
1500 continue;
1501 } elseif ($tmpval == 'user->id') {
1502 $sql_listfields[] = $keyfieldcache; // @phan-suppress-current-line SqlInjection
1503 $sql_listvalues[] = ((int) $user->id);
1504 } elseif (preg_match('/^lastrowid-/', $tmpval)) {
1505 $tmp = explode('-', $tmpval);
1506 $lastinsertid = (isset($last_insert_id_array[$tmp[1]])) ? $last_insert_id_array[$tmp[1]] : 0;
1507 $sql_listfields[] = $keyfieldcache; // @phan-suppress-current-line SqlInjection
1508 $sql_listvalues[] = (int) $lastinsertid;
1509 $keyfield = $keyfieldcache;
1510 //print $tmpkey."-".$tmpval."-".$sql_listfields."-".$sql_listvalues."<br>";exit;
1511 } elseif (preg_match('/^const-/', $tmpval)) {
1512 $tmp = explode('-', $tmpval, 2);
1513 $sql_listfields[] = $keyfieldcache; // @phan-suppress-current-line SqlInjection
1514 $sql_listvalues[] = "'".$this->db->escape($tmp[1])."'";
1515 } elseif (preg_match('/^rule-/', $tmpval)) { // Example: rule-computeAmount, rule-computeDirection, ...
1516 $fieldname = $tmpkey;
1517 if (!empty($objimport->array_import_convertvalue[0][$fieldname])) {
1518 if ($objimport->array_import_convertvalue[0][$fieldname]['rule'] == 'compute') {
1519 $file = (empty($objimport->array_import_convertvalue[0][$fieldname]['classfile']) ? $objimport->array_import_convertvalue[0][$fieldname]['file'] : $objimport->array_import_convertvalue[0][$fieldname]['classfile']);
1520 $class = $objimport->array_import_convertvalue[0][$fieldname]['class'];
1521 $method = $objimport->array_import_convertvalue[0][$fieldname]['method'];
1522 $type = $objimport->array_import_convertvalue[0][$fieldname]['type'];
1523 $resultload = dol_include_once($file);
1524 if (empty($resultload)) {
1525 dol_print_error(null, 'Error trying to call file=' . $file . ', class=' . $class . ', method=' . $method);
1526 break;
1527 }
1528 $classinstance = new $class($this->db);
1529 $computedFieldPos = isset($arrayfield[$fieldname]) ? ((int) $arrayfield[$fieldname]) : 0;
1530 $res = call_user_func_array(array($classinstance, $method), array(&$arrayrecord, $arrayfield, $computedFieldPos));
1531 if (empty($classinstance->error) && empty($classinstance->errors)) {
1532 $fieldArr = explode('.', $fieldname);
1533 if (count($fieldArr) > 0) {
1534 $fieldname = $fieldArr[1];
1535 }
1536
1537 // Set $sql_listfields and $sql_listvalues
1538 $sql_listfields[] = $this->db->sanitize($fieldname);
1539 if ($type == 'int') {
1540 $sql_listvalues[] = (int) $res;
1541 } elseif ($type == 'double') {
1542 $sql_listvalues[] = (float) $res;
1543 } else {
1544 $sql_listvalues[] = "'".$this->db->escape($res)."'";
1545 }
1546 } else {
1547 $this->errors[$error]['type'] = 'CLASSERROR';
1548 $this->errors[$error]['lib'] = implode(
1549 "\n",
1550 array_merge([$classinstance->error], $classinstance->errors)
1551 );
1552 $errorforthistable++;
1553 $error++;
1554 }
1555 }
1556 }
1557 } else {
1558 $this->errors[$error]['lib'] = 'Bad value of profile setup '.$tmpval.' for array_import_fieldshidden';
1559 $this->errors[$error]['type'] = 'Import profile setup';
1560 $error++;
1561 }
1562 }
1563 }
1564 //print 'listfields='.$sql_listfields.'<br>listvalues='.$sql_listvalues.'<br>';
1565
1566 // If no error for this $alias/$tablename, we have a complete $sql_listfields and $sql_listvalues that are defined
1567 // so we can try to make the insert or update now.
1568 if (!$errorforthistable) {
1569 //print "$alias/$tablename/$sql_listfields/$sql_listvalues<br>";
1570 if (!empty($sql_listfields)) {
1571 $updatedone = false;
1572 $insertdone = false;
1573 $where = array();
1574
1575 $is_table_category_link = false;
1576 $sanitizedfname = 'rowid';
1577 if (strpos($tablename, '_categorie_') !== false) {
1578 $is_table_category_link = true;
1579 $sanitizedfname = '*';
1580 }
1581
1582 if (!empty($updatekeys)) {
1583 // We do SELECT to get the rowid, if we already have the rowid, it's to be used below for related tables (extrafields)
1584
1585 if (empty($lastinsertid)) { // No insert done yet for a parent table
1586 $sqlSelect = "SELECT ".$sanitizedfname." FROM ".$this->db->sanitize($tablename);
1587 $data = array_combine($sql_listfields, $sql_listvalues);
1588 $where = array(); // filters to forge SQL request
1589 $filters = array(); // filters to forge output error message
1590 foreach ($updatekeys as $key) {
1591 if (! array_key_exists($key, $objimport->array_import_updatekeys[0])) {
1592 $this->errors[$error]['lib'] = 'You try to search duplicates on field '.dol_string_nohtmltag($key).' that is not an allowed field.';
1593 $this->errors[$error]['type'] = 'UPDATEKEYBADCOLUMN';
1594 $error++;
1595 break;
1596 }
1597 $col = $objimport->array_import_updatekeys[0][$key]; // Label for field name
1598 $keyfordata = preg_replace('/^.*\./i', '', $key); // Keep only field name without table name
1599 $keyfordata = preg_replace('/[^a-zA-Z0-9\._]/', '', $keyfordata); // Sanitize field name
1600
1601 if (isModEnabled("socialnetworks") && strpos($keyfordata, "socialnetworks") !== false) {
1602 $tmp = explode("_", $keyfordata);
1603 $keyfordata = $tmp[0];
1604 $socialnetwork = $tmp[1];
1605 $jsondata = $data[$keyfordata];
1606 $json = json_decode($jsondata);
1607 $stringtosearch = json_encode($socialnetwork).':'.json_encode($json->$socialnetwork);
1608 //var_dump($stringtosearch);
1609 //var_dump($this->db->escape($stringtosearch)); // This provide a value for sql string (but not for a like)
1610 $where[] = $this->db->sanitize($keyfordata)." LIKE '%".$this->db->escape($this->db->escapeforlike($stringtosearch))."%'";
1611 $filters[] = $col." LIKE '%".$this->db->escape($this->db->escapeforlike($stringtosearch))."%'";
1612 //var_dump($where[1]); // This provide a value for sql string inside a like
1613 } else {
1614 $sanitizedvalue = $data[$keyfordata]; // @phan-suppress-current-line SqlInjection
1615 /* Not required, the value in $data[$key] seems already sanitized
1616 $type = $objimport->array_import_types[0][$key]['type'] ?? 'string';
1617 if ($type == 'int') {
1618 $sanitizedvalue = (int) $data[$key];
1619 } elseif ($type == 'double') {
1620 $sanitizedvalue = (float) $data[$key];
1621 } else {
1622 $sanitizedvalue = "'".$this->db->escape($data[$key])."'";
1623 }
1624 */
1625 if ((string) $sanitizedvalue === '') {
1626 $this->errors[$error]['lib'] = 'You request to search duplicates on field '.$keyfordata.' but no value was provided for this field on this line.';
1627 $this->errors[$error]['type'] = 'UPDATEKEYBADVALUE';
1628 $error++;
1629 } else {
1630 $where[] = $this->db->sanitize($keyfordata)." = ".$sanitizedvalue;
1631 $filters[] = $col." = ".$sanitizedvalue;
1632 }
1633 }
1634 }
1635 if (!empty($tablewithentity_cache[$tablename])) {
1636 $where[] = "entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")";
1637 $filters[] = "entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")";
1638 }
1639 $sqlSelect .= " WHERE ".implode(' AND ', $where);
1640
1641 if (!$error) {
1642 $resql = $this->db->query($sqlSelect);
1643 if ($resql) {
1644 $num_rows = $this->db->num_rows($resql);
1645 if ($num_rows == 1) {
1646 $res = $this->db->fetch_object($resql);
1647 $lastinsertid = $res->rowid;
1648 $keyfield = 'rowid';
1649 if ($is_table_category_link) {
1650 $lastinsertid = 'linktable';
1651 } // 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
1652 $last_insert_id_array[$tablename] = $lastinsertid;
1653 } elseif ($num_rows > 1) {
1654 $this->errors[$error]['lib'] = $langs->trans('MultipleRecordFoundWithTheseFilters', implode(', ', $filters));
1655 $this->errors[$error]['type'] = 'SQL';
1656 $error++;
1657 } else {
1658 // No record found with filters, insert will be tried below
1659 }
1660 } else {
1661 //print 'E';
1662 $this->errors[$error]['lib'] = $this->db->lasterror();
1663 $this->errors[$error]['type'] = 'SQL';
1664 $error++;
1665 }
1666 }
1667 } else {
1668 // We have a last INSERT ID (got by previous pass), so we check if we have a row referencing this foreign key.
1669 // This is required when updating table with some extrafields. When inserting a record in parent table, we can make
1670 // a direct insert into subtable extrafields, but when me wake an update, the insertid is defined and the child record
1671 // may already exists. So we rescan the extrafield table to know if record exists or not for the rowid.
1672 // Note: For extrafield tablename, we have in importfieldshidden_array an entry 'extra.fk_object'=>'lastrowid-tableparent' so $keyfield is 'fk_object'
1673 $sqlSelect = "SELECT rowid FROM ".$tablename;
1674 if (empty($keyfield)) {
1675 $keyfield = 'rowid';
1676 }
1677
1678 $sqlSelect .= " WHERE ".$this->db->sanitize($keyfield)." = ".((int) $lastinsertid);
1679
1680 if (!empty($tablewithentity_cache[$tablename])) {
1681 $sqlSelect .= " AND entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")";
1682 }
1683
1684 $resql = $this->db->query($sqlSelect);
1685 if ($resql) {
1686 $res = $this->db->fetch_object($resql);
1687 if ($this->db->num_rows($resql) == 1) {
1688 // We have a row referencing this last foreign key, continue with UPDATE.
1689 } else {
1690 // No record found referencing this last foreign key,
1691 // force $lastinsertid to 0 so we INSERT below.
1692 $lastinsertid = 0;
1693 }
1694 } else {
1695 //print 'E';
1696 $this->errors[$error]['lib'] = $this->db->lasterror();
1697 $this->errors[$error]['type'] = 'SQL';
1698 $error++;
1699 }
1700 }
1701
1702 if (!empty($lastinsertid)) {
1703 // We db escape social network field because he isn't in field creation
1704 if (in_array("socialnetworks", $sql_listfields)) {
1705 $socialkey = array_search("socialnetworks", $sql_listfields);
1706 $tmpsql = $sql_listvalues[$socialkey];
1707 $sql_listvalues[$socialkey] = "'".$this->db->escape($tmpsql)."'";
1708 }
1709
1710 // Build SQL UPDATE request
1711 $sqlstart = "UPDATE ".$tablename;
1712
1713 $data = array_combine($sql_listfields, $sql_listvalues);
1714 $sql_set = array();
1715 foreach ($data as $key => $val) {
1716 $sql_set[] = $key." = ".$val; // $val was escaped/sanitized previously @phan-suppress-current-line SqlInjection
1717 }
1718 $sqlstart .= " SET ".implode(', ', $sql_set).", import_key = '".$this->db->escape($importid)."'";
1719 if (empty($keyfield)) {
1720 $keyfield = 'rowid';
1721 }
1722
1723 $sqlend = " WHERE ".$this->db->escape($keyfield)." = ".((int) $lastinsertid);
1724
1725 if ($is_table_category_link && !empty($where)) {
1726 '@phan-var-force string[] $where';
1727 $sqlend = " WHERE " . implode(' AND ', $where);
1728 }
1729
1730 if (!empty($tablewithentity_cache[$tablename])) {
1731 $sqlend .= " AND entity IN (".getEntity($this->getElementFromTableWithPrefix($tablename)).")";
1732 }
1733
1734 $sql = $sqlstart.$sqlend;
1735
1736 // Run update request
1737 $resql = $this->db->query($sql);
1738 if ($resql) {
1739 // No error, update has been done. $this->db->db->affected_rows can be 0 if data hasn't changed
1740 $updatedone = true;
1741 if (!$importissimulation && $importtriggermode === 'strict_line') {
1742 $restrigger = $this->triggerImportSqlOperation($tablename, 'update', is_numeric($lastinsertid) ? (int) $lastinsertid : 0, $importid, $user, $langs, $conf);
1743 if ($restrigger < 0) {
1744 $this->errors[$error]['lib'] = $langs->trans('ErrorFailedTriggerCall');
1745 $this->errors[$error]['type'] = 'TRIGGER';
1746 $error++;
1747 }
1748 } elseif (!$importissimulation) {
1749 $this->registerImportBulkEvent($tablename, 'update');
1750 }
1751 } else {
1752 //print 'E';
1753 $this->errors[$error]['lib'] = $this->db->lasterror();
1754 $this->errors[$error]['type'] = 'SQL';
1755 $error++;
1756 }
1757 }
1758 }
1759
1760 // Update not done, we do insert
1761 if (!$error && !$updatedone) {
1762 // We db escape social network field because he isn't in field creation
1763 if (in_array("socialnetworks", $sql_listfields)) {
1764 $socialkey = array_search("socialnetworks", $sql_listfields);
1765 $tmpsql = $sql_listvalues[$socialkey];
1766 $sql_listvalues[$socialkey] = "'".$this->db->escape($tmpsql)."'";
1767 }
1768
1769 // Build SQL INSERT request
1770 $sqlstart = "INSERT INTO ".$tablename."(".implode(", ", $sql_listfields).", import_key";
1771 $sqlend = ") VALUES(".implode(', ', $sql_listvalues).", '".$this->db->escape($importid)."'";
1772 if (!empty($tablewithentity_cache[$tablename])) {
1773 $sqlstart .= ", entity";
1774 $sqlend .= ", ".((int) $conf->entity);
1775 }
1776 if (!empty($objimport->array_import_tables_creator[0][$alias])) {
1777 $sqlstart .= ", ".$this->db->sanitize($objimport->array_import_tables_creator[0][$alias]);
1778 $sqlend .= ", ".((int) $user->id);
1779 }
1780 $sql = $sqlstart.$sqlend.")";
1781 //dol_syslog("import_csv.modules", LOG_DEBUG);
1782
1783 // Run insert request
1784 $resql = $this->db->query($sql);
1785 if ($resql) {
1786 if (!$is_table_category_link) {
1787 $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).
1788 }
1789 $insertdone = true;
1790 if (!$importissimulation && $importtriggermode === 'strict_line') {
1791 $triggerrowid = (!$is_table_category_link && !empty($last_insert_id_array[$tablename])) ? (int) $last_insert_id_array[$tablename] : 0;
1792 $restrigger = $this->triggerImportSqlOperation($tablename, 'insert', $triggerrowid, $importid, $user, $langs, $conf);
1793 if ($restrigger < 0) {
1794 $this->errors[$error]['lib'] = $langs->trans('ErrorFailedTriggerCall');
1795 $this->errors[$error]['type'] = 'TRIGGER';
1796 $error++;
1797 }
1798 } elseif (!$importissimulation) {
1799 $this->registerImportBulkEvent($tablename, 'insert');
1800 }
1801 } else {
1802 //print 'E';
1803 $this->errors[$error]['lib'] = $this->db->lasterror();
1804 $this->errors[$error]['type'] = 'SQL';
1805 $error++;
1806 }
1807 }
1808 }
1809 /*else
1810 {
1811 dol_print_error(null,'ErrorFieldListEmptyFor '.$alias."/".$tablename);
1812 }*/
1813 }
1814
1815 if ($error) {
1816 break;
1817 }
1818 }
1819
1820 if ($updatedone) {
1821 $this->nbupdate++;
1822 }
1823 if ($insertdone) {
1824 $this->nbinsert++;
1825 }
1826 }
1827
1828 return 1;
1829 }
1830
1831 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1843 public function import_insert($arrayrecord, $array_match_file_to_database, $objimport, $maxfields, $importid, $updatekeys)
1844 {
1845 // phpcs:enable
1846 return $this->commonImportInsert($arrayrecord, $array_match_file_to_database, $objimport, $maxfields, $importid, $updatekeys, 0);
1847 }
1848
1849 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1856 public function write_header_example($outputlangs)
1857 {
1858 // phpcs:enable
1859 $msg = get_class($this)."::".__FUNCTION__." not implemented";
1860 dol_syslog($msg, LOG_ERR);
1861 $this->errors[] = $msg;
1862 $this->error = $msg;
1863 return '';
1864 }
1865
1866 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1874 public function write_title_example($outputlangs, $headerlinefields)
1875 {
1876 // phpcs:enable
1877 $msg = get_class($this)."::".__FUNCTION__." not implemented";
1878 dol_syslog($msg, LOG_ERR);
1879 $this->errors[] = $msg;
1880 $this->error = $msg;
1881 return '';
1882 }
1883
1884 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1892 public function write_record_example($outputlangs, $contentlinevalues)
1893 {
1894 // phpcs:enable
1895 $msg = get_class($this)."::".__FUNCTION__." not implemented";
1896 dol_syslog($msg, LOG_ERR);
1897 $this->errors[] = $msg;
1898 $this->error = $msg;
1899 return '';
1900 }
1901
1902 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1909 public function write_footer_example($outputlangs)
1910 {
1911 // phpcs:enable
1912 $msg = get_class($this)."::".__FUNCTION__." not implemented";
1913 dol_syslog($msg, LOG_ERR);
1914 $this->errors[] = $msg;
1915 $this->error = $msg;
1916 return '';
1917 }
1918}
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
Class to manage triggers.
Parent class for import file readers.
write_title_example($outputlangs, $headerlinefields)
Output title line of an example file for this format.
getLibVersionForKey($key)
Renvoi version de librairie externe du driver.
getImportTriggerActions($tableElement, $operation, $element, $object=null)
Return trigger actions to execute for an import operation done in SQL legacy mode.
getImportTriggerPrefixFromObject($object)
Return trigger prefix from a business object.
getImportTriggerActionsFromHooks($tableElement, $operation, $element, $object=null)
Resolve import trigger actions from hooks.
getDriverDescForKey($key)
Return description of import drivervoi la description d'un driver import.
getElementFromTableWithPrefix($tableNameWithPrefix)
Get element from table name with prefix.
getDriverLabelForKey($key)
Return label of driver import.
getImportGenericTriggerPrefix($element, $tableElement)
Return generic trigger prefix derived from element or table.
import_get_nb_of_lines($file)
Return nb of records.
getLibLabel()
getDriverLabel
getDriverVersionForKey($key)
Renvoi version d'un driver import.
getDriverLabel()
getDriverLabel
getPictoForKey($key)
Return picto of import driver.
getLibLabelForKey($key)
Renvoi libelle de librairie externe du driver.
buildImportTriggerActionFromPrefix($triggerprefix, $operation)
Build trigger action code from prefix and operation.
getImportTriggerMode()
Return effective trigger mode for import flow.
runImportBulkTrigger($importid, $user, $langs, $conf)
Execute one global trigger for fast_bulk mode.
write_record_example($outputlangs, $contentlinevalues)
Output record of an example file for this format.
import_read_record()
Return array of next record in input file.
import_open_file($file)
Open input file.
import_read_header()
Input header line from file.
getDriverVersion()
getDriverVersion
listOfAvailableImportFormat($db, $maxfilenamelength=0)
Load into memory list of available import format.
commonImportInsert($arrayrecord, $array_match_file_to_database, $objimport, $maxfields, $importid, $updatekeys, $recordpositionbase=0)
Shared implementation of import_insert for CSV/XLSX.
registerImportBulkEvent($tablename, $operation)
Register one SQL operation into bulk trigger stats.
getDriverExtension()
getDriverExtension
getLibVersion()
getLibVersion
write_header_example($outputlangs)
Output header of an example file for this format.
triggerImportSqlOperation($tablename, $operation, $rowid, $importid, $user, $langs, $conf)
Execute triggers for SQL legacy import.
write_footer_example($outputlangs)
Output footer of an example file for this format.
__construct()
Constructor.
import_insert($arrayrecord, $array_match_file_to_database, $objimport, $maxfields, $importid, $updatekeys)
Insert a record into database.
getDriverDesc()
getDriverDesc
import_close_file()
Close file handle.
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:436
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
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.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
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 a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
const MODULE_MAPPING
This mapping defines the conversion to the current internal names from the alternative allowed names ...
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
buildzip.php
testSqlAndScriptInject($val, $type)
Security: WAF layer for SQL Injection and XSS Injection (scripts) protection (Filters on GET,...
Definition waf.inc.php:103