Completed
Branch develop (96aaeb)
by
unknown
31:19
created

Utils::compressSyslogs()   F

Complexity

Conditions 17
Paths 278

Size

Total Lines 101
Code Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 17
eloc 55
nc 278
nop 0
dl 0
loc 101
rs 3.6909
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$', '', 'name', SORT_ASC, 2, 0, '', 1);	// Do not follow symlinks
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, do not follow symbolic links)
85
			if ($dolibarr_main_data_root)
86
			{
87
				$filesarray=dol_dir_list($dolibarr_main_data_root, "all", 0, '', 'install\.lock$', 'name', SORT_ASC, 0, 0, '', 1);
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]*(\.gz)?$', 'install\.lock$', 'name', SORT_ASC, 0, 0, '', 1);
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, $langs;
535
		global $dirins;
536
537
		$error = 0;
538
539
		$modulelowercase=strtolower($module);
540
541
		// Dir for module
542
		$dir = $dirins.'/'.$modulelowercase;
543
		// Zip file to build
544
		$FILENAMEDOC='';
545
546
		// Load module
547
		dol_include_once($modulelowercase.'/core/modules/mod'.$module.'.class.php');
548
		$class='mod'.$module;
549
550
		if (class_exists($class))
551
		{
552
			try {
553
				$moduleobj = new $class($this->db);
554
			}
555
			catch(Exception $e)
556
			{
557
				$error++;
558
				dol_print_error($e->getMessage());
559
			}
560
		}
561
		else
562
		{
563
			$error++;
564
			$langs->load("errors");
565
			dol_print_error($langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module));
566
			exit;
567
		}
568
569
		$arrayversion=explode('.',$moduleobj->version,3);
570
		if (count($arrayversion))
571
		{
572
			$FILENAMEASCII=strtolower($module).'.asciidoc';
573
			$FILENAMEDOC=strtolower($module).'.html';			// TODO Use/text PDF
574
575
			$dirofmodule = dol_buildpath(strtolower($module), 0).'/doc';
576
			$dirofmoduletmp = dol_buildpath(strtolower($module), 0).'/doc/temp';
577
			$outputfiledoc = $dirofmodule.'/'.$FILENAMEDOC;
578
			if ($dirofmodule)
579
			{
580
				if (! dol_is_dir($dirofmodule)) dol_mkdir($dirofmodule);
581
				if (! dol_is_dir($dirofmoduletmp)) dol_mkdir($dirofmoduletmp);
582
				if (! is_writable($dirofmoduletmp))
583
				{
584
					$this->error = 'Dir '.$dirofmoduletmp.' does not exists or is not writable';
585
					return -1;
586
				}
587
588
				$destfile=$dirofmoduletmp.'/'.$FILENAMEASCII;
589
590
				$fhandle = fopen($destfile, 'w+');
591
				if ($fhandle)
592
				{
593
					$specs=dol_dir_list(dol_buildpath(strtolower($module).'/doc', 0), 'files', 1, '(\.md|\.asciidoc)$', array('\/temp\/'));
594
595
					$i = 0;
596
					foreach ($specs as $spec)
597
					{
598
						if (preg_match('/notindoc/', $spec['relativename'])) continue;	// Discard file
599
						if (preg_match('/disabled/', $spec['relativename'])) continue;	// Discard file
600
601
						$pathtofile = strtolower($module).'/doc/'.$spec['relativename'];
602
						$format='asciidoc';
603
						if (preg_match('/\.md$/i', $spec['name'])) $format='markdown';
604
605
						$filecursor = @file_get_contents($spec['fullname']);
606
						if ($filecursor)
607
						{
608
							fwrite($fhandle, ($i ? "\n<<<\n\n" : "").$filecursor."\n");
609
						}
610
						else
611
						{
612
							$this->error = 'Failed to concat content of file '.$spec['fullname'];
613
							return -1;
614
						}
615
616
						$i++;
617
					}
618
619
					fwrite($fhandle, "\n\n\n== DATA SPECIFICATIONS...\n\n");
620
621
					// TODO
622
					fwrite($fhandle, "TODO...");
623
624
					fclose($fhandle);
625
				}
626
627
				$conf->global->MODULEBUILDER_ASCIIDOCTOR='asciidoctor';
628
				if (empty($conf->global->MODULEBUILDER_ASCIIDOCTOR))
629
				{
630
					dol_print_error('', 'Module setup not complete');
631
					exit;
632
				}
633
634
				$command=$conf->global->MODULEBUILDER_ASCIIDOCTOR.' '.$destfile.' -n -o '.$dirofmodule.'/'.$FILENAMEDOC;
635
				$outfile=$dirofmoduletmp.'/out.tmp';
636
637
				require_once DOL_DOCUMENT_ROOT.'/core/class/utils.class.php';
638
				$utils = new Utils($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...
639
				$resarray = $utils->executeCLI($command, $outfile);
640
				if ($resarray['result'] != '0')
641
				{
642
					$this->error = $resarray['error'].' '.$resarray['output'];
643
				}
644
				$result = ($resarray['result'] == 0) ? 1 : 0;
645
			}
646
			else
647
			{
648
				$result = 0;
649
			}
650
651
			if ($result > 0)
652
			{
653
				return 1;
654
			}
655
			else
656
			{
657
				$error++;
658
				$langs->load("errors");
659
				$this->error = $langs->trans("ErrorFailToGenerateFile", $outputfiledoc);
660
			}
661
		}
662
		else
663
		{
664
			$error++;
665
			$langs->load("errors");
666
			$this->error = $langs->trans("ErrorCheckVersionIsDefined");
667
		}
668
669
		return -1;
670
	}
671
672
	/**
673
	 * This saves syslog files and compresses older ones
674
	 * Used from cronjob
675
	 * 
676
	 * @return	int		 0 if OK, < 0 if KO 
677
	 */
678
	function compressSyslogs() {
679
		global $conf;
680
681
		if(empty($conf->loghandlers['mod_syslog_file'])) { // File Syslog disabled
682
			return 0;
683
		}
684
685
		if(! function_exists('gzopen')) {
686
			return -1;
687
		}
688
689
		dol_include_once('/core/lib/files.lib.php');
690
691
		$nbSaves = ! empty($conf->global->SYSLOG_FILE_SAVES) ? intval($conf->global->SYSLOG_FILE_SAVES) : 14;
692
693
		if(empty($conf->global->SYSLOG_FILE)) {
694
			$mainlogdir = DOL_DATA_ROOT;
695
			$mainlog = 'dolibarr.log';
696
		} else {
697
			$mainlogfull = str_replace('DOL_DATA_ROOT', DOL_DATA_ROOT, $conf->global->SYSLOG_FILE);
698
			$mainlogdir = dirname($mainlogfull);
699
			$mainlog = basename($mainlogfull);
700
		}
701
702
		$tabfiles = dol_dir_list(DOL_DATA_ROOT, 'files', 0, '^(dolibarr_.+|odt2pdf)\.log$'); // Also handle other log files like dolibarr_install.log
703
		$tabfiles[] = array('name' => $mainlog, 'path' => $mainlogdir);
704
705
		foreach($tabfiles as $file) {
706
707
			$logname = $file['name'];
708
			$logpath = $file['path'];
709
710
			// Handle already compressed files
711
712
			$filter = '^'.preg_quote($logname, '/').'\.([0-9]+)\.gz$';
713
714
			$gzfilestmp = dol_dir_list($logpath, 'files', 0, $filter);
715
			$gzfiles = array();
716
717
			foreach($gzfilestmp as $gzfile) {
718
				$tabmatches = array();
719
				preg_match('/'.$filter.'/i', $gzfile['name'], $tabmatches);
720
721
				$numsave = intval($tabmatches[1]);
722
723
				$gzfiles[$numsave] = $gzfile;
724
			}
725
726
			krsort($gzfiles, SORT_NUMERIC);
727
728
			foreach($gzfiles as $numsave => $dummy) {
729
				if(dol_is_file($logpath.'/'.$logname.'.'.($numsave+1).'.gz')) {
730
					return -2;
731
				}
732
733
				if($numsave >= $nbSaves) {
734
					dol_delete_file($logpath.'/'.$logname.'.'.$numsave.'.gz');
735
				} else {
736
					dol_move($logpath.'/'.$logname.'.'.$numsave.'.gz', $logpath.'/'.$logname.'.'.($numsave+1).'.gz', 0, 1, 0, 0);
737
				}
738
			}
739
740
			// Compress last save
741
742
			if(dol_is_file($logpath.'/'.$logname.'.1')) {
743
				if($nbSaves > 1) {
744
					$gzfilehandle = gzopen($logpath.'/'.$logname.'.2.gz', 'wb9');
745
746
					if(empty($gzfilehandle)) {
747
						return -3;
748
					}
749
750
					$sourcehandle = fopen($logpath.'/'.$logname.'.1', 'r');
751
752
					if(empty($sourcehandle)) {
753
						return -4;
754
					}
755
756
					while(! feof($sourcehandle)) {
757
						gzwrite($gzfilehandle, fread($sourcehandle, 512 * 1024)); // Read 512 kB at a time
758
					}
759
760
					fclose($sourcehandle);
761
					gzclose($gzfilehandle);
762
				} else {
763
					dol_delete_file($logpath.'/'.$logname.'.1');
764
				}
765
			}
766
767
			// Compress current file et recreate it
768
769
			if(dol_is_file($logpath.'/'.$logname)) {
770
				if(dol_move($logpath.'/'.$logname, $logpath.'/'.$logname.'.1', 0, 1, 0, 0)) {
771
					$newlog = fopen($logpath.'/'.$logname, 'a+');
772
					fclose($newlog);
773
				}
774
			}
775
		}
776
777
		return 0;
778
	}
779
}