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