Completed
Branch develop (bb7c03)
by
unknown
34:20
created

Utils::generateDoc()   D

Complexity

Conditions 19
Paths 143

Size

Total Lines 138
Code Lines 78

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 19
eloc 78
nc 143
nop 1
dl 0
loc 138
rs 4.4786
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/* Copyright (C) 2016 Destailleur Laurent <[email protected]>
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
/**
19
 *   	\file       htdocs/core/class/utils.class.php
20
 *      \ingroup    core
21
 *		\brief      File for Utils class
22
 */
23
24
25
/**
26
 *		Class to manage utility methods
27
 */
28
class Utils
29
{
30
	var $db;
31
32
	var $output;   // Used by Cron method to return message
33
	var $result;   // Used by Cron method to return data
34
35
	/**
36
	 *	Constructor
37
	 *
38
	 *  @param	DoliDB	$db		Database handler
39
	 */
40
	function __construct($db)
41
	{
42
		$this->db = $db;
43
	}
44
45
46
	/**
47
	 *  Purge files into directory of data files.
48
	 *  CAN BE A CRON TASK
49
	 *
50
	 *  @param	string		$choice		Choice of purge mode ('tempfiles', 'tempfilesold' to purge temp older than 24h, 'allfiles', 'logfile')
51
	 *  @return	int						0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK)
52
	 */
53
	function purgeFiles($choice='tempfilesold')
54
	{
55
		global $conf, $langs, $dolibarr_main_data_root;
56
57
		$langs->load("admin");
58
59
		dol_syslog("Utils::purgeFiles choice=".$choice, LOG_DEBUG);
60
		require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
61
62
		$filesarray=array();
63
		if (empty($choice)) $choice='tempfilesold';
64
65
		if ($choice=='tempfiles' || $choice=='tempfilesold')
66
		{
67
			// Delete temporary files
68
			if ($dolibarr_main_data_root)
69
			{
70
				$filesarray=dol_dir_list($dolibarr_main_data_root,"directories",1,'^temp$','','','',2);
71
				if ($choice == 'tempfilesold')
72
				{
73
					$now = dol_now();
74
					foreach($filesarray as $key => $val)
75
					{
76
						if ($val['date'] > ($now - (24 * 3600))) unset($filesarray[$key]);	// Discard files not older than 24h
77
					}
78
				}
79
			}
80
		}
81
82
		if ($choice=='allfiles')
83
		{
84
			// Delete all files (except install.lock)
85
			if ($dolibarr_main_data_root)
86
			{
87
				$filesarray=dol_dir_list($dolibarr_main_data_root,"all",0,'','install\.lock$');
88
			}
89
		}
90
91
		if ($choice=='logfile')
92
		{
93
			// Define files log
94
			if ($dolibarr_main_data_root)
95
			{
96
				$filesarray=dol_dir_list($dolibarr_main_data_root, "files", 0, '.*\.log[\.0-9]*$', 'install\.lock$');
97
			}
98
99
			$filelog='';
100
			if (! empty($conf->syslog->enabled))
101
			{
102
				$filelog=$conf->global->SYSLOG_FILE;
103
				$filelog=preg_replace('/DOL_DATA_ROOT/i',DOL_DATA_ROOT,$filelog);
104
105
				$alreadyincluded=false;
106
				foreach ($filesarray as $tmpcursor)
107
				{
108
					if ($tmpcursor['fullname'] == $filelog) { $alreadyincluded=true; }
109
				}
110
				if (! $alreadyincluded) $filesarray[]=array('fullname'=>$filelog,'type'=>'file');
111
			}
112
		}
113
114
		$count=0;
115
		$countdeleted=0;
116
		$counterror=0;
117
		if (count($filesarray))
118
		{
119
			foreach($filesarray as $key => $value)
120
			{
121
				//print "x ".$filesarray[$key]['fullname']."-".$filesarray[$key]['type']."<br>\n";
122
				if ($filesarray[$key]['type'] == 'dir')
123
				{
124
					$startcount=0;
125
					$tmpcountdeleted=0;
126
					$result=dol_delete_dir_recursive($filesarray[$key]['fullname'], $startcount, 1, 0, $tmpcountdeleted);
127
					$count+=$result;
128
					$countdeleted+=$tmpcountdeleted;
129
				}
130
				elseif ($filesarray[$key]['type'] == 'file')
131
				{
132
					// If (file that is not logfile) or (if logfile with option logfile)
133
					if ($filesarray[$key]['fullname'] != $filelog || $choice=='logfile')
0 ignored issues
show
Bug introduced by
The variable $filelog does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
134
					{
135
						$result=dol_delete_file($filesarray[$key]['fullname'], 1, 1);
136
						if ($result)
137
						{
138
							$count++;
139
							$countdeleted++;
140
						}
141
						else $counterror++;
142
					}
143
				}
144
			}
145
146
			// Update cachenbofdoc
147
			if (! empty($conf->ecm->enabled) && $choice=='allfiles')
148
			{
149
				require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmdirectory.class.php';
150
				$ecmdirstatic = new EcmDirectory($this->db);
151
				$result = $ecmdirstatic->refreshcachenboffile(1);
152
			}
153
		}
154
155
		if ($count > 0)
156
		{
157
			$this->output=$langs->trans("PurgeNDirectoriesDeleted", $countdeleted);
158
			if ($count > $countdeleted) $this->output.='<br>'.$langs->trans("PurgeNDirectoriesFailed", ($count - $countdeleted));
159
		}
160
		else $this->output=$langs->trans("PurgeNothingToDelete").($choice == 'tempfilesold' ? ' (older than 24h)':'');
161
162
		//return $count;
163
		return 0;     // This function can be called by cron so must return 0 if OK
164
	}
165
166
167
	/**
168
	 *  Make a backup of database
169
	 *  CAN BE A CRON TASK
170
	 *
171
	 *  @param	string		$compression	   'gz' or 'bz' or 'none'
172
	 *  @param  string      $type              'mysql', 'postgresql', ...
173
	 *  @param  int         $usedefault        1=Use default backup profile (Set this to 1 when used as cron)
174
	 *  @param  string      $file              'auto' or filename to build
175
	 *  @param  int         $keeplastnfiles    Keep only last n files (not used yet)
176
	 *  @return	int						       0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK)
177
	 */
178
	function dumpDatabase($compression='none', $type='auto', $usedefault=1, $file='auto', $keeplastnfiles=0)
179
	{
180
		global $db, $conf, $langs, $dolibarr_main_data_root;
181
		global $dolibarr_main_db_name, $dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_port, $dolibarr_main_db_pass;
182
183
184
		$langs->load("admin");
185
186
		dol_syslog("Utils::dumpDatabase type=".$type." compression=".$compression." file=".$file, LOG_DEBUG);
187
		require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
188
189
		// Check compression parameter
190
		if (! in_array($compression, array('none', 'gz', 'bz', 'zip')))
191
		{
192
			$langs->load("errors");
193
			$this->error=$langs->transnoentitiesnoconv("ErrorBadValueForParameter", $compression, "Compression");
194
			return -1;
195
		}
196
197
		// Check type parameter
198
		if ($type == 'auto') $type = $db->type;
199
		if (! in_array($type, array('postgresql', 'pgsql', 'mysql', 'mysqli', 'mysqlnobin')))
200
		{
201
			$langs->load("errors");
202
			$this->error=$langs->transnoentitiesnoconv("ErrorBadValueForParameter", $type, "Basetype");
203
			return -1;
204
		}
205
206
		// Check file parameter
207
		if ($file == 'auto')
208
		{
209
			$prefix='dump';
210
			$ext='.sql';
211
			if (in_array($type, array('mysql', 'mysqli')))  { $prefix='mysqldump'; $ext='sql'; }
212
			//if ($label == 'PostgreSQL') { $prefix='pg_dump'; $ext='dump'; }
213
			if (in_array($type, array('pgsql'))) { $prefix='pg_dump'; $ext='sql'; }
214
			$file=$prefix.'_'.$dolibarr_main_db_name.'_'.dol_sanitizeFileName(DOL_VERSION).'_'.strftime("%Y%m%d%H%M").'.'.$ext;
215
		}
216
217
		$outputdir  = $conf->admin->dir_output.'/backup';
218
		$result=dol_mkdir($outputdir);
219
220
221
		// MYSQL
222
		if ($type == 'mysql' || $type == 'mysqli')
223
		{
224
			$cmddump=$conf->global->SYSTEMTOOLS_MYSQLDUMP;
225
226
227
			$outputfile = $outputdir.'/'.$file;
228
			// for compression format, we add extension
229
			$compression=$compression ? $compression : 'none';
230
			if ($compression == 'gz') $outputfile.='.gz';
231
			if ($compression == 'bz') $outputfile.='.bz2';
232
			$outputerror = $outputfile.'.err';
233
			dol_mkdir($conf->admin->dir_output.'/backup');
234
235
			// Parameteres execution
236
			$command=$cmddump;
237
			if (preg_match("/\s/",$command)) $command=escapeshellarg($command);	// Use quotes on command
238
239
			//$param=escapeshellarg($dolibarr_main_db_name)." -h ".escapeshellarg($dolibarr_main_db_host)." -u ".escapeshellarg($dolibarr_main_db_user)." -p".escapeshellarg($dolibarr_main_db_pass);
240
			$param=$dolibarr_main_db_name." -h ".$dolibarr_main_db_host;
241
			$param.=" -u ".$dolibarr_main_db_user;
242
			if (! empty($dolibarr_main_db_port)) $param.=" -P ".$dolibarr_main_db_port;
243
			if (! GETPOST("use_transaction"))    $param.=" -l --single-transaction";
244
			if (GETPOST("disable_fk") || $usedefault) $param.=" -K";
245
			if (GETPOST("sql_compat") && GETPOST("sql_compat") != 'NONE') $param.=" --compatible=".escapeshellarg(GETPOST("sql_compat","alpha"));
246
			if (GETPOST("drop_database"))        $param.=" --add-drop-database";
247
			if (GETPOST("sql_structure") || $usedefault)
248
			{
249
				if (GETPOST("drop") || $usedefault)	$param.=" --add-drop-table=TRUE";
250
				else 							    $param.=" --add-drop-table=FALSE";
251
			}
252
			else
253
			{
254
				$param.=" -t";
255
			}
256
			if (GETPOST("disable-add-locks")) $param.=" --add-locks=FALSE";
257
			if (GETPOST("sql_data") || $usedefault)
258
			{
259
				$param.=" --tables";
260
				if (GETPOST("showcolumns") || $usedefault)	 $param.=" -c";
261
				if (GETPOST("extended_ins") || $usedefault) $param.=" -e";
262
				else $param.=" --skip-extended-insert";
263
				if (GETPOST("delayed"))	 	 $param.=" --delayed-insert";
264
				if (GETPOST("sql_ignore"))	 $param.=" --insert-ignore";
265
				if (GETPOST("hexforbinary") || $usedefault) $param.=" --hex-blob";
266
			}
267
			else
268
			{
269
				$param.=" -d";    // No row information (no data)
270
			}
271
			$param.=" --default-character-set=utf8";    // We always save output into utf8 charset
272
			$paramcrypted=$param;
273
			$paramclear=$param;
274
			if (! empty($dolibarr_main_db_pass))
275
			{
276
				$paramcrypted.=' -p"'.preg_replace('/./i','*',$dolibarr_main_db_pass).'"';
277
				$paramclear.=' -p"'.str_replace(array('"','`'),array('\"','\`'),$dolibarr_main_db_pass).'"';
278
			}
279
280
			$errormsg='';
281
282
			// Debut appel methode execution
283
			$fullcommandcrypted=$command." ".$paramcrypted." 2>&1";
284
			$fullcommandclear=$command." ".$paramclear." 2>&1";
285
			if ($compression == 'none') $handle = fopen($outputfile, 'w');
286
			if ($compression == 'gz')   $handle = gzopen($outputfile, 'w');
287
			if ($compression == 'bz')   $handle = bzopen($outputfile, 'w');
288
289
			if ($handle)
290
			{
291
				$ok=0;
292
				dol_syslog("Run command ".$fullcommandcrypted);
293
				$handlein = popen($fullcommandclear, 'r');
294
				$i=0;
295
				while (!feof($handlein))
296
				{
297
					$i++;   // output line number
298
					$read = fgets($handlein);
299
					// Exclude warning line we don't want
300
					if ($i == 1 && preg_match('/Warning.*Using a password/i', $read)) continue;
301
					fwrite($handle,$read);
0 ignored issues
show
Bug introduced by
The variable $handle does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
302
					if (preg_match('/'.preg_quote('-- Dump completed').'/i',$read)) $ok=1;
303
					elseif (preg_match('/'.preg_quote('SET SQL_NOTES=@OLD_SQL_NOTES').'/i',$read)) $ok=1;
304
				}
305
				pclose($handlein);
306
307
				if ($compression == 'none') fclose($handle);
308
				if ($compression == 'gz')   gzclose($handle);
309
				if ($compression == 'bz')   bzclose($handle);
310
311
				if (! empty($conf->global->MAIN_UMASK))
312
					@chmod($outputfile, octdec($conf->global->MAIN_UMASK));
313
			}
314
			else
315
			{
316
				$langs->load("errors");
317
				dol_syslog("Failed to open file ".$outputfile,LOG_ERR);
318
				$errormsg=$langs->trans("ErrorFailedToWriteInDir");
319
			}
320
321
			// Get errorstring
322
			if ($compression == 'none') $handle = fopen($outputfile, 'r');
323
			if ($compression == 'gz')   $handle = gzopen($outputfile, 'r');
324
			if ($compression == 'bz')   $handle = bzopen($outputfile, 'r');
325
			if ($handle)
326
			{
327
				// Get 2048 first chars of error message.
328
				$errormsg = fgets($handle,2048);
329
				// Close file
330
				if ($compression == 'none') fclose($handle);
331
				if ($compression == 'gz')   gzclose($handle);
332
				if ($compression == 'bz')   bzclose($handle);
333
				if ($ok && preg_match('/^-- MySql/i',$errormsg)) $errormsg='';	// Pas erreur
0 ignored issues
show
Bug introduced by
The variable $ok does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
334
				else
335
				{
336
					// Renommer fichier sortie en fichier erreur
337
					//print "$outputfile -> $outputerror";
338
					@dol_delete_file($outputerror,1);
339
					@rename($outputfile,$outputerror);
340
					// Si safe_mode on et command hors du parametre exec, on a un fichier out vide donc errormsg vide
341
					if (! $errormsg)
342
					{
343
						$langs->load("errors");
344
						$errormsg=$langs->trans("ErrorFailedToRunExternalCommand");
345
					}
346
				}
347
			}
348
			// Fin execution commande
349
350
			$this->output = $errormsg;
351
			$this->error = $errormsg;
352
			$this->result = array("commandbackuplastdone" => $command." ".$paramcrypted, "commandbackuptorun" => "");
353
			//if (empty($this->output)) $this->output=$this->result['commandbackuplastdone'];
354
		}
355
356
		// MYSQL NO BIN
357
		if ($type == 'mysqlnobin')
358
		{
359
			$outputfile = $outputdir.'/'.$file;
360
			$outputfiletemp = $outputfile.'-TMP.sql';
361
			// for compression format, we add extension
362
			$compression=$compression ? $compression : 'none';
363
			if ($compression == 'gz') $outputfile.='.gz';
364
			if ($compression == 'bz') $outputfile.='.bz2';
365
			$outputerror = $outputfile.'.err';
366
			dol_mkdir($conf->admin->dir_output.'/backup');
367
368
			if ($compression == 'gz' or $compression == 'bz')
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
369
			{
370
				backup_tables($outputfiletemp);
371
				dol_compress_file($outputfiletemp, $outputfile, $compression);
372
				unlink($outputfiletemp);
373
			}
374
			else
375
			{
376
				backup_tables($outputfile);
377
			}
378
379
			$this->output = "";
380
			$this->result = array("commandbackuplastdone" => "", "commandbackuptorun" => "");
381
		}
382
383
		// POSTGRESQL
384
		if ($type == 'postgresql' || $type == 'pgsql')
385
		{
386
			$cmddump=$conf->global->SYSTEMTOOLS_POSTGRESQLDUMP;
387
388
			$outputfile = $outputdir.'/'.$file;
389
			// for compression format, we add extension
390
			$compression=$compression ? $compression : 'none';
391
			if ($compression == 'gz') $outputfile.='.gz';
392
			if ($compression == 'bz') $outputfile.='.bz2';
393
			$outputerror = $outputfile.'.err';
394
			dol_mkdir($conf->admin->dir_output.'/backup');
395
396
			// Parameteres execution
397
			$command=$cmddump;
398
			if (preg_match("/\s/",$command)) $command=escapeshellarg($command);	// Use quotes on command
399
400
			//$param=escapeshellarg($dolibarr_main_db_name)." -h ".escapeshellarg($dolibarr_main_db_host)." -u ".escapeshellarg($dolibarr_main_db_user)." -p".escapeshellarg($dolibarr_main_db_pass);
401
			//$param="-F c";
402
			$param="-F p";
403
			$param.=" --no-tablespaces --inserts -h ".$dolibarr_main_db_host;
404
			$param.=" -U ".$dolibarr_main_db_user;
405
			if (! empty($dolibarr_main_db_port)) $param.=" -p ".$dolibarr_main_db_port;
406
			if (GETPOST("sql_compat") && GETPOST("sql_compat") == 'ANSI') $param.="  --disable-dollar-quoting";
407
			if (GETPOST("drop_database"))        $param.=" -c -C";
408
			if (GETPOST("sql_structure"))
409
			{
410
				if (GETPOST("drop"))			 $param.=" --add-drop-table";
411
				if (! GETPOST("sql_data"))       $param.=" -s";
412
			}
413
			if (GETPOST("sql_data"))
414
			{
415
				if (! GETPOST("sql_structure"))	 $param.=" -a";
416
				if (GETPOST("showcolumns"))	     $param.=" -c";
417
			}
418
			$param.=' -f "'.$outputfile.'"';
419
			//if ($compression == 'none')
420
			if ($compression == 'gz')   $param.=' -Z 9';
421
			//if ($compression == 'bz')
422
			$paramcrypted=$param;
423
			$paramclear=$param;
424
			/*if (! empty($dolibarr_main_db_pass))
425
			 {
426
			 $paramcrypted.=" -W".preg_replace('/./i','*',$dolibarr_main_db_pass);
427
			 $paramclear.=" -W".$dolibarr_main_db_pass;
428
			 }*/
429
			$paramcrypted.=" -w ".$dolibarr_main_db_name;
430
			$paramclear.=" -w ".$dolibarr_main_db_name;
431
432
			$this->output = "";
433
			$this->result = array("commandbackuplastdone" => "", "commandbackuptorun" => $command." ".$paramcrypted);
434
		}
435
436
		// Clean old files
437
		if ($keeplastnfiles > 0)
438
		{
439
			$tmpfiles = dol_dir_list($conf->admin->dir_output.'/backup', 'files', 0, '', '(\.err|\.old|\.sav)$', 'date', SORT_DESC);
440
			$i=0;
441
			foreach($tmpfiles as $key => $val)
442
			{
443
				$i++;
444
				if ($i <= $keeplastnfiles) continue;
445
				dol_delete_file($val['fullname']);
446
			}
447
		}
448
449
450
		return 0;
451
	}
452
453
454
455
	/**
456
	 * Execute a CLI command.
457
	 *
458
	 * @param 	string	$command		Command line to execute.
459
	 * @param 	string	$outputfile		Output file (used only when method is 2). For exemple $conf->admin->dir_temp.'/out.tmp';
460
	 * @param	int		$execmethod		0=Use default method (that is 1 by default), 1=Use the PHP 'exec', 2=Use the 'popen' method
461
	 * @return	array					array('result'=>...,'output'=>...,'error'=>...). result = 0 means OK.
462
	 */
463
	function executeCLI($command, $outputfile, $execmethod=0)
464
	{
465
		global $conf, $langs;
466
467
		$result = 0;
468
		$output = '';
469
		$error = '';
470
471
		$command=escapeshellcmd($command);
472
		$command.=" 2>&1";
473
474
		if (! empty($conf->global->MAIN_EXEC_USE_POPEN)) $execmethod=$conf->global->MAIN_EXEC_USE_POPEN;
475
		if (empty($execmethod)) $execmethod=1;
476
		//$execmethod=1;
477
478
		dol_syslog("Utils::executeCLI execmethod=".$execmethod." system:".$command, LOG_DEBUG);
479
		$output_arr=array();
480
481
		if ($execmethod == 1)
482
		{
483
			exec($command, $output_arr, $retval);
484
			$result = $retval;
485
			if ($retval != 0)
486
			{
487
				$langs->load("errors");
488
				dol_syslog("Utils::executeCLI retval after exec=".$retval, LOG_ERR);
489
				$error = 'Error '.$retval;
490
			}
491
		}
492
		if ($execmethod == 2)	// With this method, there is no way to get the return code, only output
493
		{
494
			$ok=0;
495
			$handle = fopen($outputfile, 'w+b');
496
			if ($handle)
497
			{
498
				dol_syslog("Utils::executeCLI run command ".$command);
499
				$handlein = popen($command, 'r');
500
				while (!feof($handlein))
501
				{
502
					$read = fgets($handlein);
503
					fwrite($handle,$read);
504
					$output_arr[]=$read;
505
				}
506
				pclose($handlein);
507
				fclose($handle);
508
			}
509
			if (! empty($conf->global->MAIN_UMASK)) @chmod($outputfile, octdec($conf->global->MAIN_UMASK));
510
		}
511
512
		// Update with result
513
		if (is_array($output_arr) && count($output_arr)>0)
514
		{
515
			foreach($output_arr as $val)
516
			{
517
				$output.=$val.($execmethod == 2 ? '' : "\n");
518
			}
519
		}
520
521
		dol_syslog("Utils::executeCLI result=".$result." output=".$output." error=".$error, LOG_DEBUG);
522
523
		return array('result'=>$result, 'output'=>$output, 'error'=>$error);
524
	}
525
526
	/**
527
	 * Generate documentation of a Module
528
	 *
529
	 * @param 	string	$module		Module name
530
	 * @return	int					<0 if KO, >0 if OK
531
	 */
532
	function generateDoc($module)
533
	{
534
		global $conf, $dirins;
535
536
		$error = 0;
537
538
		$modulelowercase=strtolower($module);
539
540
		// Dir for module
541
		$dir = $dirins.'/'.$modulelowercase;
542
		// Zip file to build
543
		$FILENAMEDOC='';
544
545
		// Load module
546
		dol_include_once($modulelowercase.'/core/modules/mod'.$module.'.class.php');
547
		$class='mod'.$module;
548
549
		if (class_exists($class))
550
		{
551
			try {
552
				$moduleobj = new $class($db);
0 ignored issues
show
Bug introduced by
The variable $db does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
553
			}
554
			catch(Exception $e)
555
			{
556
				$error++;
557
				dol_print_error($e->getMessage());
558
			}
559
		}
560
		else
561
		{
562
			$error++;
563
			$langs->load("errors");
0 ignored issues
show
Bug introduced by
The variable $langs does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
564
			dol_print_error($langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module));
565
			exit;
566
		}
567
568
		$arrayversion=explode('.',$moduleobj->version,3);
569
		if (count($arrayversion))
570
		{
571
			$FILENAMEASCII=strtolower($module).'.asciidoc';
572
			$FILENAMEDOC=strtolower($module).'.html';			// TODO Use/text PDF
573
574
			$dirofmodule = dol_buildpath(strtolower($module), 0).'/doc';
575
			$dirofmoduletmp = dol_buildpath(strtolower($module), 0).'/doc/temp';
576
			$outputfiledoc = $dirofmodule.'/'.$FILENAMEDOC;
577
			if ($dirofmodule)
578
			{
579
				if (! dol_is_dir($dirofmodule)) dol_mkdir($dirofmodule);
580
				if (! dol_is_dir($dirofmoduletmp)) dol_mkdir($dirofmoduletmp);
581
				if (! is_writable($dirofmoduletmp))
582
				{
583
					$this->error = 'Dir '.$dirofmoduletmp.' does not exists or is not writable';
584
					return -1;
585
				}
586
587
				$destfile=$dirofmoduletmp.'/'.$FILENAMEASCII;
588
589
				$fhandle = fopen($destfile, 'w+');
590
				if ($fhandle)
591
				{
592
					$specs=dol_dir_list(dol_buildpath(strtolower($module).'/doc', 0), 'files', 1, '(\.md|\.asciidoc)$', array('\/temp\/'));
593
594
					$i = 0;
595
					foreach ($specs as $spec)
596
					{
597
						if (preg_match('/notindoc/', $spec['relativename'])) continue;	// Discard file
598
						if (preg_match('/disabled/', $spec['relativename'])) continue;	// Discard file
599
600
						$pathtofile = strtolower($module).'/doc/'.$spec['relativename'];
601
						$format='asciidoc';
602
						if (preg_match('/\.md$/i', $spec['name'])) $format='markdown';
603
604
						$filecursor = @file_get_contents($spec['fullname']);
605
						if ($filecursor)
606
						{
607
							fwrite($fhandle, ($i ? "\n<<<\n\n" : "").$filecursor."\n");
608
						}
609
						else
610
						{
611
							$this->error = 'Failed to concat content of file '.$spec['fullname'];
612
							return -1;
613
						}
614
615
						$i++;
616
					}
617
618
					fwrite($fhandle, "\n\n\n== DATA SPECIFICATIONS...\n\n");
619
620
					// TODO
621
					fwrite($fhandle, "TODO...");
622
623
					fclose($fhandle);
624
				}
625
626
				$conf->global->MODULEBUILDER_ASCIIDOCTOR='asciidoctor';
627
				if (empty($conf->global->MODULEBUILDER_ASCIIDOCTOR))
628
				{
629
					dol_print_error('', 'Module setup not complete');
630
					exit;
631
				}
632
633
				$command=$conf->global->MODULEBUILDER_ASCIIDOCTOR.' '.$destfile.' -n -o '.$dirofmodule.'/'.$FILENAMEDOC;
634
				$outfile=$dirofmoduletmp.'/out.tmp';
635
636
				require_once DOL_DOCUMENT_ROOT.'/core/class/utils.class.php';
637
				$utils = new Utils($db);
638
				$resarray = $utils->executeCLI($command, $outfile);
639
				if ($resarray['result'] != '0')
640
				{
641
					$this->error = $resarray['error'].' '.$resarray['output'];
642
				}
643
				$result = ($resarray['result'] == 0) ? 1 : 0;
644
			}
645
			else
646
			{
647
				$result = 0;
648
			}
649
650
			if ($result > 0)
651
			{
652
				return 1;
653
			}
654
			else
655
			{
656
				$error++;
657
				$langs->load("errors");
658
				$this->error = $langs->trans("ErrorFailToGenerateFile", $outputfiledoc);
659
			}
660
		}
661
		else
662
		{
663
			$error++;
664
			$langs->load("errors");
665
			$this->error = $langs->trans("ErrorCheckVersionIsDefined");
666
		}
667
668
		return -1;
669
	}
670
}
671