dolibarr  9.0.0
utils.class.php
Go to the documentation of this file.
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 
28 class Utils
29 {
33  public $db;
34 
35  var $output; // Used by Cron method to return message
36  var $result; // Used by Cron method to return data
37 
43  function __construct($db)
44  {
45  $this->db = $db;
46  }
47 
48 
56  function purgeFiles($choice='tempfilesold')
57  {
58  global $conf, $langs, $dolibarr_main_data_root;
59 
60  $langs->load("admin");
61 
62  dol_syslog("Utils::purgeFiles choice=".$choice, LOG_DEBUG);
63  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
64 
65  $filesarray=array();
66  if (empty($choice)) $choice='tempfilesold';
67 
68  if ($choice=='tempfiles' || $choice=='tempfilesold')
69  {
70  // Delete temporary files
71  if ($dolibarr_main_data_root)
72  {
73  $filesarray=dol_dir_list($dolibarr_main_data_root, "directories", 1, '^temp$', '', 'name', SORT_ASC, 2, 0, '', 1); // Do not follow symlinks
74  if ($choice == 'tempfilesold')
75  {
76  $now = dol_now();
77  foreach($filesarray as $key => $val)
78  {
79  if ($val['date'] > ($now - (24 * 3600))) unset($filesarray[$key]); // Discard files not older than 24h
80  }
81  }
82  }
83  }
84 
85  if ($choice=='allfiles')
86  {
87  // Delete all files (except install.lock, do not follow symbolic links)
88  if ($dolibarr_main_data_root)
89  {
90  $filesarray=dol_dir_list($dolibarr_main_data_root, "all", 0, '', 'install\.lock$', 'name', SORT_ASC, 0, 0, '', 1);
91  }
92  }
93 
94  if ($choice=='logfile')
95  {
96  // Define files log
97  if ($dolibarr_main_data_root)
98  {
99  $filesarray=dol_dir_list($dolibarr_main_data_root, "files", 0, '.*\.log[\.0-9]*(\.gz)?$', 'install\.lock$', 'name', SORT_ASC, 0, 0, '', 1);
100  }
101 
102  $filelog='';
103  if (! empty($conf->syslog->enabled))
104  {
105  $filelog=$conf->global->SYSLOG_FILE;
106  $filelog=preg_replace('/DOL_DATA_ROOT/i',DOL_DATA_ROOT,$filelog);
107 
108  $alreadyincluded=false;
109  foreach ($filesarray as $tmpcursor)
110  {
111  if ($tmpcursor['fullname'] == $filelog) { $alreadyincluded=true; }
112  }
113  if (! $alreadyincluded) $filesarray[]=array('fullname'=>$filelog,'type'=>'file');
114  }
115  }
116 
117  $count=0;
118  $countdeleted=0;
119  $counterror=0;
120  if (count($filesarray))
121  {
122  foreach($filesarray as $key => $value)
123  {
124  //print "x ".$filesarray[$key]['fullname']."-".$filesarray[$key]['type']."<br>\n";
125  if ($filesarray[$key]['type'] == 'dir')
126  {
127  $startcount=0;
128  $tmpcountdeleted=0;
129  $result=dol_delete_dir_recursive($filesarray[$key]['fullname'], $startcount, 1, 0, $tmpcountdeleted);
130  $count+=$result;
131  $countdeleted+=$tmpcountdeleted;
132  }
133  elseif ($filesarray[$key]['type'] == 'file')
134  {
135  // If (file that is not logfile) or (if mode is logfile)
136  if ($filesarray[$key]['fullname'] != $filelog || $choice=='logfile')
137  {
138  $result=dol_delete_file($filesarray[$key]['fullname'], 1, 1);
139  if ($result)
140  {
141  $count++;
142  $countdeleted++;
143  }
144  else
145  {
146  $counterror++;
147  }
148  }
149  }
150  }
151 
152  // Update cachenbofdoc
153  if (! empty($conf->ecm->enabled) && $choice=='allfiles')
154  {
155  require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmdirectory.class.php';
156  $ecmdirstatic = new EcmDirectory($this->db);
157  $result = $ecmdirstatic->refreshcachenboffile(1);
158  }
159  }
160 
161  if ($count > 0)
162  {
163  $this->output=$langs->trans("PurgeNDirectoriesDeleted", $countdeleted);
164  if ($count > $countdeleted) $this->output.='<br>'.$langs->trans("PurgeNDirectoriesFailed", ($count - $countdeleted));
165  }
166  else $this->output=$langs->trans("PurgeNothingToDelete").($choice == 'tempfilesold' ? ' (older than 24h)':'');
167 
168  //return $count;
169  return 0; // This function can be called by cron so must return 0 if OK
170  }
171 
172 
185  function dumpDatabase($compression='none', $type='auto', $usedefault=1, $file='auto', $keeplastnfiles=0, $execmethod=0)
186  {
187  global $db, $conf, $langs, $dolibarr_main_data_root;
188  global $dolibarr_main_db_name, $dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_port, $dolibarr_main_db_pass;
189 
190  $langs->load("admin");
191 
192  dol_syslog("Utils::dumpDatabase type=".$type." compression=".$compression." file=".$file, LOG_DEBUG);
193  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
194 
195  // Check compression parameter
196  if (! in_array($compression, array('none', 'gz', 'bz', 'zip')))
197  {
198  $langs->load("errors");
199  $this->error=$langs->transnoentitiesnoconv("ErrorBadValueForParameter", $compression, "Compression");
200  return -1;
201  }
202 
203  // Check type parameter
204  if ($type == 'auto') $type = $db->type;
205  if (! in_array($type, array('postgresql', 'pgsql', 'mysql', 'mysqli', 'mysqlnobin')))
206  {
207  $langs->load("errors");
208  $this->error=$langs->transnoentitiesnoconv("ErrorBadValueForParameter", $type, "Basetype");
209  return -1;
210  }
211 
212  // Check file parameter
213  if ($file == 'auto')
214  {
215  $prefix='dump';
216  $ext='sql';
217  if (in_array($type, array('mysql', 'mysqli'))) { $prefix='mysqldump'; $ext='sql'; }
218  //if ($label == 'PostgreSQL') { $prefix='pg_dump'; $ext='dump'; }
219  if (in_array($type, array('pgsql'))) { $prefix='pg_dump'; $ext='sql'; }
220  $file=$prefix.'_'.$dolibarr_main_db_name.'_'.dol_sanitizeFileName(DOL_VERSION).'_'.strftime("%Y%m%d%H%M").'.'.$ext;
221  }
222 
223  $outputdir = $conf->admin->dir_output.'/backup';
224  $result=dol_mkdir($outputdir);
225 
226 
227  // MYSQL
228  if ($type == 'mysql' || $type == 'mysqli')
229  {
230  $cmddump=$conf->global->SYSTEMTOOLS_MYSQLDUMP;
231 
232 
233  $outputfile = $outputdir.'/'.$file;
234  // for compression format, we add extension
235  $compression=$compression ? $compression : 'none';
236  if ($compression == 'gz') $outputfile.='.gz';
237  if ($compression == 'bz') $outputfile.='.bz2';
238  $outputerror = $outputfile.'.err';
239  dol_mkdir($conf->admin->dir_output.'/backup');
240 
241  // Parameteres execution
242  $command=$cmddump;
243  if (preg_match("/\s/",$command)) $command=escapeshellarg($command); // Use quotes on command
244 
245  //$param=escapeshellarg($dolibarr_main_db_name)." -h ".escapeshellarg($dolibarr_main_db_host)." -u ".escapeshellarg($dolibarr_main_db_user)." -p".escapeshellarg($dolibarr_main_db_pass);
246  $param=$dolibarr_main_db_name." -h ".$dolibarr_main_db_host;
247  $param.=" -u ".$dolibarr_main_db_user;
248  if (! empty($dolibarr_main_db_port)) $param.=" -P ".$dolibarr_main_db_port;
249  if (! GETPOST("use_transaction")) $param.=" -l --single-transaction";
250  if (GETPOST("disable_fk") || $usedefault) $param.=" -K";
251  if (GETPOST("sql_compat") && GETPOST("sql_compat") != 'NONE') $param.=" --compatible=".escapeshellarg(GETPOST("sql_compat","alpha"));
252  if (GETPOST("drop_database")) $param.=" --add-drop-database";
253  if (GETPOST("sql_structure") || $usedefault)
254  {
255  if (GETPOST("drop") || $usedefault) $param.=" --add-drop-table=TRUE";
256  else $param.=" --add-drop-table=FALSE";
257  }
258  else
259  {
260  $param.=" -t";
261  }
262  if (GETPOST("disable-add-locks")) $param.=" --add-locks=FALSE";
263  if (GETPOST("sql_data") || $usedefault)
264  {
265  $param.=" --tables";
266  if (GETPOST("showcolumns") || $usedefault) $param.=" -c";
267  if (GETPOST("extended_ins") || $usedefault) $param.=" -e";
268  else $param.=" --skip-extended-insert";
269  if (GETPOST("delayed")) $param.=" --delayed-insert";
270  if (GETPOST("sql_ignore")) $param.=" --insert-ignore";
271  if (GETPOST("hexforbinary") || $usedefault) $param.=" --hex-blob";
272  }
273  else
274  {
275  $param.=" -d"; // No row information (no data)
276  }
277  $param.=" --default-character-set=utf8"; // We always save output into utf8 charset
278  $paramcrypted=$param;
279  $paramclear=$param;
280  if (! empty($dolibarr_main_db_pass))
281  {
282  $paramcrypted.=' -p"'.preg_replace('/./i','*',$dolibarr_main_db_pass).'"';
283  $paramclear.=' -p"'.str_replace(array('"','`'),array('\"','\`'),$dolibarr_main_db_pass).'"';
284  }
285 
286  $errormsg='';
287  $handle = '';
288 
289  // Start call method to execute dump
290  $fullcommandcrypted=$command." ".$paramcrypted." 2>&1";
291  $fullcommandclear=$command." ".$paramclear." 2>&1";
292  if ($compression == 'none') $handle = fopen($outputfile, 'w');
293  if ($compression == 'gz') $handle = gzopen($outputfile, 'w');
294  if ($compression == 'bz') $handle = bzopen($outputfile, 'w');
295 
296  if ($handle)
297  {
298  if (! empty($conf->global->MAIN_EXEC_USE_POPEN)) $execmethod=$conf->global->MAIN_EXEC_USE_POPEN;
299  if (empty($execmethod)) $execmethod=1;
300 
301  $ok=0;
302  dol_syslog("Utils::dumpDatabase execmethod=".$execmethod." command:".$fullcommandcrypted, LOG_DEBUG);
303 
304  // TODO Replace with executeCLI function
305  if ($execmethod == 1)
306  {
307  exec($fullcommandclear, $readt, $retval);
308  $result = $retval;
309 
310  if ($retval != 0)
311  {
312  $langs->load("errors");
313  dol_syslog("Datadump retval after exec=".$retval, LOG_ERR);
314  $error = 'Error '.$retval;
315  $ok=0;
316  }
317  else
318  {
319  $i=0;
320  if (!empty($readt))
321  foreach($readt as $key=>$read)
322  {
323  $i++; // output line number
324  if ($i == 1 && preg_match('/Warning.*Using a password/i', $read)) continue;
325  fwrite($handle, $read.($execmethod == 2 ? '' : "\n"));
326  if (preg_match('/'.preg_quote('-- Dump completed').'/i',$read)) $ok=1;
327  elseif (preg_match('/'.preg_quote('SET SQL_NOTES=@OLD_SQL_NOTES').'/i',$read)) $ok=1;
328  }
329  }
330  }
331  if ($execmethod == 2) // With this method, there is no way to get the return code, only output
332  {
333  $handlein = popen($fullcommandclear, 'r');
334  $i=0;
335  while (!feof($handlein))
336  {
337  $i++; // output line number
338  $read = fgets($handlein);
339  // Exclude warning line we don't want
340  if ($i == 1 && preg_match('/Warning.*Using a password/i', $read)) continue;
341  fwrite($handle,$read);
342  if (preg_match('/'.preg_quote('-- Dump completed').'/i',$read)) $ok=1;
343  elseif (preg_match('/'.preg_quote('SET SQL_NOTES=@OLD_SQL_NOTES').'/i',$read)) $ok=1;
344  }
345  pclose($handlein);
346  }
347 
348 
349  if ($compression == 'none') fclose($handle);
350  if ($compression == 'gz') gzclose($handle);
351  if ($compression == 'bz') bzclose($handle);
352 
353  if (! empty($conf->global->MAIN_UMASK))
354  @chmod($outputfile, octdec($conf->global->MAIN_UMASK));
355  }
356  else
357  {
358  $langs->load("errors");
359  dol_syslog("Failed to open file ".$outputfile,LOG_ERR);
360  $errormsg=$langs->trans("ErrorFailedToWriteInDir");
361  }
362 
363  // Get errorstring
364  if ($compression == 'none') $handle = fopen($outputfile, 'r');
365  if ($compression == 'gz') $handle = gzopen($outputfile, 'r');
366  if ($compression == 'bz') $handle = bzopen($outputfile, 'r');
367  if ($handle)
368  {
369  // Get 2048 first chars of error message.
370  $errormsg = fgets($handle,2048);
371  // Close file
372  if ($compression == 'none') fclose($handle);
373  if ($compression == 'gz') gzclose($handle);
374  if ($compression == 'bz') bzclose($handle);
375  if ($ok && preg_match('/^-- MySql/i',$errormsg)) $errormsg=''; // Pas erreur
376  else
377  {
378  // Renommer fichier sortie en fichier erreur
379  //print "$outputfile -> $outputerror";
380  @dol_delete_file($outputerror, 1, 0, 0, null, false, 0);
381  @rename($outputfile,$outputerror);
382  // Si safe_mode on et command hors du parametre exec, on a un fichier out vide donc errormsg vide
383  if (! $errormsg)
384  {
385  $langs->load("errors");
386  $errormsg=$langs->trans("ErrorFailedToRunExternalCommand");
387  }
388  }
389  }
390  // Fin execution commande
391 
392  $this->output = $errormsg;
393  $this->error = $errormsg;
394  $this->result = array("commandbackuplastdone" => $command." ".$paramcrypted, "commandbackuptorun" => "");
395  //if (empty($this->output)) $this->output=$this->result['commandbackuplastdone'];
396  }
397 
398  // MYSQL NO BIN
399  if ($type == 'mysqlnobin')
400  {
401  $outputfile = $outputdir.'/'.$file;
402  $outputfiletemp = $outputfile.'-TMP.sql';
403  // for compression format, we add extension
404  $compression=$compression ? $compression : 'none';
405  if ($compression == 'gz') $outputfile.='.gz';
406  if ($compression == 'bz') $outputfile.='.bz2';
407  $outputerror = $outputfile.'.err';
408  dol_mkdir($conf->admin->dir_output.'/backup');
409 
410  if ($compression == 'gz' or $compression == 'bz')
411  {
412  $this->backupTables($outputfiletemp);
413  dol_compress_file($outputfiletemp, $outputfile, $compression);
414  unlink($outputfiletemp);
415  }
416  else
417  {
418  $this->backupTables($outputfile);
419  }
420 
421  $this->output = "";
422  $this->result = array("commandbackuplastdone" => "", "commandbackuptorun" => "");
423  }
424 
425  // POSTGRESQL
426  if ($type == 'postgresql' || $type == 'pgsql')
427  {
428  $cmddump=$conf->global->SYSTEMTOOLS_POSTGRESQLDUMP;
429 
430  $outputfile = $outputdir.'/'.$file;
431  // for compression format, we add extension
432  $compression=$compression ? $compression : 'none';
433  if ($compression == 'gz') $outputfile.='.gz';
434  if ($compression == 'bz') $outputfile.='.bz2';
435  $outputerror = $outputfile.'.err';
436  dol_mkdir($conf->admin->dir_output.'/backup');
437 
438  // Parameteres execution
439  $command=$cmddump;
440  if (preg_match("/\s/",$command)) $command=escapeshellarg($command); // Use quotes on command
441 
442  //$param=escapeshellarg($dolibarr_main_db_name)." -h ".escapeshellarg($dolibarr_main_db_host)." -u ".escapeshellarg($dolibarr_main_db_user)." -p".escapeshellarg($dolibarr_main_db_pass);
443  //$param="-F c";
444  $param="-F p";
445  $param.=" --no-tablespaces --inserts -h ".$dolibarr_main_db_host;
446  $param.=" -U ".$dolibarr_main_db_user;
447  if (! empty($dolibarr_main_db_port)) $param.=" -p ".$dolibarr_main_db_port;
448  if (GETPOST("sql_compat") && GETPOST("sql_compat") == 'ANSI') $param.=" --disable-dollar-quoting";
449  if (GETPOST("drop_database")) $param.=" -c -C";
450  if (GETPOST("sql_structure"))
451  {
452  if (GETPOST("drop")) $param.=" --add-drop-table";
453  if (! GETPOST("sql_data")) $param.=" -s";
454  }
455  if (GETPOST("sql_data"))
456  {
457  if (! GETPOST("sql_structure")) $param.=" -a";
458  if (GETPOST("showcolumns")) $param.=" -c";
459  }
460  $param.=' -f "'.$outputfile.'"';
461  //if ($compression == 'none')
462  if ($compression == 'gz') $param.=' -Z 9';
463  //if ($compression == 'bz')
464  $paramcrypted=$param;
465  $paramclear=$param;
466  /*if (! empty($dolibarr_main_db_pass))
467  {
468  $paramcrypted.=" -W".preg_replace('/./i','*',$dolibarr_main_db_pass);
469  $paramclear.=" -W".$dolibarr_main_db_pass;
470  }*/
471  $paramcrypted.=" -w ".$dolibarr_main_db_name;
472  $paramclear.=" -w ".$dolibarr_main_db_name;
473 
474  $this->output = "";
475  $this->result = array("commandbackuplastdone" => "", "commandbackuptorun" => $command." ".$paramcrypted);
476  }
477 
478  // Clean old files
479  if ($keeplastnfiles > 0)
480  {
481  $tmpfiles = dol_dir_list($conf->admin->dir_output.'/backup', 'files', 0, '', '(\.err|\.old|\.sav)$', 'date', SORT_DESC);
482  $i=0;
483  foreach($tmpfiles as $key => $val)
484  {
485  $i++;
486  if ($i <= $keeplastnfiles) continue;
487  dol_delete_file($val['fullname'], 0, 0, 0, null, false, 0);
488  }
489  }
490 
491  return 0;
492  }
493 
494 
495 
504  function executeCLI($command, $outputfile, $execmethod=0)
505  {
506  global $conf, $langs;
507 
508  $result = 0;
509  $output = '';
510  $error = '';
511 
512  $command=escapeshellcmd($command);
513  $command.=" 2>&1";
514 
515  if (! empty($conf->global->MAIN_EXEC_USE_POPEN)) $execmethod=$conf->global->MAIN_EXEC_USE_POPEN;
516  if (empty($execmethod)) $execmethod=1;
517  //$execmethod=1;
518 
519  dol_syslog("Utils::executeCLI execmethod=".$execmethod." system:".$command, LOG_DEBUG);
520  $output_arr=array();
521 
522  if ($execmethod == 1)
523  {
524  exec($command, $output_arr, $retval);
525  $result = $retval;
526  if ($retval != 0)
527  {
528  $langs->load("errors");
529  dol_syslog("Utils::executeCLI retval after exec=".$retval, LOG_ERR);
530  $error = 'Error '.$retval;
531  }
532  }
533  if ($execmethod == 2) // With this method, there is no way to get the return code, only output
534  {
535  $ok=0;
536  $handle = fopen($outputfile, 'w+b');
537  if ($handle)
538  {
539  dol_syslog("Utils::executeCLI run command ".$command);
540  $handlein = popen($command, 'r');
541  while (!feof($handlein))
542  {
543  $read = fgets($handlein);
544  fwrite($handle,$read);
545  $output_arr[]=$read;
546  }
547  pclose($handlein);
548  fclose($handle);
549  }
550  if (! empty($conf->global->MAIN_UMASK)) @chmod($outputfile, octdec($conf->global->MAIN_UMASK));
551  }
552 
553  // Update with result
554  if (is_array($output_arr) && count($output_arr)>0)
555  {
556  foreach($output_arr as $val)
557  {
558  $output.=$val.($execmethod == 2 ? '' : "\n");
559  }
560  }
561 
562  dol_syslog("Utils::executeCLI result=".$result." output=".$output." error=".$error, LOG_DEBUG);
563 
564  return array('result'=>$result, 'output'=>$output, 'error'=>$error);
565  }
566 
573  function generateDoc($module)
574  {
575  global $conf, $langs;
576  global $dirins;
577 
578  $error = 0;
579 
580  $modulelowercase=strtolower($module);
581 
582  // Dir for module
583  $dir = $dirins.'/'.$modulelowercase;
584  // Zip file to build
585  $FILENAMEDOC='';
586 
587  // Load module
588  dol_include_once($modulelowercase.'/core/modules/mod'.$module.'.class.php');
589  $class='mod'.$module;
590 
591  if (class_exists($class))
592  {
593  try {
594  $moduleobj = new $class($this->db);
595  }
596  catch(Exception $e)
597  {
598  $error++;
599  dol_print_error($e->getMessage());
600  }
601  }
602  else
603  {
604  $error++;
605  $langs->load("errors");
606  dol_print_error($langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module));
607  exit;
608  }
609 
610  $arrayversion=explode('.',$moduleobj->version,3);
611  if (count($arrayversion))
612  {
613  $FILENAMEASCII=strtolower($module).'.asciidoc';
614  $FILENAMEDOC=strtolower($module).'.html'; // TODO Use/text PDF
615 
616  $dirofmodule = dol_buildpath(strtolower($module), 0).'/doc';
617  $dirofmoduletmp = dol_buildpath(strtolower($module), 0).'/doc/temp';
618  $outputfiledoc = $dirofmodule.'/'.$FILENAMEDOC;
619  if ($dirofmodule)
620  {
621  if (! dol_is_dir($dirofmodule)) dol_mkdir($dirofmodule);
622  if (! dol_is_dir($dirofmoduletmp)) dol_mkdir($dirofmoduletmp);
623  if (! is_writable($dirofmoduletmp))
624  {
625  $this->error = 'Dir '.$dirofmoduletmp.' does not exists or is not writable';
626  return -1;
627  }
628 
629  $destfile=$dirofmoduletmp.'/'.$FILENAMEASCII;
630 
631  $fhandle = fopen($destfile, 'w+');
632  if ($fhandle)
633  {
634  $specs=dol_dir_list(dol_buildpath(strtolower($module).'/doc', 0), 'files', 1, '(\.md|\.asciidoc)$', array('\/temp\/'));
635 
636  $i = 0;
637  foreach ($specs as $spec)
638  {
639  if (preg_match('/notindoc/', $spec['relativename'])) continue; // Discard file
640  if (preg_match('/disabled/', $spec['relativename'])) continue; // Discard file
641 
642  $pathtofile = strtolower($module).'/doc/'.$spec['relativename'];
643  $format='asciidoc';
644  if (preg_match('/\.md$/i', $spec['name'])) $format='markdown';
645 
646  $filecursor = @file_get_contents($spec['fullname']);
647  if ($filecursor)
648  {
649  fwrite($fhandle, ($i ? "\n<<<\n\n" : "").$filecursor."\n");
650  }
651  else
652  {
653  $this->error = 'Failed to concat content of file '.$spec['fullname'];
654  return -1;
655  }
656 
657  $i++;
658  }
659 
660  fwrite($fhandle, "\n\n\n== DATA SPECIFICATIONS...\n\n");
661 
662  // TODO
663  fwrite($fhandle, "TODO...");
664 
665  fclose($fhandle);
666  }
667 
668  $conf->global->MODULEBUILDER_ASCIIDOCTOR='asciidoctor';
669  if (empty($conf->global->MODULEBUILDER_ASCIIDOCTOR))
670  {
671  dol_print_error('', 'Module setup not complete');
672  exit;
673  }
674 
675  $command=$conf->global->MODULEBUILDER_ASCIIDOCTOR.' '.$destfile.' -n -o '.$dirofmodule.'/'.$FILENAMEDOC;
676  $outfile=$dirofmoduletmp.'/out.tmp';
677 
678  require_once DOL_DOCUMENT_ROOT.'/core/class/utils.class.php';
679  $utils = new Utils($db);
680  $resarray = $utils->executeCLI($command, $outfile);
681  if ($resarray['result'] != '0')
682  {
683  $this->error = $resarray['error'].' '.$resarray['output'];
684  }
685  $result = ($resarray['result'] == 0) ? 1 : 0;
686  }
687  else
688  {
689  $result = 0;
690  }
691 
692  if ($result > 0)
693  {
694  return 1;
695  }
696  else
697  {
698  $error++;
699  $langs->load("errors");
700  $this->error = $langs->trans("ErrorFailToGenerateFile", $outputfiledoc);
701  }
702  }
703  else
704  {
705  $error++;
706  $langs->load("errors");
707  $this->error = $langs->trans("ErrorCheckVersionIsDefined");
708  }
709 
710  return -1;
711  }
712 
720  function compressSyslogs()
721  {
722  global $conf;
723 
724  if(empty($conf->loghandlers['mod_syslog_file'])) { // File Syslog disabled
725  return 0;
726  }
727 
728  if(! function_exists('gzopen')) {
729  $this->error = 'Support for gzopen not available in this PHP';
730  return -1;
731  }
732 
733  dol_include_once('/core/lib/files.lib.php');
734 
735  $nbSaves = ! empty($conf->global->SYSLOG_FILE_SAVES) ? intval($conf->global->SYSLOG_FILE_SAVES) : 14;
736 
737  if (empty($conf->global->SYSLOG_FILE)) {
738  $mainlogdir = DOL_DATA_ROOT;
739  $mainlog = 'dolibarr.log';
740  } else {
741  $mainlogfull = str_replace('DOL_DATA_ROOT', DOL_DATA_ROOT, $conf->global->SYSLOG_FILE);
742  $mainlogdir = dirname($mainlogfull);
743  $mainlog = basename($mainlogfull);
744  }
745 
746  $tabfiles = dol_dir_list(DOL_DATA_ROOT, 'files', 0, '^(dolibarr_.+|odt2pdf)\.log$'); // Also handle other log files like dolibarr_install.log
747  $tabfiles[] = array('name' => $mainlog, 'path' => $mainlogdir);
748 
749  foreach($tabfiles as $file) {
750 
751  $logname = $file['name'];
752  $logpath = $file['path'];
753 
754  if (dol_is_file($logpath.'/'.$logname) && dol_filesize($logpath.'/'.$logname) > 0) // If log file exists and is not empty
755  {
756  // Handle already compressed files to rename them and add +1
757 
758  $filter = '^'.preg_quote($logname, '/').'\.([0-9]+)\.gz$';
759 
760  $gzfilestmp = dol_dir_list($logpath, 'files', 0, $filter);
761  $gzfiles = array();
762 
763  foreach($gzfilestmp as $gzfile) {
764  $tabmatches = array();
765  preg_match('/'.$filter.'/i', $gzfile['name'], $tabmatches);
766 
767  $numsave = intval($tabmatches[1]);
768 
769  $gzfiles[$numsave] = $gzfile;
770  }
771 
772  krsort($gzfiles, SORT_NUMERIC);
773 
774  foreach($gzfiles as $numsave => $dummy) {
775  if (dol_is_file($logpath.'/'.$logname.'.'.($numsave+1).'.gz')) {
776  return -2;
777  }
778 
779  if($numsave >= $nbSaves) {
780  dol_delete_file($logpath.'/'.$logname.'.'.$numsave.'.gz', 0, 0, 0, null, false, 0);
781  } else {
782  dol_move($logpath.'/'.$logname.'.'.$numsave.'.gz', $logpath.'/'.$logname.'.'.($numsave+1).'.gz', 0, 1, 0, 0);
783  }
784  }
785 
786  // Compress current file and recreate it
787 
788  if ($nbSaves > 0) { // If $nbSaves is 1, we keep 1 archive .gz file, If 2, we keep 2 .gz files
789  $gzfilehandle = gzopen($logpath.'/'.$logname.'.1.gz', 'wb9');
790 
791  if (empty($gzfilehandle)) {
792  $this->error = 'Failted to open file '.$logpath.'/'.$logname.'.1.gz';
793  return -3;
794  }
795 
796  $sourcehandle = fopen($logpath.'/'.$logname, 'r');
797 
798  if (empty($sourcehandle)) {
799  $this->error = 'Failed to open file '.$logpath.'/'.$logname;
800  return -4;
801  }
802 
803  while(! feof($sourcehandle)) {
804  gzwrite($gzfilehandle, fread($sourcehandle, 512 * 1024)); // Read 512 kB at a time
805  }
806 
807  fclose($sourcehandle);
808  gzclose($gzfilehandle);
809 
810  @chmod($logpath.'/'.$logname.'.1.gz', octdec(empty($conf->global->MAIN_UMASK)?'0664':$conf->global->MAIN_UMASK));
811  }
812 
813  dol_delete_file($logpath.'/'.$logname, 0, 0, 0, null, false, 0);
814 
815  // Create empty file
816  $newlog = fopen($logpath.'/'.$logname, 'a+');
817  fclose($newlog);
818 
819  //var_dump($logpath.'/'.$logname." - ".octdec(empty($conf->global->MAIN_UMASK)?'0664':$conf->global->MAIN_UMASK));
820  @chmod($logpath.'/'.$logname, octdec(empty($conf->global->MAIN_UMASK)?'0664':$conf->global->MAIN_UMASK));
821  }
822  }
823 
824  $this->output = 'Archive log files (keeping last SYSLOG_FILE_SAVES='.$nbSaves.' files) done.';
825  return 0;
826  }
827 
838  function backupTables($outputfile, $tables='*')
839  {
840  global $db, $langs;
841  global $errormsg;
842 
843  // Set to UTF-8
844  if (is_a($db, 'DoliDBMysqli')) {
846  $db->db->set_charset('utf8');
847  } else {
849  $db->query('SET NAMES utf8');
850  $db->query('SET CHARACTER SET utf8');
851  }
852 
853  //get all of the tables
854  if ($tables == '*')
855  {
856  $tables = array();
857  $result = $db->query('SHOW FULL TABLES WHERE Table_type = \'BASE TABLE\'');
858  while($row = $db->fetch_row($result))
859  {
860  $tables[] = $row[0];
861  }
862  }
863  else
864  {
865  $tables = is_array($tables) ? $tables : explode(',',$tables);
866  }
867 
868  //cycle through
869  $handle = fopen($outputfile, 'w+');
870  if (fwrite($handle, '') === false)
871  {
872  $langs->load("errors");
873  dol_syslog("Failed to open file ".$outputfile,LOG_ERR);
874  $errormsg=$langs->trans("ErrorFailedToWriteInDir");
875  return -1;
876  }
877 
878  // Print headers and global mysql config vars
879  $sqlhead = '';
880  $sqlhead .= "-- ".$db::LABEL." dump via php with Dolibarr ".DOL_VERSION."
881 --
882 -- Host: ".$db->db->host_info." Database: ".$db->database_name."
883 -- ------------------------------------------------------
884 -- Server version ".$db->db->server_info."
885 ;;;;;;;;;;
896 
897 ";
898 
899  if (GETPOST("nobin_disable_fk")) $sqlhead .= "SET FOREIGN_KEY_CHECKS=0;\n";
900  //$sqlhead .= "SET SQL_MODE=\"NO_AUTO_VALUE_ON_ZERO\";\n";
901  if (GETPOST("nobin_use_transaction")) $sqlhead .= "SET AUTOCOMMIT=0;\nSTART TRANSACTION;\n";
902 
903  fwrite($handle, $sqlhead);
904 
905  $ignore = '';
906  if (GETPOST("nobin_sql_ignore")) $ignore = 'IGNORE ';
907  $delayed = '';
908  if (GETPOST("nobin_delayed")) $delayed = 'DELAYED ';
909 
910  // Process each table and print their definition + their datas
911  foreach($tables as $table)
912  {
913  // Saving the table structure
914  fwrite($handle, "\n--\n-- Table structure for table `".$table."`\n--\n");
915 
916  if (GETPOST("nobin_drop")) fwrite($handle,"DROP TABLE IF EXISTS `".$table."`;\n"); // Dropping table if exists prior to re create it
917  fwrite($handle,"/*!40101 SET @saved_cs_client = @@character_set_client */;\n");
918  fwrite($handle,"/*!40101 SET character_set_client = utf8 */;\n");
919  $resqldrop=$db->query('SHOW CREATE TABLE '.$table);
920  $row2 = $db->fetch_row($resqldrop);
921  if (empty($row2[1]))
922  {
923  fwrite($handle, "\n-- WARNING: Show create table ".$table." return empy string when it should not.\n");
924  }
925  else
926  {
927  fwrite($handle,$row2[1].";\n");
928  //fwrite($handle,"/*!40101 SET character_set_client = @saved_cs_client */;\n\n");
929 
930  // Dumping the data (locking the table and disabling the keys check while doing the process)
931  fwrite($handle, "\n--\n-- Dumping data for table `".$table."`\n--\n");
932  if (!GETPOST("nobin_nolocks")) fwrite($handle, "LOCK TABLES `".$table."` WRITE;\n"); // Lock the table before inserting data (when the data will be imported back)
933  if (GETPOST("nobin_disable_fk")) fwrite($handle, "ALTER TABLE `".$table."` DISABLE KEYS;\n");
934  else fwrite($handle, "/*!40000 ALTER TABLE `".$table."` DISABLE KEYS */;\n");
935 
936  $sql='SELECT * FROM '.$table;
937  $result = $db->query($sql);
938  while($row = $db->fetch_row($result))
939  {
940  // For each row of data we print a line of INSERT
941  fwrite($handle,'INSERT '.$delayed.$ignore.'INTO `'.$table.'` VALUES (');
942  $columns = count($row);
943  for($j=0; $j<$columns; $j++) {
944  // 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)
945  if ($row[$j] == null && !is_string($row[$j])) {
946  // IMPORTANT: if the field is NULL we set it NULL
947  $row[$j] = 'NULL';
948  } elseif(is_string($row[$j]) && $row[$j] == '') {
949  // if it's an empty string, we set it as an empty string
950  $row[$j] = "''";
951  } 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)
952  // if it's a number, we return it as-is
953  // $row[$j] = $row[$j];
954  } else { // else for all other cases we escape the value and put quotes around
955  $row[$j] = addslashes($row[$j]);
956  $row[$j] = preg_replace("#\n#", "\\n", $row[$j]);
957  $row[$j] = "'".$row[$j]."'";
958  }
959  }
960  fwrite($handle,implode(',', $row).");\n");
961  }
962  if (GETPOST("nobin_disable_fk")) fwrite($handle, "ALTER TABLE `".$table."` ENABLE KEYS;\n"); // Enabling back the keys/index checking
963  if (!GETPOST("nobin_nolocks")) fwrite($handle, "UNLOCK TABLES;\n"); // Unlocking the table
964  fwrite($handle,"\n\n\n");
965  }
966  }
967 
968  /* Backup Procedure structure*/
969  /*
970  $result = $db->query('SHOW PROCEDURE STATUS');
971  if ($db->num_rows($result) > 0)
972  {
973  while ($row = $db->fetch_row($result)) { $procedures[] = $row[1]; }
974  foreach($procedures as $proc)
975  {
976  fwrite($handle,"DELIMITER $$\n\n");
977  fwrite($handle,"DROP PROCEDURE IF EXISTS '$name'.'$proc'$$\n");
978  $resqlcreateproc=$db->query("SHOW CREATE PROCEDURE '$proc'");
979  $row2 = $db->fetch_row($resqlcreateproc);
980  fwrite($handle,"\n".$row2[2]."$$\n\n");
981  fwrite($handle,"DELIMITER ;\n\n");
982  }
983  }
984  */
985  /* Backup Procedure structure*/
986 
987  // Write the footer (restore the previous database settings)
988  $sqlfooter="\n\n";
989  if (GETPOST("nobin_use_transaction")) $sqlfooter .= "COMMIT;\n";
990  if (GETPOST("nobin_disable_fk")) $sqlfooter .= "SET FOREIGN_KEY_CHECKS=1;\n";
991  $sqlfooter.="\n\n-- Dump completed on ".date('Y-m-d G-i-s');
992  fwrite($handle, $sqlfooter);
993 
994  fclose($handle);
995 
996  return 1;
997  }
998 }
dumpDatabase($compression='none', $type='auto', $usedefault=1, $file='auto', $keeplastnfiles=0, $execmethod=0)
Make a backup of database CAN BE A CRON TASK.
Class to manage utility methods.
Definition: utils.class.php:28
dol_compress_file($inputfile, $outputfile, $mode="gz")
Compress a file.
Definition: files.lib.php:1877
GETPOST($paramname, $check='none', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
dol_filesize($pathoffile)
Return size of a file.
Definition: files.lib.php:552
executeCLI($command, $outputfile, $execmethod=0)
Execute a CLI command.
dol_print_error($db='', $error='', $errors=null)
Affiche message erreur system avec toutes les informations pour faciliter le diagnostic et la remonte...
dol_is_dir($folder)
Test if filename is a directory.
Definition: files.lib.php:438
compressSyslogs()
This saves syslog files and compresses older ones.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvirus=0, $indexdatabase=1)
Move a file into another name.
Definition: files.lib.php:814
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='')
Write log message into outputs.
if(! function_exists('dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories) ...
Definition: files.lib.php:1273
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1)
Remove a file or several files with a mask.
Definition: files.lib.php:1139
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:59
dol_now($mode='gmt')
Return date for now.
dol_is_file($pathoffile)
Return if path is a file.
Definition: files.lib.php:451
purgeFiles($choice='tempfilesold')
Purge files into directory of data files.
Definition: utils.class.php:56
generateDoc($module)
Generate documentation of a Module.
dol_mkdir($dir, $dataroot='', $newmask=null)
Creation of a directory (this can create recursive subdir)
__construct($db)
Constructor.
Definition: utils.class.php:43
Class to manage ECM directories.