utils.class.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. <?php
  2. /* Copyright (C) 2016 Destailleur Laurent <eldy@users.sourceforge.net>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 3 of the License, or
  7. * any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. /**
  18. * \file htdocs/core/class/utils.class.php
  19. * \ingroup core
  20. * \brief File for Utils class
  21. */
  22. /**
  23. * Class to manage utility methods
  24. */
  25. class Utils
  26. {
  27. var $db;
  28. var $output; // Used by Cron method to return message
  29. var $result; // Used by Cron method to return data
  30. /**
  31. * Constructor
  32. *
  33. * @param DoliDB $db Database handler
  34. */
  35. function __construct($db)
  36. {
  37. $this->db = $db;
  38. }
  39. /**
  40. * Purge files into directory of data files.
  41. * CAN BE A CRON TASK
  42. *
  43. * @param string $choice Choice of purge mode ('tempfiles', 'tempfilesold' to purge temp older than 24h, 'allfiles', 'logfiles')
  44. * @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK)
  45. */
  46. function purgeFiles($choice='tempfilesold')
  47. {
  48. global $conf, $langs, $dolibarr_main_data_root;
  49. $langs->load("admin");
  50. dol_syslog("Utils::purgeFiles choice=".$choice, LOG_DEBUG);
  51. require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  52. $filesarray=array();
  53. if (empty($choice)) $choice='tempfilesold';
  54. if ($choice=='tempfiles' || $choice=='tempfilesold')
  55. {
  56. // Delete temporary files
  57. if ($dolibarr_main_data_root)
  58. {
  59. $filesarray=dol_dir_list($dolibarr_main_data_root,"directories",1,'^temp$','','','',2);
  60. if ($choice == 'tempfilesold')
  61. {
  62. $now = dol_now();
  63. foreach($filesarray as $key => $val)
  64. {
  65. if ($val['date'] > ($now - (24 * 3600))) unset($filesarray[$key]); // Discard files not older than 24h
  66. }
  67. }
  68. }
  69. }
  70. if ($choice=='allfiles')
  71. {
  72. // Delete all files
  73. if ($dolibarr_main_data_root)
  74. {
  75. $filesarray=dol_dir_list($dolibarr_main_data_root,"all",0,'','install\.lock$');
  76. }
  77. }
  78. if ($choice=='logfile')
  79. {
  80. // Define filelog to discard it from purge
  81. $filelog='';
  82. if (! empty($conf->syslog->enabled))
  83. {
  84. $filelog=$conf->global->SYSLOG_FILE;
  85. $filelog=preg_replace('/DOL_DATA_ROOT/i',DOL_DATA_ROOT,$filelog);
  86. }
  87. $filesarray[]=array('fullname'=>$filelog,'type'=>'file');
  88. }
  89. $count=0;
  90. if (count($filesarray))
  91. {
  92. foreach($filesarray as $key => $value)
  93. {
  94. //print "x ".$filesarray[$key]['fullname']."<br>\n";
  95. if ($filesarray[$key]['type'] == 'dir')
  96. {
  97. $count+=dol_delete_dir_recursive($filesarray[$key]['fullname']);
  98. }
  99. elseif ($filesarray[$key]['type'] == 'file')
  100. {
  101. // If (file that is not logfile) or (if logfile with option logfile)
  102. if ($filesarray[$key]['fullname'] != $filelog || $choice=='logfile')
  103. {
  104. $count+=(dol_delete_file($filesarray[$key]['fullname'])?1:0);
  105. }
  106. }
  107. }
  108. // Update cachenbofdoc
  109. if (! empty($conf->ecm->enabled) && $choice=='allfiles')
  110. {
  111. require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmdirectory.class.php';
  112. $ecmdirstatic = new EcmDirectory($this->db);
  113. $result = $ecmdirstatic->refreshcachenboffile(1);
  114. }
  115. }
  116. if ($count > 0) $this->output=$langs->trans("PurgeNDirectoriesDeleted", $count);
  117. else $this->output=$langs->trans("PurgeNothingToDelete");
  118. //return $count;
  119. return 0; // This function can be called by cron so must return 0 if OK
  120. }
  121. /**
  122. * Make a backup of database
  123. * CAN BE A CRON TASK
  124. *
  125. * @param string $compression 'gz' or 'bz' or 'none'
  126. * @param string $type 'mysql', 'postgresql', ...
  127. * @param int $usedefault 1=Use default backup profile (Set this to 1 when used as cron)
  128. * @param string $file 'auto' or filename to build
  129. * @param int $keeplastnfiles Keep only last n files (not used yet)
  130. * @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK)
  131. */
  132. function dumpDatabase($compression='none', $type='auto', $usedefault=1, $file='auto', $keeplastnfiles=0)
  133. {
  134. global $db, $conf, $langs, $dolibarr_main_data_root;
  135. global $dolibarr_main_db_name, $dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_port, $dolibarr_main_db_pass;
  136. $langs->load("admin");
  137. dol_syslog("Utils::dumpDatabase type=".$type." compression=".$compression." file=".$file, LOG_DEBUG);
  138. require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  139. // Check compression parameter
  140. if (! in_array($compression, array('none', 'gz', 'bz', 'zip')))
  141. {
  142. $langs->load("errors");
  143. $this->error=$langs->transnoentitiesnoconv("ErrorBadValueForParameter", $compression, "Compression");
  144. return -1;
  145. }
  146. // Check type parameter
  147. if ($type == 'auto') $type = $db->type;
  148. if (! in_array($type, array('pgsql', 'mysql', 'mysqli','mysqlnobin')))
  149. {
  150. $langs->load("errors");
  151. $this->error=$langs->transnoentitiesnoconv("ErrorBadValueForParameter", $type, "Basetype");
  152. return -1;
  153. }
  154. // Check file parameter
  155. if ($file == 'auto')
  156. {
  157. $prefix='dump';
  158. $ext='.sql';
  159. if (in_array($type, array('mysql', 'mysqli'))) { $prefix='mysqldump'; $ext='sql'; }
  160. //if ($label == 'PostgreSQL') { $prefix='pg_dump'; $ext='dump'; }
  161. if (in_array($type, array('pgsql'))) { $prefix='pg_dump'; $ext='sql'; }
  162. $file=$prefix.'_'.$dolibarr_main_db_name.'_'.dol_sanitizeFileName(DOL_VERSION).'_'.strftime("%Y%m%d%H%M").'.'.$ext;
  163. }
  164. $outputdir = $conf->admin->dir_output.'/backup';
  165. $result=dol_mkdir($outputdir);
  166. // MYSQL
  167. if ($type == 'mysql' || $type == 'mysqli')
  168. {
  169. $cmddump=$conf->global->SYSTEMTOOLS_MYSQLDUMP;
  170. $outputfile = $outputdir.'/'.$file;
  171. // for compression format, we add extension
  172. $compression=$compression ? $compression : 'none';
  173. if ($compression == 'gz') $outputfile.='.gz';
  174. if ($compression == 'bz') $outputfile.='.bz2';
  175. $outputerror = $outputfile.'.err';
  176. dol_mkdir($conf->admin->dir_output.'/backup');
  177. // Parameteres execution
  178. $command=$cmddump;
  179. if (preg_match("/\s/",$command)) $command=escapeshellarg($command); // Use quotes on command
  180. //$param=escapeshellarg($dolibarr_main_db_name)." -h ".escapeshellarg($dolibarr_main_db_host)." -u ".escapeshellarg($dolibarr_main_db_user)." -p".escapeshellarg($dolibarr_main_db_pass);
  181. $param=$dolibarr_main_db_name." -h ".$dolibarr_main_db_host;
  182. $param.=" -u ".$dolibarr_main_db_user;
  183. if (! empty($dolibarr_main_db_port)) $param.=" -P ".$dolibarr_main_db_port;
  184. if (! GETPOST("use_transaction")) $param.=" -l --single-transaction";
  185. if (GETPOST("disable_fk") || $usedefault) $param.=" -K";
  186. if (GETPOST("sql_compat") && GETPOST("sql_compat") != 'NONE') $param.=" --compatible=".escapeshellarg(GETPOST("sql_compat","alpha"));
  187. if (GETPOST("drop_database")) $param.=" --add-drop-database";
  188. if (GETPOST("sql_structure") || $usedefault)
  189. {
  190. if (GETPOST("drop") || $usedefault) $param.=" --add-drop-table=TRUE";
  191. else $param.=" --add-drop-table=FALSE";
  192. }
  193. else
  194. {
  195. $param.=" -t";
  196. }
  197. if (GETPOST("disable-add-locks")) $param.=" --add-locks=FALSE";
  198. if (GETPOST("sql_data") || $usedefault)
  199. {
  200. $param.=" --tables";
  201. if (GETPOST("showcolumns") || $usedefault) $param.=" -c";
  202. if (GETPOST("extended_ins") || $usedefault) $param.=" -e";
  203. else $param.=" --skip-extended-insert";
  204. if (GETPOST("delayed")) $param.=" --delayed-insert";
  205. if (GETPOST("sql_ignore")) $param.=" --insert-ignore";
  206. if (GETPOST("hexforbinary") || $usedefault) $param.=" --hex-blob";
  207. }
  208. else
  209. {
  210. $param.=" -d"; // No row information (no data)
  211. }
  212. $param.=" --default-character-set=utf8"; // We always save output into utf8 charset
  213. $paramcrypted=$param;
  214. $paramclear=$param;
  215. if (! empty($dolibarr_main_db_pass))
  216. {
  217. $paramcrypted.=' -p"'.preg_replace('/./i','*',$dolibarr_main_db_pass).'"';
  218. $paramclear.=' -p"'.str_replace(array('"','`'),array('\"','\`'),$dolibarr_main_db_pass).'"';
  219. }
  220. $errormsg='';
  221. // Debut appel methode execution
  222. $fullcommandcrypted=$command." ".$paramcrypted." 2>&1";
  223. $fullcommandclear=$command." ".$paramclear." 2>&1";
  224. if ($compression == 'none') $handle = fopen($outputfile, 'w');
  225. if ($compression == 'gz') $handle = gzopen($outputfile, 'w');
  226. if ($compression == 'bz') $handle = bzopen($outputfile, 'w');
  227. if ($handle)
  228. {
  229. $ok=0;
  230. dol_syslog("Run command ".$fullcommandcrypted);
  231. $handlein = popen($fullcommandclear, 'r');
  232. $i=0;
  233. while (!feof($handlein))
  234. {
  235. $i++; // output line number
  236. $read = fgets($handlein);
  237. // Exclude warning line we don't want
  238. if ($i == 1 && preg_match('/Warning.*Using a password/i', $read)) continue;
  239. fwrite($handle,$read);
  240. if (preg_match('/'.preg_quote('-- Dump completed').'/i',$read)) $ok=1;
  241. elseif (preg_match('/'.preg_quote('SET SQL_NOTES=@OLD_SQL_NOTES').'/i',$read)) $ok=1;
  242. }
  243. pclose($handlein);
  244. if ($compression == 'none') fclose($handle);
  245. if ($compression == 'gz') gzclose($handle);
  246. if ($compression == 'bz') bzclose($handle);
  247. if (! empty($conf->global->MAIN_UMASK))
  248. @chmod($outputfile, octdec($conf->global->MAIN_UMASK));
  249. }
  250. else
  251. {
  252. $langs->load("errors");
  253. dol_syslog("Failed to open file ".$outputfile,LOG_ERR);
  254. $errormsg=$langs->trans("ErrorFailedToWriteInDir");
  255. }
  256. // Get errorstring
  257. if ($compression == 'none') $handle = fopen($outputfile, 'r');
  258. if ($compression == 'gz') $handle = gzopen($outputfile, 'r');
  259. if ($compression == 'bz') $handle = bzopen($outputfile, 'r');
  260. if ($handle)
  261. {
  262. // Get 2048 first chars of error message.
  263. $errormsg = fgets($handle,2048);
  264. // Close file
  265. if ($compression == 'none') fclose($handle);
  266. if ($compression == 'gz') gzclose($handle);
  267. if ($compression == 'bz') bzclose($handle);
  268. if ($ok && preg_match('/^-- MySql/i',$errormsg)) $errormsg=''; // Pas erreur
  269. else
  270. {
  271. // Renommer fichier sortie en fichier erreur
  272. //print "$outputfile -> $outputerror";
  273. @dol_delete_file($outputerror,1);
  274. @rename($outputfile,$outputerror);
  275. // Si safe_mode on et command hors du parametre exec, on a un fichier out vide donc errormsg vide
  276. if (! $errormsg)
  277. {
  278. $langs->load("errors");
  279. $errormsg=$langs->trans("ErrorFailedToRunExternalCommand");
  280. }
  281. }
  282. }
  283. // Fin execution commande
  284. $this->output = $errormsg;
  285. $this->error = $errormsg;
  286. $this->result = array("commandbackuplastdone" => $command." ".$paramcrypted, "commandbackuptorun" => "");
  287. //if (empty($this->output)) $this->output=$this->result['commandbackuplastdone'];
  288. }
  289. // MYSQL NO BIN
  290. if ($type == 'mysqlnobin')
  291. {
  292. $outputfile = $outputdir.'/'.$file;
  293. $outputfiletemp = $outputfile.'-TMP.sql';
  294. // for compression format, we add extension
  295. $compression=$compression ? $compression : 'none';
  296. if ($compression == 'gz') $outputfile.='.gz';
  297. if ($compression == 'bz') $outputfile.='.bz2';
  298. $outputerror = $outputfile.'.err';
  299. dol_mkdir($conf->admin->dir_output.'/backup');
  300. if ($compression == 'gz' or $compression == 'bz')
  301. {
  302. backup_tables($outputfiletemp);
  303. dol_compress_file($outputfiletemp, $outputfile, $compression);
  304. unlink($outputfiletemp);
  305. }
  306. else
  307. {
  308. backup_tables($outputfile);
  309. }
  310. $this->output = "";
  311. $this->result = array("commandbackuplastdone" => "", "commandbackuptorun" => "");
  312. }
  313. // POSTGRESQL
  314. if ($type == 'postgresql')
  315. {
  316. $cmddump=$conf->global->SYSTEMTOOLS_POSTGRESQLDUMP;
  317. $outputfile = $outputdir.'/'.$file;
  318. // for compression format, we add extension
  319. $compression=$compression ? $compression : 'none';
  320. if ($compression == 'gz') $outputfile.='.gz';
  321. if ($compression == 'bz') $outputfile.='.bz2';
  322. $outputerror = $outputfile.'.err';
  323. dol_mkdir($conf->admin->dir_output.'/backup');
  324. // Parameteres execution
  325. $command=$cmddump;
  326. if (preg_match("/\s/",$command)) $command=escapeshellarg($command); // Use quotes on command
  327. //$param=escapeshellarg($dolibarr_main_db_name)." -h ".escapeshellarg($dolibarr_main_db_host)." -u ".escapeshellarg($dolibarr_main_db_user)." -p".escapeshellarg($dolibarr_main_db_pass);
  328. //$param="-F c";
  329. $param="-F p";
  330. $param.=" --no-tablespaces --inserts -h ".$dolibarr_main_db_host;
  331. $param.=" -U ".$dolibarr_main_db_user;
  332. if (! empty($dolibarr_main_db_port)) $param.=" -p ".$dolibarr_main_db_port;
  333. if (GETPOST("sql_compat") && GETPOST("sql_compat") == 'ANSI') $param.=" --disable-dollar-quoting";
  334. if (GETPOST("drop_database")) $param.=" -c -C";
  335. if (GETPOST("sql_structure"))
  336. {
  337. if (GETPOST("drop")) $param.=" --add-drop-table";
  338. if (! GETPOST("sql_data")) $param.=" -s";
  339. }
  340. if (GETPOST("sql_data"))
  341. {
  342. if (! GETPOST("sql_structure")) $param.=" -a";
  343. if (GETPOST("showcolumns")) $param.=" -c";
  344. }
  345. $param.=' -f "'.$outputfile.'"';
  346. //if ($compression == 'none')
  347. if ($compression == 'gz') $param.=' -Z 9';
  348. //if ($compression == 'bz')
  349. $paramcrypted=$param;
  350. $paramclear=$param;
  351. /*if (! empty($dolibarr_main_db_pass))
  352. {
  353. $paramcrypted.=" -W".preg_replace('/./i','*',$dolibarr_main_db_pass);
  354. $paramclear.=" -W".$dolibarr_main_db_pass;
  355. }*/
  356. $paramcrypted.=" -w ".$dolibarr_main_db_name;
  357. $paramclear.=" -w ".$dolibarr_main_db_name;
  358. $this->output = "";
  359. $this->result = array("commandbackuplastdone" => "", "commandbackuptorun" => $command." ".$paramcrypted);
  360. }
  361. // Clean old files
  362. if ($keeplastnfiles > 0)
  363. {
  364. $tmpfiles = dol_dir_list($conf->admin->dir_output.'/backup', 'files', 0, '', '(\.err|\.old|\.sav)$', 'date', SORT_DESC);
  365. $i=0;
  366. foreach($tmpfiles as $key => $val)
  367. {
  368. $i++;
  369. if ($i <= $keeplastnfiles) continue;
  370. dol_delete_file($val['fullname']);
  371. }
  372. }
  373. return 0;
  374. }
  375. }