FIX Several pb in export of documents

FIX Must escape shell
FIX Must exclude logs and some dirs for compressed backup
FIX gzip and bzip2 must use option -f
This commit is contained in:
Laurent Destailleur 2019-09-03 22:39:24 +02:00 committed by atm-greg
parent f4df3d01b2
commit 82ace4b4ef
4 changed files with 520 additions and 372 deletions

View File

@ -29,15 +29,15 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
$langs->load("admin"); $langs->load("admin");
$action=GETPOST('action','alpha'); $action=GETPOST('action', 'alpha');
$sortfield = GETPOST('sortfield','alpha'); $sortfield = GETPOST('sortfield', 'alpha');
$sortorder = GETPOST('sortorder','alpha'); $sortorder = GETPOST('sortorder', 'alpha');
$page = GETPOST('page','int'); $page = GETPOST('page', 'int');
if (! $sortorder) $sortorder="DESC"; if (! $sortorder) $sortorder="DESC";
if (! $sortfield) $sortfield="date"; if (! $sortfield) $sortfield="date";
if (empty($page) || $page == -1) { $page = 0; } if (empty($page) || $page == -1) { $page = 0; }
$limit = GETPOST('limit','int')?GETPOST('limit','int'):$conf->liste_limit; $limit = GETPOST('limit', 'int')?GETPOST('limit', 'int'):$conf->liste_limit;
$offset = $limit * $page; $offset = $limit * $page;
if (! $user->admin) if (! $user->admin)
@ -50,10 +50,20 @@ if (! $user->admin)
if ($action == 'delete') if ($action == 'delete')
{ {
$file=$conf->admin->dir_output.'/backup/'.basename(GETPOST('urlfile', 'alpha')); if (preg_match('/^backup\//', GETPOST('urlfile', 'alpha')))
$ret=dol_delete_file($file, 1); {
if ($ret) setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile')), null, 'mesgs'); $file=$conf->admin->dir_output.'/backup/'.basename(GETPOST('urlfile', 'alpha'));
else setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile')), null, 'errors'); $ret=dol_delete_file($file, 1);
if ($ret) setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile')), null, 'mesgs');
else setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile')), null, 'errors');
}
else
{
$file=$conf->admin->dir_output.'/documents/'.basename(GETPOST('urlfile', 'alpha'));
$ret=dol_delete_file($file, 1);
if ($ret) setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile')), null, 'mesgs');
else setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile')), null, 'errors');
}
$action=''; $action='';
} }
@ -70,7 +80,7 @@ $type=$db->type;
//var_dump($db); //var_dump($db);
$help_url='EN:Backups|FR:Sauvegardes|ES:Copias_de_seguridad'; $help_url='EN:Backups|FR:Sauvegardes|ES:Copias_de_seguridad';
llxHeader('','',$help_url); llxHeader('', '', $help_url);
?> ?>
<script type="text/javascript"> <script type="text/javascript">
@ -110,11 +120,11 @@ jQuery(document).ready(function() {
</script> </script>
<?php <?php
print load_fiche_titre($langs->trans("Backup"),'','title_setup'); print load_fiche_titre($langs->trans("Backup"), '', 'title_setup');
//print_barre_liste($langs->trans("Backup"), '', '', '', '', '', $langs->trans("BackupDesc",DOL_DATA_ROOT), 0, 0, 'title_setup'); //print_barre_liste($langs->trans("Backup"), '', '', '', '', '', $langs->trans("BackupDesc",DOL_DATA_ROOT), 0, 0, 'title_setup');
print '<div class="center">'; print '<div class="center opacitymedium">';
print $langs->trans("BackupDesc",DOL_DATA_ROOT); print $langs->trans("BackupDesc", DOL_DATA_ROOT);
print '</div>'; print '</div>';
print '<br>'; print '<br>';
@ -128,7 +138,7 @@ print '<br>';
<fieldset id="fieldsetexport"><legend class="legendforfieldsetstep" style="font-size: 3em">1</legend> <fieldset id="fieldsetexport"><legend class="legendforfieldsetstep" style="font-size: 3em">1</legend>
<?php <?php
print $langs->trans("BackupDesc3",$dolibarr_main_db_name).'<br>'; print $langs->trans("BackupDesc3", $dolibarr_main_db_name).'<br>';
//print $langs->trans("BackupDescY").'<br>'; //print $langs->trans("BackupDescY").'<br>';
print '<br>'; print '<br>';
?> ?>
@ -166,7 +176,7 @@ print '<tr '.$bc[false].'><td style="padding-left: 8px">';
</div> </div>
<?php <?php
} }
else if (in_array($type, array('pgsql'))) elseif (in_array($type, array('pgsql')))
{ {
?> ?>
<div class="formelementrow"><input type="radio" name="what" value="postgresql" id="radio_dump_postgresql" /> <div class="formelementrow"><input type="radio" name="what" value="postgresql" id="radio_dump_postgresql" />
@ -211,6 +221,7 @@ print '<tr '.$bc[false].'><td style="padding-left: 8px">';
<div class="formelementrow"><input type="checkbox" <div class="formelementrow"><input type="checkbox"
name="use_transaction" value="yes" id="checkbox_use_transaction" /> <label name="use_transaction" value="yes" id="checkbox_use_transaction" /> <label
for="checkbox_use_transaction"> <?php echo $langs->trans("UseTransactionnalMode"); ?></label> for="checkbox_use_transaction"> <?php echo $langs->trans("UseTransactionnalMode"); ?></label>
</div> </div>
<?php if (! empty($conf->global->MYSQL_OLD_OPTION_DISABLE_FK)) { ?> <?php if (! empty($conf->global->MYSQL_OLD_OPTION_DISABLE_FK)) { ?>
@ -233,14 +244,6 @@ print '<tr '.$bc[false].'><td style="padding-left: 8px">';
<option value="ORACLE">ORACLE</option> <option value="ORACLE">ORACLE</option>
<option value="POSTGRESQL">POSTGRESQL</option> <option value="POSTGRESQL">POSTGRESQL</option>
</select> <br> </select> <br>
<input type="checkbox" name="use_mysql_quick_param" value="yes" id="checkbox_use_quick" />
<label for="checkbox_use_quick">
<?php echo $form->textwithpicto(
$langs->trans('ExportUseMySQLQuickParameter'),
$langs->trans('ExportUseMySQLQuickParameterHelp')
); ?>
</label>
<br/>
<!-- <input type="checkbox" name="drop_database" value="yes" <!-- <input type="checkbox" name="drop_database" value="yes"
id="checkbox_drop_database" /> <label for="checkbox_drop_database"><?php echo $langs->trans("AddDropDatabase"); ?></label> id="checkbox_drop_database" /> <label for="checkbox_drop_database"><?php echo $langs->trans("AddDropDatabase"); ?></label>
--> -->
@ -453,8 +456,10 @@ print "\n";
<br> <br>
<div align="center"><input type="submit" class="button" <div class="center">
value="<?php echo $langs->trans("GenerateBackup") ?>" id="buttonGo" /><br> <input type="submit" class="button reposition" value="<?php echo $langs->trans("GenerateBackup") ?>" id="buttonGo">
<input type="hidden" name="page_y" value="<?php echo GETPOST('page_y', 'int'); ?>">
<br>
<br> <br>
<?php <?php
@ -466,7 +471,7 @@ if (! empty($_SESSION["commandbackuplastdone"]))
//print $paramclear; //print $paramclear;
// Now run command and show result // Now show result
print '<b>'.$langs->trans("BackupResult").':</b> '; print '<b>'.$langs->trans("BackupResult").':</b> ';
print $_SESSION["commandbackupresult"]; print $_SESSION["commandbackupresult"];
@ -476,7 +481,7 @@ if (! empty($_SESSION["commandbackuplastdone"]))
} }
if (! empty($_SESSION["commandbackuptorun"])) if (! empty($_SESSION["commandbackuptorun"]))
{ {
print '<br><font class="warning">'.$langs->trans("YouMustRunCommandFromCommandLineAfterLoginToUser",$dolibarr_main_db_user,$dolibarr_main_db_user).':</font><br>'."\n"; print '<br><font class="warning">'.$langs->trans("YouMustRunCommandFromCommandLineAfterLoginToUser", $dolibarr_main_db_user, $dolibarr_main_db_user).':</font><br>'."\n";
print '<textarea id="commandbackuptoruntext" rows="'.ROWS_2.'" class="centpercent">'.$_SESSION["commandbackuptorun"].'</textarea><br>'."\n"; print '<textarea id="commandbackuptoruntext" rows="'.ROWS_2.'" class="centpercent">'.$_SESSION["commandbackuptorun"].'</textarea><br>'."\n";
print ajax_autoselect("commandbackuptoruntext", 0); print ajax_autoselect("commandbackuptoruntext", 0);
print '<br>'; print '<br>';
@ -505,8 +510,8 @@ print '</table>';
<div class="ficheaddleft"> <div class="ficheaddleft">
<?php <?php
$filearray=dol_dir_list($conf->admin->dir_output.'/backup','files',0,'','',$sortfield,(strtolower($sortorder)=='asc'?SORT_ASC:SORT_DESC),1); $filearray=dol_dir_list($conf->admin->dir_output.'/backup', 'files', 0, '', '', $sortfield, (strtolower($sortorder)=='asc'?SORT_ASC:SORT_DESC), 1);
$result=$formfile->list_of_documents($filearray,null,'systemtools','',1,'backup/',1,0,$langs->trans("NoBackupFileAvailable"),0,$langs->trans("PreviousDumpFiles")); $result=$formfile->list_of_documents($filearray, null, 'systemtools', '', 1, 'backup/', 1, 0, $langs->trans("NoBackupFileAvailable"), 0, $langs->trans("PreviousDumpFiles"));
print '<br>'; print '<br>';
?> ?>
@ -526,7 +531,7 @@ print '<br>';
<fieldset><legend class="legendforfieldsetstep" style="font-size: 3em">2</legend> <fieldset><legend class="legendforfieldsetstep" style="font-size: 3em">2</legend>
<?php <?php
print $langs->trans("BackupDesc2",DOL_DATA_ROOT).'<br>'; print $langs->trans("BackupDesc2", DOL_DATA_ROOT).'<br>';
print $langs->trans("BackupDescX").'<br><br>'; print $langs->trans("BackupDescX").'<br><br>';
?> ?>
@ -582,7 +587,7 @@ print "\n";
?> ?>
<br> <br>
<div align="center"><input type="submit" class="button" <div class="center"><input type="submit" class="button reposition"
value="<?php echo $langs->trans("GenerateBackup") ?>" id="buttonGo" /><br> value="<?php echo $langs->trans("GenerateBackup") ?>" id="buttonGo" /><br>
<br> <br>
</div> </div>
@ -593,8 +598,8 @@ print "\n";
<div class="ficheaddleft"> <div class="ficheaddleft">
<?php <?php
$filearray=dol_dir_list($conf->admin->dir_output.'/documents','files',0,'','',$sortfield,(strtolower($sortorder)=='asc'?SORT_ASC:SORT_DESC),1); $filearray=dol_dir_list($conf->admin->dir_output.'/documents', 'files', 0, '', '', $sortfield, (strtolower($sortorder)=='asc'?SORT_ASC:SORT_DESC), 1);
$result=$formfile->list_of_documents($filearray,null,'systemtools','',1,'documents/',1,0,$langs->trans("NoBackupFileAvailable"),0,$langs->trans("PreviousDumpFiles")); $result=$formfile->list_of_documents($filearray, null, 'systemtools', '', 1, 'documents/', 1, 0, $langs->trans("NoBackupFileAvailable"), 0, $langs->trans("PreviousDumpFiles"));
print '<br>'; print '<br>';
?> ?>
@ -605,9 +610,6 @@ print '<br>';
</fieldset> </fieldset>
</form> </form>
<?php <?php
// End of page // End of page

View File

@ -30,22 +30,22 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
$langs->load("admin"); $langs->load("admin");
$action=GETPOST('action','alpha'); $action=GETPOST('action', 'alpha');
$what=GETPOST('what','alpha'); $what=GETPOST('what', 'alpha');
$export_type=GETPOST('export_type','alpha'); $export_type=GETPOST('export_type', 'alpha');
$file=GETPOST('zipfilename_template','alpha'); $file=GETPOST('zipfilename_template', 'alpha');
$compression = GETPOST('compression'); $compression = GETPOST('compression');
$file = dol_sanitizeFileName($file); $file = dol_sanitizeFileName($file);
$sortfield = GETPOST('sortfield','alpha'); $sortfield = GETPOST('sortfield', 'alpha');
$sortorder = GETPOST('sortorder','alpha'); $sortorder = GETPOST('sortorder', 'alpha');
$page = GETPOST("page",'int'); $page = GETPOST("page", 'int');
if (! $sortorder) $sortorder="DESC"; if (! $sortorder) $sortorder="DESC";
if (! $sortfield) $sortfield="date"; if (! $sortfield) $sortfield="date";
if ($page < 0) { $page = 0; } if ($page < 0) { $page = 0; }
elseif (empty($page)) $page = 0; elseif (empty($page)) $page = 0;
$limit = GETPOST('limit','int')?GETPOST('limit','int'):$conf->liste_limit; $limit = GETPOST('limit', 'int')?GETPOST('limit', 'int'):$conf->liste_limit;
$offset = $limit * $page; $offset = $limit * $page;
if (! $user->admin) accessforbidden(); if (! $user->admin) accessforbidden();
@ -112,21 +112,27 @@ $utils = new Utils($db);
if ($compression == 'zip') if ($compression == 'zip')
{ {
$ret = dol_compress_dir(DOL_DATA_ROOT, $outputdir."/".$file, $compression); $ret = dol_compress_dir(DOL_DATA_ROOT, $outputdir."/".$file, $compression, '/(\.log|\/temp\/|documents\/admin\/documents\/)/');
if ($ret < 0) if ($ret < 0)
{ {
$errormsg = $langs->trans("ErrorFailedToWriteInDir",$outputfile); $errormsg = $langs->trans("ErrorFailedToWriteInDir", $outputdir);
} }
} }
elseif (in_array($compression, array('gz', 'bz'))) elseif (in_array($compression, array('gz', 'bz')))
{ {
$file = substr($file, 0, strrpos($file, '.')); $userlogin = ($user->login ? $user->login : 'unknown');
$file .= '.tar';
$cmd = 'tar -cf '.$outputdir."/".$file." --exclude=documents/admin/documents -C ".DOL_DATA_ROOT." ".DOL_DATA_ROOT."/../documents/";
exec($cmd, $out, $retval);
//var_dump($cmd, DOL_DATA_ROOT);exit;
if ($retval != 0) $outputfile = $conf->admin->dir_temp.'/export_files.'.$userlogin.'.out'; // File used with popen method
$file = substr($file, 0, strrpos($file, '.'));
$file .= '.tar';
// We also exclude '/temp/' dir and 'documents/admin/documents'
$cmd = "tar -cf ".$outputdir."/".$file." --exclude-vcs --exclude 'temp' --exclude 'dolibarr.log' --exclude='documents/admin/documents' -C ".dirname(DOL_DATA_ROOT)." ".basename(DOL_DATA_ROOT);
$result = $utils->executeCLI($cmd, $outputfile);
$retval = $result['error'];
if ($result['result'] || ! empty($retval))
{ {
$langs->load("errors"); $langs->load("errors");
dol_syslog("Documents tar retval after exec=".$retval, LOG_ERR); dol_syslog("Documents tar retval after exec=".$retval, LOG_ERR);
@ -136,15 +142,17 @@ elseif (in_array($compression, array('gz', 'bz')))
{ {
if ($compression == 'gz') if ($compression == 'gz')
{ {
$cmd = "gzip " . $outputdir."/".$file; $cmd = "gzip -f " . $outputdir."/".$file;
} }
if ($compression == 'bz') if ($compression == 'bz')
{ {
$cmd = "bzip2 " . $outputdir."/".$file; $cmd = "bzip2 -f " . $outputdir."/".$file;
} }
exec($cmd, $out, $retval); $result = $utils->executeCLI($cmd, $outputfile);
if ($retval != 0)
$retval = $result['error'];
if ($result['result'] || ! empty($retval))
{ {
$errormsg = 'Error '.$compression.' generation return '.$retval; $errormsg = 'Error '.$compression.' generation return '.$retval;
unlink($outputdir."/".$file); unlink($outputdir."/".$file);
@ -166,4 +174,3 @@ header("Location: dolibarr_export.php");
$time_end = time(); $time_end = time();
$db->close(); $db->close();

View File

@ -32,15 +32,15 @@ class Utils
*/ */
public $db; public $db;
var $output; // Used by Cron method to return message public $output; // Used by Cron method to return message
var $result; // Used by Cron method to return data public $result; // Used by Cron method to return data
/** /**
* Constructor * Constructor
* *
* @param DoliDB $db Database handler * @param DoliDB $db Database handler
*/ */
function __construct($db) public function __construct($db)
{ {
$this->db = $db; $this->db = $db;
} }
@ -54,7 +54,7 @@ class Utils
* @param int $nbsecondsold Nb of seconds old to accept deletion of a directory if $choice is 'tempfilesold' * @param int $nbsecondsold Nb of seconds old to accept deletion of a directory if $choice is 'tempfilesold'
* @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK) * @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK)
*/ */
function purgeFiles($choice = 'tempfilesold', $nbsecondsold = 86400) public function purgeFiles($choice = 'tempfilesold', $nbsecondsold = 86400)
{ {
global $conf, $langs, $dolibarr_main_data_root; global $conf, $langs, $dolibarr_main_data_root;
@ -106,7 +106,7 @@ class Utils
if (! empty($conf->syslog->enabled)) if (! empty($conf->syslog->enabled))
{ {
$filelog=$conf->global->SYSLOG_FILE; $filelog=$conf->global->SYSLOG_FILE;
$filelog=preg_replace('/DOL_DATA_ROOT/i',DOL_DATA_ROOT,$filelog); $filelog=preg_replace('/DOL_DATA_ROOT/i', DOL_DATA_ROOT, $filelog);
$alreadyincluded=false; $alreadyincluded=false;
foreach ($filesarray as $tmpcursor) foreach ($filesarray as $tmpcursor)
@ -193,7 +193,7 @@ class Utils
* @param int $execmethod 0=Use default method (that is 1 by default), 1=Use the PHP 'exec', 2=Use the 'popen' method * @param int $execmethod 0=Use default method (that is 1 by default), 1=Use the PHP 'exec', 2=Use the 'popen' method
* @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK) * @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK)
*/ */
function dumpDatabase($compression='none', $type='auto', $usedefault=1, $file='auto', $keeplastnfiles=0, $execmethod=0) public function dumpDatabase($compression = 'none', $type = 'auto', $usedefault = 1, $file = 'auto', $keeplastnfiles = 0, $execmethod = 0)
{ {
global $db, $conf, $langs, $dolibarr_main_data_root; global $db, $conf, $langs, $dolibarr_main_data_root;
global $dolibarr_main_db_name, $dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_port, $dolibarr_main_db_pass; global $dolibarr_main_db_name, $dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_port, $dolibarr_main_db_pass;
@ -251,8 +251,8 @@ class Utils
// Parameteres execution // Parameteres execution
$command = $cmddump; $command = $cmddump;
$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. $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.
if (preg_match("/\s/",$command)) $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 if (preg_match("/\s/", $command)) $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
//$param=escapeshellarg($dolibarr_main_db_name)." -h ".escapeshellarg($dolibarr_main_db_host)." -u ".escapeshellarg($dolibarr_main_db_user)." -p".escapeshellarg($dolibarr_main_db_pass); //$param=escapeshellarg($dolibarr_main_db_name)." -h ".escapeshellarg($dolibarr_main_db_host)." -u ".escapeshellarg($dolibarr_main_db_user)." -p".escapeshellarg($dolibarr_main_db_pass);
$param=$dolibarr_main_db_name." -h ".$dolibarr_main_db_host; $param=$dolibarr_main_db_name." -h ".$dolibarr_main_db_host;
@ -262,7 +262,6 @@ class Utils
if (GETPOST("disable_fk", "alpha") || $usedefault) $param.=" -K"; if (GETPOST("disable_fk", "alpha") || $usedefault) $param.=" -K";
if (GETPOST("sql_compat", "alpha") && GETPOST("sql_compat", "alpha") != 'NONE') $param.=" --compatible=".escapeshellarg(GETPOST("sql_compat", "alpha")); if (GETPOST("sql_compat", "alpha") && GETPOST("sql_compat", "alpha") != 'NONE') $param.=" --compatible=".escapeshellarg(GETPOST("sql_compat", "alpha"));
if (GETPOST("drop_database", "alpha")) $param.=" --add-drop-database"; if (GETPOST("drop_database", "alpha")) $param.=" --add-drop-database";
if (GETPOST("use_mysql_quick_param", "alpha"))$param.=" --quick";
if (GETPOST("sql_structure", "alpha") || $usedefault) if (GETPOST("sql_structure", "alpha") || $usedefault)
{ {
if (GETPOST("drop", "alpha") || $usedefault) $param.=" --add-drop-table=TRUE"; if (GETPOST("drop", "alpha") || $usedefault) $param.=" --add-drop-table=TRUE";
@ -292,8 +291,8 @@ class Utils
$paramclear=$param; $paramclear=$param;
if (! empty($dolibarr_main_db_pass)) if (! empty($dolibarr_main_db_pass))
{ {
$paramcrypted.=' -p"'.preg_replace('/./i','*',$dolibarr_main_db_pass).'"'; $paramcrypted.=' -p"'.preg_replace('/./i', '*', $dolibarr_main_db_pass).'"';
$paramclear.=' -p"'.str_replace(array('"','`'),array('\"','\`'),$dolibarr_main_db_pass).'"'; $paramclear.=' -p"'.str_replace(array('"','`'), array('\"','\`'), $dolibarr_main_db_pass).'"';
} }
$errormsg=''; $errormsg='';
@ -317,27 +316,29 @@ class Utils
// TODO Replace with executeCLI function // TODO Replace with executeCLI function
if ($execmethod == 1) if ($execmethod == 1)
{ {
exec($fullcommandclear, $readt, $retval); $output_arr = array(); $retval = null;
$result = $retval; exec($fullcommandclear, $output_arr, $retval);
if ($retval != 0) if ($retval != 0)
{ {
$langs->load("errors"); $langs->load("errors");
dol_syslog("Datadump retval after exec=".$retval, LOG_ERR); dol_syslog("Datadump retval after exec=".$retval, LOG_ERR);
$error = 'Error '.$retval; $errormsg = 'Error '.$retval;
$ok=0; $ok=0;
} }
else else
{ {
$i=0; $i=0;
if (!empty($readt)) if (!empty($output_arr))
foreach($readt as $key=>$read)
{ {
$i++; // output line number foreach($output_arr as $key => $read)
if ($i == 1 && preg_match('/Warning.*Using a password/i', $read)) continue; {
fwrite($handle, $read.($execmethod == 2 ? '' : "\n")); $i++; // output line number
if (preg_match('/'.preg_quote('-- Dump completed').'/i',$read)) $ok=1; if ($i == 1 && preg_match('/Warning.*Using a password/i', $read)) continue;
elseif (preg_match('/'.preg_quote('SET SQL_NOTES=@OLD_SQL_NOTES').'/i',$read)) $ok=1; fwrite($handle, $read.($execmethod == 2 ? '' : "\n"));
if (preg_match('/'.preg_quote('-- Dump completed').'/i', $read)) $ok=1;
elseif (preg_match('/'.preg_quote('SET SQL_NOTES=@OLD_SQL_NOTES').'/i', $read)) $ok=1;
}
} }
} }
} }
@ -351,9 +352,9 @@ class Utils
$read = fgets($handlein); $read = fgets($handlein);
// Exclude warning line we don't want // Exclude warning line we don't want
if ($i == 1 && preg_match('/Warning.*Using a password/i', $read)) continue; if ($i == 1 && preg_match('/Warning.*Using a password/i', $read)) continue;
fwrite($handle,$read); fwrite($handle, $read);
if (preg_match('/'.preg_quote('-- Dump completed').'/i',$read)) $ok=1; if (preg_match('/'.preg_quote('-- Dump completed').'/i', $read)) $ok=1;
elseif (preg_match('/'.preg_quote('SET SQL_NOTES=@OLD_SQL_NOTES').'/i',$read)) $ok=1; elseif (preg_match('/'.preg_quote('SET SQL_NOTES=@OLD_SQL_NOTES').'/i', $read)) $ok=1;
} }
pclose($handlein); pclose($handlein);
} }
@ -369,7 +370,7 @@ class Utils
else else
{ {
$langs->load("errors"); $langs->load("errors");
dol_syslog("Failed to open file ".$outputfile,LOG_ERR); dol_syslog("Failed to open file ".$outputfile, LOG_ERR);
$errormsg=$langs->trans("ErrorFailedToWriteInDir"); $errormsg=$langs->trans("ErrorFailedToWriteInDir");
} }
@ -380,18 +381,18 @@ class Utils
if ($handle) if ($handle)
{ {
// Get 2048 first chars of error message. // Get 2048 first chars of error message.
$errormsg = fgets($handle,2048); $errormsg = fgets($handle, 2048);
// Close file // Close file
if ($compression == 'none') fclose($handle); if ($compression == 'none') fclose($handle);
if ($compression == 'gz') gzclose($handle); if ($compression == 'gz') gzclose($handle);
if ($compression == 'bz') bzclose($handle); if ($compression == 'bz') bzclose($handle);
if ($ok && preg_match('/^-- MySql/i',$errormsg)) $errormsg=''; // Pas erreur if ($ok && preg_match('/^-- MySql/i', $errormsg)) $errormsg=''; // Pas erreur
else else
{ {
// Renommer fichier sortie en fichier erreur // Renommer fichier sortie en fichier erreur
//print "$outputfile -> $outputerror"; //print "$outputfile -> $outputerror";
@dol_delete_file($outputerror, 1, 0, 0, null, false, 0); @dol_delete_file($outputerror, 1, 0, 0, null, false, 0);
@rename($outputfile,$outputerror); @rename($outputfile, $outputerror);
// Si safe_mode on et command hors du parametre exec, on a un fichier out vide donc errormsg vide // Si safe_mode on et command hors du parametre exec, on a un fichier out vide donc errormsg vide
if (! $errormsg) if (! $errormsg)
{ {
@ -450,8 +451,8 @@ class Utils
// Parameteres execution // Parameteres execution
$command = $cmddump; $command = $cmddump;
$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. $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.
if (preg_match("/\s/",$command)) $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 if (preg_match("/\s/", $command)) $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
//$param=escapeshellarg($dolibarr_main_db_name)." -h ".escapeshellarg($dolibarr_main_db_host)." -u ".escapeshellarg($dolibarr_main_db_user)." -p".escapeshellarg($dolibarr_main_db_pass); //$param=escapeshellarg($dolibarr_main_db_name)." -h ".escapeshellarg($dolibarr_main_db_host)." -u ".escapeshellarg($dolibarr_main_db_user)." -p".escapeshellarg($dolibarr_main_db_pass);
//$param="-F c"; //$param="-F c";
@ -515,7 +516,7 @@ class Utils
* @param int $execmethod 0=Use default method (that is 1 by default), 1=Use the PHP 'exec', 2=Use the 'popen' method * @param int $execmethod 0=Use default method (that is 1 by default), 1=Use the PHP 'exec', 2=Use the 'popen' method
* @return array array('result'=>...,'output'=>...,'error'=>...). result = 0 means OK. * @return array array('result'=>...,'output'=>...,'error'=>...). result = 0 means OK.
*/ */
function executeCLI($command, $outputfile, $execmethod=0) public function executeCLI($command, $outputfile, $execmethod = 0)
{ {
global $conf, $langs; global $conf, $langs;
@ -535,6 +536,7 @@ class Utils
if ($execmethod == 1) if ($execmethod == 1)
{ {
$retval = null;
exec($command, $output_arr, $retval); exec($command, $output_arr, $retval);
$result = $retval; $result = $retval;
if ($retval != 0) if ($retval != 0)
@ -546,7 +548,6 @@ class Utils
} }
if ($execmethod == 2) // With this method, there is no way to get the return code, only output if ($execmethod == 2) // With this method, there is no way to get the return code, only output
{ {
$ok=0;
$handle = fopen($outputfile, 'w+b'); $handle = fopen($outputfile, 'w+b');
if ($handle) if ($handle)
{ {
@ -555,7 +556,7 @@ class Utils
while (!feof($handlein)) while (!feof($handlein))
{ {
$read = fgets($handlein); $read = fgets($handlein);
fwrite($handle,$read); fwrite($handle, $read);
$output_arr[]=$read; $output_arr[]=$read;
} }
pclose($handlein); pclose($handlein);
@ -584,14 +585,15 @@ class Utils
* @param string $module Module name * @param string $module Module name
* @return int <0 if KO, >0 if OK * @return int <0 if KO, >0 if OK
*/ */
function generateDoc($module) public function generateDoc($module)
{ {
global $conf, $langs; global $conf, $langs, $user, $mysoc;
global $dirins; global $dirins;
$error = 0; $error = 0;
$modulelowercase=strtolower($module); $modulelowercase=strtolower($module);
$now=dol_now();
// Dir for module // Dir for module
$dir = $dirins.'/'.$modulelowercase; $dir = $dirins.'/'.$modulelowercase;
@ -621,11 +623,12 @@ class Utils
exit; exit;
} }
$arrayversion=explode('.',$moduleobj->version,3); $arrayversion=explode('.', $moduleobj->version, 3);
if (count($arrayversion)) if (count($arrayversion))
{ {
$FILENAMEASCII=strtolower($module).'.asciidoc'; $FILENAMEASCII=strtolower($module).'.asciidoc';
$FILENAMEDOC=strtolower($module).'.html'; // TODO Use/text PDF $FILENAMEDOC=strtolower($module).'.html';
$FILENAMEDOCPDF=strtolower($module).'.pdf';
$dirofmodule = dol_buildpath(strtolower($module), 0); $dirofmodule = dol_buildpath(strtolower($module), 0);
$dirofmoduledoc = dol_buildpath(strtolower($module), 0).'/doc'; $dirofmoduledoc = dol_buildpath(strtolower($module), 0).'/doc';
@ -641,13 +644,25 @@ class Utils
return -1; return -1;
} }
$conf->global->MODULEBUILDER_ASCIIDOCTOR='asciidoctor'; if (empty($conf->global->MODULEBUILDER_ASCIIDOCTOR) && empty($conf->global->MODULEBUILDER_ASCIIDOCTORPDF))
if (empty($conf->global->MODULEBUILDER_ASCIIDOCTOR))
{ {
$this->error = 'Setup of module ModuleBuilder not complete'; $this->error = 'Setup of module ModuleBuilder not complete';
return -1; return -1;
} }
// Copy some files into temp directory, so instruction include::ChangeLog.md[] will works inside the asciidoc file.
dol_copy($dirofmodule.'/README.md', $dirofmoduletmp.'/README.md', 0, 1);
dol_copy($dirofmodule.'/ChangeLog.md', $dirofmoduletmp.'/ChangeLog.md', 0, 1);
// Replace into README.md and ChangeLog.md (in case they are included into documentation with tag __README__ or __CHANGELOG__)
$arrayreplacement=array();
$arrayreplacement['/^#\s.*/m']=''; // Remove first level of title into .md files
$arrayreplacement['/^#/m']='##'; // Add on # to increase level
dolReplaceInFile($dirofmoduletmp.'/README.md', $arrayreplacement, '', 0, 0, 1);
dolReplaceInFile($dirofmoduletmp.'/ChangeLog.md', $arrayreplacement, '', 0, 0, 1);
$destfile=$dirofmoduletmp.'/'.$FILENAMEASCII; $destfile=$dirofmoduletmp.'/'.$FILENAMEASCII;
$fhandle = fopen($destfile, 'w+'); $fhandle = fopen($destfile, 'w+');
@ -680,35 +695,48 @@ class Utils
$i++; $i++;
} }
fwrite($fhandle, "\n\n\n== DATA SPECIFICATIONS...\n\n");
// TODO
fwrite($fhandle, "TODO...");
fwrite($fhandle, "\n\n\n== CHANGELOG...\n\n");
// TODO
fwrite($fhandle, "TODO...");
fclose($fhandle); fclose($fhandle);
}
// Copy some files into temp directory $contentreadme=file_get_contents($dirofmoduletmp.'/README.md');
dol_copy($dirofmodule.'/README.md', $dirofmoduletmp.'/README.md', 0, 1); $contentchangelog=file_get_contents($dirofmoduletmp.'/ChangeLog.md');
dol_copy($dirofmodule.'/ChangeLog.md', $dirofmoduletmp.'/ChangeLog.md', 0, 1);
include DOL_DOCUMENT_ROOT.'/core/lib/parsemd.lib.php';
//var_dump($phpfileval['fullname']);
$arrayreplacement=array(
'mymodule'=>strtolower($module),
'MyModule'=>$module,
'MYMODULE'=>strtoupper($module),
'My module'=>$module,
'my module'=>$module,
'Mon module'=>$module,
'mon module'=>$module,
'htdocs/modulebuilder/template'=>strtolower($module),
'__MYCOMPANY_NAME__'=>$mysoc->name,
'__KEYWORDS__'=>$module,
'__USER_FULLNAME__'=>$user->getFullName($langs),
'__USER_EMAIL__'=>$user->email,
'__YYYY-MM-DD__'=>dol_print_date($now, 'dayrfc'),
'---Put here your own copyright and developer email---'=>dol_print_date($now, 'dayrfc').' '.$user->getFullName($langs).($user->email?' <'.$user->email.'>':''),
'__DATA_SPECIFICATION__'=>'Not yet available',
'__README__'=>dolMd2Asciidoc($contentreadme),
'__CHANGELOG__'=>dolMd2Asciidoc($contentchangelog),
);
dolReplaceInFile($destfile, $arrayreplacement);
}
// Launch doc generation // Launch doc generation
$currentdir = getcwd(); $currentdir = getcwd();
chdir($dirofmodule); chdir($dirofmodule);
require_once DOL_DOCUMENT_ROOT.'/core/class/utils.class.php';
$utils = new Utils($db);
// Build HTML doc
$command=$conf->global->MODULEBUILDER_ASCIIDOCTOR.' '.$destfile.' -n -o '.$dirofmoduledoc.'/'.$FILENAMEDOC; $command=$conf->global->MODULEBUILDER_ASCIIDOCTOR.' '.$destfile.' -n -o '.$dirofmoduledoc.'/'.$FILENAMEDOC;
$outfile=$dirofmoduletmp.'/out.tmp'; $outfile=$dirofmoduletmp.'/out.tmp';
require_once DOL_DOCUMENT_ROOT.'/core/class/utils.class.php';
$utils = new Utils($this->db);
$resarray = $utils->executeCLI($command, $outfile); $resarray = $utils->executeCLI($command, $outfile);
if ($resarray['result'] != '0') if ($resarray['result'] != '0')
{ {
@ -716,6 +744,16 @@ class Utils
} }
$result = ($resarray['result'] == 0) ? 1 : 0; $result = ($resarray['result'] == 0) ? 1 : 0;
// Build PDF doc
$command=$conf->global->MODULEBUILDER_ASCIIDOCTORPDF.' '.$destfile.' -n -o '.$dirofmoduledoc.'/'.$FILENAMEDOCPDF;
$outfile=$dirofmoduletmp.'/outpdf.tmp';
$resarray = $utils->executeCLI($command, $outfile);
if ($resarray['result'] != '0')
{
$this->error = $resarray['error'].' '.$resarray['output'];
}
$result = ($resarray['result'] == 0) ? 1 : 0;
chdir($currentdir); chdir($currentdir);
} }
else else
@ -751,7 +789,7 @@ class Utils
* *
* @return int 0 if OK, < 0 if KO * @return int 0 if OK, < 0 if KO
*/ */
function compressSyslogs() public function compressSyslogs()
{ {
global $conf; global $conf;
@ -857,7 +895,7 @@ class Utils
$this->output = 'Archive log files (keeping last SYSLOG_FILE_SAVES='.$nbSaves.' files) done.'; $this->output = 'Archive log files (keeping last SYSLOG_FILE_SAVES='.$nbSaves.' files) done.';
return 0; return 0;
} }
/** Backup the db OR just a table without mysqldump binary, with PHP only (does not require any exec permission) /** Backup the db OR just a table without mysqldump binary, with PHP only (does not require any exec permission)
* Author: David Walsh (http://davidwalsh.name/backup-mysql-database-php) * Author: David Walsh (http://davidwalsh.name/backup-mysql-database-php)
@ -869,7 +907,7 @@ class Utils
* @param string $tables Table name or '*' for all * @param string $tables Table name or '*' for all
* @return int <0 if KO, >0 if OK * @return int <0 if KO, >0 if OK
*/ */
function backupTables($outputfile, $tables='*') public function backupTables($outputfile, $tables = '*')
{ {
global $db, $langs; global $db, $langs;
global $errormsg; global $errormsg;
@ -896,7 +934,7 @@ class Utils
} }
else else
{ {
$tables = is_array($tables) ? $tables : explode(',',$tables); $tables = is_array($tables) ? $tables : explode(',', $tables);
} }
//cycle through //cycle through
@ -904,7 +942,7 @@ class Utils
if (fwrite($handle, '') === false) if (fwrite($handle, '') === false)
{ {
$langs->load("errors"); $langs->load("errors");
dol_syslog("Failed to open file ".$outputfile,LOG_ERR); dol_syslog("Failed to open file ".$outputfile, LOG_ERR);
$errormsg=$langs->trans("ErrorFailedToWriteInDir"); $errormsg=$langs->trans("ErrorFailedToWriteInDir");
return -1; return -1;
} }
@ -947,9 +985,9 @@ class Utils
// Saving the table structure // Saving the table structure
fwrite($handle, "\n--\n-- Table structure for table `".$table."`\n--\n"); fwrite($handle, "\n--\n-- Table structure for table `".$table."`\n--\n");
if (GETPOST("nobin_drop")) fwrite($handle,"DROP TABLE IF EXISTS `".$table."`;\n"); // Dropping table if exists prior to re create it if (GETPOST("nobin_drop")) fwrite($handle, "DROP TABLE IF EXISTS `".$table."`;\n"); // Dropping table if exists prior to re create it
fwrite($handle,"/*!40101 SET @saved_cs_client = @@character_set_client */;\n"); fwrite($handle, "/*!40101 SET @saved_cs_client = @@character_set_client */;\n");
fwrite($handle,"/*!40101 SET character_set_client = utf8 */;\n"); fwrite($handle, "/*!40101 SET character_set_client = utf8 */;\n");
$resqldrop=$db->query('SHOW CREATE TABLE '.$table); $resqldrop=$db->query('SHOW CREATE TABLE '.$table);
$row2 = $db->fetch_row($resqldrop); $row2 = $db->fetch_row($resqldrop);
if (empty($row2[1])) if (empty($row2[1]))
@ -958,7 +996,7 @@ class Utils
} }
else else
{ {
fwrite($handle,$row2[1].";\n"); fwrite($handle, $row2[1].";\n");
//fwrite($handle,"/*!40101 SET character_set_client = @saved_cs_client */;\n\n"); //fwrite($handle,"/*!40101 SET character_set_client = @saved_cs_client */;\n\n");
// Dumping the data (locking the table and disabling the keys check while doing the process) // Dumping the data (locking the table and disabling the keys check while doing the process)
@ -972,7 +1010,7 @@ class Utils
while($row = $db->fetch_row($result)) while($row = $db->fetch_row($result))
{ {
// For each row of data we print a line of INSERT // For each row of data we print a line of INSERT
fwrite($handle,'INSERT '.$delayed.$ignore.'INTO `'.$table.'` VALUES ('); fwrite($handle, 'INSERT '.$delayed.$ignore.'INTO `'.$table.'` VALUES (');
$columns = count($row); $columns = count($row);
for($j=0; $j<$columns; $j++) { for($j=0; $j<$columns; $j++) {
// 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) // 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)
@ -991,11 +1029,11 @@ class Utils
$row[$j] = "'".$row[$j]."'"; $row[$j] = "'".$row[$j]."'";
} }
} }
fwrite($handle,implode(',', $row).");\n"); fwrite($handle, implode(',', $row).");\n");
} }
if (GETPOST("nobin_disable_fk")) fwrite($handle, "ALTER TABLE `".$table."` ENABLE KEYS;\n"); // Enabling back the keys/index checking if (GETPOST("nobin_disable_fk")) fwrite($handle, "ALTER TABLE `".$table."` ENABLE KEYS;\n"); // Enabling back the keys/index checking
if (!GETPOST("nobin_nolocks")) fwrite($handle, "UNLOCK TABLES;\n"); // Unlocking the table if (!GETPOST("nobin_nolocks")) fwrite($handle, "UNLOCK TABLES;\n"); // Unlocking the table
fwrite($handle,"\n\n\n"); fwrite($handle, "\n\n\n");
} }
} }

File diff suppressed because it is too large Load Diff