PageRenderTime 60ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/htdocs/core/class/utils.class.php

http://github.com/Dolibarr/dolibarr
PHP | 1162 lines | 829 code | 151 blank | 182 comment | 261 complexity | 8a3610f1c65ed81c13f8fa486b76c16f MD5 | raw file
Possible License(s): GPL-2.0, AGPL-3.0, LGPL-2.0, CC-BY-SA-4.0, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-3.0, GPL-3.0, LGPL-2.1, MIT
  1. <?php
  2. /* Copyright (C) 2016 Laurent Destailleur <eldy@users.sourceforge.net>
  3. * Copyright (C) 2021 Regis Houssin <regis.houssin@inodbox.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. * 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 <https://www.gnu.org/licenses/>.
  17. */
  18. /**
  19. * \file htdocs/core/class/utils.class.php
  20. * \ingroup core
  21. * \brief File for Utils class
  22. */
  23. /**
  24. * Class to manage utility methods
  25. */
  26. class Utils
  27. {
  28. /**
  29. * @var DoliDB Database handler.
  30. */
  31. public $db;
  32. public $output; // Used by Cron method to return message
  33. public $result; // Used by Cron method to return data
  34. /**
  35. * Constructor
  36. *
  37. * @param DoliDB $db Database handler
  38. */
  39. public function __construct($db)
  40. {
  41. $this->db = $db;
  42. }
  43. /**
  44. * Purge files into directory of data files.
  45. * CAN BE A CRON TASK
  46. *
  47. * @param string $choices Choice of purge mode ('tempfiles', 'tempfilesold' to purge temp older than $nbsecondsold seconds, 'logfiles', or mix of this). Note 'allfiles' is possible too but very dangerous.
  48. * @param int $nbsecondsold Nb of seconds old to accept deletion of a directory if $choice is 'tempfilesold'
  49. * @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK)
  50. */
  51. public function purgeFiles($choices = 'tempfilesold+logfiles', $nbsecondsold = 86400)
  52. {
  53. global $conf, $langs, $dolibarr_main_data_root;
  54. $langs->load("admin");
  55. require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  56. if (empty($choices)) {
  57. $choices = 'tempfilesold+logfiles';
  58. }
  59. dol_syslog("Utils::purgeFiles choice=".$choices, LOG_DEBUG);
  60. $count = 0;
  61. $countdeleted = 0;
  62. $counterror = 0;
  63. $filelog = '';
  64. $choicesarray = preg_split('/[\+,]/', $choices);
  65. foreach ($choicesarray as $choice) {
  66. $filesarray = array();
  67. if ($choice == 'tempfiles' || $choice == 'tempfilesold') {
  68. // Delete temporary files
  69. if ($dolibarr_main_data_root) {
  70. $filesarray = dol_dir_list($dolibarr_main_data_root, "directories", 1, '^temp$', '', 'name', SORT_ASC, 2, 0, '', 1); // Do not follow symlinks
  71. if ($choice == 'tempfilesold') {
  72. $now = dol_now();
  73. foreach ($filesarray as $key => $val) {
  74. if ($val['date'] > ($now - ($nbsecondsold))) {
  75. unset($filesarray[$key]); // Discard temp dir not older than $nbsecondsold
  76. }
  77. }
  78. }
  79. }
  80. }
  81. if ($choice == 'allfiles') {
  82. // Delete all files (except install.lock, do not follow symbolic links)
  83. if ($dolibarr_main_data_root) {
  84. $filesarray = dol_dir_list($dolibarr_main_data_root, "all", 0, '', 'install\.lock$', 'name', SORT_ASC, 0, 0, '', 1);
  85. }
  86. }
  87. if ($choice == 'logfile' || $choice == 'logfiles') {
  88. // Define files log
  89. if ($dolibarr_main_data_root) {
  90. $filesarray = dol_dir_list($dolibarr_main_data_root, "files", 0, '.*\.log[\.0-9]*(\.gz)?$', 'install\.lock$', 'name', SORT_ASC, 0, 0, '', 1);
  91. }
  92. if (!empty($conf->syslog->enabled)) {
  93. $filelog = $conf->global->SYSLOG_FILE;
  94. $filelog = preg_replace('/DOL_DATA_ROOT/i', DOL_DATA_ROOT, $filelog);
  95. $alreadyincluded = false;
  96. foreach ($filesarray as $tmpcursor) {
  97. if ($tmpcursor['fullname'] == $filelog) {
  98. $alreadyincluded = true;
  99. }
  100. }
  101. if (!$alreadyincluded) {
  102. $filesarray[] = array('fullname'=>$filelog, 'type'=>'file');
  103. }
  104. }
  105. }
  106. if (is_array($filesarray) && count($filesarray)) {
  107. foreach ($filesarray as $key => $value) {
  108. //print "x ".$filesarray[$key]['fullname']."-".$filesarray[$key]['type']."<br>\n";
  109. if ($filesarray[$key]['type'] == 'dir') {
  110. $startcount = 0;
  111. $tmpcountdeleted = 0;
  112. $result = dol_delete_dir_recursive($filesarray[$key]['fullname'], $startcount, 1, 0, $tmpcountdeleted);
  113. if (!in_array($filesarray[$key]['fullname'], array($conf->api->dir_temp, $conf->user->dir_temp))) { // The 2 directories $conf->api->dir_temp and $conf->user->dir_temp are recreated at end, so we do not count them
  114. $count += $result;
  115. $countdeleted += $tmpcountdeleted;
  116. }
  117. } elseif ($filesarray[$key]['type'] == 'file') {
  118. // If (file that is not logfile) or (if mode is logfile)
  119. if ($filesarray[$key]['fullname'] != $filelog || $choice == 'logfile' || $choice == 'logfiles') {
  120. $result = dol_delete_file($filesarray[$key]['fullname'], 1, 1);
  121. if ($result) {
  122. $count++;
  123. $countdeleted++;
  124. } else {
  125. $counterror++;
  126. }
  127. }
  128. }
  129. }
  130. // Update cachenbofdoc
  131. if (!empty($conf->ecm->enabled) && $choice == 'allfiles') {
  132. require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmdirectory.class.php';
  133. $ecmdirstatic = new EcmDirectory($this->db);
  134. $result = $ecmdirstatic->refreshcachenboffile(1);
  135. }
  136. }
  137. }
  138. if ($count > 0) {
  139. $this->output = $langs->trans("PurgeNDirectoriesDeleted", $countdeleted);
  140. if ($count > $countdeleted) {
  141. $this->output .= '<br>'.$langs->trans("PurgeNDirectoriesFailed", ($count - $countdeleted));
  142. }
  143. } else {
  144. $this->output = $langs->trans("PurgeNothingToDelete").(in_array('tempfilesold', $choicesarray) ? ' (older than 24h for temp files)' : '');
  145. }
  146. // Recreate temp dir that are not automatically recreated by core code for performance purpose, we need them
  147. if (!empty($conf->api->enabled)) {
  148. dol_mkdir($conf->api->dir_temp);
  149. }
  150. dol_mkdir($conf->user->dir_temp);
  151. //return $count;
  152. return 0; // This function can be called by cron so must return 0 if OK
  153. }
  154. /**
  155. * Make a backup of database
  156. * CAN BE A CRON TASK
  157. *
  158. * @param string $compression 'gz' or 'bz' or 'none'
  159. * @param string $type 'mysql', 'postgresql', ...
  160. * @param int $usedefault 1=Use default backup profile (Set this to 1 when used as cron)
  161. * @param string $file 'auto' or filename to build
  162. * @param int $keeplastnfiles Keep only last n files (not used yet)
  163. * @param int $execmethod 0=Use default method (that is 1 by default), 1=Use the PHP 'exec', 2=Use the 'popen' method
  164. * @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK)
  165. */
  166. public function dumpDatabase($compression = 'none', $type = 'auto', $usedefault = 1, $file = 'auto', $keeplastnfiles = 0, $execmethod = 0)
  167. {
  168. global $db, $conf, $langs, $dolibarr_main_data_root;
  169. global $dolibarr_main_db_name, $dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_port, $dolibarr_main_db_pass;
  170. global $dolibarr_main_db_character_set;
  171. $langs->load("admin");
  172. dol_syslog("Utils::dumpDatabase type=".$type." compression=".$compression." file=".$file, LOG_DEBUG);
  173. require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  174. // Check compression parameter
  175. if (!in_array($compression, array('none', 'gz', 'bz', 'zip', 'zstd'))) {
  176. $langs->load("errors");
  177. $this->error = $langs->transnoentitiesnoconv("ErrorBadValueForParameter", $compression, "Compression");
  178. return -1;
  179. }
  180. // Check type parameter
  181. if ($type == 'auto') {
  182. $type = $this->db->type;
  183. }
  184. if (!in_array($type, array('postgresql', 'pgsql', 'mysql', 'mysqli', 'mysqlnobin'))) {
  185. $langs->load("errors");
  186. $this->error = $langs->transnoentitiesnoconv("ErrorBadValueForParameter", $type, "Basetype");
  187. return -1;
  188. }
  189. // Check file parameter
  190. if ($file == 'auto') {
  191. $prefix = 'dump';
  192. $ext = 'sql';
  193. if (in_array($type, array('mysql', 'mysqli'))) {
  194. $prefix = 'mysqldump';
  195. $ext = 'sql';
  196. }
  197. //if ($label == 'PostgreSQL') { $prefix='pg_dump'; $ext='dump'; }
  198. if (in_array($type, array('pgsql'))) {
  199. $prefix = 'pg_dump';
  200. $ext = 'sql';
  201. }
  202. $file = $prefix.'_'.$dolibarr_main_db_name.'_'.dol_sanitizeFileName(DOL_VERSION).'_'.strftime("%Y%m%d%H%M").'.'.$ext;
  203. }
  204. $outputdir = $conf->admin->dir_output.'/backup';
  205. $result = dol_mkdir($outputdir);
  206. $errormsg = '';
  207. // MYSQL
  208. if ($type == 'mysql' || $type == 'mysqli') {
  209. $cmddump = $conf->global->SYSTEMTOOLS_MYSQLDUMP;
  210. $outputfile = $outputdir.'/'.$file;
  211. // for compression format, we add extension
  212. $compression = $compression ? $compression : 'none';
  213. if ($compression == 'gz') {
  214. $outputfile .= '.gz';
  215. } elseif ($compression == 'bz') {
  216. $outputfile .= '.bz2';
  217. } elseif ($compression == 'zstd') {
  218. $outputfile .= '.zst';
  219. }
  220. $outputerror = $outputfile.'.err';
  221. dol_mkdir($conf->admin->dir_output.'/backup');
  222. // Parameteres execution
  223. $command = $cmddump;
  224. $command = preg_replace('/(\$|%)/', '', $command); // We removed chars that can be used to inject vars that contains space inside path of command without seeing there is a space to bypass the escapeshellarg.
  225. if (preg_match("/\s/", $command)) {
  226. $command = escapeshellarg($command); // If there is spaces, we add quotes on command to be sure $command is only a program and not a program+parameters
  227. }
  228. //$param=escapeshellarg($dolibarr_main_db_name)." -h ".escapeshellarg($dolibarr_main_db_host)." -u ".escapeshellarg($dolibarr_main_db_user)." -p".escapeshellarg($dolibarr_main_db_pass);
  229. $param = $dolibarr_main_db_name." -h ".$dolibarr_main_db_host;
  230. $param .= " -u ".$dolibarr_main_db_user;
  231. if (!empty($dolibarr_main_db_port)) {
  232. $param .= " -P ".$dolibarr_main_db_port;
  233. }
  234. if (!GETPOST("use_transaction", "alpha")) {
  235. $param .= " -l --single-transaction";
  236. }
  237. if (GETPOST("disable_fk", "alpha") || $usedefault) {
  238. $param .= " -K";
  239. }
  240. if (GETPOST("sql_compat", "alpha") && GETPOST("sql_compat", "alpha") != 'NONE') {
  241. $param .= " --compatible=".escapeshellarg(GETPOST("sql_compat", "alpha"));
  242. }
  243. if (GETPOST("drop_database", "alpha")) {
  244. $param .= " --add-drop-database";
  245. }
  246. if (GETPOST("use_mysql_quick_param", "alpha")) {
  247. $param .= " --quick";
  248. }
  249. if (GETPOST("sql_structure", "alpha") || $usedefault) {
  250. if (GETPOST("drop", "alpha") || $usedefault) {
  251. $param .= " --add-drop-table=TRUE";
  252. } else {
  253. $param .= " --add-drop-table=FALSE";
  254. }
  255. } else {
  256. $param .= " -t";
  257. }
  258. if (GETPOST("disable-add-locks", "alpha")) {
  259. $param .= " --add-locks=FALSE";
  260. }
  261. if (GETPOST("sql_data", "alpha") || $usedefault) {
  262. $param .= " --tables";
  263. if (GETPOST("showcolumns", "alpha") || $usedefault) {
  264. $param .= " -c";
  265. }
  266. if (GETPOST("extended_ins", "alpha") || $usedefault) {
  267. $param .= " -e";
  268. } else {
  269. $param .= " --skip-extended-insert";
  270. }
  271. if (GETPOST("delayed", "alpha")) {
  272. $param .= " --delayed-insert";
  273. }
  274. if (GETPOST("sql_ignore", "alpha")) {
  275. $param .= " --insert-ignore";
  276. }
  277. if (GETPOST("hexforbinary", "alpha") || $usedefault) {
  278. $param .= " --hex-blob";
  279. }
  280. } else {
  281. $param .= " -d"; // No row information (no data)
  282. }
  283. if ($dolibarr_main_db_character_set == 'utf8mb4') {
  284. // We save output into utf8mb4 charset
  285. $param .= " --default-character-set=utf8mb4 --no-tablespaces";
  286. } else {
  287. $param .= " --default-character-set=utf8 --no-tablespaces"; // We always save output into utf8 charset
  288. }
  289. $paramcrypted = $param;
  290. $paramclear = $param;
  291. if (!empty($dolibarr_main_db_pass)) {
  292. $paramcrypted .= ' -p"'.preg_replace('/./i', '*', $dolibarr_main_db_pass).'"';
  293. $paramclear .= ' -p"'.str_replace(array('"', '`', '$'), array('\"', '\`', '\$'), $dolibarr_main_db_pass).'"';
  294. }
  295. $handle = '';
  296. // Start call method to execute dump
  297. $fullcommandcrypted = $command." ".$paramcrypted." 2>&1";
  298. $fullcommandclear = $command." ".$paramclear." 2>&1";
  299. if ($compression == 'none') {
  300. $handle = fopen($outputfile, 'w');
  301. } elseif ($compression == 'gz') {
  302. $handle = gzopen($outputfile, 'w');
  303. } elseif ($compression == 'bz') {
  304. $handle = bzopen($outputfile, 'w');
  305. } elseif ($compression == 'zstd') {
  306. $handle = fopen($outputfile, 'w');
  307. }
  308. $ok = 0;
  309. if ($handle) {
  310. if (!empty($conf->global->MAIN_EXEC_USE_POPEN)) {
  311. $execmethod = $conf->global->MAIN_EXEC_USE_POPEN;
  312. }
  313. if (empty($execmethod)) {
  314. $execmethod = 1;
  315. }
  316. dol_syslog("Utils::dumpDatabase execmethod=".$execmethod." command:".$fullcommandcrypted, LOG_INFO);
  317. // TODO Replace with executeCLI function
  318. if ($execmethod == 1) {
  319. $output_arr = array();
  320. $retval = null;
  321. exec($fullcommandclear, $output_arr, $retval);
  322. if ($retval != 0) {
  323. $langs->load("errors");
  324. dol_syslog("Datadump retval after exec=".$retval, LOG_ERR);
  325. $errormsg = 'Error '.$retval;
  326. $ok = 0;
  327. } else {
  328. $i = 0;
  329. if (!empty($output_arr)) {
  330. foreach ($output_arr as $key => $read) {
  331. $i++; // output line number
  332. if ($i == 1 && preg_match('/Warning.*Using a password/i', $read)) {
  333. continue;
  334. }
  335. fwrite($handle, $read.($execmethod == 2 ? '' : "\n"));
  336. if (preg_match('/'.preg_quote('-- Dump completed').'/i', $read)) {
  337. $ok = 1;
  338. } elseif (preg_match('/'.preg_quote('SET SQL_NOTES=@OLD_SQL_NOTES').'/i', $read)) {
  339. $ok = 1;
  340. }
  341. }
  342. }
  343. }
  344. }
  345. if ($execmethod == 2) { // With this method, there is no way to get the return code, only output
  346. $handlein = popen($fullcommandclear, 'r');
  347. $i = 0;
  348. while (!feof($handlein)) {
  349. $i++; // output line number
  350. $read = fgets($handlein);
  351. // Exclude warning line we don't want
  352. if ($i == 1 && preg_match('/Warning.*Using a password/i', $read)) {
  353. continue;
  354. }
  355. fwrite($handle, $read);
  356. if (preg_match('/'.preg_quote('-- Dump completed').'/i', $read)) {
  357. $ok = 1;
  358. } elseif (preg_match('/'.preg_quote('SET SQL_NOTES=@OLD_SQL_NOTES').'/i', $read)) {
  359. $ok = 1;
  360. }
  361. }
  362. pclose($handlein);
  363. }
  364. if ($compression == 'none') {
  365. fclose($handle);
  366. } elseif ($compression == 'gz') {
  367. gzclose($handle);
  368. } elseif ($compression == 'bz') {
  369. bzclose($handle);
  370. } elseif ($compression == 'zstd') {
  371. fclose($handle);
  372. }
  373. if (!empty($conf->global->MAIN_UMASK)) {
  374. @chmod($outputfile, octdec($conf->global->MAIN_UMASK));
  375. }
  376. } else {
  377. $langs->load("errors");
  378. dol_syslog("Failed to open file ".$outputfile, LOG_ERR);
  379. $errormsg = $langs->trans("ErrorFailedToWriteInDir");
  380. }
  381. // Get errorstring
  382. if ($compression == 'none') {
  383. $handle = fopen($outputfile, 'r');
  384. } elseif ($compression == 'gz') {
  385. $handle = gzopen($outputfile, 'r');
  386. } elseif ($compression == 'bz') {
  387. $handle = bzopen($outputfile, 'r');
  388. } elseif ($compression == 'zstd') {
  389. $handle = fopen($outputfile, 'r');
  390. }
  391. if ($handle) {
  392. // Get 2048 first chars of error message.
  393. $errormsg = fgets($handle, 2048);
  394. //$ok=0;$errormsg=''; To force error
  395. // Close file
  396. if ($compression == 'none') {
  397. fclose($handle);
  398. } elseif ($compression == 'gz') {
  399. gzclose($handle);
  400. } elseif ($compression == 'bz') {
  401. bzclose($handle);
  402. } elseif ($compression == 'zstd') {
  403. fclose($handle);
  404. }
  405. if ($ok && preg_match('/^-- (MySql|MariaDB)/i', $errormsg)) { // No error
  406. $errormsg = '';
  407. } else {
  408. // Renommer fichier sortie en fichier erreur
  409. //print "$outputfile -> $outputerror";
  410. @dol_delete_file($outputerror, 1, 0, 0, null, false, 0);
  411. @rename($outputfile, $outputerror);
  412. // Si safe_mode on et command hors du parametre exec, on a un fichier out vide donc errormsg vide
  413. if (!$errormsg) {
  414. $langs->load("errors");
  415. $errormsg = $langs->trans("ErrorFailedToRunExternalCommand");
  416. }
  417. }
  418. }
  419. // Fin execution commande
  420. $this->output = $errormsg;
  421. $this->error = $errormsg;
  422. $this->result = array("commandbackuplastdone" => $command." ".$paramcrypted, "commandbackuptorun" => "");
  423. //if (empty($this->output)) $this->output=$this->result['commandbackuplastdone'];
  424. }
  425. // MYSQL NO BIN
  426. if ($type == 'mysqlnobin') {
  427. $outputfile = $outputdir.'/'.$file;
  428. $outputfiletemp = $outputfile.'-TMP.sql';
  429. // for compression format, we add extension
  430. $compression = $compression ? $compression : 'none';
  431. if ($compression == 'gz') {
  432. $outputfile .= '.gz';
  433. }
  434. if ($compression == 'bz') {
  435. $outputfile .= '.bz2';
  436. }
  437. $outputerror = $outputfile.'.err';
  438. dol_mkdir($conf->admin->dir_output.'/backup');
  439. if ($compression == 'gz' or $compression == 'bz') {
  440. $this->backupTables($outputfiletemp);
  441. dol_compress_file($outputfiletemp, $outputfile, $compression);
  442. unlink($outputfiletemp);
  443. } else {
  444. $this->backupTables($outputfile);
  445. }
  446. $this->output = "";
  447. $this->result = array("commandbackuplastdone" => "", "commandbackuptorun" => "");
  448. }
  449. // POSTGRESQL
  450. if ($type == 'postgresql' || $type == 'pgsql') {
  451. $cmddump = $conf->global->SYSTEMTOOLS_POSTGRESQLDUMP;
  452. $outputfile = $outputdir.'/'.$file;
  453. // for compression format, we add extension
  454. $compression = $compression ? $compression : 'none';
  455. if ($compression == 'gz') {
  456. $outputfile .= '.gz';
  457. }
  458. if ($compression == 'bz') {
  459. $outputfile .= '.bz2';
  460. }
  461. $outputerror = $outputfile.'.err';
  462. dol_mkdir($conf->admin->dir_output.'/backup');
  463. // Parameteres execution
  464. $command = $cmddump;
  465. $command = preg_replace('/(\$|%)/', '', $command); // We removed chars that can be used to inject vars that contains space inside path of command without seeing there is a space to bypass the escapeshellarg.
  466. if (preg_match("/\s/", $command)) {
  467. $command = escapeshellarg($command); // If there is spaces, we add quotes on command to be sure $command is only a program and not a program+parameters
  468. }
  469. //$param=escapeshellarg($dolibarr_main_db_name)." -h ".escapeshellarg($dolibarr_main_db_host)." -u ".escapeshellarg($dolibarr_main_db_user)." -p".escapeshellarg($dolibarr_main_db_pass);
  470. //$param="-F c";
  471. $param = "-F p";
  472. $param .= " --no-tablespaces --inserts -h ".$dolibarr_main_db_host;
  473. $param .= " -U ".$dolibarr_main_db_user;
  474. if (!empty($dolibarr_main_db_port)) {
  475. $param .= " -p ".$dolibarr_main_db_port;
  476. }
  477. if (GETPOST("sql_compat") && GETPOST("sql_compat") == 'ANSI') {
  478. $param .= " --disable-dollar-quoting";
  479. }
  480. if (GETPOST("drop_database")) {
  481. $param .= " -c -C";
  482. }
  483. if (GETPOST("sql_structure")) {
  484. if (GETPOST("drop")) {
  485. $param .= " --add-drop-table";
  486. }
  487. if (!GETPOST("sql_data")) {
  488. $param .= " -s";
  489. }
  490. }
  491. if (GETPOST("sql_data")) {
  492. if (!GETPOST("sql_structure")) {
  493. $param .= " -a";
  494. }
  495. if (GETPOST("showcolumns")) {
  496. $param .= " -c";
  497. }
  498. }
  499. $param .= ' -f "'.$outputfile.'"';
  500. //if ($compression == 'none')
  501. if ($compression == 'gz') {
  502. $param .= ' -Z 9';
  503. }
  504. //if ($compression == 'bz')
  505. $paramcrypted = $param;
  506. $paramclear = $param;
  507. /*if (! empty($dolibarr_main_db_pass))
  508. {
  509. $paramcrypted.=" -W".preg_replace('/./i','*',$dolibarr_main_db_pass);
  510. $paramclear.=" -W".$dolibarr_main_db_pass;
  511. }*/
  512. $paramcrypted .= " -w ".$dolibarr_main_db_name;
  513. $paramclear .= " -w ".$dolibarr_main_db_name;
  514. $this->output = "";
  515. $this->result = array("commandbackuplastdone" => "", "commandbackuptorun" => $command." ".$paramcrypted);
  516. }
  517. // Clean old files
  518. if (!$errormsg && $keeplastnfiles > 0) {
  519. $tmpfiles = dol_dir_list($conf->admin->dir_output.'/backup', 'files', 0, '', '(\.err|\.old|\.sav)$', 'date', SORT_DESC);
  520. $i = 0;
  521. foreach ($tmpfiles as $key => $val) {
  522. $i++;
  523. if ($i <= $keeplastnfiles) {
  524. continue;
  525. }
  526. dol_delete_file($val['fullname'], 0, 0, 0, null, false, 0);
  527. }
  528. }
  529. return ($errormsg ? -1 : 0);
  530. }
  531. /**
  532. * Execute a CLI command.
  533. *
  534. * @param string $command Command line to execute.
  535. * Warning: The command line is sanitize so can't contains any redirection char '>'. Use param $redirectionfile if you need it.
  536. * @param string $outputfile A path for an output file (used only when method is 2). For example: $conf->admin->dir_temp.'/out.tmp';
  537. * @param int $execmethod 0=Use default method (that is 1 by default), 1=Use the PHP 'exec', 2=Use the 'popen' method
  538. * @param string $redirectionfile If defined, a redirection of output to this files is added.
  539. * @param int $noescapecommand 1=Do not escape command. Warning: Using this parameter need you alreay sanitized the command. if not, it will lead to security vulnerability.
  540. * This parameter is provided for backward compatibility with external modules. Always use 0 in core.
  541. * @return array array('result'=>...,'output'=>...,'error'=>...). result = 0 means OK.
  542. */
  543. public function executeCLI($command, $outputfile, $execmethod = 0, $redirectionfile = null, $noescapecommand = 0)
  544. {
  545. global $conf, $langs;
  546. $result = 0;
  547. $output = '';
  548. $error = '';
  549. if (empty($noescapecommand)) {
  550. $command = escapeshellcmd($command);
  551. }
  552. if ($redirectionfile) {
  553. $command .= " > ".dol_sanitizePathName($redirectionfile);
  554. }
  555. $command .= " 2>&1";
  556. if (!empty($conf->global->MAIN_EXEC_USE_POPEN)) {
  557. $execmethod = $conf->global->MAIN_EXEC_USE_POPEN;
  558. }
  559. if (empty($execmethod)) {
  560. $execmethod = 1;
  561. }
  562. //$execmethod=1;
  563. dol_syslog("Utils::executeCLI execmethod=".$execmethod." system:".$command, LOG_DEBUG);
  564. $output_arr = array();
  565. if ($execmethod == 1) {
  566. $retval = null;
  567. exec($command, $output_arr, $retval);
  568. $result = $retval;
  569. if ($retval != 0) {
  570. $langs->load("errors");
  571. dol_syslog("Utils::executeCLI retval after exec=".$retval, LOG_ERR);
  572. $error = 'Error '.$retval;
  573. }
  574. }
  575. if ($execmethod == 2) { // With this method, there is no way to get the return code, only output
  576. $handle = fopen($outputfile, 'w+b');
  577. if ($handle) {
  578. dol_syslog("Utils::executeCLI run command ".$command);
  579. $handlein = popen($command, 'r');
  580. while (!feof($handlein)) {
  581. $read = fgets($handlein);
  582. fwrite($handle, $read);
  583. $output_arr[] = $read;
  584. }
  585. pclose($handlein);
  586. fclose($handle);
  587. }
  588. if (!empty($conf->global->MAIN_UMASK)) {
  589. @chmod($outputfile, octdec($conf->global->MAIN_UMASK));
  590. }
  591. }
  592. // Update with result
  593. if (is_array($output_arr) && count($output_arr) > 0) {
  594. foreach ($output_arr as $val) {
  595. $output .= $val.($execmethod == 2 ? '' : "\n");
  596. }
  597. }
  598. dol_syslog("Utils::executeCLI result=".$result." output=".$output." error=".$error, LOG_DEBUG);
  599. return array('result'=>$result, 'output'=>$output, 'error'=>$error);
  600. }
  601. /**
  602. * Generate documentation of a Module
  603. *
  604. * @param string $module Module name
  605. * @return int <0 if KO, >0 if OK
  606. */
  607. public function generateDoc($module)
  608. {
  609. global $conf, $langs, $user, $mysoc;
  610. global $dirins;
  611. $error = 0;
  612. $modulelowercase = strtolower($module);
  613. $now = dol_now();
  614. // Dir for module
  615. $dir = $dirins.'/'.$modulelowercase;
  616. // Zip file to build
  617. $FILENAMEDOC = '';
  618. // Load module
  619. dol_include_once($modulelowercase.'/core/modules/mod'.$module.'.class.php');
  620. $class = 'mod'.$module;
  621. if (class_exists($class)) {
  622. try {
  623. $moduleobj = new $class($this->db);
  624. } catch (Exception $e) {
  625. $error++;
  626. dol_print_error($e->getMessage());
  627. }
  628. } else {
  629. $error++;
  630. $langs->load("errors");
  631. dol_print_error($langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module));
  632. exit;
  633. }
  634. $arrayversion = explode('.', $moduleobj->version, 3);
  635. if (count($arrayversion)) {
  636. $FILENAMEASCII = strtolower($module).'.asciidoc';
  637. $FILENAMEDOC = strtolower($module).'.html';
  638. $FILENAMEDOCPDF = strtolower($module).'.pdf';
  639. $dirofmodule = dol_buildpath(strtolower($module), 0);
  640. $dirofmoduledoc = dol_buildpath(strtolower($module), 0).'/doc';
  641. $dirofmoduletmp = dol_buildpath(strtolower($module), 0).'/doc/temp';
  642. $outputfiledoc = $dirofmoduledoc.'/'.$FILENAMEDOC;
  643. if ($dirofmoduledoc) {
  644. if (!dol_is_dir($dirofmoduledoc)) {
  645. dol_mkdir($dirofmoduledoc);
  646. }
  647. if (!dol_is_dir($dirofmoduletmp)) {
  648. dol_mkdir($dirofmoduletmp);
  649. }
  650. if (!is_writable($dirofmoduletmp)) {
  651. $this->error = 'Dir '.$dirofmoduletmp.' does not exists or is not writable';
  652. return -1;
  653. }
  654. if (empty($conf->global->MODULEBUILDER_ASCIIDOCTOR) && empty($conf->global->MODULEBUILDER_ASCIIDOCTORPDF)) {
  655. $this->error = 'Setup of module ModuleBuilder not complete';
  656. return -1;
  657. }
  658. // Copy some files into temp directory, so instruction include::ChangeLog.md[] will works inside the asciidoc file.
  659. dol_copy($dirofmodule.'/README.md', $dirofmoduletmp.'/README.md', 0, 1);
  660. dol_copy($dirofmodule.'/ChangeLog.md', $dirofmoduletmp.'/ChangeLog.md', 0, 1);
  661. // Replace into README.md and ChangeLog.md (in case they are included into documentation with tag __README__ or __CHANGELOG__)
  662. $arrayreplacement = array();
  663. $arrayreplacement['/^#\s.*/m'] = ''; // Remove first level of title into .md files
  664. $arrayreplacement['/^#/m'] = '##'; // Add on # to increase level
  665. dolReplaceInFile($dirofmoduletmp.'/README.md', $arrayreplacement, '', 0, 0, 1);
  666. dolReplaceInFile($dirofmoduletmp.'/ChangeLog.md', $arrayreplacement, '', 0, 0, 1);
  667. $destfile = $dirofmoduletmp.'/'.$FILENAMEASCII;
  668. $fhandle = fopen($destfile, 'w+');
  669. if ($fhandle) {
  670. $specs = dol_dir_list(dol_buildpath(strtolower($module).'/doc', 0), 'files', 1, '(\.md|\.asciidoc)$', array('\/temp\/'));
  671. $i = 0;
  672. foreach ($specs as $spec) {
  673. if (preg_match('/notindoc/', $spec['relativename'])) {
  674. continue; // Discard file
  675. }
  676. if (preg_match('/example/', $spec['relativename'])) {
  677. continue; // Discard file
  678. }
  679. if (preg_match('/disabled/', $spec['relativename'])) {
  680. continue; // Discard file
  681. }
  682. $pathtofile = strtolower($module).'/doc/'.$spec['relativename'];
  683. $format = 'asciidoc';
  684. if (preg_match('/\.md$/i', $spec['name'])) {
  685. $format = 'markdown';
  686. }
  687. $filecursor = @file_get_contents($spec['fullname']);
  688. if ($filecursor) {
  689. fwrite($fhandle, ($i ? "\n<<<\n\n" : "").$filecursor."\n");
  690. } else {
  691. $this->error = 'Failed to concat content of file '.$spec['fullname'];
  692. return -1;
  693. }
  694. $i++;
  695. }
  696. fclose($fhandle);
  697. $contentreadme = file_get_contents($dirofmoduletmp.'/README.md');
  698. $contentchangelog = file_get_contents($dirofmoduletmp.'/ChangeLog.md');
  699. include DOL_DOCUMENT_ROOT.'/core/lib/parsemd.lib.php';
  700. //var_dump($phpfileval['fullname']);
  701. $arrayreplacement = array(
  702. 'mymodule'=>strtolower($module),
  703. 'MyModule'=>$module,
  704. 'MYMODULE'=>strtoupper($module),
  705. 'My module'=>$module,
  706. 'my module'=>$module,
  707. 'Mon module'=>$module,
  708. 'mon module'=>$module,
  709. 'htdocs/modulebuilder/template'=>strtolower($module),
  710. '__MYCOMPANY_NAME__'=>$mysoc->name,
  711. '__KEYWORDS__'=>$module,
  712. '__USER_FULLNAME__'=>$user->getFullName($langs),
  713. '__USER_EMAIL__'=>$user->email,
  714. '__YYYY-MM-DD__'=>dol_print_date($now, 'dayrfc'),
  715. '---Put here your own copyright and developer email---'=>dol_print_date($now, 'dayrfc').' '.$user->getFullName($langs).($user->email ? ' <'.$user->email.'>' : ''),
  716. '__DATA_SPECIFICATION__'=>'Not yet available',
  717. '__README__'=>dolMd2Asciidoc($contentreadme),
  718. '__CHANGELOG__'=>dolMd2Asciidoc($contentchangelog),
  719. );
  720. dolReplaceInFile($destfile, $arrayreplacement);
  721. }
  722. // Launch doc generation
  723. $currentdir = getcwd();
  724. chdir($dirofmodule);
  725. require_once DOL_DOCUMENT_ROOT.'/core/class/utils.class.php';
  726. $utils = new Utils($this->db);
  727. // Build HTML doc
  728. $command = $conf->global->MODULEBUILDER_ASCIIDOCTOR.' '.$destfile.' -n -o '.$dirofmoduledoc.'/'.$FILENAMEDOC;
  729. $outfile = $dirofmoduletmp.'/out.tmp';
  730. $resarray = $utils->executeCLI($command, $outfile);
  731. if ($resarray['result'] != '0') {
  732. $this->error = $resarray['error'].' '.$resarray['output'];
  733. }
  734. $result = ($resarray['result'] == 0) ? 1 : 0;
  735. // Build PDF doc
  736. $command = $conf->global->MODULEBUILDER_ASCIIDOCTORPDF.' '.$destfile.' -n -o '.$dirofmoduledoc.'/'.$FILENAMEDOCPDF;
  737. $outfile = $dirofmoduletmp.'/outpdf.tmp';
  738. $resarray = $utils->executeCLI($command, $outfile);
  739. if ($resarray['result'] != '0') {
  740. $this->error = $resarray['error'].' '.$resarray['output'];
  741. }
  742. $result = ($resarray['result'] == 0) ? 1 : 0;
  743. chdir($currentdir);
  744. } else {
  745. $result = 0;
  746. }
  747. if ($result > 0) {
  748. return 1;
  749. } else {
  750. $error++;
  751. $langs->load("errors");
  752. $this->error = $langs->trans("ErrorFailToGenerateFile", $outputfiledoc);
  753. }
  754. } else {
  755. $error++;
  756. $langs->load("errors");
  757. $this->error = $langs->trans("ErrorCheckVersionIsDefined");
  758. }
  759. return -1;
  760. }
  761. /**
  762. * This saves syslog files and compresses older ones.
  763. * Nb of archive to keep is defined into $conf->global->SYSLOG_FILE_SAVES
  764. * CAN BE A CRON TASK
  765. *
  766. * @return int 0 if OK, < 0 if KO
  767. */
  768. public function compressSyslogs()
  769. {
  770. global $conf;
  771. if (empty($conf->loghandlers['mod_syslog_file'])) { // File Syslog disabled
  772. return 0;
  773. }
  774. if (!function_exists('gzopen')) {
  775. $this->error = 'Support for gzopen not available in this PHP';
  776. return -1;
  777. }
  778. dol_include_once('/core/lib/files.lib.php');
  779. $nbSaves = empty($conf->global->SYSLOG_FILE_SAVES) ? 10 : intval($conf->global->SYSLOG_FILE_SAVES);
  780. if (empty($conf->global->SYSLOG_FILE)) {
  781. $mainlogdir = DOL_DATA_ROOT;
  782. $mainlog = 'dolibarr.log';
  783. } else {
  784. $mainlogfull = str_replace('DOL_DATA_ROOT', DOL_DATA_ROOT, $conf->global->SYSLOG_FILE);
  785. $mainlogdir = dirname($mainlogfull);
  786. $mainlog = basename($mainlogfull);
  787. }
  788. $tabfiles = dol_dir_list(DOL_DATA_ROOT, 'files', 0, '^(dolibarr_.+|odt2pdf)\.log$'); // Also handle other log files like dolibarr_install.log
  789. $tabfiles[] = array('name' => $mainlog, 'path' => $mainlogdir);
  790. foreach ($tabfiles as $file) {
  791. $logname = $file['name'];
  792. $logpath = $file['path'];
  793. if (dol_is_file($logpath.'/'.$logname) && dol_filesize($logpath.'/'.$logname) > 0) { // If log file exists and is not empty
  794. // Handle already compressed files to rename them and add +1
  795. $filter = '^'.preg_quote($logname, '/').'\.([0-9]+)\.gz$';
  796. $gzfilestmp = dol_dir_list($logpath, 'files', 0, $filter);
  797. $gzfiles = array();
  798. foreach ($gzfilestmp as $gzfile) {
  799. $tabmatches = array();
  800. preg_match('/'.$filter.'/i', $gzfile['name'], $tabmatches);
  801. $numsave = intval($tabmatches[1]);
  802. $gzfiles[$numsave] = $gzfile;
  803. }
  804. krsort($gzfiles, SORT_NUMERIC);
  805. foreach ($gzfiles as $numsave => $dummy) {
  806. if (dol_is_file($logpath.'/'.$logname.'.'.($numsave + 1).'.gz')) {
  807. return -2;
  808. }
  809. if ($numsave >= $nbSaves) {
  810. dol_delete_file($logpath.'/'.$logname.'.'.$numsave.'.gz', 0, 0, 0, null, false, 0);
  811. } else {
  812. dol_move($logpath.'/'.$logname.'.'.$numsave.'.gz', $logpath.'/'.$logname.'.'.($numsave + 1).'.gz', 0, 1, 0, 0);
  813. }
  814. }
  815. // Compress current file and recreate it
  816. if ($nbSaves > 0) { // If $nbSaves is 1, we keep 1 archive .gz file, If 2, we keep 2 .gz files
  817. $gzfilehandle = gzopen($logpath.'/'.$logname.'.1.gz', 'wb9');
  818. if (empty($gzfilehandle)) {
  819. $this->error = 'Failted to open file '.$logpath.'/'.$logname.'.1.gz';
  820. return -3;
  821. }
  822. $sourcehandle = fopen($logpath.'/'.$logname, 'r');
  823. if (empty($sourcehandle)) {
  824. $this->error = 'Failed to open file '.$logpath.'/'.$logname;
  825. return -4;
  826. }
  827. while (!feof($sourcehandle)) {
  828. gzwrite($gzfilehandle, fread($sourcehandle, 512 * 1024)); // Read 512 kB at a time
  829. }
  830. fclose($sourcehandle);
  831. gzclose($gzfilehandle);
  832. @chmod($logpath.'/'.$logname.'.1.gz', octdec(empty($conf->global->MAIN_UMASK) ? '0664' : $conf->global->MAIN_UMASK));
  833. }
  834. dol_delete_file($logpath.'/'.$logname, 0, 0, 0, null, false, 0);
  835. // Create empty file
  836. $newlog = fopen($logpath.'/'.$logname, 'a+');
  837. fclose($newlog);
  838. //var_dump($logpath.'/'.$logname." - ".octdec(empty($conf->global->MAIN_UMASK)?'0664':$conf->global->MAIN_UMASK));
  839. @chmod($logpath.'/'.$logname, octdec(empty($conf->global->MAIN_UMASK) ? '0664' : $conf->global->MAIN_UMASK));
  840. }
  841. }
  842. $this->output = 'Archive log files (keeping last SYSLOG_FILE_SAVES='.$nbSaves.' files) done.';
  843. return 0;
  844. }
  845. /** Backup the db OR just a table without mysqldump binary, with PHP only (does not require any exec permission)
  846. * Author: David Walsh (http://davidwalsh.name/backup-mysql-database-php)
  847. * Updated and enhanced by Stephen Larroque (lrq3000) and by the many commentators from the blog
  848. * Note about foreign keys constraints: for Dolibarr, since there are a lot of constraints and when imported the tables will be inserted in the dumped order, not in constraints order, then we ABSOLUTELY need to use SET FOREIGN_KEY_CHECKS=0; when importing the sql dump.
  849. * Note2: db2SQL by Howard Yeend can be an alternative, by using SHOW FIELDS FROM and SHOW KEYS FROM we could generate a more precise dump (eg: by getting the type of the field and then precisely outputting the right formatting - in quotes, numeric or null - instead of trying to guess like we are doing now).
  850. *
  851. * @param string $outputfile Output file name
  852. * @param string $tables Table name or '*' for all
  853. * @return int <0 if KO, >0 if OK
  854. */
  855. public function backupTables($outputfile, $tables = '*')
  856. {
  857. global $db, $langs;
  858. global $errormsg;
  859. // Set to UTF-8
  860. if (is_a($db, 'DoliDBMysqli')) {
  861. /** @var DoliDBMysqli $db */
  862. $db->db->set_charset('utf8');
  863. } else {
  864. /** @var DoliDB $db */
  865. $db->query('SET NAMES utf8');
  866. $db->query('SET CHARACTER SET utf8');
  867. }
  868. //get all of the tables
  869. if ($tables == '*') {
  870. $tables = array();
  871. $result = $db->query('SHOW FULL TABLES WHERE Table_type = \'BASE TABLE\'');
  872. while ($row = $db->fetch_row($result)) {
  873. $tables[] = $row[0];
  874. }
  875. } else {
  876. $tables = is_array($tables) ? $tables : explode(',', $tables);
  877. }
  878. //cycle through
  879. $handle = fopen($outputfile, 'w+');
  880. if (fwrite($handle, '') === false) {
  881. $langs->load("errors");
  882. dol_syslog("Failed to open file ".$outputfile, LOG_ERR);
  883. $errormsg = $langs->trans("ErrorFailedToWriteInDir");
  884. return -1;
  885. }
  886. // Print headers and global mysql config vars
  887. $sqlhead = '';
  888. $sqlhead .= "-- ".$db::LABEL." dump via php with Dolibarr ".DOL_VERSION."
  889. --
  890. -- Host: ".$db->db->host_info." Database: ".$db->database_name."
  891. -- ------------------------------------------------------
  892. -- Server version ".$db->db->server_info."
  893. /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
  894. /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
  895. /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
  896. /*!40101 SET NAMES utf8 */;
  897. /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
  898. /*!40103 SET TIME_ZONE='+00:00' */;
  899. /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
  900. /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
  901. /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
  902. /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
  903. ";
  904. if (GETPOST("nobin_disable_fk")) {
  905. $sqlhead .= "SET FOREIGN_KEY_CHECKS=0;\n";
  906. }
  907. //$sqlhead .= "SET SQL_MODE=\"NO_AUTO_VALUE_ON_ZERO\";\n";
  908. if (GETPOST("nobin_use_transaction")) {
  909. $sqlhead .= "SET AUTOCOMMIT=0;\nSTART TRANSACTION;\n";
  910. }
  911. fwrite($handle, $sqlhead);
  912. $ignore = '';
  913. if (GETPOST("nobin_sql_ignore")) {
  914. $ignore = 'IGNORE ';
  915. }
  916. $delayed = '';
  917. if (GETPOST("nobin_delayed")) {
  918. $delayed = 'DELAYED ';
  919. }
  920. // Process each table and print their definition + their datas
  921. foreach ($tables as $table) {
  922. // Saving the table structure
  923. fwrite($handle, "\n--\n-- Table structure for table `".$table."`\n--\n");
  924. if (GETPOST("nobin_drop")) {
  925. fwrite($handle, "DROP TABLE IF EXISTS `".$table."`;\n"); // Dropping table if exists prior to re create it
  926. }
  927. fwrite($handle, "/*!40101 SET @saved_cs_client = @@character_set_client */;\n");
  928. fwrite($handle, "/*!40101 SET character_set_client = utf8 */;\n");
  929. $resqldrop = $db->query('SHOW CREATE TABLE '.$table);
  930. $row2 = $db->fetch_row($resqldrop);
  931. if (empty($row2[1])) {
  932. fwrite($handle, "\n-- WARNING: Show create table ".$table." return empy string when it should not.\n");
  933. } else {
  934. fwrite($handle, $row2[1].";\n");
  935. //fwrite($handle,"/*!40101 SET character_set_client = @saved_cs_client */;\n\n");
  936. // Dumping the data (locking the table and disabling the keys check while doing the process)
  937. fwrite($handle, "\n--\n-- Dumping data for table `".$table."`\n--\n");
  938. if (!GETPOST("nobin_nolocks")) {
  939. fwrite($handle, "LOCK TABLES `".$table."` WRITE;\n"); // Lock the table before inserting data (when the data will be imported back)
  940. }
  941. if (GETPOST("nobin_disable_fk")) {
  942. fwrite($handle, "ALTER TABLE `".$table."` DISABLE KEYS;\n");
  943. } else {
  944. fwrite($handle, "/*!40000 ALTER TABLE `".$table."` DISABLE KEYS */;\n");
  945. }
  946. $sql = "SELECT * FROM ".$table; // Here SELECT * is allowed because we don't have definition of columns to take
  947. $result = $db->query($sql);
  948. while ($row = $db->fetch_row($result)) {
  949. // For each row of data we print a line of INSERT
  950. fwrite($handle, "INSERT ".$delayed.$ignore."INTO ".$table." VALUES (");
  951. $columns = count($row);
  952. for ($j = 0; $j < $columns; $j++) {
  953. // Processing each columns of the row to ensure that we correctly save the value (eg: add quotes for string - in fact we add quotes for everything, it's easier)
  954. if ($row[$j] == null && !is_string($row[$j])) {
  955. // IMPORTANT: if the field is NULL we set it NULL
  956. $row[$j] = 'NULL';
  957. } elseif (is_string($row[$j]) && $row[$j] == '') {
  958. // if it's an empty string, we set it as an empty string
  959. $row[$j] = "''";
  960. } elseif (is_numeric($row[$j]) && !strcmp($row[$j], $row[$j] + 0)) { // test if it's a numeric type and the numeric version ($nb+0) == string version (eg: if we have 01, it's probably not a number but rather a string, else it would not have any leading 0)
  961. // if it's a number, we return it as-is
  962. // $row[$j] = $row[$j];
  963. } else { // else for all other cases we escape the value and put quotes around
  964. $row[$j] = addslashes($row[$j]);
  965. $row[$j] = preg_replace("#\n#", "\\n", $row[$j]);
  966. $row[$j] = "'".$row[$j]."'";
  967. }
  968. }
  969. fwrite($handle, implode(',', $row).");\n");
  970. }
  971. if (GETPOST("nobin_disable_fk")) {
  972. fwrite($handle, "ALTER TABLE `".$table."` ENABLE KEYS;\n"); // Enabling back the keys/index checking
  973. }
  974. if (!GETPOST("nobin_nolocks")) {
  975. fwrite($handle, "UNLOCK TABLES;\n"); // Unlocking the table
  976. }
  977. fwrite($handle, "\n\n\n");
  978. }
  979. }
  980. /* Backup Procedure structure*/
  981. /*
  982. $result = $db->query('SHOW PROCEDURE STATUS');
  983. if ($db->num_rows($result) > 0)
  984. {
  985. while ($row = $db->fetch_row($result)) { $procedures[] = $row[1]; }
  986. foreach($procedures as $proc)
  987. {
  988. fwrite($handle,"DELIMITER $$\n\n");
  989. fwrite($handle,"DROP PROCEDURE IF EXISTS '$name'.'$proc'$$\n");
  990. $resqlcreateproc=$db->query("SHOW CREATE PROCEDURE '$proc'");
  991. $row2 = $db->fetch_row($resqlcreateproc);
  992. fwrite($handle,"\n".$row2[2]."$$\n\n");
  993. fwrite($handle,"DELIMITER ;\n\n");
  994. }
  995. }
  996. */
  997. /* Backup Procedure structure*/
  998. // Write the footer (restore the previous database settings)
  999. $sqlfooter = "\n\n";
  1000. if (GETPOST("nobin_use_transaction")) {
  1001. $sqlfooter .= "COMMIT;\n";
  1002. }
  1003. if (GETPOST("nobin_disable_fk")) {
  1004. $sqlfooter .= "SET FOREIGN_KEY_CHECKS=1;\n";
  1005. }
  1006. $sqlfooter .= "\n\n-- Dump completed on ".date('Y-m-d G-i-s');
  1007. fwrite($handle, $sqlfooter);
  1008. fclose($handle);
  1009. return 1;
  1010. }
  1011. }