dolibarr  13.0.2
modules.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2003-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2003 Jean-Louis Bergamo <jlb@j1b.org>
4  * Copyright (C) 2004-2017 Laurent Destailleur <eldy@users.sourceforge.net>
5  * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
6  * Copyright (C) 2005-2017 Regis Houssin <regis.houssin@inodbox.com>
7  * Copyright (C) 2011 Juanjo Menent <jmenent@2byte.es>
8  * Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
9  * Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
10  * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 3 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program. If not, see <https://www.gnu.org/licenses/>.
24  */
25 
31 if (!defined('CSRFCHECK_WITH_TOKEN')) {
32  define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET
33 }
34 
35 require '../main.inc.php';
36 require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
37 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
38 require_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
39 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
40 require_once DOL_DOCUMENT_ROOT.'/admin/dolistore/class/dolistore.class.php';
41 
42 // Load translation files required by the page
43 $langs->loadLangs(array("errors", "admin", "modulebuilder"));
44 
45 $mode = GETPOSTISSET('mode') ? GETPOST('mode', 'alpha') : (empty($conf->global->MAIN_MODULE_SETUP_ON_LIST_BY_DEFAULT) ? 'commonkanban' : 'common');
46 if (empty($mode)) {
47  $mode = 'common';
48 }
49 $action = GETPOST('action', 'aZ09');
50 //var_dump($_POST);exit;
51 $value = GETPOST('value', 'alpha');
52 $page_y = GETPOST('page_y', 'int');
53 $search_keyword = GETPOST('search_keyword', 'alpha');
54 $search_status = GETPOST('search_status', 'alpha');
55 $search_nature = GETPOST('search_nature', 'alpha');
56 $search_version = GETPOST('search_version', 'alpha');
57 
58 
59 // For dolistore search
60 $options = array();
61 $options['per_page'] = 20;
62 $options['categorie'] = ((GETPOST('categorie', 'int') ?GETPOST('categorie', 'int') : 0) + 0);
63 $options['start'] = ((GETPOST('start', 'int') ?GETPOST('start', 'int') : 0) + 0);
64 $options['end'] = ((GETPOST('end', 'int') ?GETPOST('end', 'int') : 0) + 0);
65 $options['search'] = GETPOST('search_keyword', 'alpha');
66 $dolistore = new Dolistore(false);
67 
68 
69 if (!$user->admin) {
71 }
72 
73 $familyinfo = array(
74  'hr'=>array('position'=>'001', 'label'=>$langs->trans("ModuleFamilyHr")),
75  'crm'=>array('position'=>'006', 'label'=>$langs->trans("ModuleFamilyCrm")),
76  'srm'=>array('position'=>'007', 'label'=>$langs->trans("ModuleFamilySrm")),
77  'financial'=>array('position'=>'009', 'label'=>$langs->trans("ModuleFamilyFinancial")),
78  'products'=>array('position'=>'012', 'label'=>$langs->trans("ModuleFamilyProducts")),
79  'projects'=>array('position'=>'015', 'label'=>$langs->trans("ModuleFamilyProjects")),
80  'ecm'=>array('position'=>'018', 'label'=>$langs->trans("ModuleFamilyECM")),
81  'technic'=>array('position'=>'021', 'label'=>$langs->trans("ModuleFamilyTechnic")),
82  'portal'=>array('position'=>'040', 'label'=>$langs->trans("ModuleFamilyPortal")),
83  'interface'=>array('position'=>'050', 'label'=>$langs->trans("ModuleFamilyInterface")),
84  'base'=>array('position'=>'060', 'label'=>$langs->trans("ModuleFamilyBase")),
85  'other'=>array('position'=>'100', 'label'=>$langs->trans("ModuleFamilyOther")),
86 );
87 
88 $param = '';
89 if (!GETPOST('buttonreset', 'alpha')) {
90  if ($search_keyword) {
91  $param .= '&search_keyword='.urlencode($search_keyword);
92  }
93  if ($search_status && $search_status != '-1') {
94  $param .= '&search_status='.urlencode($search_status);
95  }
96  if ($search_nature && $search_nature != '-1') {
97  $param .= '&search_nature='.urlencode($search_nature);
98  }
99  if ($search_version && $search_version != '-1') {
100  $param .= '&search_version='.urlencode($search_version);
101  }
102 }
103 
104 $dirins = DOL_DOCUMENT_ROOT.'/custom';
105 $urldolibarrmodules = 'https://www.dolistore.com/';
106 
107 // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
108 $hookmanager->initHooks(array('adminmodules', 'globaladmin'));
109 
110 
111 /*
112  * Actions
113  */
114 
115 $formconfirm = '';
116 
117 $parameters = array();
118 $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
119 if ($reshook < 0) {
120  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
121 }
122 
123 if (GETPOST('buttonreset', 'alpha')) {
124  $search_keyword = '';
125  $search_status = '';
126  $search_nature = '';
127  $search_version = '';
128 }
129 
130 if ($action == 'install') {
131  $error = 0;
132 
133  // $original_file should match format module_modulename-x.y[.z].zip
134  $original_file = basename($_FILES["fileinstall"]["name"]);
135  $original_file = preg_replace('/\(\d+\)\.zip$/i', '.zip', $original_file);
136  $newfile = $conf->admin->dir_temp.'/'.$original_file.'/'.$original_file;
137 
138  if (!$original_file) {
139  $langs->load("Error");
140  setEventMessages($langs->trans("ErrorModuleFileRequired"), null, 'warnings');
141  $error++;
142  } else {
143  if (!$error && !preg_match('/\.zip$/i', $original_file)) {
144  $langs->load("errors");
145  setEventMessages($langs->trans("ErrorFileMustBeADolibarrPackage", $original_file), null, 'errors');
146  $error++;
147  }
148  if (!$error && !preg_match('/^(module[a-zA-Z0-9]*|theme)_.*\-([0-9][0-9\.]*)\.zip$/i', $original_file)) {
149  $langs->load("errors");
150  setEventMessages($langs->trans("ErrorFilenameDosNotMatchDolibarrPackageRules", $original_file, 'module_*-x.y*.zip'), null, 'errors');
151  $error++;
152  }
153  if (empty($_FILES['fileinstall']['tmp_name'])) {
154  $langs->load("errors");
155  setEventMessages($langs->trans("ErrorFileNotUploaded"), null, 'errors');
156  $error++;
157  }
158  }
159 
160  if (!$error) {
161  if ($original_file) {
162  @dol_delete_dir_recursive($conf->admin->dir_temp.'/'.$original_file);
163  dol_mkdir($conf->admin->dir_temp.'/'.$original_file);
164  }
165 
166  $tmpdir = preg_replace('/\.zip$/i', '', $original_file).'.dir';
167  if ($tmpdir) {
168  @dol_delete_dir_recursive($conf->admin->dir_temp.'/'.$tmpdir);
169  dol_mkdir($conf->admin->dir_temp.'/'.$tmpdir);
170  }
171 
172  $result = dol_move_uploaded_file($_FILES['fileinstall']['tmp_name'], $newfile, 1, 0, $_FILES['fileinstall']['error']);
173  if ($result > 0) {
174  $result = dol_uncompress($newfile, $conf->admin->dir_temp.'/'.$tmpdir);
175 
176  if (!empty($result['error'])) {
177  $langs->load("errors");
178  setEventMessages($langs->trans($result['error'], $original_file), null, 'errors');
179  $error++;
180  } else {
181  // Now we move the dir of the module
182  $modulename = preg_replace('/module_/', '', $original_file);
183  $modulename = preg_replace('/\-([0-9][0-9\.]*)\.zip$/i', '', $modulename);
184  // Search dir $modulename
185  $modulenamedir = $conf->admin->dir_temp.'/'.$tmpdir.'/'.$modulename; // Example ./mymodule
186 
187  if (!dol_is_dir($modulenamedir)) {
188  $modulenamedir = $conf->admin->dir_temp.'/'.$tmpdir.'/htdocs/'.$modulename; // Example ./htdocs/mymodule
189  //var_dump($modulenamedir);
190  if (!dol_is_dir($modulenamedir)) {
191  setEventMessages($langs->trans("ErrorModuleFileSeemsToHaveAWrongFormat").'<br>'.$langs->trans("ErrorModuleFileSeemsToHaveAWrongFormat2", $modulename, 'htdocs/'.$modulename), null, 'errors');
192  $error++;
193  }
194  }
195 
196  if (!$error) {
197  // TODO Make more test
198  }
199 
200  dol_syslog("Uncompress of module file is a success.");
201 
202  $modulenamearrays = array();
203  if (dol_is_file($modulenamedir.'/metapackage.conf')) {
204  // This is a meta package
205  $metafile = file_get_contents($modulenamedir.'/metapackage.conf');
206  $modulenamearrays = explode("\n", $metafile);
207  }
208  $modulenamearrays[$modulename] = $modulename;
209  //var_dump($modulenamearrays);exit;
210 
211  foreach ($modulenamearrays as $modulenameval) {
212  if (strpos($modulenameval, '#') === 0) {
213  continue; // Discard comments
214  }
215  if (strpos($modulenameval, '//') === 0) {
216  continue; // Discard comments
217  }
218  if (!trim($modulenameval)) {
219  continue;
220  }
221 
222  // Now we install the module
223  if (!$error) {
224  @dol_delete_dir_recursive($dirins.'/'.$modulenameval); // delete the zip file
225  dol_syslog("We copy now directory ".$conf->admin->dir_temp.'/'.$tmpdir.'/htdocs/'.$modulenameval." into target dir ".$dirins.'/'.$modulenameval);
226  $result = dolCopyDir($modulenamedir, $dirins.'/'.$modulenameval, '0444', 1);
227  if ($result <= 0) {
228  dol_syslog('Failed to call dolCopyDir result='.$result." with param ".$modulenamedir." and ".$dirins.'/'.$modulenameval, LOG_WARNING);
229  $langs->load("errors");
230  setEventMessages($langs->trans("ErrorFailToCopyDir", $modulenamedir, $dirins.'/'.$modulenameval), null, 'errors');
231  $error++;
232  }
233  }
234  }
235  }
236  } else {
237  setEventMessages($langs->trans("ErrorFailToRenameFile", $_FILES['fileinstall']['tmp_name'], $newfile), null, 'errors');
238  $error++;
239  }
240  }
241 
242  if (!$error) {
243  setEventMessages($langs->trans("SetupIsReadyForUse", DOL_URL_ROOT.'/admin/modules.php?mainmenu=home', $langs->transnoentitiesnoconv("Home").' - '.$langs->transnoentitiesnoconv("Setup").' - '.$langs->transnoentitiesnoconv("Modules")), null, 'warnings');
244  }
245 }
246 
247 if ($action == 'set' && $user->admin) {
248  $resarray = activateModule($value);
249  if (!empty($resarray['errors'])) {
250  setEventMessages('', $resarray['errors'], 'errors');
251  } else {
252  //var_dump($resarray);exit;
253  if ($resarray['nbperms'] > 0) {
254  $tmpsql = "SELECT COUNT(rowid) as nb FROM ".MAIN_DB_PREFIX."user WHERE admin <> 1";
255  $resqltmp = $db->query($tmpsql);
256  if ($resqltmp) {
257  $obj = $db->fetch_object($resqltmp);
258  //var_dump($obj->nb);exit;
259  if ($obj && $obj->nb > 1) {
260  $msg = $langs->trans('ModuleEnabledAdminMustCheckRights');
261  setEventMessages($msg, null, 'warnings');
262  }
263  } else {
264  dol_print_error($db);
265  }
266  }
267  }
268  header("Location: ".$_SERVER["PHP_SELF"]."?mode=".$mode.$param.($page_y ? '&page_y='.$page_y : ''));
269  exit;
270 } elseif ($action == 'reset' && $user->admin && GETPOST('confirm') == 'yes') {
271  $result = unActivateModule($value);
272  if ($result) {
273  setEventMessages($result, null, 'errors');
274  }
275  header("Location: ".$_SERVER["PHP_SELF"]."?mode=".$mode.$param.($page_y ? '&page_y='.$page_y : ''));
276  exit;
277 }
278 
279 
280 
281 /*
282  * View
283  */
284 
285 $form = new Form($db);
286 
287 $morejs = array();
288 $morecss = array("/admin/dolistore/css/dolistore.css");
289 
290 // Set dir where external modules are installed
291 if (!dol_is_dir($dirins)) {
292  dol_mkdir($dirins);
293 }
294 $dirins_ok = (dol_is_dir($dirins));
295 
296 $help_url = 'EN:First_setup|FR:Premiers_paramétrages|ES:Primeras_configuraciones';
297 llxHeader('', $langs->trans("Setup"), $help_url, '', '', '', $morejs, $morecss, 0, 0);
298 
299 
300 // Search modules dirs
301 $modulesdir = dolGetModulesDirs();
302 
303 $arrayofnatures = array('core'=>$langs->transnoentitiesnoconv("Core"), 'external'=>$langs->transnoentitiesnoconv("External").' - ['.$langs->trans("AllPublishers").']');
304 $arrayofwarnings = array(); // Array of warning each module want to show when activated
305 $arrayofwarningsext = array(); // Array of warning each module want to show when we activate an external module
306 $filename = array();
307 $modules = array();
308 $orders = array();
309 $categ = array();
310 
311 $i = 0; // is a sequencer of modules found
312 $j = 0; // j is module number. Automatically affected if module number not defined.
313 $modNameLoaded = array();
314 
315 foreach ($modulesdir as $dir) {
316  // Load modules attributes in arrays (name, numero, orders) from dir directory
317  //print $dir."\n<br>";
318  dol_syslog("Scan directory ".$dir." for module descriptor files (modXXX.class.php)");
319  $handle = @opendir($dir);
320  if (is_resource($handle)) {
321  while (($file = readdir($handle)) !== false) {
322  //print "$i ".$file."\n<br>";
323  if (is_readable($dir.$file) && substr($file, 0, 3) == 'mod' && substr($file, dol_strlen($file) - 10) == '.class.php') {
324  $modName = substr($file, 0, dol_strlen($file) - 10);
325 
326  if ($modName) {
327  if (!empty($modNameLoaded[$modName])) { // In cache of already loaded modules ?
328  $mesg = "Error: Module ".$modName." was found twice: Into ".$modNameLoaded[$modName]." and ".$dir.". You probably have an old file on your disk.<br>";
329  setEventMessages($mesg, null, 'warnings');
330  dol_syslog($mesg, LOG_ERR);
331  continue;
332  }
333 
334  try {
335  $res = include_once $dir.$file; // A class already exists in a different file will send a non catchable fatal error.
336  if (class_exists($modName)) {
337  try {
338  $objMod = new $modName($db);
339  $modNameLoaded[$modName] = $dir;
340  if (!$objMod->numero > 0 && $modName != 'modUser') {
341  dol_syslog('The module descriptor '.$modName.' must have a numero property', LOG_ERR);
342  }
343  $j = $objMod->numero;
344 
345  $modulequalified = 1;
346 
347  // We discard modules according to features level (PS: if module is activated we always show it)
348  $const_name = 'MAIN_MODULE_'.strtoupper(preg_replace('/^mod/i', '', get_class($objMod)));
349  if ($objMod->version == 'development' && (empty($conf->global->$const_name) && ($conf->global->MAIN_FEATURES_LEVEL < 2))) {
350  $modulequalified = 0;
351  }
352  if ($objMod->version == 'experimental' && (empty($conf->global->$const_name) && ($conf->global->MAIN_FEATURES_LEVEL < 1))) {
353  $modulequalified = 0;
354  }
355  if (preg_match('/deprecated/', $objMod->version) && (empty($conf->global->$const_name) && ($conf->global->MAIN_FEATURES_LEVEL >= 0))) {
356  $modulequalified = 0;
357  }
358 
359  // We discard modules according to property ->hidden
360  if (!empty($objMod->hidden)) {
361  $modulequalified = 0;
362  }
363 
364  if ($modulequalified > 0) {
365  $publisher = dol_escape_htmltag($objMod->getPublisher());
366  $external = ($objMod->isCoreOrExternalModule() == 'external');
367  if ($external) {
368  if ($publisher) {
369  $arrayofnatures['external_'.$publisher] = $langs->trans("External").' - '.$publisher;
370  } else {
371  $arrayofnatures['external_'] = $langs->trans("External").' - '.$langs->trans("UnknownPublishers");
372  }
373  }
374  ksort($arrayofnatures);
375 
376  // Define array $categ with categ with at least one qualified module
377  $filename[$i] = $modName;
378  $modules[$modName] = $objMod;
379 
380  // Gives the possibility to the module, to provide his own family info and position of this family
381  if (is_array($objMod->familyinfo) && !empty($objMod->familyinfo)) {
382  $familyinfo = array_merge($familyinfo, $objMod->familyinfo);
383  $familykey = key($objMod->familyinfo);
384  } else {
385  $familykey = $objMod->family;
386  }
387 
388  $moduleposition = ($objMod->module_position ? $objMod->module_position : '50');
389  if ($moduleposition == '50' && ($objMod->isCoreOrExternalModule() == 'external')) {
390  $moduleposition = '80'; // External modules at end by default
391  }
392 
393  // Add list of warnings to show into arrayofwarnings and arrayofwarningsext
394  if (!empty($objMod->warnings_activation)) {
395  $arrayofwarnings[$modName] = $objMod->warnings_activation;
396  }
397  if (!empty($objMod->warnings_activation_ext)) {
398  $arrayofwarningsext[$modName] = $objMod->warnings_activation_ext;
399  }
400 
401  $familyposition = (empty($familyinfo[$familykey]['position']) ? 0 : $familyinfo[$familykey]['position']);
402  $listOfOfficialModuleGroups = array('hr', 'technic', 'interface', 'technic', 'portal', 'financial', 'crm', 'base', 'products', 'srm', 'ecm', 'projects', 'other');
403  if ($external && !in_array($familykey, $listOfOfficialModuleGroups)) {
404  // If module is extern and into a custom group (not into an official predefined one), it must appear at end (custom groups should not be before official groups).
405  if (is_numeric($familyposition)) {
406  $familyposition = sprintf("%03d", (int) $familyposition + 100);
407  }
408  }
409 
410  $orders[$i] = $familyposition."_".$familykey."_".$moduleposition."_".$j; // Sort by family, then by module position then number
411 
412  // Set categ[$i]
413  $specialstring = 'unknown';
414  if ($objMod->version == 'development' || $objMod->version == 'experimental') {
415  $specialstring = 'expdev';
416  }
417  if (isset($categ[$specialstring])) {
418  $categ[$specialstring]++; // Array of all different modules categories
419  } else {
420  $categ[$specialstring] = 1;
421  }
422  $j++;
423  $i++;
424  } else {
425  dol_syslog("Module ".get_class($objMod)." not qualified");
426  }
427  } catch (Exception $e) {
428  dol_syslog("Failed to load ".$dir.$file." ".$e->getMessage(), LOG_ERR);
429  }
430  } else {
431  print "Warning bad descriptor file : ".$dir.$file." (Class ".$modName." not found into file)<br>";
432  }
433  } catch (Exception $e) {
434  dol_syslog("Failed to load ".$dir.$file." ".$e->getMessage(), LOG_ERR);
435  }
436  }
437  }
438  }
439  closedir($handle);
440  } else {
441  dol_syslog("htdocs/admin/modules.php: Failed to open directory ".$dir.". See permission and open_basedir option.", LOG_WARNING);
442  }
443 }
444 
445 if ($action == 'reset_confirm' && $user->admin) {
446  if (!empty($modules[$value])) {
447  $objMod = $modules[$value];
448 
449  if (!empty($objMod->langfiles)) {
450  $langs->loadLangs($objMod->langfiles);
451  }
452 
453  $form = new Form($db);
454  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?value='.$value.'&mode='.$mode.$param, $langs->trans('ConfirmUnactivation'), $langs->trans(GETPOST('confirm_message_code')), 'reset', '', 'no', 1);
455  }
456 }
457 
458 print $formconfirm;
459 
460 asort($orders);
461 //var_dump($orders);
462 //var_dump($categ);
463 //var_dump($modules);
464 
465 $nbofactivatedmodules = count($conf->modules);
466 $moreinfo = $langs->trans("TitleNumberOfActivatedModules");
467 $moreinfo2 = ($nbofactivatedmodules - 1)." / ".count($modules);
468 if ($nbofactivatedmodules <= 1) {
469  $moreinfo2 .= ' '.img_warning($langs->trans("YouMustEnableOneModule"));
470 }
471 
472 print load_fiche_titre($langs->trans("ModulesSetup"), '', 'title_setup');
473 
474 // Start to show page
475 if ($mode == 'common' || $mode == 'commonkanban') {
476  $desc = $langs->trans("ModulesDesc", '{picto}');
477  $desc = str_replace('{picto}', img_picto('', 'switch_off'), $desc);
478  print '<span class="opacitymedium hideonsmartphone">'.$desc."<br><br></span>\n";
479 }
480 if ($mode == 'marketplace') {
481  print '<span class="opacitymedium hideonsmartphone">'.$langs->trans("ModulesMarketPlaceDesc")."<br><br></span>\n";
482 }
483 if ($mode == 'deploy') {
484  print '<span class="opacitymedium hideonsmartphone">'.$langs->trans("ModulesDeployDesc", $langs->transnoentitiesnoconv("AvailableModules"))."<br><br></span>\n";
485 }
486 if ($mode == 'develop') {
487  print '<span class="opacitymedium hideonsmartphone">'.$langs->trans("ModulesDevelopDesc")."<br><br></span>\n";
488 }
489 
490 
491 $head = modules_prepare_head();
492 
493 
494 if ($mode == 'common' || $mode == 'commonkanban') {
495  dol_set_focus('#search_keyword');
496 
497  print '<form method="POST" id="searchFormList" action="'.$_SERVER["PHP_SELF"].'">';
498  if ($optioncss != '') {
499  print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
500  }
501  print '<input type="hidden" name="token" value="'.newToken().'">';
502  print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
503  print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
504  print '<input type="hidden" name="page" value="'.$page.'">';
505  print '<input type="hidden" name="mode" value="'.$mode.'">';
506 
507  print dol_get_fiche_head($head, 'modules', '', -1);
508 
509  $moreforfilter = '<div class="valignmiddle">';
510 
511  $moreforfilter .= '<div class="floatright right pagination"><ul><li>';
512  $moreforfilter .= dolGetButtonTitle($langs->trans('ViewKanban'), '', 'fa fa-th-list imgforviewmode', $_SERVER["PHP_SELF"].'?mode=commonkanban'.$param, '', 1, array('morecss'=>'reposition'.($mode == 'common' ? '' : ' btnTitleSelected')));
513  $moreforfilter .= dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-list-alt imgforviewmode', $_SERVER["PHP_SELF"].'?mode=common'.$param, '', 1, array('morecss'=>'reposition'.($mode == 'commonkanban' ? '' : ' btnTitleSelected')));
514  $moreforfilter .= '</li></ul></div>';
515 
516  $moreforfilter .= '<div class="floatright center marginrightonly hideonsmartphone" style="padding-top: 3px"><span class="">'.$moreinfo.'</span><br><b class="largenumber">'.$moreinfo2.'</b></div>';
517 
518  $moreforfilter .= '<div class="colorbacktimesheet float valignmiddle">';
519  $moreforfilter .= '<div class="divsearchfield paddingtop">';
520  $moreforfilter .= $langs->trans('Keyword').': <input type="text" id="search_keyword" name="search_keyword" class="maxwidth100" value="'.dol_escape_htmltag($search_keyword).'">';
521  $moreforfilter .= '</div>';
522  $moreforfilter .= '<div class="divsearchfield paddingtop">';
523  $moreforfilter .= $langs->trans('Origin').': '.$form->selectarray('search_nature', $arrayofnatures, dol_escape_htmltag($search_nature), 1, 0, 0, '', 0, 0, 0, '', 'maxwidth200', 1);
524  $moreforfilter .= '</div>';
525  if (!empty($conf->global->MAIN_FEATURES_LEVEL)) {
526  $array_version = array('stable'=>$langs->transnoentitiesnoconv("Stable"));
527  if ($conf->global->MAIN_FEATURES_LEVEL < 0) {
528  $array_version['deprecated'] = $langs->trans("Deprecated");
529  }
530  if ($conf->global->MAIN_FEATURES_LEVEL > 0) {
531  $array_version['experimental'] = $langs->trans("Experimental");
532  }
533  if ($conf->global->MAIN_FEATURES_LEVEL > 1) {
534  $array_version['development'] = $langs->trans("Development");
535  }
536  $moreforfilter .= '<div class="divsearchfield paddingtop">';
537  $moreforfilter .= $langs->trans('Version').': '.$form->selectarray('search_version', $array_version, $search_version, 1, 0, 0, '', 0, 0, 0, '', 'maxwidth150', 1);
538  $moreforfilter .= '</div>';
539  }
540  $moreforfilter .= '<div class="divsearchfield paddingtop">';
541  $moreforfilter .= $langs->trans('Status').': '.$form->selectarray('search_status', array('active'=>$langs->transnoentitiesnoconv("Enabled"), 'disabled'=>$langs->transnoentitiesnoconv("Disabled")), $search_status, 1, 0, 0, '', 0, 0, 0, '', 'maxwidth150', 1);
542  $moreforfilter .= '</div>';
543  $moreforfilter .= ' ';
544  $moreforfilter .= '<div class="divsearchfield">';
545  $moreforfilter .= '<input type="submit" name="buttonsubmit" class="button" value="'.dol_escape_htmltag($langs->trans("Refresh")).'">';
546  $moreforfilter .= ' ';
547  $moreforfilter .= '<input type="submit" name="buttonreset" class="butActionDelete noborderbottom" value="'.dol_escape_htmltag($langs->trans("Reset")).'">';
548  $moreforfilter .= '</div>';
549  $moreforfilter .= '</div>';
550 
551  $moreforfilter .= '</div>';
552 
553  if (!empty($moreforfilter)) {
554  print $moreforfilter;
555  $parameters = array();
556  $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook
557  print $hookmanager->resPrint;
558  }
559 
560  $moreforfilter = '';
561 
562  print '<div class="clearboth"></div><br>';
563 
564  $object = new stdClass();
565  $parameters = array();
566  $reshook = $hookmanager->executeHooks('insertExtraHeader', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
567  if ($reshook < 0) {
568  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
569  }
570 
571  // Show list of modules
572  $oldfamily = '';
573  $linenum = 0;
574 
575  foreach ($orders as $key => $value) {
576  $linenum++;
577  $tab = explode('_', $value);
578  $familykey = $tab[1];
579  $module_position = $tab[2];
580 
581  $modName = $filename[$key];
582  $objMod = $modules[$modName];
583 
584  //print $objMod->name." - ".$key." - ".$objMod->version."<br>";
585  if ($mode == 'expdev' && $objMod->version != 'development' && $objMod->version != 'experimental') {
586  continue; // Discard if not for current tab
587  }
588 
589  if (!$objMod->getName()) {
590  dol_syslog("Error for module ".$key." - Property name of module looks empty", LOG_WARNING);
591  continue;
592  }
593 
594  $const_name = 'MAIN_MODULE_'.strtoupper(preg_replace('/^mod/i', '', get_class($objMod)));
595 
596  // Check filters
597  $modulename = $objMod->getName();
598  $moduletechnicalname = $objMod->name;
599  $moduledesc = $objMod->getDesc();
600  $moduledesclong = $objMod->getDescLong();
601  $moduleauthor = $objMod->getPublisher();
602 
603  // We discard showing according to filters
604  if ($search_keyword) {
605  $qualified = 0;
606  if (preg_match('/'.preg_quote($search_keyword).'/i', $modulename)
607  || preg_match('/'.preg_quote($search_keyword).'/i', $moduletechnicalname)
608  || preg_match('/'.preg_quote($search_keyword).'/i', $moduledesc)
609  || preg_match('/'.preg_quote($search_keyword).'/i', $moduledesclong)
610  || preg_match('/'.preg_quote($search_keyword).'/i', $moduleauthor)
611  ) {
612  $qualified = 1;
613  }
614  if (!$qualified) {
615  continue;
616  }
617  }
618  if ($search_status) {
619  if ($search_status == 'active' && empty($conf->global->$const_name)) {
620  continue;
621  }
622  if ($search_status == 'disabled' && !empty($conf->global->$const_name)) {
623  continue;
624  }
625  }
626  if ($search_nature) {
627  if (preg_match('/^external/', $search_nature) && $objMod->isCoreOrExternalModule() != 'external') {
628  continue;
629  }
630  $reg = array();
631  if (preg_match('/^external_(.*)$/', $search_nature, $reg)) {
632  //print $reg[1].'-'.dol_escape_htmltag($objMod->getPublisher());
633  $publisher = dol_escape_htmltag($objMod->getPublisher());
634  if ($reg[1] && dol_escape_htmltag($reg[1]) != $publisher) {
635  continue;
636  }
637  if (!$reg[1] && !empty($publisher)) {
638  continue;
639  }
640  }
641  if ($search_nature == 'core' && $objMod->isCoreOrExternalModule() == 'external') {
642  continue;
643  }
644  }
645  if ($search_version) {
646  if (($objMod->version == 'development' || $objMod->version == 'experimental' || preg_match('/deprecated/', $objMod->version)) && $search_version == 'stable') {
647  continue;
648  }
649  if ($objMod->version != 'development' && ($search_version == 'development')) {
650  continue;
651  }
652  if ($objMod->version != 'experimental' && ($search_version == 'experimental')) {
653  continue;
654  }
655  if (!preg_match('/deprecated/', $objMod->version) && ($search_version == 'deprecated')) {
656  continue;
657  }
658  }
659 
660  // Load all lang files of module
661  if (isset($objMod->langfiles) && is_array($objMod->langfiles)) {
662  foreach ($objMod->langfiles as $domain) {
663  $langs->load($domain);
664  }
665  }
666 
667  // Print a separator if we change family
668  if ($familykey != $oldfamily) {
669  if ($oldfamily) {
670  print '</table></div><br>';
671  }
672 
673  $familytext = empty($familyinfo[$familykey]['label']) ? $familykey : $familyinfo[$familykey]['label'];
674 
675  print load_fiche_titre($familytext, '', '', 0, '', 'modulefamilygroup');
676 
677  if ($mode == 'commonkanban') {
678  print '<div class="box-flex-container">';
679  } else {
680  print '<div class="div-table-responsive">';
681  print '<table class="tagtable liste" summary="list_of_modules">'."\n";
682  }
683 
684  $atleastoneforfamily = 0;
685  }
686 
687  $atleastoneforfamily++;
688 
689  if ($familykey != $oldfamily) {
690  $familytext = empty($familyinfo[$familykey]['label']) ? $familykey : $familyinfo[$familykey]['label'];
691  $oldfamily = $familykey;
692  }
693 
694  // Version (with picto warning or not)
695  $version = $objMod->getVersion(0);
696  $versiontrans = '';
697  if (preg_match('/development/i', $version)) {
698  $versiontrans .= img_warning($langs->trans("Development"), '', 'floatleft paddingright');
699  }
700  if (preg_match('/experimental/i', $version)) {
701  $versiontrans .= img_warning($langs->trans("Experimental"), '', 'floatleft paddingright');
702  }
703  if (preg_match('/deprecated/i', $version)) {
704  $versiontrans .= img_warning($langs->trans("Deprecated"), '', 'floatleft paddingright');
705  }
706  if ($objMod->isCoreOrExternalModule() == 'external' || preg_match('/development|experimental|deprecated/i', $version)) {
707  $versiontrans .= $objMod->getVersion(1);
708  }
709 
710  // Define imginfo
711  $imginfo = "info";
712  if ($objMod->isCoreOrExternalModule() == 'external') {
713  $imginfo = "info_black";
714  }
715 
716  $codeenabledisable = '';
717  $codetoconfig = '';
718 
719  // Activate/Disable and Setup (2 columns)
720  if (!empty($conf->global->$const_name)) { // If module is already activated
721  // Set $codeenabledisable
722  $disableSetup = 0;
723  if (!empty($arrayofwarnings[$modName])) {
724  $codeenabledisable .= '<!-- This module has a warning to show when we activate it (note: your country is '.$mysoc->country_code.') -->'."\n";
725  }
726  if (!empty($objMod->disabled)) {
727  $codeenabledisable .= $langs->trans("Disabled");
728  } elseif (!empty($objMod->always_enabled) || ((!empty($conf->multicompany->enabled) && $objMod->core_enabled) && ($user->entity || $conf->entity != 1))) {
729  if (method_exists($objMod, 'alreadyUsed') && $objMod->alreadyUsed()) {
730  $codeenabledisable .= $langs->trans("Used");
731  } else {
732  $codeenabledisable .= img_picto($langs->trans("Required"), 'switch_on', '', false, 0, 0, '', 'opacitymedium valignmiddle');
733  //print $langs->trans("Required");
734  }
735  if (!empty($conf->multicompany->enabled) && $user->entity) {
736  $disableSetup++;
737  }
738  } else {
739  if (!empty($objMod->warnings_unactivation[$mysoc->country_code]) && method_exists($objMod, 'alreadyUsed') && $objMod->alreadyUsed()) {
740  $codeenabledisable .= '<a class="reposition valignmiddle" href="'.$_SERVER["PHP_SELF"].'?id='.$objMod->numero.'&amp;token='.newToken().'&amp;module_position='.$module_position.'&amp;action=reset_confirm&amp;confirm_message_code='.$objMod->warnings_unactivation[$mysoc->country_code].'&amp;value='.$modName.'&amp;mode='.$mode.$param.'">';
741  $codeenabledisable .= img_picto($langs->trans("Activated"), 'switch_on');
742  $codeenabledisable .= '</a>';
743  } else {
744  $codeenabledisable .= '<a class="reposition valignmiddle" href="'.$_SERVER["PHP_SELF"].'?id='.$objMod->numero.'&amp;token='.newToken().'&amp;module_position='.$module_position.'&amp;action=reset&amp;value='.$modName.'&amp;mode='.$mode.'&amp;confirm=yes'.$param.'">';
745  $codeenabledisable .= img_picto($langs->trans("Activated"), 'switch_on');
746  $codeenabledisable .= '</a>';
747  }
748  }
749 
750  // Set $codetoconfig
751  if (!empty($objMod->config_page_url) && !$disableSetup) {
752  $backtourlparam = '';
753  if ($search_keyword != '') {
754  $backtourlparam .= ($backtourlparam ? '&' : '?').'search_keyword='.$search_keyword; // No urlencode here, done later
755  }
756  if ($search_nature > -1) {
757  $backtourlparam .= ($backtourlparam ? '&' : '?').'search_nature='.$search_nature;
758  }
759  if ($search_version > -1) {
760  $backtourlparam .= ($backtourlparam ? '&' : '?').'search_version='.$search_version;
761  }
762  if ($search_status > -1) {
763  $backtourlparam .= ($backtourlparam ? '&' : '?').'search_status='.$search_status;
764  }
765  $backtourl = $_SERVER["PHP_SELF"].$backtourlparam;
766 
767  $regs = array();
768  if (is_array($objMod->config_page_url)) {
769  $i = 0;
770  foreach ($objMod->config_page_url as $page) {
771  $urlpage = $page;
772  if ($i++) {
773  $codetoconfig .= '<a href="'.$urlpage.'" title="'.$langs->trans($page).'">'.img_picto(ucfirst($page), "setup").'</a>';
774  // print '<a href="'.$page.'">'.ucfirst($page).'</a>&nbsp;';
775  } else {
776  if (preg_match('/^([^@]+)@([^@]+)$/i', $urlpage, $regs)) {
777  $urltouse = dol_buildpath('/'.$regs[2].'/admin/'.$regs[1], 1);
778  $codetoconfig .= '<a href="'.$urltouse.(preg_match('/\?/', $urltouse) ? '&' : '?').'save_lastsearch_values=1&backtopage='.urlencode($backtourl).'" title="'.$langs->trans("Setup").'">'.img_picto($langs->trans("Setup"), "setup", 'style="padding-right: 6px"', false, 0, 0, '', 'fa-15').'</a>';
779  } else {
780  $urltouse = $urlpage;
781  $codetoconfig .= '<a href="'.$urltouse.(preg_match('/\?/', $urltouse) ? '&' : '?').'save_lastsearch_values=1&backtopage='.urlencode($backtourl).'" title="'.$langs->trans("Setup").'">'.img_picto($langs->trans("Setup"), "setup", 'style="padding-right: 6px"', false, 0, 0, '', 'fa-15').'</a>';
782  }
783  }
784  }
785  } elseif (preg_match('/^([^@]+)@([^@]+)$/i', $objMod->config_page_url, $regs)) {
786  $codetoconfig .= '<a class="valignmiddle" href="'.dol_buildpath('/'.$regs[2].'/admin/'.$regs[1], 1).'?save_lastsearch_values=1&backtopage='.urlencode($backtourl).'" title="'.$langs->trans("Setup").'">'.img_picto($langs->trans("Setup"), "setup", 'style="padding-right: 6px"', false, 0, 0, '', 'fa-15').'</a>';
787  } else {
788  $codetoconfig .= '<a class="valignmiddle" href="'.$objMod->config_page_url.'?save_lastsearch_values=1&backtopage='.urlencode($backtourl).'" title="'.$langs->trans("Setup").'">'.img_picto($langs->trans("Setup"), "setup", 'style="padding-right: 6px"', false, 0, 0, '', 'fa-15').'</a>';
789  }
790  } else {
791  $codetoconfig .= img_picto($langs->trans("NothingToSetup"), "setup", 'class="opacitytransp" style="padding-right: 6px"', false, 0, 0, '', 'fa-15');
792  }
793  } else // Module not yet activated
794  {
795  // Set $codeenabledisable
796  if (!empty($objMod->always_enabled)) {
797  // Should never happened
798  } elseif (!empty($objMod->disabled)) {
799  $codeenabledisable .= $langs->trans("Disabled");
800  } else {
801  // Module qualified for activation
802  $warningmessage = '';
803  if (!empty($arrayofwarnings[$modName])) {
804  $codeenabledisable .= '<!-- This module is a core module and it may have a warning to show when we activate it (note: your country is '.$mysoc->country_code.') -->'."\n";
805  foreach ($arrayofwarnings[$modName] as $keycountry => $cursorwarningmessage) {
806  if (preg_match('/^always/', $keycountry) || ($mysoc->country_code && preg_match('/^'.$mysoc->country_code.'/', $keycountry))) {
807  $warningmessage .= ($warningmessage ? "\n" : "").$langs->trans($cursorwarningmessage, $objMod->getName(), $mysoc->country_code);
808  }
809  }
810  }
811  if ($objMod->isCoreOrExternalModule() == 'external' && !empty($arrayofwarningsext)) {
812  $codeenabledisable .= '<!-- This module is an external module and it may have a warning to show (note: your country is '.$mysoc->country_code.') -->'."\n";
813  foreach ($arrayofwarningsext as $keymodule => $arrayofwarningsextbycountry) {
814  $keymodulelowercase = strtolower(preg_replace('/^mod/', '', $keymodule));
815  if (in_array($keymodulelowercase, $conf->modules)) { // If module that request warning is on
816  foreach ($arrayofwarningsextbycountry as $keycountry => $cursorwarningmessage) {
817  if (preg_match('/^always/', $keycountry) || ($mysoc->country_code && preg_match('/^'.$mysoc->country_code.'/', $keycountry))) {
818  $warningmessage .= ($warningmessage ? "\n" : "").$langs->trans($cursorwarningmessage, $objMod->getName(), $mysoc->country_code, $modules[$keymodule]->getName());
819  $warningmessage .= ($warningmessage ? "\n" : "").($warningmessage ? "\n" : "").$langs->trans("Module").' : '.$objMod->getName();
820  if (!empty($objMod->editor_name)) {
821  $warningmessage .= ($warningmessage ? "\n" : "").$langs->trans("Publisher").' : '.$objMod->editor_name;
822  }
823  if (!empty($objMod->editor_name)) {
824  $warningmessage .= ($warningmessage ? "\n" : "").$langs->trans("ModuleTriggeringThisWarning").' : '.$modules[$keymodule]->getName();
825  }
826  }
827  }
828  }
829  }
830  }
831  $codeenabledisable .= '<!-- Message to show: '.$warningmessage.' -->'."\n";
832  $codeenabledisable .= '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?id='.$objMod->numero.'&amp;token='.newToken().'&amp;module_position='.$module_position.'&amp;action=set&amp;value='.$modName.'&amp;mode='.$mode.$param.'"';
833  if ($warningmessage) {
834  $codeenabledisable .= ' onclick="return confirm(\''.dol_escape_js($warningmessage).'\');"';
835  }
836  $codeenabledisable .= '>';
837  $codeenabledisable .= img_picto($langs->trans("Disabled"), 'switch_off');
838  $codeenabledisable .= "</a>\n";
839  }
840 
841  // Set $codetoconfig
842  $codetoconfig .= img_picto($langs->trans("NothingToSetup"), "setup", 'class="opacitytransp" style="padding-right: 6px"');
843  }
844 
845  if ($mode == 'commonkanban') {
846  // Output Kanban
847  print $objMod->getKanbanView($codeenabledisable, $codetoconfig);
848  } else {
849  print '<tr class="oddeven">'."\n";
850  if (!empty($conf->global->MAIN_MODULES_SHOW_LINENUMBERS)) {
851  print '<td width="20px">'.$linenum.'</td>';
852  }
853 
854  // Picto + Name of module
855  print ' <td width="200px">';
856  $alttext = '';
857  //if (is_array($objMod->need_dolibarr_version)) $alttext.=($alttext?' - ':'').'Dolibarr >= '.join('.',$objMod->need_dolibarr_version);
858  //if (is_array($objMod->phpmin)) $alttext.=($alttext?' - ':'').'PHP >= '.join('.',$objMod->phpmin);
859  if (!empty($objMod->picto)) {
860  if (preg_match('/^\//i', $objMod->picto)) {
861  print img_picto($alttext, $objMod->picto, 'class="valignmiddle pictomodule paddingrightonly"', 1);
862  } else {
863  print img_object($alttext, $objMod->picto, 'class="valignmiddle pictomodule paddingrightonly"');
864  }
865  } else {
866  print img_object($alttext, 'generic', 'class="valignmiddle paddingrightonly"');
867  }
868  print ' <span class="valignmiddle">'.$objMod->getName().'</span>';
869  print "</td>\n";
870 
871  // Desc
872  print '<td class="valignmiddle tdoverflowmax300">';
873  print nl2br($objMod->getDesc());
874  print "</td>\n";
875 
876  // Help
877  print '<td class="center nowrap" style="width: 82px;">';
878  //print $form->textwithpicto('', $text, 1, $imginfo, 'minheight20', 0, 2, 1);
879  print '<a href="javascript:document_preview(\''.DOL_URL_ROOT.'/admin/modulehelp.php?id='.$objMod->numero.'\',\'text/html\',\''.dol_escape_js($langs->trans("Module")).'\')">'.img_picto(($objMod->isCoreOrExternalModule() == 'external' ? $langs->trans("ExternalModule").' - ' : '').$langs->trans("ClickToShowDescription"), $imginfo).'</a>';
880  print '</td>';
881 
882  // Version
883  print '<td class="center nowrap" width="120px">';
884  print $versiontrans;
885  if (!empty($conf->global->CHECKLASTVERSION_EXTERNALMODULE)) { // This is a bad practice to activate a synch external access during building of a page. 1 external module can hang the application.
886  require_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
887  if (!empty($objMod->url_last_version)) {
888  $newversion = getURLContent($objMod->url_last_version);
889  if (isset($newversion['content'])) {
890  if (version_compare($newversion['content'], $versiontrans) > 0) {
891  print "&nbsp;<span class='butAction' title='".$langs->trans('LastStableVersion')."'>".$newversion['content']."</span>";
892  }
893  }
894  }
895  }
896  print "</td>\n";
897 
898  // Link enable/disable
899  print '<td class="center valignmiddle" width="60px">';
900  print $codeenabledisable;
901  print "</td>\n";
902 
903  // Link config
904  print '<td class="tdsetuppicto right valignmiddle" width="60px">';
905  print $codetoconfig;
906  print '</td>';
907 
908  print "</tr>\n";
909  }
910  }
911 
912  if ($oldfamily) {
913  if ($mode == 'commonkanban') {
914  print '</div>';
915  } else {
916  print "</table>\n";
917  print '</div>';
918  }
919  }
920 
921  print dol_get_fiche_end();
922 
923  print '<br>';
924 
925  // Show warning about external users
926  print info_admin(showModulesExludedForExternal($modules))."\n";
927 
928  print '</form>';
929 }
930 
931 if ($mode == 'marketplace') {
932  print dol_get_fiche_head($head, $mode, '', -1);
933 
934  // Marketplace
935  print '<div class="div-table-responsive-no-min">';
936  print '<table summary="list_of_modules" class="noborder centpercent">'."\n";
937  print '<tr class="liste_titre">'."\n";
938  print '<td class="hideonsmartphone">'.$form->textwithpicto($langs->trans("Provider"), $langs->trans("WebSiteDesc")).'</td>';
939  print '<td></td>';
940  print '<td>'.$langs->trans("URL").'</td>';
941  print '</tr>';
942 
943  print '<tr class="oddeven">'."\n";
944  $url = 'https://www.dolistore.com';
945  print '<td class="hideonsmartphone"><a href="'.$url.'" target="_blank" rel="external"><img border="0" class="imgautosize imgmaxwidth180" src="'.DOL_URL_ROOT.'/theme/dolistore_logo.png"></a></td>';
946  print '<td>'.$langs->trans("DoliStoreDesc").'</td>';
947  print '<td><a href="'.$url.'" target="_blank" rel="external">'.$url.'</a></td>';
948  print '</tr>';
949 
950  print "</table>\n";
951  print '</div>';
952 
953  print dol_get_fiche_end();
954 
955  print '<br>';
956 
957  if (empty($conf->global->MAIN_DISABLE_DOLISTORE_SEARCH) && $conf->global->MAIN_FEATURES_LEVEL >= 1) {
958  // $options is array with filter criterias
959  //var_dump($options);
960  $dolistore->getRemoteCategories();
961  $dolistore->getRemoteProducts($options);
962 
963  print '<span class="opacitymedium">'.$langs->trans('DOLISTOREdescriptionLong').'</span><br><br>';
964 
965  $previouslink = $dolistore->get_previous_link();
966  $nextlink = $dolistore->get_next_link();
967 
968  print '<div class="liste_titre liste_titre_bydiv centpercent"><div class="divsearchfield">';
969 
970  print '<form method="POST" class="centpercent" id="searchFormList" action="'.$dolistore->url.'">';
971  ?>
972  <input type="hidden" name="token" value="<?php echo newToken(); ?>">
973  <input type="hidden" name="mode" value="marketplace">
974  <div class="divsearchfield"><?php echo $langs->trans('Keyword') ?>:
975  <input name="search_keyword" placeholder="<?php echo $langs->trans('Chercher un module') ?>" id="search_keyword" type="text" size="50" value="<?php echo $options['search'] ?>"><br>
976  </div>
977  <div class="divsearchfield">
978  <input class="button buttongen" value="<?php echo $langs->trans('Rechercher') ?>" type="submit">
979  <a class="buttonreset" href="<?php echo $dolistore->url ?>"><?php echo $langs->trans('Reset') ?></a>
980 
981  &nbsp;
982  </div>
983  <?php
984  print $previouslink;
985  print $nextlink;
986  print '</form>';
987 
988 
989  print '</div></div>';
990  print '<div class="clearboth"></div>';
991 
992  ?>
993 
994  <div id="category-tree-left">
995  <ul class="tree">
996  <?php echo $dolistore->get_categories(); ?>
997  </ul>
998  </div>
999  <div id="listing-content">
1000  <table summary="list_of_modules" id="list_of_modules" class="productlist centpercent">
1001  <tbody id="listOfModules">
1002  <?php echo $dolistore->get_products($categorie); ?>
1003  </tbody>
1004  </table>
1005  </div>
1006 
1007  <?php
1008  }
1009 }
1010 
1011 
1012 // Install external module
1013 
1014 if ($mode == 'deploy') {
1015  print dol_get_fiche_head($head, $mode, '', -1);
1016 
1017  $dolibarrdataroot = preg_replace('/([\\/]+)$/i', '', DOL_DATA_ROOT);
1018  $allowonlineinstall = true;
1019  $allowfromweb = 1;
1020  if (dol_is_file($dolibarrdataroot.'/installmodules.lock')) {
1021  $allowonlineinstall = false;
1022  }
1023 
1024  $fullurl = '<a href="'.$urldolibarrmodules.'" target="_blank">'.$urldolibarrmodules.'</a>';
1025  $message = '';
1026  if (!empty($allowonlineinstall)) {
1027  if (!in_array('/custom', explode(',', $dolibarr_main_url_root_alt))) {
1028  $message = info_admin($langs->trans("ConfFileMustContainCustom", DOL_DOCUMENT_ROOT.'/custom', DOL_DOCUMENT_ROOT));
1029  $allowfromweb = -1;
1030  } else {
1031  if ($dirins_ok) {
1032  if (!is_writable(dol_osencode($dirins))) {
1033  $langs->load("errors");
1034  $message = info_admin($langs->trans("ErrorFailedToWriteInDir", $dirins), 0, 0, '1', 'warning');
1035  $allowfromweb = 0;
1036  }
1037  } else {
1038  $message = info_admin($langs->trans("NotExistsDirect", $dirins).$langs->trans("InfDirAlt").$langs->trans("InfDirExample"));
1039  $allowfromweb = 0;
1040  }
1041  }
1042  } else {
1043  $message = info_admin($langs->trans("InstallModuleFromWebHasBeenDisabledByFile", $dolibarrdataroot.'/installmodules.lock'));
1044  $allowfromweb = 0;
1045  }
1046 
1047  if ($allowfromweb < 1) {
1048  print $langs->trans("SomethingMakeInstallFromWebNotPossible");
1049  print $message;
1050  //print $langs->trans("SomethingMakeInstallFromWebNotPossible2");
1051  print '<br>';
1052  }
1053 
1054  print '<br>';
1055 
1056  if ($allowfromweb >= 0) {
1057  if ($allowfromweb == 1) {
1058  //print $langs->trans("ThisIsProcessToFollow").'<br>';
1059  } else {
1060  print $langs->trans("ThisIsAlternativeProcessToFollow").'<br>';
1061  print '<b>'.$langs->trans("StepNb", 1).'</b>: ';
1062  print str_replace('{s1}', $fullurl, $langs->trans("FindPackageFromWebSite", '{s1}')).'<br>';
1063  print '<b>'.$langs->trans("StepNb", 2).'</b>: ';
1064  print str_replace('{s1}', $fullurl, $langs->trans("DownloadPackageFromWebSite", '{s1}')).'<br>';
1065  print '<b>'.$langs->trans("StepNb", 3).'</b>: ';
1066  }
1067 
1068  if ($allowfromweb == 1) {
1069  print $langs->trans("UnpackPackageInModulesRoot", $dirins).'<br>';
1070 
1071  print '<br>';
1072 
1073  print '<form enctype="multipart/form-data" method="POST" class="noborder" action="'.$_SERVER["PHP_SELF"].'" name="forminstall">';
1074  print '<input type="hidden" name="token" value="'.newToken().'">';
1075  print '<input type="hidden" name="action" value="install">';
1076  print '<input type="hidden" name="mode" value="deploy">';
1077 
1078  print $langs->trans("YouCanSubmitFile");
1079 
1080  $max = $conf->global->MAIN_UPLOAD_DOC; // In Kb
1081  $maxphp = @ini_get('upload_max_filesize'); // In unknown
1082  if (preg_match('/k$/i', $maxphp)) {
1083  $maxphp = $maxphp * 1;
1084  }
1085  if (preg_match('/m$/i', $maxphp)) {
1086  $maxphp = $maxphp * 1024;
1087  }
1088  if (preg_match('/g$/i', $maxphp)) {
1089  $maxphp = $maxphp * 1024 * 1024;
1090  }
1091  if (preg_match('/t$/i', $maxphp)) {
1092  $maxphp = $maxphp * 1024 * 1024 * 1024;
1093  }
1094  $maxphp2 = @ini_get('post_max_size'); // In unknown
1095  if (preg_match('/k$/i', $maxphp2)) {
1096  $maxphp2 = $maxphp2 * 1;
1097  }
1098  if (preg_match('/m$/i', $maxphp2)) {
1099  $maxphp2 = $maxphp2 * 1024;
1100  }
1101  if (preg_match('/g$/i', $maxphp2)) {
1102  $maxphp2 = $maxphp2 * 1024 * 1024;
1103  }
1104  if (preg_match('/t$/i', $maxphp2)) {
1105  $maxphp2 = $maxphp2 * 1024 * 1024 * 1024;
1106  }
1107  // Now $max and $maxphp and $maxphp2 are in Kb
1108  $maxmin = $max;
1109  $maxphptoshow = $maxphptoshowparam = '';
1110  if ($maxphp > 0) {
1111  $maxmin = min($max, $maxphp);
1112  $maxphptoshow = $maxphp;
1113  $maxphptoshowparam = 'upload_max_filesize';
1114  }
1115  if ($maxphp2 > 0) {
1116  $maxmin = min($max, $maxphp2);
1117  if ($maxphp2 < $maxphp) {
1118  $maxphptoshow = $maxphp2;
1119  $maxphptoshowparam = 'post_max_size';
1120  }
1121  }
1122 
1123  if ($maxmin > 0) {
1124  print '<script type="text/javascript">
1125  $(document).ready(function() {
1126  jQuery("#fileinstall").on("change", function() {
1127  if(this.files[0].size > '.($maxmin * 1024).'){
1128  alert("'.dol_escape_js($langs->trans("ErrorFileSizeTooLarge")).'");
1129  this.value = "";
1130  };
1131  });
1132  });
1133  </script>'."\n";
1134  // MAX_FILE_SIZE doit précéder le champ input de type file
1135  print '<input type="hidden" name="max_file_size" value="'.($maxmin * 1024).'">';
1136  }
1137 
1138  print '<input class="flat minwidth400" type="file" name="fileinstall" id="fileinstall"> ';
1139 
1140  print '<input type="submit" name="send" value="'.dol_escape_htmltag($langs->trans("Upload")).'" class="button">';
1141 
1142  if (!empty($conf->global->MAIN_UPLOAD_DOC)) {
1143  if ($user->admin) {
1144  $langs->load('other');
1145  print ' ';
1146  print info_admin($langs->trans("ThisLimitIsDefinedInSetup", $max, $maxphptoshow, $maxphptoshowparam), 1);
1147  }
1148  } else {
1149  print ' ('.$langs->trans("UploadDisabled").')';
1150  }
1151 
1152  print '</form>';
1153 
1154  print '<br>';
1155  print '<br>';
1156 
1157  print '<div class="center"><div class="logo_setup"></div></div>';
1158  } else {
1159  print $langs->trans("UnpackPackageInModulesRoot", $dirins).'<br>';
1160  print '<b>'.$langs->trans("StepNb", 4).'</b>: ';
1161  print $langs->trans("SetupIsReadyForUse").'<br>';
1162  }
1163  }
1164 
1165  if (!empty($result['return'])) {
1166  print '<br>';
1167 
1168  foreach ($result['return'] as $value) {
1169  echo $value.'<br>';
1170  }
1171  }
1172 
1173  print dol_get_fiche_end();
1174 }
1175 
1176 if ($mode == 'develop') {
1177  print dol_get_fiche_head($head, $mode, '', -1);
1178 
1179  // Marketplace
1180  print "<table summary=\"list_of_modules\" class=\"noborder\" width=\"100%\">\n";
1181  print "<tr class=\"liste_titre\">\n";
1182  //print '<td>'.$langs->trans("Logo").'</td>';
1183  print '<td colspan="2">'.$langs->trans("DevelopYourModuleDesc").'</td>';
1184  print '<td>'.$langs->trans("URL").'</td>';
1185  print '</tr>';
1186 
1187  print '<tr class="oddeven" height="80">'."\n";
1188  print '<td class="left">';
1189  print '<div class="imgmaxheight50 logo_setup"></div>';
1190  print '</td>';
1191  print '<td>'.$langs->trans("TryToUseTheModuleBuilder", $langs->transnoentitiesnoconv("ModuleBuilder")).'</td>';
1192  print '<td>'.$langs->trans("SeeTopRightMenu").'</td>';
1193  print '</tr>';
1194 
1195  print '<tr class="oddeven" height="80">'."\n";
1196  $url = 'https://partners.dolibarr.org';
1197  print '<td class="left">';
1198  print'<a href="'.$url.'" target="_blank" rel="external"><img border="0" class="imgautosize imgmaxwidth180" src="'.DOL_URL_ROOT.'/theme/dolibarr_preferred_partner.png"></a>';
1199  print '</td>';
1200  print '<td>'.$langs->trans("DoliPartnersDesc").'</td>';
1201  print '<td><a href="'.$url.'" target="_blank" rel="external">'.$url.'</a></td>';
1202  print '</tr>';
1203 
1204  print "</table>\n";
1205 
1207 }
1208 
1209 // End of page
1210 llxFooter();
1211 $db->close();
GETPOST($paramname, $check= 'alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayreplacement=null, $excludesubdir=0)
Copy a dir to another dir.
Definition: files.lib.php:720
unActivateModule($value, $requiredby=1)
Disable a module.
Definition: admin.lib.php:1100
dolGetButtonTitle($label, $helpText= '', $iconClass= 'fa fa-file', $url= '', $id= '', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
dolGetModulesDirs($subdir= '')
Return list of modules directories.
dol_is_dir($folder)
Test if filename is a directory.
Definition: files.lib.php:432
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
img_warning($titlealt= 'default', $moreatt= '', $morecss= 'pictowarning')
Show warning logo.
llxHeader()
Empty header.
Definition: wrapper.php:45
setEventMessages($mesg, $mesgs, $style= 'mesgs', $messagekey= '')
Set event messages in dol_events session object.
Class to manage generation of HTML components Only common components must be here.
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname.
document_preview(file, type, title)
Function show document preview.
load_fiche_titre($titre, $morehtmlright= '', $picto= 'generic', $pictoisfullpath=0, $id= '', $morecssontable= '', $morehtmlcenter= '')
Load a title with picto.
dol_strlen($string, $stringencoding= 'UTF-8')
Make a strlen call.
img_picto($titlealt, $picto, $moreatt= '', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt= '', $morecss= '', $marginleftonlyshort=2)
Show picto whatever it&#39;s its name (generic function)
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename= '', $restricttologhandler= '', $logcontext=null)
Write log message into outputs.
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories) ...
Definition: files.lib.php:1286
accessforbidden($message= '', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program Calling this function terminate execution ...
dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $nohook=0, $varfiles= 'addedfile', $upload_dir= '')
Make control on an uploaded file from an GUI page and move it to final destination.
Definition: files.lib.php:999
dol_is_file($pathoffile)
Return if path is a file.
Definition: files.lib.php:457
print $_SERVER["PHP_SELF"]
Edit parameters.
dol_uncompress($inputfile, $outputdir)
Uncompress a file.
Definition: files.lib.php:2033
dol_get_fiche_head($links=array(), $active= '', $title= '', $notab=0, $picto= '', $pictoisfullpath=0, $morehtmlright= '', $morecss= '', $limittoshow=0, $moretabssuffix= '')
Show tabs of a record.
print
Draft customers invoices.
Definition: index.php:89
Class Dolistore.
dol_print_error($db= '', $error= '', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
newToken()
Return the value of token currently saved into session with name &#39;newtoken&#39;.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
activateModule($value, $withdeps=1)
Enable a module.
Definition: admin.lib.php:971
print $_SERVER["PHP_SELF"] n
Edit parameters.
Definition: categories.php:101
modules_prepare_head()
Prepare array with list of tabs.
Definition: admin.lib.php:633
llxFooter()
Empty footer.
Definition: wrapper.php:59
dol_set_focus($selector)
Set focus onto field with selector (similar behaviour of &#39;autofocus&#39; HTML5 tag)
dol_mkdir($dir, $dataroot= '', $newmask=null)
Creation of a directory (this can create recursive subdir)
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $keepmoretags= '', $escapeonlyhtmltags=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields...