PageRenderTime 52ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/htdocs/core/lib/admin.lib.php

https://bitbucket.org/speedealing/speedealing
PHP | 1098 lines | 723 code | 132 blank | 243 comment | 198 complexity | 3bf3f3c09b4b6ee2a40d079588e750ff MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, GPL-3.0, MIT
  1. <?php
  2. /* Copyright (C) 2008-2011 Laurent Destailleur <eldy@users.sourceforge.net>
  3. * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. * or see http://www.gnu.org/
  18. */
  19. /**
  20. * \file htdocs/core/lib/admin.lib.php
  21. * \brief Library of admin functions
  22. */
  23. /**
  24. * Renvoi une version en chaine depuis une version en tableau
  25. *
  26. * @param array $versionarray Tableau de version (vermajeur,vermineur,autre)
  27. * @return string Chaine version
  28. */
  29. function versiontostring($versionarray) {
  30. $string = '?';
  31. if (isset($versionarray[0]))
  32. $string = $versionarray[0];
  33. if (isset($versionarray[1]))
  34. $string.='.' . $versionarray[1];
  35. if (isset($versionarray[2]))
  36. $string.='.' . $versionarray[2];
  37. return $string;
  38. }
  39. /**
  40. * Compare 2 versions (stored into 2 arrays)
  41. *
  42. * @param array $versionarray1 Array of version (vermajor,verminor,patch)
  43. * @param array $versionarray2 Array of version (vermajor,verminor,patch)
  44. * @return int -4,-3,-2,-1 if versionarray1<versionarray2 (value depends on level of difference)
  45. * 0 if same
  46. * 1,2,3,4 if versionarray1>versionarray2 (value depends on level of difference)
  47. */
  48. function versioncompare($versionarray1, $versionarray2) {
  49. $ret = 0;
  50. $level = 0;
  51. $count1 = count($versionarray1);
  52. $count2 = count($versionarray2);
  53. $maxcount = max($count1, $count2);
  54. while ($level < $maxcount) {
  55. $operande1 = isset($versionarray1[$level]) ? $versionarray1[$level] : 0;
  56. $operande2 = isset($versionarray2[$level]) ? $versionarray2[$level] : 0;
  57. if (preg_match('/alpha|dev/i', $operande1))
  58. $operande1 = -3;
  59. if (preg_match('/alpha|dev/i', $operande2))
  60. $operande2 = -3;
  61. if (preg_match('/beta/i', $operande1))
  62. $operande1 = -2;
  63. if (preg_match('/beta/i', $operande2))
  64. $operande2 = -2;
  65. if (preg_match('/rc/i', $operande1))
  66. $operande1 = -1;
  67. if (preg_match('/rc/i', $operande2))
  68. $operande2 = -1;
  69. $level++;
  70. //print 'level '.$level.' '.$operande1.'-'.$operande2.'<br>';
  71. if ($operande1 < $operande2) {
  72. $ret = -$level;
  73. break;
  74. }
  75. if ($operande1 > $operande2) {
  76. $ret = $level;
  77. break;
  78. }
  79. }
  80. //print join('.',$versionarray1).'('.count($versionarray1).') / '.join('.',$versionarray2).'('.count($versionarray2).') => '.$ret;
  81. return $ret;
  82. }
  83. /**
  84. * Return version PHP
  85. *
  86. * @return array Tableau de version (vermajeur,vermineur,autre)
  87. */
  88. function versionphparray() {
  89. return explode('.', PHP_VERSION);
  90. }
  91. /**
  92. * Return version Dolibarr
  93. *
  94. * @return array Tableau de version (vermajeur,vermineur,autre)
  95. */
  96. function versiondolibarrarray() {
  97. return explode('.', DOL_VERSION);
  98. }
  99. /**
  100. * Launch a sql file. Function used by:
  101. * - Migrate process (dolibarr-xyz-abc.sql)
  102. * - Loading sql menus (auguria)
  103. * - Running specific Sql by a module init
  104. * Install process however does not use it.
  105. * Note that Sql files must have all comments at start of line.
  106. *
  107. * @param string $sqlfile Full path to sql file
  108. * @param int $silent 1=Do not output anything, 0=Output line for update page
  109. * @param int $entity Entity targeted for multicompany module
  110. * @param int $usesavepoint 1=Run a savepoint before each request and a rollback to savepoint if error (this allow to have some request with errors inside global transactions).
  111. * @param string $handler Handler targeted for menu
  112. * @param string $okerror Family of errors we accept ('default', 'none')
  113. * @return int <=0 if KO, >0 if OK
  114. */
  115. function run_sql($sqlfile, $silent = 1, $entity = '', $usesavepoint = 1, $handler = '', $okerror = 'default') {
  116. global $db, $conf, $langs, $user;
  117. dol_syslog("Admin.lib::run_sql run sql file " . $sqlfile . " silent=" . $silent . " entity=" . $entity . " usesavepoint=" . $usesavepoint . " handler=" . $handler . " okerror=" . $okerror, LOG_DEBUG);
  118. $ok = 0;
  119. $error = 0;
  120. $i = 0;
  121. $buffer = '';
  122. $arraysql = Array();
  123. // Get version of database
  124. $versionarray = $db->getVersionArray();
  125. $fp = fopen($sqlfile, "r");
  126. if ($fp) {
  127. while (!feof($fp)) {
  128. $buf = fgets($fp, 4096);
  129. // Test if request must be ran only for particular database or version (if yes, we must remove the -- comment)
  130. if (preg_match('/^--\sV(MYSQL|PGSQL|)([0-9\.]+)/i', $buf, $reg)) {
  131. $qualified = 1;
  132. // restrict on database type
  133. if (!empty($reg[1])) {
  134. if (!preg_match('/' . preg_quote($reg[1]) . '/i', $db->type))
  135. $qualified = 0;
  136. }
  137. // restrict on version
  138. if ($qualified) {
  139. $versionrequest = explode('.', $reg[2]);
  140. //print var_dump($versionrequest);
  141. //print var_dump($versionarray);
  142. if (!count($versionrequest) || !count($versionarray) || versioncompare($versionrequest, $versionarray) > 0) {
  143. $qualified = 0;
  144. }
  145. }
  146. if ($qualified) {
  147. // Version qualified, delete SQL comments
  148. $buf = preg_replace('/^--\sV(MYSQL|PGSQL|)([0-9\.]+)/i', '', $buf);
  149. //print "Ligne $i qualifi?e par version: ".$buf.'<br>';
  150. }
  151. }
  152. // Add line buf to buffer if not a comment
  153. if (!preg_match('/^--/', $buf)) {
  154. $buf = preg_replace('/--.*$/', '', $buf); //remove comment from a line that not start with -- before add it to the buffer
  155. $buffer .= trim($buf);
  156. }
  157. // print $buf.'<br>';
  158. if (preg_match('/;/', $buffer)) { // If string contains ';', it's end of a request string, we save it in arraysql.
  159. // Found new request
  160. if ($buffer)
  161. $arraysql[$i] = $buffer;
  162. $i++;
  163. $buffer = '';
  164. }
  165. }
  166. if ($buffer)
  167. $arraysql[$i] = $buffer;
  168. fclose($fp);
  169. }
  170. else {
  171. dol_syslog("Admin.lib::run_sql failed to open file " . $sqlfile, LOG_ERR);
  172. }
  173. // Loop on each request to see if there is a __+MAX_table__ key
  174. $listofmaxrowid = array(); // This is a cache table
  175. foreach ($arraysql as $i => $sql) {
  176. $newsql = $sql;
  177. // Replace __+MAX_table__ with max of table
  178. while (preg_match('/__\+MAX_([A-Za-z_]+)__/i', $newsql, $reg)) {
  179. $table = $reg[1];
  180. if (!isset($listofmaxrowid[$table])) {
  181. //var_dump($db);
  182. $sqlgetrowid = 'SELECT MAX(rowid) as max from ' . $table;
  183. $resql = $db->query($sqlgetrowid);
  184. if ($resql) {
  185. $obj = $db->fetch_object($resql);
  186. $listofmaxrowid[$table] = $obj->max;
  187. if (empty($listofmaxrowid[$table]))
  188. $listofmaxrowid[$table] = 0;
  189. }
  190. else {
  191. dol_syslog('Admin.lib::run_sql Failed to get max rowid for ' . $table . ' ' . $db->lasterror() . ' sql=' . $sqlgetrowid, LOG_ERR);
  192. if (!$silent)
  193. print '<tr><td valign="top" colspan="2">';
  194. if (!$silent)
  195. print '<div class="error">' . $langs->trans("Failed to get max rowid for " . $table) . "</div></td>";
  196. if (!$silent)
  197. print '</tr>';
  198. $error++;
  199. break;
  200. }
  201. }
  202. $from = '__+MAX_' . $table . '__';
  203. $to = '+' . $listofmaxrowid[$table];
  204. $newsql = str_replace($from, $to, $newsql);
  205. dol_syslog('Admin.lib::run_sql New Request ' . ($i + 1) . ' (replacing ' . $from . ' to ' . $to . ') sql=' . $newsql, LOG_DEBUG);
  206. $arraysql[$i] = $newsql;
  207. }
  208. }
  209. // Loop on each request to execute request
  210. $cursorinsert = 0;
  211. $listofinsertedrowid = array();
  212. foreach ($arraysql as $i => $sql) {
  213. if ($sql) {
  214. // Replace the prefix tables
  215. if (MAIN_DB_PREFIX != 'llx_') {
  216. $sql = preg_replace('/llx_/i', MAIN_DB_PREFIX, $sql);
  217. }
  218. if (!empty($handler))
  219. $sql = preg_replace('/__HANDLER__/i', "'" . $handler . "'", $sql);
  220. $newsql = preg_replace('/__ENTITY__/i', (!empty($entity) ? $entity : $conf->entity), $sql);
  221. // Ajout trace sur requete (eventuellement a commenter si beaucoup de requetes)
  222. if (!$silent)
  223. print '<tr><td valign="top">' . $langs->trans("Request") . ' ' . ($i + 1) . " sql='" . $newsql . "'</td></tr>\n";
  224. dol_syslog('Admin.lib::run_sql Request ' . ($i + 1) . ' sql=' . $newsql, LOG_DEBUG);
  225. // Replace for encrypt data
  226. if (preg_match_all('/__ENCRYPT\(\'([A-Za-z0-9_]+)\'\)__/i', $newsql, $reg)) {
  227. $num = count($reg[0]);
  228. for ($i = 0; $i < $num; $i++) {
  229. $from = $reg[0][$i];
  230. $to = $db->encrypt($reg[1][$i], 1);
  231. $newsql = str_replace($from, $to, $newsql);
  232. }
  233. }
  234. // Replace for decrypt data
  235. if (preg_match_all('/__DECRYPT\(\'([A-Za-z0-9_]+)\'\)__/i', $newsql, $reg)) {
  236. $num = count($reg[0]);
  237. for ($i = 0; $i < $num; $i++) {
  238. $from = $reg[0][$i];
  239. $to = $db->decrypt($reg[1][$i]);
  240. $newsql = str_replace($from, $to, $newsql);
  241. }
  242. }
  243. // Replace __x__ with rowid of insert nb x
  244. while (preg_match('/__([0-9]+)__/', $newsql, $reg)) {
  245. $cursor = $reg[1];
  246. if (empty($listofinsertedrowid[$cursor])) {
  247. if (!$silent)
  248. print '<tr><td valign="top" colspan="2">';
  249. if (!$silent)
  250. print '<div class="error">' . $langs->trans("FileIsNotCorrect") . "</div></td>";
  251. if (!$silent)
  252. print '</tr>';
  253. $error++;
  254. break;
  255. }
  256. $from = '__' . $cursor . '__';
  257. $to = $listofinsertedrowid[$cursor];
  258. $newsql = str_replace($from, $to, $newsql);
  259. dol_syslog('Admin.lib::run_sql New Request ' . ($i + 1) . ' (replacing ' . $from . ' to ' . $to . ') sql=' . $newsql, LOG_DEBUG);
  260. }
  261. $result = $db->query($newsql, $usesavepoint);
  262. if ($result) {
  263. if (!$silent)
  264. print '<!-- Result = OK -->' . "\n";
  265. if (preg_replace('/insert into ([^\s]+)/i', $newsql, $reg)) {
  266. $cursorinsert++;
  267. // It's an insert
  268. $table = preg_replace('/([^a-zA-Z_]+)/i', '', $reg[1]);
  269. $insertedrowid = $db->last_insert_id($table);
  270. $listofinsertedrowid[$cursorinsert] = $insertedrowid;
  271. dol_syslog('Admin.lib::run_sql Insert nb ' . $cursorinsert . ', done in table ' . $table . ', rowid is ' . $listofinsertedrowid[$cursorinsert], LOG_DEBUG);
  272. }
  273. // print '<td align="right">OK</td>';
  274. } else {
  275. $errno = $db->errno();
  276. if (!$silent)
  277. print '<!-- Result = ' . $errno . ' -->' . "\n";
  278. // Define list of errors we accept (array $okerrors)
  279. $okerrors = array(// By default
  280. 'DB_ERROR_TABLE_ALREADY_EXISTS',
  281. 'DB_ERROR_COLUMN_ALREADY_EXISTS',
  282. 'DB_ERROR_KEY_NAME_ALREADY_EXISTS',
  283. 'DB_ERROR_TABLE_OR_KEY_ALREADY_EXISTS', // PgSql use same code for table and key already exist
  284. 'DB_ERROR_RECORD_ALREADY_EXISTS',
  285. 'DB_ERROR_NOSUCHTABLE',
  286. 'DB_ERROR_NOSUCHFIELD',
  287. 'DB_ERROR_NO_FOREIGN_KEY_TO_DROP',
  288. 'DB_ERROR_NO_INDEX_TO_DROP',
  289. 'DB_ERROR_CANNOT_CREATE', // Qd contrainte deja existante
  290. 'DB_ERROR_CANT_DROP_PRIMARY_KEY',
  291. 'DB_ERROR_PRIMARY_KEY_ALREADY_EXISTS'
  292. );
  293. if ($okerror == 'none')
  294. $okerrors = array();
  295. // Is it an error we accept
  296. if (!in_array($errno, $okerrors)) {
  297. if (!$silent)
  298. print '<tr><td valign="top" colspan="2">';
  299. if (!$silent)
  300. print '<div class="error">' . $langs->trans("Error") . " " . $db->errno() . ": " . $newsql . "<br>" . $db->error() . "</div></td>";
  301. if (!$silent)
  302. print '</tr>' . "\n";
  303. dol_syslog('Admin.lib::run_sql Request ' . ($i + 1) . " Error " . $db->errno() . " " . $newsql . "<br>" . $db->error(), LOG_ERR);
  304. $error++;
  305. }
  306. }
  307. if (!$silent)
  308. print '</tr>' . "\n";
  309. }
  310. }
  311. if ($error == 0) {
  312. if (!$silent)
  313. print '<tr><td>' . $langs->trans("ProcessMigrateScript") . '</td>';
  314. if (!$silent)
  315. print '<td align="right">' . $langs->trans("OK") . '</td></tr>' . "\n";
  316. $ok = 1;
  317. }
  318. else {
  319. if (!$silent)
  320. print '<tr><td>' . $langs->trans("ProcessMigrateScript") . '</td>';
  321. if (!$silent)
  322. print '<td align="right"><font class="error">' . $langs->trans("KO") . '</font></td></tr>' . "\n";
  323. $ok = 0;
  324. }
  325. return $ok;
  326. }
  327. /**
  328. * Effacement d'une constante dans la base de donnees
  329. *
  330. * @param DoliDB $db Database handler
  331. * @param string $name Name of constant or rowid of line
  332. * @param int $entity Multi company id, -1 for all entities
  333. * @return int <0 if KO, >0 if OK
  334. *
  335. * @see dolibarr_get_const, dolibarr_set_const, dol_set_user_param
  336. */
  337. function dolibarr_del_const($db, $name, $entity = 1) {
  338. global $conf;
  339. dol_syslog("admin.lib::dolibarr_del_const sql=" . $sql);
  340. unset ($conf->global->$name);
  341. $conf->record();
  342. return 1;
  343. }
  344. /**
  345. * Recupere une constante depuis la base de donnees.
  346. *
  347. * @param DoliDB $db Database handler
  348. * @param string $name Nom de la constante
  349. * @param int $entity Multi company id
  350. * @return string Valeur de la constante
  351. *
  352. * @see dolibarr_del_const, dolibarr_set_const, dol_set_user_param
  353. */
  354. function dolibarr_get_const($db, $name, $entity = 1) {
  355. global $conf;
  356. $value = '';
  357. dol_syslog("admin.lib::dolibarr_get_const sql=" . $sql);
  358. $value = $conf->global->$name;
  359. return $value;
  360. }
  361. /**
  362. * Insert a parameter (key,value) into database.
  363. *
  364. * @param DoliDB $db Database handler
  365. * @param string $name Name of constant
  366. * @param string $value Value of constant
  367. * @param string $type Type of constante (chaine par defaut)
  368. * @param int $visible Is constant visible in Setup->Other page (0 by default)
  369. * @param string $note Note on parameter
  370. * @param int $entity Multi company id (0 means all entities)
  371. * @return int -1 if KO, 1 if OK
  372. *
  373. * @see dolibarr_del_const, dolibarr_get_const, dol_set_user_param
  374. */
  375. function dolibarr_set_const($db, $name, $value, $type = 'chaine', $visible = 0, $note = '', $entity = 1) {
  376. global $conf;
  377. // Clean parameters
  378. $name = trim($name);
  379. // Check parameters
  380. if (empty($name)) {
  381. dol_print_error($db, "Error: Call to function dolibarr_set_const with wrong parameters", LOG_ERR);
  382. exit;
  383. }
  384. //dol_syslog("dolibarr_set_const name=$name, value=$value type=$type, visible=$visible, note=$note entity=$entity");
  385. dol_syslog("admin.lib::dolibarr_set_const sql=" . $sql, LOG_DEBUG);
  386. //print $name;exit;
  387. if (strcmp($value, '')) { // true if different. Must work for $value='0' or $value=0
  388. $conf->global->$name = $value;
  389. $conf->record();
  390. }
  391. return 1;
  392. }
  393. /**
  394. * Prepare array with list of tabs
  395. *
  396. * @return array Array of tabs to shoc
  397. */
  398. function security_prepare_head() {
  399. global $langs, $conf, $user;
  400. $h = 0;
  401. $head = array();
  402. $head[$h][0] = DOL_URL_ROOT . "/admin/proxy.php";
  403. $head[$h][1] = $langs->trans("ExternalAccess");
  404. $head[$h][2] = 'proxy';
  405. $h++;
  406. $head[$h][0] = DOL_URL_ROOT . "/admin/security_other.php";
  407. $head[$h][1] = $langs->trans("Miscellanous");
  408. $head[$h][2] = 'misc';
  409. $h++;
  410. $head[$h][0] = DOL_URL_ROOT . "/admin/security.php";
  411. $head[$h][1] = $langs->trans("Passwords");
  412. $head[$h][2] = 'passwords';
  413. $h++;
  414. $head[$h][0] = DOL_URL_ROOT . "/admin/events.php";
  415. $head[$h][1] = $langs->trans("Audit");
  416. $head[$h][2] = 'audit';
  417. $h++;
  418. $head[$h][0] = DOL_URL_ROOT . "/admin/perms.php";
  419. $head[$h][1] = $langs->trans("DefaultRights");
  420. $head[$h][2] = 'default';
  421. $h++;
  422. return $head;
  423. }
  424. /**
  425. * Return list of session
  426. *
  427. * @return array Array list of sessions
  428. */
  429. function listOfSessions() {
  430. global $conf;
  431. $arrayofSessions = array();
  432. $sessPath = ini_get("session.save_path") . '/';
  433. dol_syslog('admin.lib:listOfSessions sessPath=' . $sessPath);
  434. $dh = @opendir(dol_osencode($sessPath));
  435. if ($dh) {
  436. while (($file = @readdir($dh)) !== false) {
  437. if (preg_match('/^sess_/i', $file) && $file != "." && $file != "..") {
  438. $fullpath = $sessPath . $file;
  439. if (!@is_dir($fullpath) && is_readable($fullpath)) {
  440. $sessValues = file_get_contents($fullpath); // get raw session data
  441. if (preg_match('/dol_login/i', $sessValues) && // limit to dolibarr session
  442. preg_match('/dol_entity\|s:([0-9]+):"(' . $conf->entity . ')"/i', $sessValues) && // limit to current entity
  443. preg_match('/dol_company\|s:([0-9]+):"(' . $conf->global->MAIN_INFO_SOCIETE_NOM . ')"/i', $sessValues)) { // limit to company name
  444. $tmp = explode('_', $file);
  445. $idsess = $tmp[1];
  446. $login = preg_match('/dol_login\|s:[0-9]+:"([A-Za-z0-9]+)"/i', $sessValues, $regs);
  447. $arrayofSessions[$idsess]["login"] = $regs[1];
  448. $arrayofSessions[$idsess]["age"] = time() - filectime($fullpath);
  449. $arrayofSessions[$idsess]["creation"] = filectime($fullpath);
  450. $arrayofSessions[$idsess]["modification"] = filemtime($fullpath);
  451. $arrayofSessions[$idsess]["raw"] = $sessValues;
  452. }
  453. }
  454. }
  455. }
  456. @closedir($dh);
  457. }
  458. return $arrayofSessions;
  459. }
  460. /**
  461. * Purge existing sessions
  462. *
  463. * @param int $mysessionid To avoid to try to delete my own session
  464. * @return int >0 if OK, <0 if KO
  465. */
  466. function purgeSessions($mysessionid) {
  467. global $conf;
  468. $arrayofSessions = array();
  469. $sessPath = ini_get("session.save_path") . "/";
  470. dol_syslog('admin.lib:purgeSessions mysessionid=' . $mysessionid . ' sessPath=' . $sessPath);
  471. $error = 0;
  472. $dh = @opendir(dol_osencode($sessPath));
  473. while (($file = @readdir($dh)) !== false) {
  474. if ($file != "." && $file != "..") {
  475. $fullpath = $sessPath . $file;
  476. if (!@is_dir($fullpath)) {
  477. $sessValues = file_get_contents($fullpath); // get raw session data
  478. if (preg_match('/dol_login/i', $sessValues) && // limit to dolibarr session
  479. preg_match('/dol_entity\|s:([0-9]+):"(' . $conf->entity . ')"/i', $sessValues) && // limit to current entity
  480. preg_match('/dol_company\|s:([0-9]+):"(' . $conf->global->MAIN_INFO_SOCIETE_NOM . ')"/i', $sessValues)) { // limit to company name
  481. $tmp = explode('_', $file);
  482. $idsess = $tmp[1];
  483. // We remove session if it's not ourself
  484. if ($idsess != $mysessionid) {
  485. $res = @unlink($fullpath);
  486. if (!$res)
  487. $error++;
  488. }
  489. }
  490. }
  491. }
  492. }
  493. @closedir($dh);
  494. if (!$error)
  495. return 1;
  496. else
  497. return -$error;
  498. }
  499. /**
  500. * Enable a module
  501. *
  502. * @param string $value Name of module to activate
  503. * @param int $withdeps Activate/Disable also all dependencies
  504. * @return string Error message or '';
  505. */
  506. function activateModule($value, $withdeps = 1) {
  507. global $db, $modules, $langs, $conf;
  508. // Check parameters
  509. if (empty($value))
  510. return 'ErrorBadParameter';
  511. $ret = '';
  512. $modName = $value;
  513. $modFile = $modName . ".class.php";
  514. // Loop on each directory to fill $modulesdir
  515. $modulesdir = array();
  516. foreach ($conf->file->dol_document_root as $type => $dirroot) {
  517. $modulesdir[] = $dirroot . "/core/modules/";
  518. $handle = @opendir(dol_osencode($dirroot));
  519. if (is_resource($handle)) {
  520. while (($file = readdir($handle)) !== false) {
  521. if (is_dir($dirroot . '/' . $file) && substr($file, 0, 1) <> '.' && substr($file, 0, 3) <> 'CVS' && $file != 'includes') {
  522. if (is_dir($dirroot . '/' . $file . '/core/modules/')) {
  523. $modulesdir[] = $dirroot . '/' . $file . '/core/modules/';
  524. }
  525. }
  526. }
  527. closedir($handle);
  528. }
  529. }
  530. // Loop on each directory
  531. $found = false;
  532. foreach ($modulesdir as $dir) {
  533. if (file_exists($dir . $modFile)) {
  534. $found = @include_once $dir . $modFile;
  535. if ($found)
  536. break;
  537. }
  538. }
  539. $objMod = new $modName($db);
  540. // Test if PHP version ok
  541. $verphp = versionphparray();
  542. $vermin = isset($objMod->phpmin) ? $objMod->phpmin : 0;
  543. if (is_array($vermin) && versioncompare($verphp, $vermin) < 0) {
  544. return $langs->trans("ErrorModuleRequirePHPVersion", versiontostring($vermin));
  545. }
  546. // Test if Dolibarr version ok
  547. $verdol = versiondolibarrarray();
  548. $vermin = isset($objMod->need_dolibarr_version) ? $objMod->need_dolibarr_version : 0;
  549. //print 'eee'.versioncompare($verdol,$vermin).join(',',$verdol).' - '.join(',',$vermin);exit;
  550. if (is_array($vermin) && versioncompare($verdol, $vermin) < 0) {
  551. return $langs->trans("ErrorModuleRequireSpeedealingVersion", versiontostring($vermin));
  552. }
  553. // Test if javascript requirement ok
  554. if (!empty($objMod->need_javascript_ajax) && empty($conf->use_javascript_ajax)) {
  555. return $langs->trans("ErrorModuleRequireJavascript");
  556. }
  557. $result = $objMod->init();
  558. if ($result <= 0)
  559. $ret = $objMod->error;
  560. if (!$ret && $withdeps) {
  561. if (isset($objMod->depends) && is_array($objMod->depends) && !empty($objMod->depends)) {
  562. // Activation des modules dont le module depend
  563. $num = count($objMod->depends);
  564. for ($i = 0; $i < $num; $i++) {
  565. foreach ($modulesdir as $dir) {
  566. if (file_exists($dir . $objMod->depends[$i] . ".class.php")) {
  567. activateModule($objMod->depends[$i]);
  568. }
  569. }
  570. }
  571. }
  572. if (isset($objMod->conflictwith) && is_array($objMod->conflictwith) && !empty($objMod->conflictwith)) {
  573. // Desactivation des modules qui entrent en conflit
  574. $num = count($objMod->conflictwith);
  575. for ($i = 0; $i < $num; $i++) {
  576. foreach ($modulesdir as $dir) {
  577. if (file_exists($dir . $objMod->conflictwith[$i] . ".class.php")) {
  578. unActivateModule($objMod->conflictwith[$i], 0);
  579. }
  580. }
  581. }
  582. }
  583. }
  584. return $ret;
  585. }
  586. /**
  587. * Disable a module
  588. *
  589. * @param string $value Nom du module a desactiver
  590. * @param int $requiredby 1=Desactive aussi modules dependants
  591. * @return string Error message or '';
  592. */
  593. function unActivateModule($value, $requiredby = 1) {
  594. global $db, $modules, $conf;
  595. // Check parameters
  596. if (empty($value))
  597. return 'ErrorBadParameter';
  598. $ret = '';
  599. $modName = $value;
  600. $modFile = $modName . ".class.php";
  601. // Loop on each directory to fill $modulesdir
  602. $modulesdir = array();
  603. foreach ($conf->file->dol_document_root as $type => $dirroot) {
  604. $modulesdir[] = $dirroot . "/core/modules/";
  605. $handle = @opendir(dol_osencode($dirroot));
  606. if (is_resource($handle)) {
  607. while (($file = readdir($handle)) !== false) {
  608. if (is_dir($dirroot . '/' . $file) && substr($file, 0, 1) <> '.' && substr($file, 0, 3) <> 'CVS' && $file != 'includes') {
  609. if (is_dir($dirroot . '/' . $file . '/core/modules/')) {
  610. $modulesdir[] = $dirroot . '/' . $file . '/core/modules/';
  611. }
  612. }
  613. }
  614. closedir($handle);
  615. }
  616. }
  617. // Loop on each directory
  618. $found = false;
  619. foreach ($modulesdir as $dir) {
  620. if (file_exists($dir . $modFile)) {
  621. $found = @include_once $dir . $modFile;
  622. if ($found)
  623. break;
  624. }
  625. }
  626. if ($found) {
  627. $objMod = new $modName($db);
  628. $result = $objMod->remove();
  629. } else {
  630. // TODO Cannot instantiate abstract class
  631. //$genericMod = new DolibarrModul($db);
  632. //$genericMod->name=preg_replace('/^mod/i','',$modName);
  633. //$genericMod->rights_class=strtolower(preg_replace('/^mod/i','',$modName));
  634. //$genericMod->const_name='MAIN_MODULE_'.strtoupper(preg_replace('/^mod/i','',$modName));
  635. dol_syslog("modules::unActivateModule Failed to find module file, we use generic function with name " . $modName);
  636. //$genericMod->_remove();
  637. }
  638. // Desactivation des modules qui dependent de lui
  639. if ($requiredby) {
  640. $countrb = count($objMod->requiredby);
  641. for ($i = 0; $i < $countrb; $i++) {
  642. unActivateModule($objMod->requiredby[$i]);
  643. }
  644. }
  645. return $ret;
  646. }
  647. /**
  648. * Add external modules to list of dictionnaries
  649. *
  650. * @param array &$taborder Taborder
  651. * @param array &$tabname Tabname
  652. * @param array &$tablib Tablib
  653. * @param array &$tabsql Tabsql
  654. * @param array &$tabsqlsort Tabsqlsort
  655. * @param array &$tabfield Tabfield
  656. * @param array &$tabfieldvalue Tabfieldvalue
  657. * @param array &$tabfieldinsert Tabfieldinsert
  658. * @param array &$tabrowid Tabrowid
  659. * @param array &$tabcond Tabcond
  660. * @param array &$tabhelp Tabhelp
  661. * @return int 1
  662. */
  663. function complete_dictionnary_with_modules(&$taborder, &$tabname, &$tablib, &$tabsql, &$tabsqlsort, &$tabfield, &$tabfieldvalue, &$tabfieldinsert, &$tabrowid, &$tabcond, &$tabhelp) {
  664. global $db, $modules, $conf, $langs;
  665. // Search modules
  666. $filename = array();
  667. $modules = array();
  668. $orders = array();
  669. $categ = array();
  670. $dirmod = array();
  671. $modulesdir = array();
  672. $i = 0; // is a sequencer of modules found
  673. $j = 0; // j is module number. Automatically affected if module number not defined.
  674. foreach ($conf->file->dol_document_root as $type => $dirroot) {
  675. $modulesdir[$dirroot . '/core/modules/'] = $dirroot . '/core/modules/';
  676. $handle = @opendir($dirroot);
  677. if (is_resource($handle)) {
  678. while (($file = readdir($handle)) !== false) {
  679. if (is_dir($dirroot . '/' . $file) && substr($file, 0, 1) <> '.' && substr($file, 0, 3) <> 'CVS' && $file != 'includes') {
  680. if (is_dir($dirroot . '/' . $file . '/core/modules/')) {
  681. $modulesdir[$dirroot . '/' . $file . '/core/modules/'] = $dirroot . '/' . $file . '/core/modules/';
  682. }
  683. }
  684. }
  685. closedir($handle);
  686. }
  687. }
  688. //var_dump($modulesdir);
  689. foreach ($modulesdir as $dir) {
  690. // Load modules attributes in arrays (name, numero, orders) from dir directory
  691. //print $dir."\n<br>";
  692. dol_syslog("Scan directory " . $dir . " for modules");
  693. $handle = @opendir(dol_osencode($dir));
  694. if (is_resource($handle)) {
  695. while (($file = readdir($handle)) !== false) {
  696. //print "$i ".$file."\n<br>";
  697. if (is_readable($dir . $file) && substr($file, 0, 3) == 'mod' && substr($file, dol_strlen($file) - 10) == '.class.php') {
  698. $modName = substr($file, 0, dol_strlen($file) - 10);
  699. if ($modName) {
  700. include_once $dir . $file;
  701. $objMod = new $modName($db);
  702. if ($objMod->numero > 0) {
  703. $j = $objMod->numero;
  704. } else {
  705. $j = 1000 + $i;
  706. }
  707. $modulequalified = 1;
  708. // We discard modules according to features level (PS: if module is activated we always show it)
  709. $const_name = 'MAIN_MODULE_' . strtoupper(preg_replace('/^mod/i', '', get_class($objMod)));
  710. if ($objMod->version == 'development' && $conf->global->MAIN_FEATURES_LEVEL < 2 && !$conf->global->$const_name)
  711. $modulequalified = 0;
  712. if ($objMod->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1 && !$conf->global->$const_name)
  713. $modulequalified = 0;
  714. if ($modulequalified) {
  715. // Load languages files of module
  716. if (isset($objMod->langfiles) && is_array($objMod->langfiles)) {
  717. foreach ($objMod->langfiles as $langfile) {
  718. $langs->load($langfile);
  719. }
  720. }
  721. $modules[$i] = $objMod;
  722. $filename[$i] = $modName;
  723. $orders[$i] = $objMod->family . "_" . $j; // Tri par famille puis numero module
  724. //print "x".$modName." ".$orders[$i]."\n<br>";
  725. if (isset($categ[$objMod->special]))
  726. $categ[$objMod->special]++; // Array of all different modules categories
  727. else
  728. $categ[$objMod->special] = 1;
  729. $dirmod[$i] = $dirroot;
  730. // Complete arrays
  731. //&$tabname,&$tablib,&$tabsql,&$tabsqlsort,&$tabfield,&$tabfieldvalue,&$tabfieldinsert,&$tabrowid,&$tabcond
  732. //$objMod
  733. if (!empty($objMod->dictionnaries)) {
  734. //var_dump($objMod->dictionnaries['tabname']);
  735. $taborder[] = 0;
  736. foreach ($objMod->dictionnaries['tabname'] as $val) {
  737. $taborder[] = count($tabname) + 1;
  738. $tabname[] = $val;
  739. }
  740. foreach ($objMod->dictionnaries['tablib'] as $val)
  741. $tablib[] = $val;
  742. foreach ($objMod->dictionnaries['tabsql'] as $val)
  743. $tabsql[] = $val;
  744. foreach ($objMod->dictionnaries['tabsqlsort'] as $val)
  745. $tabsqlsort[] = $val;
  746. foreach ($objMod->dictionnaries['tabfield'] as $val)
  747. $tabfield[] = $val;
  748. foreach ($objMod->dictionnaries['tabfieldvalue'] as $val)
  749. $tabfieldvalue[] = $val;
  750. foreach ($objMod->dictionnaries['tabfieldinsert'] as $val)
  751. $tabfieldinsert[] = $val;
  752. foreach ($objMod->dictionnaries['tabrowid'] as $val)
  753. $tabrowid[] = $val;
  754. foreach ($objMod->dictionnaries['tabcond'] as $val)
  755. $tabcond[] = $val;
  756. if (!empty($objMod->dictionnaries['tabhelp']))
  757. foreach ($objMod->dictionnaries['tabhelp'] as $val)
  758. $tabhelp[] = $val;
  759. //foreach($objMod->dictionnaries['tabsqlsort'] as $val) $tablib[] = $val;
  760. //$tabname = array_merge ($tabname, $objMod->dictionnaries['tabname']);
  761. //var_dump($tabcond);
  762. //exit;
  763. }
  764. $j++;
  765. $i++;
  766. }
  767. else
  768. dol_syslog("Module " . get_class($objMod) . " not qualified");
  769. }
  770. }
  771. }
  772. closedir($handle);
  773. }
  774. else {
  775. dol_syslog("htdocs/admin/modules.php: Failed to open directory " . $dir . ". See permission and open_basedir option.", LOG_WARNING);
  776. }
  777. }
  778. return 1;
  779. }
  780. /**
  781. * Show array with constants to edit
  782. *
  783. * @param array $tableau Array of constants
  784. * @return void
  785. */
  786. function form_constantes($tableau) {
  787. global $db, $bc, $langs, $conf, $_Avery_Labels;
  788. $form = new Form($db);
  789. print '<table class="noborder" width="100%">';
  790. print '<tr class="liste_titre">';
  791. print '<td>' . $langs->trans("Description") . '</td>';
  792. print '<td>' . $langs->trans("Value") . '*</td>';
  793. print '<td>&nbsp;</td>';
  794. print '<td align="center" width="80">' . $langs->trans("Action") . '</td>';
  795. print "</tr>\n";
  796. $var = true;
  797. $listofparam = array();
  798. foreach ($tableau as $const) { // Loop on each param
  799. $sql = "SELECT ";
  800. $sql.= "rowid";
  801. $sql.= ", " . $db->decrypt('name') . " as name";
  802. $sql.= ", " . $db->decrypt('value') . " as value";
  803. $sql.= ", type";
  804. $sql.= ", note";
  805. $sql.= " FROM " . MAIN_DB_PREFIX . "const";
  806. $sql.= " WHERE " . $db->decrypt('name') . " = '" . $const . "'";
  807. $sql.= " AND entity IN (0, " . $conf->entity . ")";
  808. $sql.= " ORDER BY name ASC, entity DESC";
  809. $result = $db->query($sql);
  810. dol_syslog("List params sql=" . $sql);
  811. if ($result) {
  812. $obj = $db->fetch_object($result); // Take first result of select
  813. $var = !$var;
  814. // For avoid warning in strict mode
  815. if (empty($obj)) {
  816. $obj = (object) array('rowid' => '', 'name' => '', 'value' => '', 'type' => '', 'note' => '');
  817. }
  818. print "\n" . '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST">';
  819. print "<tr " . $bc[$var] . ">";
  820. // Affiche nom constante
  821. print '<td>';
  822. print '<input type="hidden" name="token" value="' . $_SESSION['newtoken'] . '">';
  823. print '<input type="hidden" name="action" value="update">';
  824. print '<input type="hidden" name="rowid" value="' . $obj->rowid . '">';
  825. print '<input type="hidden" name="constname" value="' . $const . '">';
  826. print '<input type="hidden" name="constnote" value="' . nl2br(dol_escape_htmltag($obj->note)) . '">';
  827. print $langs->trans('Desc' . $const);
  828. if ($const == 'ADHERENT_MAILMAN_URL') {
  829. print '. ' . $langs->trans("Example") . ': <a href="#" id="exampleclick1">' . img_down() . '</a><br>';
  830. //print 'http://lists.domain.com/cgi-bin/mailman/admin/%LISTE%/members?adminpw=%MAILMAN_ADMINPW%&subscribees=%EMAIL%&send_welcome_msg_to_this_batch=1';
  831. print '<div id="example1" class="hidden">';
  832. print 'http://lists.domain.com/cgi-bin/mailman/admin/%LISTE%/members/add?subscribees_upload=%EMAIL%&amp;adminpw=%MAILMAN_ADMINPW%&amp;subscribe_or_invite=0&amp;send_welcome_msg_to_this_batch=0&amp;notification_to_list_owner=0';
  833. print '</div>';
  834. }
  835. if ($const == 'ADHERENT_MAILMAN_UNSUB_URL') {
  836. print '. ' . $langs->trans("Example") . ': <a href="#" id="exampleclick2">' . img_down() . '</a><br>';
  837. print '<div id="example2" class="hidden">';
  838. print 'http://lists.domain.com/cgi-bin/mailman/admin/%LISTE%/members/remove?unsubscribees_upload=%EMAIL%&amp;adminpw=%MAILMAN_ADMINPW%&amp;send_unsub_ack_to_this_batch=0&amp;send_unsub_notifications_to_list_owner=0';
  839. print '</div>';
  840. //print 'http://lists.domain.com/cgi-bin/mailman/admin/%LISTE%/members/remove?adminpw=%MAILMAN_ADMINPW%&unsubscribees=%EMAIL%';
  841. }
  842. print "</td>\n";
  843. if ($const == 'ADHERENT_CARD_TYPE' || $const == 'ADHERENT_ETIQUETTE_TYPE') {
  844. print '<td>';
  845. // List of possible labels (defined into $_Avery_Labels variable set into format_cards.lib.php)
  846. require_once DOL_DOCUMENT_ROOT . '/core/lib/format_cards.lib.php';
  847. $arrayoflabels = array();
  848. foreach (array_keys($_Avery_Labels) as $codecards) {
  849. $arrayoflabels[$codecards] = $_Avery_Labels[$codecards]['name'];
  850. }
  851. print $form->selectarray('constvalue', $arrayoflabels, ($obj->value ? $obj->value : 'CARD'), 1, 0, 0);
  852. print '</td><td>';
  853. print '<input type="hidden" name="consttype" value="yesno">';
  854. print '</td>';
  855. } else {
  856. print '<td>';
  857. //print 'aa'.$const;
  858. if (in_array($const, array('ADHERENT_CARD_TEXT', 'ADHERENT_CARD_TEXT_RIGHT', 'ADHERENT_ETIQUETTE_TEXT'))) {
  859. print '<textarea class="flat" name="constvalue" cols="50" rows="5" wrap="soft">' . "\n";
  860. print $obj->value;
  861. print "</textarea>\n";
  862. print '</td><td>';
  863. print '<input type="hidden" name="consttype" value="texte">';
  864. } else if (in_array($const, array('ADHERENT_AUTOREGISTER_NOTIF_MAIL', 'ADHERENT_AUTOREGISTER_MAIL', 'ADHERENT_MAIL_VALID', 'ADHERENT_MAIL_COTIS', 'ADHERENT_MAIL_RESIL'))) {
  865. require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
  866. $doleditor = new DolEditor('constvalue_' . $const, $obj->value, '', 160, 'dolibarr_notes', '', false, false, $conf->fckeditor->enabled, 5, 60);
  867. $doleditor->Create();
  868. print '</td><td>';
  869. print '<input type="hidden" name="consttype" value="texte">';
  870. } else if ($obj->type == 'yesno') {
  871. print $form->selectyesno('constvalue', $obj->value, 1);
  872. print '</td><td>';
  873. print '<input type="hidden" name="consttype" value="yesno">';
  874. } else {
  875. print '<input type="text" class="flat" size="48" name="constvalue" value="' . dol_escape_htmltag($obj->value) . '">';
  876. print '</td><td>';
  877. print '<input type="hidden" name="consttype" value="chaine">';
  878. }
  879. print '</td>';
  880. }
  881. print '<td align="center">';
  882. print '<input type="submit" class="button" value="' . $langs->trans("Update") . '" name="Button"> &nbsp;';
  883. // print '<a href="adherent.php?name='.$const.'&action=unset">'.img_delete().'</a>';
  884. print "</td>";
  885. print "</tr>\n";
  886. print "</form>\n";
  887. }
  888. }
  889. print '</table>';
  890. }
  891. /**
  892. * Add document model used by doc generator
  893. *
  894. * @param string $name Model name
  895. * @param string $type Model type
  896. * @param string $label Model label
  897. * @param string $description Model description
  898. * @return int <0 if KO, >0 if OK
  899. */
  900. function addDocumentModel($name, $type, $label = '', $description = '') {
  901. global $db, $conf;
  902. $db->begin();
  903. $sql = "INSERT INTO " . MAIN_DB_PREFIX . "document_model (nom, type, entity, libelle, description)";
  904. $sql.= " VALUES ('" . $db->escape($name) . "','" . $type . "'," . $conf->entity . ", ";
  905. $sql.= ($label ? "'" . $db->escape($label) . "'" : 'null') . ", ";
  906. $sql.= (!empty($description) ? "'" . $db->escape($description) . "'" : "null");
  907. $sql.= ")";
  908. dol_syslog("admin.lib::addDocumentModel sql=" . $sql);
  909. $resql = $db->query($sql);
  910. if ($resql) {
  911. $db->commit();
  912. return 1;
  913. } else {
  914. dol_print_error($db);
  915. $db->rollback();
  916. return -1;
  917. }
  918. }
  919. /**
  920. * Delete document model used by doc generator
  921. *
  922. * @param string $name Model name
  923. * @param string $type Model type
  924. * @return int <0 if KO, >0 if OK
  925. */
  926. function delDocumentModel($name, $type) {
  927. global $db, $conf;
  928. $db->begin();
  929. $sql = "DELETE FROM " . MAIN_DB_PREFIX . "document_model";
  930. $sql.= " WHERE nom = '" . $db->escape($name) . "'";
  931. $sql.= " AND type = '" . $type . "'";
  932. $sql.= " AND entity = " . $conf->entity;
  933. dol_syslog("admin.lib::delDocumentModel sql=" . $sql);
  934. $resql = $db->query($sql);
  935. if ($resql) {
  936. $db->commit();
  937. return 1;
  938. } else {
  939. dol_print_error($db);
  940. $db->rollback();
  941. return -1;
  942. }
  943. }
  944. /**
  945. * Return the php_info into an array
  946. *
  947. * @return array Array with PHP infos
  948. */
  949. function phpinfo_array() {
  950. ob_start();
  951. phpinfo();
  952. $info_arr = array();
  953. $info_lines = explode("\n", strip_tags(ob_get_clean(), "<tr><td><h2>")); // end of ob_start()
  954. $cat = "General";
  955. foreach ($info_lines as $line) {
  956. // new cat?
  957. preg_match("~<h2>(.*)</h2>~", $line, $title) ? $cat = $title[1] : null;
  958. if (preg_match("~<tr><td[^>]+>([^<]*)</td><td[^>]+>([^<]*)</td></tr>~", $line, $val)) {
  959. $info_arr[trim($cat)][trim($val[1])] = $val[2];
  960. } elseif (preg_match("~<tr><td[^>]+>([^<]*)</td><td[^>]+>([^<]*)</td><td[^>]+>([^<]*)</td></tr>~", $line, $val)) {
  961. $info_arr[trim($cat)][trim($val[1])] = array("local" => $val[2], "master" => $val[3]);
  962. }
  963. }
  964. return $info_arr;
  965. }
  966. ?>