Completed
Branch develop (bccfa3)
by
unknown
31:46
created

files.lib.php ➔ dolReplaceInFile()   C

Complexity

Conditions 13
Paths 17

Size

Total Lines 53
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 29
nc 17
nop 4
dl 0
loc 53
rs 6.3327
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) 2008-2012  Laurent Destailleur <[email protected]>
3
 * Copyright (C) 2012-2015  Regis Houssin       <[email protected]>
4
 * Copyright (C) 2012-2016  Juanjo Menent       <[email protected]>
5
 * Copyright (C) 2015       Marcos García       <[email protected]>
6
 * Copyright (C) 2016       Raphaël Doursenaud  <[email protected]>
7
 *
8
 * This program is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation; either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20
 * or see http://www.gnu.org/
21
 */
22
23
/**
24
 *  \file		htdocs/core/lib/files.lib.php
25
 *  \brief		Library for file managing functions
26
 */
27
28
/**
29
 * Make a basename working with all page code (default PHP basenamed fails with cyrillic).
30
 * We supose dir separator for input is '/'.
31
 *
32
 * @param	string	$pathfile	String to find basename.
33
 * @return	string				Basename of input
34
 */
35
function dol_basename($pathfile)
36
{
37
    return preg_replace('/^.*\/([^\/]+)$/','$1',rtrim($pathfile,'/'));
38
}
39
40
/**
41
 *  Scan a directory and return a list of files/directories.
42
 *  Content for string is UTF8 and dir separator is "/".
43
 *
44
 *  @param	string		$path        	Starting path from which to search. This is a full path.
45
 *  @param	string		$types        	Can be "directories", "files", or "all"
46
 *  @param	int			$recursive		Determines whether subdirectories are searched
47
 *  @param	string		$filter        	Regex filter to restrict list. This regex value must be escaped for '/' by doing preg_quote($var,'/'), since this char is used for preg_match function, 
48
 *                                      but must not contains the start and end '/'. Filter is checked into basename only.
49
 *  @param	array		$excludefilter  Array of Regex for exclude filter (example: array('(\.meta|_preview.*\.png)$','^\.')). Exclude is checked into fullpath.
50
 *  @param	string		$sortcriteria	Sort criteria ("","fullname","name","date","size")
51
 *  @param	string		$sortorder		Sort order (SORT_ASC, SORT_DESC)
52
 *	@param	int			$mode			0=Return array minimum keys loaded (faster), 1=Force all keys like date and size to be loaded (slower), 2=Force load of date only, 3=Force load of size only
53
 *  @param	int			$nohook			Disable all hooks
54
 *  @return	array						Array of array('name'=>'xxx','fullname'=>'/abc/xxx','date'=>'yyy','size'=>99,'type'=>'dir|file',...)
55
 *  @see dol_dir_list_indatabase
56
 */
57
function dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter="", $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=false)
58
{
59
	global $db, $hookmanager;
60
	global $object;
61
62
	dol_syslog("files.lib.php::dol_dir_list path=".$path." types=".$types." recursive=".$recursive." filter=".$filter." excludefilter=".json_encode($excludefilter));
63
	//print 'xxx'."files.lib.php::dol_dir_list path=".$path." types=".$types." recursive=".$recursive." filter=".$filter." excludefilter=".json_encode($excludefilter);
64
65
	$loaddate=($mode==1||$mode==2)?true:false;
66
	$loadsize=($mode==1||$mode==3)?true:false;
67
68
	// Clean parameters
69
	$path=preg_replace('/([\\/]+)$/i','',$path);
70
	$newpath=dol_osencode($path);
71
72
	$reshook = 0;
73
	$file_list = array();
74
	
75
	$hookmanager->resArray=array();
76
	
77
	if (! $nohook)
1 ignored issue
show
Bug Best Practice introduced by
The expression $nohook of type false|integer is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
78
	{
79
		$hookmanager->initHooks(array('fileslib'));
80
81
		$parameters=array(
82
				'path' => $newpath,
83
				'types'=> $types,
84
				'recursive' => $recursive,
85
				'filter' => $filter,
86
				'excludefilter' => $excludefilter,
87
				'sortcriteria' => $sortcriteria,
88
				'sortorder' => $sortorder,
89
				'loaddate' => $loaddate,
90
				'loadsize' => $loadsize,
91
				'mode' => $mode
92
		);
93
		$reshook=$hookmanager->executeHooks('getDirList', $parameters, $object);
94
	}
95
96
	// $hookmanager->resArray may contain array stacked by other modules
97
	if (empty($reshook))
98
	{
99
		if (! is_dir($newpath)) return array();
100
101
		if ($dir = opendir($newpath))
102
		{
103
			$filedate='';
104
			$filesize='';
105
106
			while (false !== ($file = readdir($dir)))        // $file is always a basename (into directory $newpath)
107
			{
108
				if (! utf8_check($file)) $file=utf8_encode($file);	// To be sure data is stored in utf8 in memory
109
110
				$qualified=1;
111
112
				// Define excludefilterarray
113
				$excludefilterarray=array('^\.');
114
				if (is_array($excludefilter))
115
				{
116
					$excludefilterarray=array_merge($excludefilterarray,$excludefilter);
117
				}
118
				else if ($excludefilter) $excludefilterarray[]=$excludefilter;
119
				// Check if file is qualified
120
				foreach($excludefilterarray as $filt)
121
				{
122
					if (preg_match('/'.$filt.'/i',$file)) {
123
						$qualified=0; break;
124
					}
125
				}
126
127
				if ($qualified)
128
				{
129
					$isdir=is_dir(dol_osencode($path."/".$file));
130
					// Check whether this is a file or directory and whether we're interested in that type
131
					if ($isdir && (($types=="directories") || ($types=="all") || $recursive))
132
					{
133
						// Add entry into file_list array
134
						if (($types=="directories") || ($types=="all"))
135
						{
136
							if ($loaddate || $sortcriteria == 'date') $filedate=dol_filemtime($path."/".$file);
137
							if ($loadsize || $sortcriteria == 'size') $filesize=dol_filesize($path."/".$file);
138
139
							if (! $filter || preg_match('/'.$filter.'/i',$file))	// We do not search key $filter into all $path, only into $file part
140
							{
141
								preg_match('/([^\/]+)\/[^\/]+$/',$path.'/'.$file,$reg);
142
								$level1name=(isset($reg[1])?$reg[1]:'');
143
								$file_list[] = array(
144
										"name" => $file,
145
										"path" => $path,
146
										"level1name" => $level1name,
147
										"fullname" => $path.'/'.$file,
148
										"date" => $filedate,
149
										"size" => $filesize,
150
										"type" => 'dir'
151
								);
152
							}
153
						}
154
155
						// if we're in a directory and we want recursive behavior, call this function again
156
						if ($recursive)
157
						{
158
							$file_list = array_merge($file_list,dol_dir_list($path."/".$file, $types, $recursive, $filter, $excludefilter, $sortcriteria, $sortorder, $mode, $nohook));
159
						}
160
					}
161
					else if (! $isdir && (($types == "files") || ($types == "all")))
162
					{
163
						// Add file into file_list array
164
						if ($loaddate || $sortcriteria == 'date') $filedate=dol_filemtime($path."/".$file);
165
						if ($loadsize || $sortcriteria == 'size') $filesize=dol_filesize($path."/".$file);
166
167
						if (! $filter || preg_match('/'.$filter.'/i',$file))	// We do not search key $filter into $path, only into $file
168
						{
169
							preg_match('/([^\/]+)\/[^\/]+$/',$path.'/'.$file,$reg);
170
							$level1name=(isset($reg[1])?$reg[1]:'');
171
							$file_list[] = array(
172
									"name" => $file,
173
									"path" => $path,
174
									"level1name" => $level1name,
175
									"fullname" => $path.'/'.$file,
176
									"date" => $filedate,
177
									"size" => $filesize,
178
									"type" => 'file'
179
							);
180
						}
181
					}
182
				}
183
			}
184
			closedir($dir);
185
186
			// Obtain a list of columns
187
			if (! empty($sortcriteria))
188
			{
189
				$myarray=array();
190
				foreach ($file_list as $key => $row)
191
				{
192
					$myarray[$key] = (isset($row[$sortcriteria])?$row[$sortcriteria]:'');
193
				}
194
				// Sort the data
195
				if ($sortorder) array_multisort($myarray, $sortorder, $file_list);
196
			}
197
		}
198
	}
199
	
200
	$file_list = array_merge($file_list, $hookmanager->resArray);
201
	
202
	return $file_list;
203
}
204
205
206
/**
207
 *  Scan a directory and return a list of files/directories.
208
 *  Content for string is UTF8 and dir separator is "/".
209
 *
210
 *  @param	string		$path        	Starting path from which to search. Example: 'produit/MYPROD'
211
 *  @param	string		$filter        	Regex filter to restrict list. This regex value must be escaped for '/', since this char is used for preg_match function
212
 *  @param	array|null	$excludefilter  Array of Regex for exclude filter (example: array('(\.meta|_preview.*\.png)$','^\.'))
213
 *  @param	string		$sortcriteria	Sort criteria ("","fullname","name","date","size")
214
 *  @param	string		$sortorder		Sort order (SORT_ASC, SORT_DESC)
215
 *	@param	int			$mode			0=Return array minimum keys loaded (faster), 1=Force all keys like description
216
 *  @return	array						Array of array('name'=>'xxx','fullname'=>'/abc/xxx','type'=>'dir|file',...)
217
 *  @see dol_dir_list
218
 */
219
function dol_dir_list_in_database($path, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0)
220
{
221
    global $conf, $db;
222
    
223
    $sql=" SELECT rowid, label, entity, filename, filepath, fullpath_orig, keywords, cover, gen_or_uploaded, extraparams, date_c, date_m, fk_user_c, fk_user_m, acl, position";
224
    if ($mode) $sql.=", description";
225
    $sql.=" FROM ".MAIN_DB_PREFIX."ecm_files";
226
    $sql.=" WHERE filepath = '".$db->escape($path)."'";
227
    $sql.=" AND entity = ".$conf->entity;
228
229
    $resql = $db->query($sql);
230
    if ($resql)
231
    {
232
        $file_list=array();
233
        $num = $db->num_rows($resql);
234
        $i = 0;
235
        while ($i < $num)
236
        {
237
            $obj = $db->fetch_object($resql);            
238
            if ($obj)
239
            {
240
                preg_match('/([^\/]+)\/[^\/]+$/',DOL_DATA_ROOT.'/'.$obj->filepath.'/'.$obj->filename,$reg);
241
                $level1name=(isset($reg[1])?$reg[1]:'');
242
                $file_list[] = array(
243
                    "rowid" => $obj->rowid,
244
                    "label" => $obj->label,         // md5
245
    				"name" => $obj->filename,
246
    				"path" => DOL_DATA_ROOT.'/'.$obj->filepath,
247
                    "level1name" => $level1name,
248
    				"fullname" => DOL_DATA_ROOT.'/'.$obj->filepath.'/'.$obj->filename,
249
    				"fullpath_orig" => $obj->fullpath_orig,
250
                    "date_c" => $db->jdate($obj->date_c),
251
                    "date_m" => $db->jdate($obj->date_m),
252
    				"type" => 'file',
253
                    "keywords" => $obj->keywords,
254
                    "cover" => $obj->cover,
255
                    "position" => (int) $obj->position,
256
                    "acl" => $obj->acl
257
                );
258
            }
259
            $i++;
260
        }
261
        
262
        // Obtain a list of columns
263
        if (! empty($sortcriteria))
264
        {
265
            $myarray=array();
266
            foreach ($file_list as $key => $row)
267
            {
268
                $myarray[$key] = (isset($row[$sortcriteria])?$row[$sortcriteria]:'');
269
            }
270
            // Sort the data
271
            if ($sortorder) array_multisort($myarray, $sortorder, $file_list);
272
        }
273
        
274
        return $file_list;
275
    }
276
    else
277
    {
278
        dol_print_error($db);
279
        return array();
280
    }
281
}
282
    
283
284
/**
285
 * Fast compare of 2 files identified by their properties ->name, ->date and ->size
286
 *
287
 * @param	string 	$a		File 1
288
 * @param 	string	$b		File 2
289
 * @return 	int				1, 0, 1
290
 */
291
function dol_compare_file($a, $b)
292
{
293
	global $sortorder;
294
	global $sortfield;
295
296
	$sortorder=strtoupper($sortorder);
297
298
	if ($sortorder == 'ASC') { $retup=-1; $retdown=1; }
299
	else { $retup=1; $retdown=-1; }
300
301
	if ($sortfield == 'name')
302
	{
303
		if ($a->name == $b->name) return 0;
304
		return ($a->name < $b->name) ? $retup : $retdown;
305
	}
306
	if ($sortfield == 'date')
307
	{
308
		if ($a->date == $b->date) return 0;
309
		return ($a->date < $b->date) ? $retup : $retdown;
310
	}
311
	if ($sortfield == 'size')
312
	{
313
		if ($a->size == $b->size) return 0;
314
		return ($a->size < $b->size) ? $retup : $retdown;
315
	}
316
}
317
318
319
/**
320
 * Test if filename is a directory
321
 *
322
 * @param	string		$folder     Name of folder
323
 * @return	boolean     			True if it's a directory, False if not found
324
 */
325
function dol_is_dir($folder)
326
{
327
    $newfolder=dol_osencode($folder);
328
    if (is_dir($newfolder)) return true;
329
    else return false;
330
}
331
332
/**
333
 * Return if path is a file
334
 *
335
 * @param   string		$pathoffile		Path of file
336
 * @return  boolean     			    True or false
337
 */
338
function dol_is_file($pathoffile)
339
{
340
    $newpathoffile=dol_osencode($pathoffile);
341
    return is_file($newpathoffile);
342
}
343
344
/**
345
 * Return if path is an URL
346
 *
347
 * @param   string		$url	Url
348
 * @return  boolean      	   	True or false
349
 */
350
function dol_is_url($url)
351
{
352
    $tmpprot=array('file','http','https','ftp','zlib','data','ssh','ssh2','ogg','expect');
353
    foreach($tmpprot as $prot)
354
    {
355
        if (preg_match('/^'.$prot.':/i',$url)) return true;
356
    }
357
    return false;
358
}
359
360
/**
361
 * 	Test if a folder is empty
362
 *
363
 * 	@param	string	$folder		Name of folder
364
 * 	@return boolean				True if dir is empty or non-existing, False if it contains files
365
 */
366
function dol_dir_is_emtpy($folder)
367
{
368
	$newfolder=dol_osencode($folder);
369
	if (is_dir($newfolder))
370
	{
371
		$handle = opendir($newfolder);
372
        $folder_content = '';
373
		while ((gettype($name = readdir($handle)) != "boolean"))
374
		{
375
			$name_array[] = $name;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$name_array was never initialized. Although not strictly required by PHP, it is generally a good practice to add $name_array = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
376
		}
377
		foreach($name_array as $temp) $folder_content .= $temp;
0 ignored issues
show
Bug introduced by
The variable $name_array 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...
378
379
        closedir($handle);
380
381
		if ($folder_content == "...") return true;
382
		else return false;
383
	}
384
	else
385
	return true; // Dir does not exists
386
}
387
388
/**
389
 * 	Count number of lines in a file
390
 *
391
 * 	@param	string	$file		Filename
392
 * 	@return int					<0 if KO, Number of lines in files if OK
393
 */
394
function dol_count_nb_of_line($file)
395
{
396
	$nb=0;
397
398
	$newfile=dol_osencode($file);
399
	//print 'x'.$file;
400
	$fp=fopen($newfile,'r');
401
	if ($fp)
402
	{
403
		while (!feof($fp))
404
		{
405
			$line=fgets($fp);
406
            // We increase count only if read was success. We need test because feof return true only after fgets so we do n+1 fgets for a file with n lines.
407
			if (! $line === false) $nb++;
408
		}
409
		fclose($fp);
410
	}
411
	else
412
	{
413
		$nb=-1;
414
	}
415
416
	return $nb;
417
}
418
419
420
/**
421
 * Return size of a file
422
 *
423
 * @param 	string		$pathoffile		Path of file
424
 * @return 	integer						File size
425
 */
426
function dol_filesize($pathoffile)
427
{
428
	$newpathoffile=dol_osencode($pathoffile);
429
	return filesize($newpathoffile);
430
}
431
432
/**
433
 * Return time of a file
434
 *
435
 * @param 	string		$pathoffile		Path of file
436
 * @return 	int					Time of file
437
 */
438
function dol_filemtime($pathoffile)
439
{
440
	$newpathoffile=dol_osencode($pathoffile);
441
	return @filemtime($newpathoffile); // @Is to avoid errors if files does not exists
442
}
443
444
/**
445
 * Make replacement of strings into a file.
446
 *
447
 * @param	string	$srcfile			Source file (can't be a directory)
448
 * @param	array	$arrayreplacement	Array with strings to replace
449
 * @param	string	$destfile			Destination file (can't be a directory). If empty, will be same than source file.
450
 * @param	int		$newmask			Mask for new file (0 by default means $conf->global->MAIN_UMASK). Example: '0666'
451
 * @return	int							<0 if error, 0 if nothing done (dest file already exists), >0 if OK
452
 * @see		dolCopyr
453
 */
454
function dolReplaceInFile($srcfile, $arrayreplacement, $destfile='', $newmask=0)
455
{
456
    global $conf;
457
458
    dol_syslog("files.lib.php::dolReplaceInFile srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask);
459
460
    if (empty($srcfile)) return -1;
461
    if (empty($destfile)) $destfile=$srcfile;
462
    
463
    $destexists=dol_is_file($destfile);
464
    if (($destfile != $srcfile) && $destexists) return 0;
465
    
466
    $tmpdestfile=$destfile.'.tmp';
467
468
    $newpathofsrcfile=dol_osencode($srcfile);
469
    $newpathoftmpdestfile=dol_osencode($tmpdestfile);
470
    $newpathofdestfile=dol_osencode($destfile);
471
    $newdirdestfile=dirname($newpathofdestfile);
472
473
    if ($destexists && ! is_writable($newpathofdestfile))
474
    {
475
        dol_syslog("files.lib.php::dolReplaceInFile failed Permission denied to overwrite target file", LOG_WARNING);
476
        return -1;
477
    }
478
    if (! is_writable($newdirdestfile))
479
    {
480
        dol_syslog("files.lib.php::dolReplaceInFile failed Permission denied to write into target directory ".$newdirdestfile, LOG_WARNING);
481
        return -2;
482
    }
483
   
484
    dol_delete_file($tmpdestfile);
485
    
486
    
487
    
488
    
489
    // Rename
490
    $result=dol_move($newpathoftmpdestfile, $newpathofdestfile, $newmask, (($destfile == $srcfile)?1:0));
491
    if (! $result)
492
    {
493
        dol_syslog("files.lib.php::dolReplaceInFile failed to move tmp file to final dest", LOG_WARNING);
494
        return -3;
495
    }
496
    if (empty($newmask) && ! empty($conf->global->MAIN_UMASK)) $newmask=$conf->global->MAIN_UMASK;
497
    if (empty($newmask))	// This should no happen
498
    {
499
        dol_syslog("Warning: dolReplaceInFile called with empty value for newmask and no default value defined", LOG_WARNING);
500
        $newmask='0664';
501
    }
502
503
    @chmod($newpathofdestfile, octdec($newmask));
504
505
    return 1;
506
}
507
508
/**
509
 * Copy a file to another file.
510
 *
511
 * @param	string	$srcfile			Source file (can't be a directory)
512
 * @param	string	$destfile			Destination file (can't be a directory)
513
 * @param	int		$newmask			Mask for new file (0 by default means $conf->global->MAIN_UMASK). Example: '0666'
514
 * @param 	int		$overwriteifexists	Overwrite file if exists (1 by default)
515
 * @return	int							<0 if error, 0 if nothing done (dest file already exists and overwriteifexists=0), >0 if OK
516
 * @see		dolCopyr
517
 */
518
function dol_copy($srcfile, $destfile, $newmask=0, $overwriteifexists=1)
519
{
520
	global $conf;
521
522
	dol_syslog("files.lib.php::dol_copy srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwriteifexists=".$overwriteifexists);
523
524
	if (empty($srcfile) || empty($destfile)) return -1;
525
526
	$destexists=dol_is_file($destfile);
527
	if (! $overwriteifexists && $destexists) return 0;
528
529
	$newpathofsrcfile=dol_osencode($srcfile);
530
    $newpathofdestfile=dol_osencode($destfile);
531
    $newdirdestfile=dirname($newpathofdestfile);
532
533
    if ($destexists && ! is_writable($newpathofdestfile))
534
    {
535
        dol_syslog("files.lib.php::dol_copy failed Permission denied to overwrite target file", LOG_WARNING);
536
        return -1;
537
    }
538
    if (! is_writable($newdirdestfile))
539
    {
540
        dol_syslog("files.lib.php::dol_copy failed Permission denied to write into target directory ".$newdirdestfile, LOG_WARNING);
541
        return -2;
542
    }
543
    // Copy with overwriting if exists
544
    $result=@copy($newpathofsrcfile, $newpathofdestfile);
545
	//$result=copy($newpathofsrcfile, $newpathofdestfile);	// To see errors, remove @
546
	if (! $result)
547
	{
548
	    dol_syslog("files.lib.php::dol_copy failed to copy", LOG_WARNING);
549
	    return -3;
550
	}
551
	if (empty($newmask) && ! empty($conf->global->MAIN_UMASK)) $newmask=$conf->global->MAIN_UMASK;
552
	if (empty($newmask))	// This should no happen
553
	{
554
		dol_syslog("Warning: dol_copy called with empty value for newmask and no default value defined", LOG_WARNING);
555
		$newmask='0664';
556
	}
557
558
	@chmod($newpathofdestfile, octdec($newmask));
559
560
	return 1;
561
}
562
563
/**
564
 * Copy a dir to another dir.
565
 *
566
 * @param	string	$srcfile			Source file (a directory)
567
 * @param	string	$destfile			Destination file (a directory)
568
 * @param	int		$newmask			Mask for new file (0 by default means $conf->global->MAIN_UMASK). Example: '0666'
569
 * @param 	int		$overwriteifexists	Overwrite file if exists (1 by default)
570
 * @return	int							<0 if error, 0 if nothing done (dest dir already exists and overwriteifexists=0), >0 if OK
571
 * @see		dol_copy
572
 */
573
function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists)
574
{
575
	global $conf;
576
577
	$result=0;
578
579
	dol_syslog("files.lib.php::dolCopyDir srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwriteifexists=".$overwriteifexists);
580
581
	if (empty($srcfile) || empty($destfile)) return -1;
582
583
	$destexists=dol_is_dir($destfile);
584
	if (! $overwriteifexists && $destexists) return 0;
585
    
586
    if (! $destexists)
587
    {
588
        // We must set mask just before creating dir, becaause it can be set differently by dol_copy
589
        umask(0);
590
        $dirmaskdec=octdec($newmask);
591
        if (empty($newmask) && ! empty($conf->global->MAIN_UMASK)) $dirmaskdec=octdec($conf->global->MAIN_UMASK);
592
        $dirmaskdec |= octdec('0200');  // Set w bit required to be able to create content for recursive subdirs files
593
        dol_mkdir($destfile."/".$file, '', decoct($dirmaskdec));
0 ignored issues
show
Bug introduced by
The variable $file seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
594
    }
595
    
596
	$srcfile=dol_osencode($srcfile);
597
	$destfile=dol_osencode($destfile);
598
599
    // recursive function to copy
600
    // all subdirectories and contents:
601
	if (is_dir($srcfile))
602
	{
603
        $dir_handle=opendir($srcfile);
604
        while ($file=readdir($dir_handle))
605
        {
606
            if ($file!="." && $file!="..")
607
            {
608
                if (is_dir($srcfile."/".$file))
609
                {
610
                    if (!is_dir($destfile."/".$file))
611
                    {
612
                        // We must set mask just before creating dir, becaause it can be set differently by dol_copy
613
                    	umask(0);
614
						$dirmaskdec=octdec($newmask);
615
						if (empty($newmask) && ! empty($conf->global->MAIN_UMASK)) $dirmaskdec=octdec($conf->global->MAIN_UMASK);
616
						$dirmaskdec |= octdec('0200');  // Set w bit required to be able to create content for recursive subdirs files
617
                    	dol_mkdir($destfile."/".$file, '', decoct($dirmaskdec));
618
                    }
619
                    $tmpresult=dolCopyDir($srcfile."/".$file, $destfile."/".$file, $newmask, $overwriteifexists);
620
                }
621
                else
622
				{
623
                    $tmpresult=dol_copy($srcfile."/".$file, $destfile."/".$file, $newmask, $overwriteifexists);
624
                }
625
                // Set result
626
                if ($result > 0 && $tmpresult >= 0)
627
                {
628
                    // Do nothing, so we don't set result to 0 if tmpresult is 0 and result was success in a previous pass
629
                }
630
                else
631
                {
632
                    $result=$tmpresult;
633
                }
634
                if ($result < 0) break;
635
                
636
            }
637
        }
638
        closedir($dir_handle);
639
    }
640
    else
641
	{
642
        $result=dol_copy($srcfile, $destfile, $newmask, $overwriteifexists);
643
    }
644
645
    return $result;
646
}
647
648
649
/**
650
 * Move a file into another name.
651
 * This function differs from dol_move_uploaded_file, because it can be called in any context.
652
 *
653
 * @param	string  $srcfile            Source file (can't be a directory. use native php @rename() to move a directory)
654
 * @param   string	$destfile           Destination file (can't be a directory. use native php @rename() to move a directory)
655
 * @param   integer	$newmask            Mask in octal string for new file (0 by default means $conf->global->MAIN_UMASK)
656
 * @param   int		$overwriteifexists  Overwrite file if exists (1 by default)
657
 * @return  boolean 		            True if OK, false if KO
658
 */
659
function dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1)
660
{
661
    global $user, $db, $conf;
662
    $result=false;
663
664
    dol_syslog("files.lib.php::dol_move srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwritifexists=".$overwriteifexists);
665
    $srcexists=dol_is_file($srcfile);
666
    $destexists=dol_is_file($destfile);
667
668
    if (! $srcexists) 
669
    {
670
        dol_syslog("files.lib.php::dol_move srcfile does not exists. we ignore the move request.");
671
        return false;
672
    }
673
    
674
    if ($overwriteifexists || ! $destexists)
675
    {
676
        $newpathofsrcfile=dol_osencode($srcfile);
677
        $newpathofdestfile=dol_osencode($destfile);
678
679
        $result=@rename($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @
680
        if (! $result)
681
        {
682
        	if ($destexists)
683
        	{
684
        		dol_syslog("files.lib.php::dol_move Failed. We try to delete target first and move after.", LOG_WARNING);
685
        		// We force delete and try again. Rename function sometimes fails to replace dest file with some windows NTFS partitions.
686
        		dol_delete_file($destfile);
687
        		$result=@rename($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @
688
        	}
689
        	else dol_syslog("files.lib.php::dol_move Failed.", LOG_WARNING);
690
        }
691
692
        // Move ok
693
        if ($result)
694
        {
695
            // Rename entry into ecm database
696
            $rel_filetorenamebefore = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $srcfile);
697
            $rel_filetorenameafter = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $destfile);
698
            if (! preg_match('/(\/temp\/|\/thumbs|\.meta$)/', $rel_filetorenameafter))     // If not a tmp file
699
            {
700
                $rel_filetorenamebefore = preg_replace('/^[\\/]/', '', $rel_filetorenamebefore);
701
                $rel_filetorenameafter = preg_replace('/^[\\/]/', '', $rel_filetorenameafter);
702
                //var_dump($rel_filetorenamebefore.' - '.$rel_filetorenameafter);
703
704
                dol_syslog("Try to rename also entries in database for full relative path before = ".$rel_filetorenamebefore." after = ".$rel_filetorenameafter, LOG_DEBUG);
705
                include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
706
                $ecmfile=new EcmFiles($db);
707
                $result = $ecmfile->fetch(0, '', $rel_filetorenamebefore);
708
                if ($result > 0)   // If found
709
                {
710
                    $filename = basename($rel_filetorenameafter);
711
                    $rel_dir = dirname($rel_filetorenameafter);
712
                    $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
713
                    $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
714
                    
715
                    $ecmfile->filepath = $rel_dir;
716
                    $ecmfile->filename = $filename;
717
                    $result = $ecmfile->update($user);
718
                }
719
                elseif ($result == 0)   // If not found
720
                {
721
                    $filename = basename($rel_filetorenameafter);
722
                    $rel_dir = dirname($rel_filetorenameafter);
723
                    $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
724
                    $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
725
                    	
726
                    $ecmfile->filepath = $rel_dir;
727
                    $ecmfile->filename = $filename;
728
                    $ecmfile->label = md5_file(dol_osencode($destfile));        // $destfile is a full path to file
729
                    $ecmfile->fullpath_orig = $srcfile;
730
                    $ecmfile->gen_or_uploaded = 'unknown';
731
                    $ecmfile->description = '';    // indexed content
732
                    $ecmfile->keyword = '';        // keyword content
733
                    $result = $ecmfile->create($user);
734
                    if ($result < 0)
735
                    {
736
                        setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
737
                    }                    
738
                }
739
                elseif ($result < 0)
740
                {
741
                    setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
742
                }
743
            }        
744
        }
745
        
746
        if (empty($newmask)) $newmask=empty($conf->global->MAIN_UMASK)?'0755':$conf->global->MAIN_UMASK;
747
        $newmaskdec=octdec($newmask);
748
        // Currently method is restricted to files (dol_delete_files previously used is for files, and mask usage if for files too)
749
        // to allow mask usage for dir, we shoul introduce a new param "isdir" to 1 to complete newmask like this
750
        // if ($isdir) $newmaskdec |= octdec('0111');  // Set x bit required for directories
751
        @chmod($newpathofdestfile, $newmaskdec);
752
    }
753
754
    return $result;
755
}
756
757
/**
758
 *	Unescape a file submitted by upload.
759
 *  PHP escape char " (%22) or char ' (%27) into $FILES.
760
 *
761
 *	@param	string	$filename		Filename
762
 *	@return	string					Filename sanitized
763
 */
764
function dol_unescapefile($filename)
765
{
766
	// Remove path information and dots around the filename, to prevent uploading
767
	// into different directories or replacing hidden system files.
768
	// Also remove control characters and spaces (\x00..\x20) around the filename:
769
	return trim(basename($filename), ".\x00..\x20");
770
}
771
772
/**
773
 *	Make control on an uploaded file from an GUI page and move it to final destination.
774
 * 	If there is errors (virus found, antivir in error, bad filename), file is not moved.
775
 *  Note: This function can be used only into a HTML page context. Use dol_move if you are outside.
776
 *
777
 *	@param	string	$src_file			Source full path filename ($_FILES['field']['tmp_name'])
778
 *	@param	string	$dest_file			Target full path filename  ($_FILES['field']['name'])
779
 * 	@param	int		$allowoverwrite		1=Overwrite target file if it already exists
780
 * 	@param	int		$disablevirusscan	1=Disable virus scan
781
 * 	@param	integer	$uploaderrorcode	Value of PHP upload error code ($_FILES['field']['error'])
782
 * 	@param	int		$nohook				Disable all hooks
783
 * 	@param	string	$varfiles			_FILES var name
784
 *	@return int       			  		>0 if OK, <0 or string if KO
785
 *  @see    dol_move
786
 */
787
function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $nohook=0, $varfiles='addedfile')
788
{
789
	global $conf, $db, $user, $langs;
790
	global $object, $hookmanager;
791
792
	$reshook=0;
793
	$file_name = $dest_file;
794
795
	if (empty($nohook))
796
	{
797
		// If an upload error has been reported
798
		if ($uploaderrorcode)
799
		{
800
			switch($uploaderrorcode)
801
			{
802
				case UPLOAD_ERR_INI_SIZE:	// 1
803
					return 'ErrorFileSizeTooLarge';
804
					break;
805
				case UPLOAD_ERR_FORM_SIZE:	// 2
806
					return 'ErrorFileSizeTooLarge';
807
					break;
808
				case UPLOAD_ERR_PARTIAL:	// 3
809
					return 'ErrorPartialFile';
810
					break;
811
				case UPLOAD_ERR_NO_TMP_DIR:	//
812
					return 'ErrorNoTmpDir';
813
					break;
814
				case UPLOAD_ERR_CANT_WRITE:
815
					return 'ErrorFailedToWriteInDir';
816
					break;
817
				case UPLOAD_ERR_EXTENSION:
818
					return 'ErrorUploadBlockedByAddon';
819
					break;
820
				default:
821
					break;
822
			}
823
		}
824
825
		// If we need to make a virus scan
826
		if (empty($disablevirusscan) && file_exists($src_file) && ! empty($conf->global->MAIN_ANTIVIRUS_COMMAND))
827
		{
828
			if (! class_exists('AntiVir')) {
829
				require_once DOL_DOCUMENT_ROOT.'/core/class/antivir.class.php';
830
			}
831
			$antivir=new AntiVir($db);
832
			$result = $antivir->dol_avscan_file($src_file);
833
			if ($result < 0)	// If virus or error, we stop here
834
			{
835
				$reterrors=$antivir->errors;
836
				dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: result='.$result.' errors='.join(',',$antivir->errors), LOG_WARNING);
837
				return 'ErrorFileIsInfectedWithAVirus: '.join(',',$reterrors);
838
			}
839
		}
840
841
		// Security:
842
		// Disallow file with some extensions. We renamed them.
843
		// Car si on a mis le rep documents dans un rep de la racine web (pas bien), cela permet d'executer du code a la demande.
844
		if (preg_match('/\.htm|\.html|\.php|\.pl|\.cgi$/i',$dest_file) && empty($conf->global->MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED))
845
		{
846
			$file_name.= '.noexe';
847
		}
848
849
		// Security:
850
		// We refuse cache files/dirs, upload using .. and pipes into filenames.
851
		if (preg_match('/^\./',$src_file) || preg_match('/\.\./',$src_file) || preg_match('/[<>|]/',$src_file))
852
		{
853
			dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING);
854
			return -1;
855
		}
856
857
		// Security:
858
		// On interdit fichiers caches, remontees de repertoire ainsi que les pipe dans les noms de fichiers.
859
		if (preg_match('/^\./',$dest_file) || preg_match('/\.\./',$dest_file) || preg_match('/[<>|]/',$dest_file))
860
		{
861
			dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING);
862
			return -2;
863
		}
864
865
		$reshook=$hookmanager->initHooks(array('fileslib'));
866
867
		$parameters=array('dest_file' => $dest_file, 'src_file' => $src_file, 'file_name' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite);
868
		$reshook=$hookmanager->executeHooks('moveUploadedFile', $parameters, $object);
869
	}
870
871
	if ($reshook < 0)	// At least one blocking error returned by one hook
872
	{
873
		$errmsg = join(',', $hookmanager->errors);
874
		if (empty($errmsg)) $errmsg = 'ErrorReturnedBySomeHooks';	// Should not occurs. Added if hook is bugged and does not set ->errors when there is error.
875
		return $errmsg;
876
	}
877
	elseif (empty($reshook))
878
	{
879
		// The file functions must be in OS filesystem encoding.
880
		$src_file_osencoded=dol_osencode($src_file);
881
		$file_name_osencoded=dol_osencode($file_name);
882
883
		// Check if destination dir is writable
884
		// TODO
885
886
		// Check if destination file already exists
887
		if (! $allowoverwrite)
888
		{
889
			if (file_exists($file_name_osencoded))
890
			{
891
				dol_syslog("Files.lib::dol_move_uploaded_file File ".$file_name." already exists. Return 'ErrorFileAlreadyExists'", LOG_WARNING);
892
				return 'ErrorFileAlreadyExists';
893
			}
894
		}
895
896
		// Move file
897
		$return=move_uploaded_file($src_file_osencoded, $file_name_osencoded);
898
		if ($return)
899
		{
900
			if (! empty($conf->global->MAIN_UMASK)) @chmod($file_name_osencoded, octdec($conf->global->MAIN_UMASK));
901
			dol_syslog("Files.lib::dol_move_uploaded_file Success to move ".$src_file." to ".$file_name." - Umask=".$conf->global->MAIN_UMASK, LOG_DEBUG);
902
			return 1;	// Success
903
		}
904
		else
905
		{
906
			dol_syslog("Files.lib::dol_move_uploaded_file Failed to move ".$src_file." to ".$file_name, LOG_ERR);
907
			return -3;	// Unknown error
908
		}
909
	}
910
911
	return 1;	// Success
912
}
913
914
/**
915
 *  Remove a file or several files with a mask
916
 *
917
 *  @param	string	$file           File to delete or mask of files to delete
918
 *  @param  int		$disableglob    Disable usage of glob like * so function is an exact delete function that will return error if no file found
919
 *  @param  int		$nophperrors    Disable all PHP output errors
920
 *  @param	int		$nohook			Disable all hooks
921
 *  @param	object	$object			Current object in use
922
 *  @return boolean         		True if no error (file is deleted or if glob is used and there's nothing to delete), False if error
923
 *  @see dol_delete_dir
924
 */
925
function dol_delete_file($file,$disableglob=0,$nophperrors=0,$nohook=0,$object=null)
0 ignored issues
show
Coding Style introduced by
dol_delete_file uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
926
{
927
	global $db, $conf, $user, $langs;
928
	global $hookmanager;
929
930
	$langs->load("other");
931
	$langs->load("errors");
932
933
	dol_syslog("dol_delete_file file=".$file." disableglob=".$disableglob." nophperrors=".$nophperrors." nohook=".$nohook);
934
935
	// Security:
936
	// We refuse transversal using .. and pipes into filenames.
937
	if (preg_match('/\.\./',$file) || preg_match('/[<>|]/',$file))
938
	{
939
        dol_syslog("Refused to delete file ".$file, LOG_WARNING);
940
	    return False;
941
	}
942
	
943
	if (empty($nohook))
944
	{
945
		$hookmanager->initHooks(array('fileslib'));
946
947
		$parameters=array(
948
				'GET' => $_GET,
949
				'file' => $file,
950
				'disableglob'=> $disableglob,
951
				'nophperrors' => $nophperrors
952
		);
953
		$reshook=$hookmanager->executeHooks('deleteFile', $parameters, $object);
954
	}
955
956
	if (empty($nohook) && $reshook != 0) // reshook = 0 to do standard actions, 1 = ok, -1 = ko
957
	{
958
		if ($reshook < 0) return false;
0 ignored issues
show
Bug introduced by
The variable $reshook 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...
959
		return true;
960
	}
961
	else
962
	{
963
		$error=0;
964
965
		//print "x".$file." ".$disableglob;exit;
966
		$file_osencoded=dol_osencode($file);    // New filename encoded in OS filesystem encoding charset
967
		if (empty($disableglob) && ! empty($file_osencoded))
968
		{
969
			$ok=true;
970
			$globencoded=str_replace('[','\[',$file_osencoded);
971
			$globencoded=str_replace(']','\]',$globencoded);
972
			$listofdir=glob($globencoded);
973
			if (! empty($listofdir) && is_array($listofdir))
974
			{
975
				foreach ($listofdir as $filename)
976
				{
977
					if ($nophperrors) $ok=@unlink($filename);
978
					else $ok=unlink($filename);
979
					if ($ok) 
980
					{
981
					    dol_syslog("Removed file ".$filename, LOG_DEBUG);
982
					    
983
	                    // Delete entry into ecm database
984
    				    $rel_filetodelete = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $filename);
985
    				    if (! preg_match('/(\/temp\/|\/thumbs\/|\.meta$)/', $rel_filetodelete))     // If not a tmp file
986
    				    {
987
    				        $rel_filetodelete = preg_replace('/^[\\/]/', '', $rel_filetodelete);
988
    				        
989
    				        dol_syslog("Try to remove also entries in database for full relative path = ".$rel_filetodelete, LOG_DEBUG);
990
        				    include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
991
        				    $ecmfile=new EcmFiles($db);
992
        				    $result = $ecmfile->fetch(0, '', $rel_filetodelete);
993
        				    if ($result >= 0 && $ecmfile->id > 0)
994
        				    {
995
        				        $result = $ecmfile->delete($user);
996
        				    }
997
        				    if ($result < 0)
998
        				    {
999
        				        setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
1000
        				    }
1001
    				    }
1002
					}
1003
					else dol_syslog("Failed to remove file ".$filename, LOG_WARNING);
1004
					// TODO Failure to remove can be because file was already removed or because of permission
1005
					// If error because of not exists, we must should return true and we should return false if this is a permission problem
1006
				}
1007
			}
1008
			else dol_syslog("No files to delete found", LOG_DEBUG);
1009
		}
1010
		else
1011
		{
1012
			$ok=false;
1013
			if ($nophperrors) $ok=@unlink($file_osencoded);
1014
			else $ok=unlink($file_osencoded);
1015
			if ($ok) dol_syslog("Removed file ".$file_osencoded, LOG_DEBUG);
1016
			else dol_syslog("Failed to remove file ".$file_osencoded, LOG_WARNING);      
1017
		}
1018
1019
		return $ok;
1020
	}
1021
}
1022
1023
/**
1024
 *  Remove a directory (not recursive, so content must be empty).
1025
 *  If directory is not empty, return false
1026
 *
1027
 *  @param	string	$dir            Directory to delete
1028
 *  @param  int		$nophperrors    Disable all PHP output errors
1029
 *  @return boolean         		True if success, false if error
1030
 *  @see dol_delete_file
1031
 */
1032
function dol_delete_dir($dir,$nophperrors=0)
1033
{
1034
	// Security:
1035
	// We refuse transversal using .. and pipes into filenames.
1036
	if (preg_match('/\.\./',$dir) || preg_match('/[<>|]/',$dir))
1037
	{
1038
        dol_syslog("Refused to delete dir ".$dir, LOG_WARNING);
1039
	    return False;
1040
	}
1041
	
1042
    $dir_osencoded=dol_osencode($dir);
1043
    return ($nophperrors?@rmdir($dir_osencoded):rmdir($dir_osencoded));
1044
}
1045
1046
/**
1047
 *  Remove a directory $dir and its subdirectories (or only files and subdirectories)
1048
 *
1049
 *  @param	string	$dir            Dir to delete
1050
 *  @param  int		$count          Counter to count nb of deleted elements
1051
 *  @param  int		$nophperrors    Disable all PHP output errors
1052
 *  @param	int		$onlysub		Delete only files and subdir, not main directory
1053
 *  @return int             		Number of files and directory removed
1054
 */
1055
function dol_delete_dir_recursive($dir,$count=0,$nophperrors=0,$onlysub=0)
1056
{
1057
    dol_syslog("functions.lib:dol_delete_dir_recursive ".$dir,LOG_DEBUG);
1058
    if (dol_is_dir($dir))
1059
    {
1060
        $dir_osencoded=dol_osencode($dir);
1061
        if ($handle = opendir("$dir_osencoded"))
1062
        {
1063
            while (false !== ($item = readdir($handle)))
1064
            {
1065
                if (! utf8_check($item)) $item=utf8_encode($item);  // should be useless
1066
1067
                if ($item != "." && $item != "..")
1068
                {
1069
                    if (is_dir(dol_osencode("$dir/$item")))
1070
                    {
1071
                        $count=dol_delete_dir_recursive("$dir/$item",$count,$nophperrors);
1072
                    }
1073
                    else
1074
                    {
1075
                        dol_delete_file("$dir/$item",1,$nophperrors);
1076
                        $count++;
1077
                        //echo " removing $dir/$item<br>\n";
1078
                    }
1079
                }
1080
            }
1081
            closedir($handle);
1082
1083
            if (empty($onlysub))
1084
            {
1085
	            dol_delete_dir($dir,$nophperrors);
1086
    	        $count++;
1087
        	    //echo "removing $dir<br>\n";
1088
            }
1089
        }
1090
    }
1091
1092
    //echo "return=".$count;
1093
    return $count;
1094
}
1095
1096
1097
/**
1098
 *  Delete all preview files linked to object instance
1099
 *
1100
 *  @param	object	$object		Object to clean
1101
 *  @return	int					0 if error, 1 if OK
1102
 */
1103
function dol_delete_preview($object)
1104
{
1105
	global $langs,$conf;
1106
1107
	// Define parent dir of elements
1108
	$element = $object->element;
1109
1110
    if ($object->element == 'order_supplier')		$dir = $conf->fournisseur->dir_output.'/commande';
1111
    elseif ($object->element == 'invoice_supplier')	$dir = $conf->fournisseur->dir_output.'/facture';
1112
    elseif ($object->element == 'project')			$dir = $conf->projet->dir_output;
1113
    elseif ($object->element == 'shipping')			$dir = $conf->expedition->dir_output.'/sending';
1114
    elseif ($object->element == 'delivery')			$dir = $conf->expedition->dir_output.'/receipt';
1115
    elseif ($object->element == 'fichinter')		$dir = $conf->ficheinter->dir_output;
1116
    else $dir=empty($conf->$element->dir_output)?'':$conf->$element->dir_output;
1117
1118
    if (empty($dir)) return 'ErrorObjectNoSupportedByFunction';
1119
1120
	$refsan = dol_sanitizeFileName($object->ref);
1121
	$dir = $dir . "/" . $refsan ;
1122
	$file = $dir . "/" . $refsan . ".pdf.png";
1123
	$multiple = $file . ".";
1124
1125
	if (file_exists($file) && is_writable($file))
1126
	{
1127
		if (! dol_delete_file($file,1))
1128
		{
1129
			$object->error=$langs->trans("ErrorFailedToDeleteFile",$file);
1130
			return 0;
1131
		}
1132
	}
1133
	else
1134
	{
1135
		for ($i = 0; $i < 20; $i++)
1136
		{
1137
			$preview = $multiple.$i;
1138
1139
			if (file_exists($preview) && is_writable($preview))
1140
			{
1141
				if ( ! dol_delete_file($preview,1) )
1142
				{
1143
					$object->error=$langs->trans("ErrorFailedToOpenFile",$preview);
1144
					return 0;
1145
				}
1146
			}
1147
		}
1148
	}
1149
1150
	return 1;
1151
}
1152
1153
/**
1154
 *	Create a meta file with document file into same directory.
1155
 *	This should allow "grep" search.
1156
 *  This feature is enabled only if option MAIN_DOC_CREATE_METAFILE is set.
1157
 *
1158
 *	@param	CommonObject	$object		Object
1159
 *	@return	int					0 if we did nothing, >0 success, <0 error
1160
 */
1161
function dol_meta_create($object)
1162
{
1163
	global $conf;
1164
1165
	if (empty($conf->global->MAIN_DOC_CREATE_METAFILE)) return 0;	// By default, no metafile.
1166
1167
	// Define parent dir of elements
1168
	$element=$object->element;
1169
1170
	if ($object->element == 'order_supplier')		$dir = $conf->fournisseur->dir_output.'/commande';
1171
	elseif ($object->element == 'invoice_supplier')	$dir = $conf->fournisseur->dir_output.'/facture';
1172
	elseif ($object->element == 'project')			$dir = $conf->projet->dir_output;
1173
	elseif ($object->element == 'shipping')			$dir = $conf->expedition->dir_output.'/sending';
1174
	elseif ($object->element == 'delivery')			$dir = $conf->expedition->dir_output.'/receipt';
1175
	elseif ($object->element == 'fichinter')		$dir = $conf->ficheinter->dir_output;
1176
	else $dir=empty($conf->$element->dir_output)?'':$conf->$element->dir_output;
1177
1178
	if ($dir)
1179
	{
1180
		$object->fetch_thirdparty();
1181
1182
		$facref = dol_sanitizeFileName($object->ref);
1183
		$dir = $dir . "/" . $facref;
1184
		$file = $dir . "/" . $facref . ".meta";
1185
1186
		if (! is_dir($dir))
1187
		{
1188
			dol_mkdir($dir);
1189
		}
1190
1191
		if (is_dir($dir))
1192
		{
1193
			$nblignes = count($object->lines);
1194
			$client = $object->thirdparty->name . " " . $object->thirdparty->address . " " . $object->thirdparty->zip . " " . $object->thirdparty->town;
1195
			$meta = "REFERENCE=\"" . $object->ref . "\"
1196
			DATE=\"" . dol_print_date($object->date,'') . "\"
1197
			NB_ITEMS=\"" . $nblignes . "\"
1198
			CLIENT=\"" . $client . "\"
1199
			TOTAL_HT=\"" . $object->total_ht . "\"
1200
			TOTAL_TTC=\"" . $object->total_ttc . "\"\n";
1201
1202
			for ($i = 0 ; $i < $nblignes ; $i++)
1203
			{
1204
				//Pour les articles
1205
				$meta .= "ITEM_" . $i . "_QUANTITY=\"" . $object->lines[$i]->qty . "\"
1206
				ITEM_" . $i . "_TOTAL_HT=\"" . $object->lines[$i]->total_ht . "\"
1207
				ITEM_" . $i . "_TVA=\"" .$object->lines[$i]->tva_tx . "\"
1208
				ITEM_" . $i . "_DESCRIPTION=\"" . str_replace("\r\n","",nl2br($object->lines[$i]->desc)) . "\"
1209
				";
1210
			}
1211
		}
1212
1213
		$fp = fopen($file,"w");
1214
		fputs($fp,$meta);
0 ignored issues
show
Bug introduced by
The variable $meta 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...
1215
		fclose($fp);
1216
		if (! empty($conf->global->MAIN_UMASK))
1217
		@chmod($file, octdec($conf->global->MAIN_UMASK));
1218
1219
		return 1;
1220
	}
1221
1222
	return 0;
1223
}
1224
1225
1226
1227
/**
1228
 * Scan a directory and init $_SESSION to manage uploaded files with list of all found files.
1229
 * Note: Only email module seems to use this. Other feature initialize the $_SESSION doing $formmail->clear_attached_files(); $formmail->add_attached_files()
1230
 *
1231
 * @param	string	$pathtoscan				Path to scan
1232
 * @param   string  $trackid                Track id (used to prefix name of session vars to avoid conflict)
1233
 * @return	void
1234
 */
1235
function dol_init_file_process($pathtoscan='', $trackid='')
1236
{
1237
	$listofpaths=array();
1238
	$listofnames=array();
1239
	$listofmimes=array();
1240
1241
	if ($pathtoscan)
1242
	{
1243
		$listoffiles=dol_dir_list($pathtoscan,'files');
1244
		foreach($listoffiles as $key => $val)
1245
		{
1246
			$listofpaths[]=$val['fullname'];
1247
			$listofnames[]=$val['name'];
1248
			$listofmimes[]=dol_mimetype($val['name']);
1249
		}
1250
	}
1251
    $keytoavoidconflict = empty($trackid)?'':'-'.$trackid;
1252
	$_SESSION["listofpaths".$keytoavoidconflict]=join(';',$listofpaths);
1253
	$_SESSION["listofnames".$keytoavoidconflict]=join(';',$listofnames);
1254
	$_SESSION["listofmimes".$keytoavoidconflict]=join(';',$listofmimes);
1255
}
1256
1257
1258
/**
1259
 * Get and save an upload file (for example after submitting a new file a mail form).
1260
 * All information used are in db, conf, langs, user and _FILES.
1261
 * Note: This function can be used only into a HTML page context.
1262
 *
1263
 * @param	string	$upload_dir				Directory where to store uploaded file (note: used to forge $destpath = $upload_dir + filename)
1264
 * @param	int		$allowoverwrite			1=Allow overwrite existing file
1265
 * @param	int		$donotupdatesession		1=Do no edit _SESSION variable
1266
 * @param	string	$varfiles				_FILES var name
1267
 * @param	string	$savingdocmask			Mask to use to define output filename. For example 'XXXXX-__YYYYMMDD__-__file__'
1268
 * @param	string	$link					Link to add (to add a link instead of a file)
1269
 * @param   string  $trackid                Track id (used to prefix name of session vars to avoid conflict)
1270
 * @return	int                             <=0 if KO, >0 if OK
1271
 */
1272
function dol_add_file_process($upload_dir, $allowoverwrite=0, $donotupdatesession=0, $varfiles='addedfile', $savingdocmask='', $link=null, $trackid='')
0 ignored issues
show
Coding Style introduced by
dol_add_file_process uses the super-global variable $_FILES which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
1273
{
1274
	global $db,$user,$conf,$langs;
1275
1276
	$res = 0;
1277
	
1278
	if (! empty($_FILES[$varfiles])) // For view $_FILES[$varfiles]['error']
1279
	{
1280
		dol_syslog('dol_add_file_process upload_dir='.$upload_dir.' allowoverwrite='.$allowoverwrite.' donotupdatesession='.$donotupdatesession.' savingdocmask='.$savingdocmask, LOG_DEBUG);
1281
		if (dol_mkdir($upload_dir) >= 0)
1282
		{
1283
			$TFile = $_FILES[$varfiles];
1284
			if (!is_array($TFile['name']))
1285
			{
1286
				foreach ($TFile as $key => &$val)
1287
				{
1288
					$val = array($val);
1289
				}
1290
			}
1291
			
1292
			$nbfile = count($TFile['name']);
1293
			
1294
			for ($i = 0; $i < $nbfile; $i++)
1295
			{
1296
				// Define $destfull (path to file including filename) and $destfile (only filename)
1297
				$destfull=$upload_dir . "/" . $TFile['name'][$i];
1298
				$destfile=$TFile['name'][$i];
1299
	
1300
				$savingdocmask = dol_sanitizeFileName($savingdocmask);
1301
	
1302
				if ($savingdocmask)
1303
				{
1304
					$destfull=$upload_dir . "/" . preg_replace('/__file__/',$TFile['name'][$i],$savingdocmask);
1305
					$destfile=preg_replace('/__file__/',$TFile['name'][$i],$savingdocmask);
1306
				}
1307
1308
				// lowercase extension
1309
				$info = pathinfo($destfull);
1310
				$destfull = $info['dirname'].'/'.$info['filename'].'.'.strtolower($info['extension']);
1311
				$info = pathinfo($destfile);
1312
				$destfile = $info['filename'].'.'.strtolower($info['extension']);
1313
1314
				$resupload = dol_move_uploaded_file($TFile['tmp_name'][$i], $destfull, $allowoverwrite, 0, $TFile['error'][$i], 0, $varfiles);
1315
				
1316
				if (is_numeric($resupload) && $resupload > 0)   // $resupload can be 'ErrorFileAlreadyExists'
1317
				{
1318
					global $maxwidthsmall, $maxheightsmall, $maxwidthmini, $maxheightmini;
1319
				
1320
					include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
1321
					
1322
					// Generate thumbs.
1323
					if (image_format_supported($destfull) == 1)
1324
					{
1325
					    // Create thumbs
1326
					    // We can't use $object->addThumbs here because there is no $object known
1327
					
1328
					    // Used on logon for example
1329
					    $imgThumbSmall = vignette($destfull, $maxwidthsmall, $maxheightsmall, '_small', 50, "thumbs");
1330
					    // Create mini thumbs for image (Ratio is near 16/9)
1331
					    // Used on menu or for setup page for example
1332
					    $imgThumbMini = vignette($destfull, $maxwidthmini, $maxheightmini, '_mini', 50, "thumbs");
1333
					}
1334
					
1335
					// Update session
1336
					if (empty($donotupdatesession))
1337
					{
1338
						include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
1339
						$formmail = new FormMail($db);
1340
						$formmail->trackid = $trackid;
1341
						$formmail->add_attached_files($destfull, $destfile, $TFile['type'][$i]);
1342
					}
1343
					
1344
					// Update table of files
1345
					if ($donotupdatesession) 
1346
					{
1347
					    $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $upload_dir);
1348
				    
1349
					    if (! preg_match('/[\\/]temp[\\/]/', $rel_dir))     // If not a tmp dir
1350
					    {
1351
					        $filename = basename($destfile);
1352
					        $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir);
1353
					        $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir);
1354
    					    
1355
    					    include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
1356
    					    $ecmfile=new EcmFiles($db);
1357
    					    $ecmfile->filepath = $rel_dir;
1358
    					    $ecmfile->filename = $filename;
1359
    					    $ecmfile->label = md5_file(dol_osencode($destfull));
1360
    					    $ecmfile->fullpath_orig = $TFile['name'][$i];
1361
    					    $ecmfile->gen_or_uploaded = 'uploaded';
1362
    					    $ecmfile->description = '';    // indexed content
1363
    					    $ecmfile->keyword = '';        // keyword content
1364
    					    $result = $ecmfile->create($user);
1365
                            if ($result < 0)
1366
                            {
1367
                                setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
1368
                            }
1369
					    }
1370
					}
1371
1372
					$res = 1;
1373
					setEventMessages($langs->trans("FileTransferComplete"), null, 'mesgs');
1374
				}
1375
				else
1376
				{
1377
					$langs->load("errors");
1378
					if ($resupload < 0)	// Unknown error
1379
					{
1380
						setEventMessages($langs->trans("ErrorFileNotUploaded"), null, 'errors');
1381
					}
1382
					else if (preg_match('/ErrorFileIsInfectedWithAVirus/',$resupload))	// Files infected by a virus
1383
					{
1384
						setEventMessages($langs->trans("ErrorFileIsInfectedWithAVirus"), null, 'errors');
1385
					}
1386
					else	// Known error
1387
					{
1388
						setEventMessages($langs->trans($resupload), null, 'errors');
1389
					}
1390
				}
1391
			}
1392
			
1393
		}
1394
	} elseif ($link) {
1395
		require_once DOL_DOCUMENT_ROOT . '/core/class/link.class.php';
1396
		$linkObject = new Link($db);
1397
		$linkObject->entity = $conf->entity;
1398
		$linkObject->url = $link;
1399
		$linkObject->objecttype = GETPOST('objecttype', 'alpha');
1400
		$linkObject->objectid = GETPOST('objectid', 'int');
1401
		$linkObject->label = GETPOST('label', 'alpha');
1402
		$res = $linkObject->create($user);
1403
		$langs->load('link');
1404
		if ($res > 0) {
1405
			setEventMessages($langs->trans("LinkComplete"), null, 'mesgs');
1406
		} else {
1407
			setEventMessages($langs->trans("ErrorFileNotLinked"), null, 'errors');
1408
		}
1409
	}
1410
	else
1411
	{
1412
		$langs->load("errors");
1413
		setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("File")), null, 'errors');
1414
	}
1415
	
1416
	return $res;
1417
}
1418
1419
1420
/**
1421
 * Remove an uploaded file (for example after submitting a new file a mail form).
1422
 * All information used are in db, conf, langs, user and _FILES.
1423
 *
1424
 * @param	int		$filenb					File nb to delete
1425
 * @param	int		$donotupdatesession		1=Do not edit _SESSION variable
1426
 * @param   int		$donotdeletefile        1=Do not delete physically file
1427
 * @param   string  $trackid                Track id (used to prefix name of session vars to avoid conflict)
1428
 * @return	void
1429
 */
1430
function dol_remove_file_process($filenb,$donotupdatesession=0,$donotdeletefile=1,$trackid='')
0 ignored issues
show
Coding Style introduced by
dol_remove_file_process uses the super-global variable $_FILES which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
1431
{
1432
	global $db,$user,$conf,$langs,$_FILES;
1433
1434
	$keytodelete=$filenb;
1435
	$keytodelete--;
1436
1437
	$listofpaths=array();
1438
	$listofnames=array();
1439
	$listofmimes=array();
1440
    $keytoavoidconflict = empty($trackid)?'':'-'.$trackid;
1441
	if (! empty($_SESSION["listofpaths".$keytoavoidconflict])) $listofpaths=explode(';',$_SESSION["listofpaths".$keytoavoidconflict]);
1442
	if (! empty($_SESSION["listofnames".$keytoavoidconflict])) $listofnames=explode(';',$_SESSION["listofnames".$keytoavoidconflict]);
1443
	if (! empty($_SESSION["listofmimes".$keytoavoidconflict])) $listofmimes=explode(';',$_SESSION["listofmimes".$keytoavoidconflict]);
1444
1445
	if ($keytodelete >= 0)
1446
	{
1447
		$pathtodelete=$listofpaths[$keytodelete];
1448
		$filetodelete=$listofnames[$keytodelete];
1449
		if (empty($donotdeletefile)) $result = dol_delete_file($pathtodelete,1);  // The delete of ecm database is inside the function dol_delete_file
1450
		else $result=0;
1451
		if ($result >= 0)
1452
		{
1453
			if (empty($donotdeletefile))
1454
			{
1455
				$langs->load("other");
1456
				setEventMessages($langs->trans("FileWasRemoved",$filetodelete), null, 'mesgs');
1457
			}
1458
			if (empty($donotupdatesession))
1459
			{
1460
				include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
1461
				$formmail = new FormMail($db);
1462
				$formmail->trackid = $trackid;
1463
				$formmail->remove_attached_files($keytodelete);
1464
			}
1465
		}
1466
	}
1467
}
1468
1469
/**
1470
 * 	Convert an image file into anoher format.
1471
 *  This need Imagick php extension.
1472
 *
1473
 *  @param	string	$fileinput  Input file name
1474
 *  @param  string	$ext        Format of target file (It is also extension added to file if fileoutput is not provided).
1475
 *  @param	string	$fileoutput	Output filename
1476
 *  @return	int					<0 if KO, >0 if OK
1477
 */
1478
function dol_convert_file($fileinput,$ext='png',$fileoutput='')
1479
{
1480
	global $langs;
1481
1482
	$image=new Imagick();
1483
	$ret = $image->readImage($fileinput);
1484
	if ($ret)
1485
	{
1486
		$ret = $image->setImageFormat($ext);
1487
		if ($ret)
1488
		{
1489
			if (empty($fileoutput)) $fileoutput=$fileinput.".".$ext;
1490
1491
			$count = $image->getNumberImages();
1492
			$ret = $image->writeImages($fileoutput, true);
1493
			if ($ret) return $count;
1494
			else return -3;
1495
		}
1496
		else
1497
		{
1498
			return -2;
1499
		}
1500
	}
1501
	else
1502
	{
1503
		return -1;
1504
	}
1505
}
1506
1507
1508
/**
1509
 * Compress a file
1510
 *
1511
 * @param 	string	$inputfile		Source file name
1512
 * @param 	string	$outputfile		Target file name
1513
 * @param 	string	$mode			'gz' or 'bz' or 'zip'
1514
 * @return	int						<0 if KO, >0 if OK
1515
 */
1516
function dol_compress_file($inputfile, $outputfile, $mode="gz")
1517
{
1518
    $foundhandler=0;
1519
1520
    try
1521
    {
1522
        $data = implode("", file(dol_osencode($inputfile)));
1523
        if ($mode == 'gz')     { $foundhandler=1; $compressdata = gzencode($data, 9); }
1524
        elseif ($mode == 'bz') { $foundhandler=1; $compressdata = bzcompress($data, 9); }
1525
        elseif ($mode == 'zip')
1526
        {
1527
            if (defined('ODTPHP_PATHTOPCLZIP'))
1528
            {
1529
                $foundhandler=1;
1530
1531
                include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
1532
                $archive = new PclZip($outputfile);
1533
                $archive->add($inputfile, PCLZIP_OPT_REMOVE_PATH, dirname($inputfile));
1534
                //$archive->add($inputfile);
1535
                return 1;
1536
            }
1537
        }
1538
1539
        if ($foundhandler)
1540
        {
1541
            $fp = fopen($outputfile, "w");
1542
            fwrite($fp, $compressdata);
0 ignored issues
show
Bug introduced by
The variable $compressdata 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...
1543
            fclose($fp);
1544
            return 1;
1545
        }
1546
        else
1547
        {
1548
            dol_syslog("Try to zip with format ".$mode." with no handler for this format",LOG_ERR);
1549
            return -2;
1550
        }
1551
    }
1552
    catch (Exception $e)
1553
    {
1554
        global $langs, $errormsg;
1555
        $langs->load("errors");
1556
        dol_syslog("Failed to open file ".$outputfile,LOG_ERR);
1557
        $errormsg=$langs->trans("ErrorFailedToWriteInDir");
1558
        return -1;
1559
    }
1560
}
1561
1562
/**
1563
 * Uncompress a file
1564
 *
1565
 * @param 	string 	$inputfile		File to uncompress
1566
 * @param 	string	$outputdir		Target dir name
1567
 * @return 	array					array('error'=>'Error code') or array() if no error
1568
 */
1569
function dol_uncompress($inputfile,$outputdir)
1570
{
1571
    global $conf, $langs;
1572
1573
    if (! empty($conf->global->ODTPHP_PATHTOPCLZIP))
1574
    {
1575
    	dol_syslog("Constant ODTPHP_PATHTOPCLZIP for pclzip library is set to ".$conf->global->ODTPHP_PATHTOPCLZIP.", so we use Pclzip to unzip into ".$outputdir);
1576
        include_once $conf->global->ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php';
1577
        $archive = new PclZip($inputfile);
1578
        $result=$archive->extract(PCLZIP_OPT_PATH, $outputdir);
1579
        //var_dump($result);
1580
        if (! is_array($result) && $result <= 0) return array('error'=>$archive->errorInfo(true));
1581
        else
1582
		{
1583
			$ok=1; $errmsg='';
1584
			// Loop on each file to check result for unzipping file
1585
			foreach($result as $key => $val)
1586
			{
1587
				if ($val['status'] == 'path_creation_fail')
1588
				{
1589
					$langs->load("errors");
1590
					$ok=0;
1591
					$errmsg=$langs->trans("ErrorFailToCreateDir", $val['filename']);
1592
					break;
1593
				}
1594
			}
1595
1596
			if ($ok) return array();
1597
			else return array('error'=>$errmsg);
1598
		}
1599
    }
1600
1601
    if (class_exists('ZipArchive'))
1602
    {
1603
    	dol_syslog("Class ZipArchive is set so we unzip using ZipArchive to unzip into ".$outputdir);
1604
    	$zip = new ZipArchive;
1605
        $res = $zip->open($inputfile);
1606
        if ($res === TRUE)
1607
        {
1608
            $zip->extractTo($outputdir.'/');
1609
            $zip->close();
1610
            return array();
1611
        }
1612
        else
1613
        {
1614
            return array('error'=>'ErrUnzipFails');
1615
        }
1616
    }
1617
1618
    return array('error'=>'ErrNoZipEngine');
1619
}
1620
1621
1622
/**
1623
 * Return file(s) into a directory (by default most recent)
1624
 *
1625
 * @param 	string		$dir			Directory to scan
1626
 * @param	string		$regexfilter	Regex filter to restrict list. This regex value must be escaped for '/', since this char is used for preg_match function
1627
 * @param	array		$excludefilter  Array of Regex for exclude filter (example: array('(\.meta|_preview.*\.png)$','^\.')). This regex value must be escaped for '/', since this char is used for preg_match function
1628
 * @param	int			$nohook			Disable all hooks
1629
 * @return	string						Full path to most recent file
1630
 */
1631
function dol_most_recent_file($dir,$regexfilter='',$excludefilter=array('(\.meta|_preview.*\.png)$','^\.'),$nohook=false)
1632
{
1633
    $tmparray=dol_dir_list($dir,'files',0,$regexfilter,$excludefilter,'date',SORT_DESC,'',$nohook);
1634
    return $tmparray[0];
1635
}
1636
1637
/**
1638
 * Security check when accessing to a document (used by document.php, viewimage.php and webservices)
1639
 *
1640
 * @param	string	$modulepart			Module of document ('module', 'module_user_temp', 'module_user' or 'module_temp')
1641
 * @param	string	$original_file		Relative path with filename, relative to modulepart.
1642
 * @param	string	$entity				Restrict onto entity
1643
 * @param  	User	$fuser				User object (forced)
1644
 * @param	string	$refname			Ref of object to check permission for external users (autodetect if not provided)
1645
 * @return	mixed						Array with access information : 'accessallowed' & 'sqlprotectagainstexternals' & 'original_file' (as a full path name)
1646
 */
1647
function dol_check_secure_access_document($modulepart,$original_file,$entity,$fuser='',$refname='')
1648
{
1649
	global $user, $conf, $db;
1650
	global $dolibarr_main_data_root;
1651
	
1652
	if (! is_object($fuser)) $fuser=$user;
1653
1654
	if (empty($modulepart)) return 'ErrorBadParameter';
1655
	if (empty($entity)) $entity=0;
1656
	dol_syslog('modulepart='.$modulepart.' original_file='.$original_file);
1657
	// We define $accessallowed and $sqlprotectagainstexternals
1658
	$accessallowed=0;
1659
	$sqlprotectagainstexternals='';
1660
	$ret=array();
1661
1662
    // Find the subdirectory name as the reference. For exemple original_file='10/myfile.pdf' -> refname='10'
1663
	if (empty($refname)) $refname=basename(dirname($original_file)."/");
1664
1665
	$relative_original_file = $original_file;
1666
1667
	// Wrapping for some images
1668
	if (($modulepart == 'mycompany' || $modulepart == 'companylogo') && !empty($conf->mycompany->dir_output))
1669
	{
1670
		$accessallowed=1;
1671
		$original_file=$conf->mycompany->dir_output.'/logos/'.$original_file;
1672
	}
1673
	// Wrapping for users photos
1674
	elseif ($modulepart == 'userphoto' && !empty($conf->user->dir_output))
1675
	{
1676
		$accessallowed=1;
1677
		$original_file=$conf->user->dir_output.'/'.$original_file;
1678
	}
1679
	// Wrapping for members photos
1680
	elseif ($modulepart == 'memberphoto' && !empty($conf->adherent->dir_output))
1681
	{
1682
		$accessallowed=1;
1683
		$original_file=$conf->adherent->dir_output.'/'.$original_file;
1684
	}
1685
	// Wrapping pour les apercu factures
1686
	elseif ($modulepart == 'apercufacture' && !empty($conf->facture->dir_output))
1687
	{
1688
		if ($fuser->rights->facture->lire) $accessallowed=1;
1689
		$original_file=$conf->facture->dir_output.'/'.$original_file;
1690
	}
1691
	// Wrapping pour les apercu propal
1692
	elseif ($modulepart == 'apercupropal' && !empty($conf->propal->dir_output))
1693
	{
1694
		if ($fuser->rights->propale->lire) $accessallowed=1;
1695
		$original_file=$conf->propal->dir_output.'/'.$original_file;
1696
	}
1697
	// Wrapping pour les apercu commande
1698
	elseif ($modulepart == 'apercucommande' && !empty($conf->commande->dir_output))
1699
	{
1700
		if ($fuser->rights->commande->lire) $accessallowed=1;
1701
		$original_file=$conf->commande->dir_output.'/'.$original_file;
1702
	}
1703
	// Wrapping pour les apercu intervention
1704
	elseif (($modulepart == 'apercufichinter' || $modulepart == 'apercuficheinter') && !empty($conf->ficheinter->dir_output))
1705
	{
1706
	    if ($fuser->rights->ficheinter->lire) $accessallowed=1;
1707
	    $original_file=$conf->ficheinter->dir_output.'/'.$original_file;
1708
	}
1709
	// Wrapping pour les apercu supplier proposal
1710
	elseif (($modulepart == 'apercusupplier_proposal' || $modulepart == 'apercusupplier_proposal') && !empty($conf->supplier_proposal->dir_output))
1711
	{
1712
	    if ($fuser->rights->supplier_proposal->lire) $accessallowed=1;
1713
	    $original_file=$conf->supplier_proposal->dir_output.'/'.$original_file;
1714
	}
1715
	// Wrapping pour les apercu supplier order
1716
	elseif (($modulepart == 'apercusupplier_order' || $modulepart == 'apercusupplier_order') && !empty($conf->fournisseur->commande->dir_output))
1717
	{
1718
	    if ($fuser->rights->fournisseur->commande->lire) $accessallowed=1;
1719
	    $original_file=$conf->fournisseur->commande->dir_output.'/'.$original_file;
1720
	}
1721
	// Wrapping pour les apercu supplier invoice
1722
	elseif (($modulepart == 'apercusupplier_invoice' || $modulepart == 'apercusupplier_invoice') && !empty($conf->fournisseur->facture->dir_output))
1723
	{
1724
	    if ($fuser->rights->fournisseur->facture->lire) $accessallowed=1;
1725
	    $original_file=$conf->fournisseur->facture->dir_output.'/'.$original_file;
1726
	}
1727
	// Wrapping pour les images des stats propales
1728
	elseif ($modulepart == 'propalstats' && !empty($conf->propal->dir_temp))
1729
	{
1730
		if ($fuser->rights->propale->lire) $accessallowed=1;
1731
		$original_file=$conf->propal->dir_temp.'/'.$original_file;
1732
	}
1733
	// Wrapping pour les images des stats commandes
1734
	elseif ($modulepart == 'orderstats' && !empty($conf->commande->dir_temp))
1735
	{
1736
		if ($fuser->rights->commande->lire) $accessallowed=1;
1737
		$original_file=$conf->commande->dir_temp.'/'.$original_file;
1738
	}
1739
	elseif ($modulepart == 'orderstatssupplier' && !empty($conf->fournisseur->dir_output))
1740
	{
1741
		if ($fuser->rights->fournisseur->commande->lire) $accessallowed=1;
1742
		$original_file=$conf->fournisseur->dir_output.'/commande/temp/'.$original_file;
1743
	}
1744
	// Wrapping pour les images des stats factures
1745
	elseif ($modulepart == 'billstats' && !empty($conf->facture->dir_temp))
1746
	{
1747
		if ($fuser->rights->facture->lire) $accessallowed=1;
1748
		$original_file=$conf->facture->dir_temp.'/'.$original_file;
1749
	}
1750
	elseif ($modulepart == 'billstatssupplier' && !empty($conf->fournisseur->dir_output))
1751
	{
1752
		if ($fuser->rights->fournisseur->facture->lire) $accessallowed=1;
1753
		$original_file=$conf->fournisseur->dir_output.'/facture/temp/'.$original_file;
1754
	}
1755
	// Wrapping pour les images des stats expeditions
1756
	elseif ($modulepart == 'expeditionstats' && !empty($conf->expedition->dir_temp))
1757
	{
1758
		if ($fuser->rights->expedition->lire) $accessallowed=1;
1759
		$original_file=$conf->expedition->dir_temp.'/'.$original_file;
1760
	}
1761
	// Wrapping pour les images des stats expeditions
1762
	elseif ($modulepart == 'tripsexpensesstats' && !empty($conf->deplacement->dir_temp))
1763
	{
1764
		if ($fuser->rights->deplacement->lire) $accessallowed=1;
1765
		$original_file=$conf->deplacement->dir_temp.'/'.$original_file;
1766
	}
1767
	// Wrapping pour les images des stats expeditions
1768
	elseif ($modulepart == 'memberstats' && !empty($conf->adherent->dir_temp))
1769
	{
1770
		if ($fuser->rights->adherent->lire) $accessallowed=1;
1771
		$original_file=$conf->adherent->dir_temp.'/'.$original_file;
1772
	}
1773
	// Wrapping pour les images des stats produits
1774
	elseif (preg_match('/^productstats_/i',$modulepart) && !empty($conf->product->dir_temp))
1775
	{
1776
		if ($fuser->rights->produit->lire || $fuser->rights->service->lire) $accessallowed=1;
1777
		$original_file=(!empty($conf->product->multidir_temp[$entity])?$conf->product->multidir_temp[$entity]:$conf->service->multidir_temp[$entity]).'/'.$original_file;
1778
	}
1779
	// Wrapping for taxes
1780
	elseif ($modulepart == 'tax' && !empty($conf->tax->dir_output))
1781
	{
1782
		if ($fuser->rights->tax->charges->lire) $accessallowed=1;
1783
		$original_file=$conf->tax->dir_output.'/'.$original_file;
1784
	}
1785
	// Wrapping for events
1786
	elseif ($modulepart == 'actions' && !empty($conf->agenda->dir_output))
1787
	{
1788
		if ($fuser->rights->agenda->myactions->read) $accessallowed=1;
1789
		$original_file=$conf->agenda->dir_output.'/'.$original_file;
1790
	}
1791
	// Wrapping for categories
1792
	elseif ($modulepart == 'category' && !empty($conf->categorie->dir_output))
1793
	{
1794
		if ($fuser->rights->categorie->lire) $accessallowed=1;
1795
		$original_file=$conf->categorie->multidir_output[$entity].'/'.$original_file;
1796
	}
1797
	// Wrapping pour les prelevements
1798
	elseif ($modulepart == 'prelevement' && !empty($conf->prelevement->dir_output))
1799
	{
1800
		if ($fuser->rights->prelevement->bons->lire || preg_match('/^specimen/i',$original_file)) $accessallowed=1;
1801
		$original_file=$conf->prelevement->dir_output.'/'.$original_file;
1802
	}
1803
	// Wrapping pour les graph energie
1804
	elseif ($modulepart == 'graph_stock' && !empty($conf->stock->dir_temp))
1805
	{
1806
		$accessallowed=1;
1807
		$original_file=$conf->stock->dir_temp.'/'.$original_file;
1808
	}
1809
	// Wrapping pour les graph fournisseurs
1810
	elseif ($modulepart == 'graph_fourn' && !empty($conf->fournisseur->dir_temp))
1811
	{
1812
		$accessallowed=1;
1813
		$original_file=$conf->fournisseur->dir_temp.'/'.$original_file;
1814
	}
1815
	// Wrapping pour les graph des produits
1816
	elseif ($modulepart == 'graph_product' && !empty($conf->product->dir_temp))
1817
	{
1818
		$accessallowed=1;
1819
		$original_file=$conf->product->multidir_temp[$entity].'/'.$original_file;
1820
	}
1821
	// Wrapping pour les code barre
1822
	elseif ($modulepart == 'barcode')
1823
	{
1824
		$accessallowed=1;
1825
		// If viewimage is called for barcode, we try to output an image on the fly, with no build of file on disk.
1826
		//$original_file=$conf->barcode->dir_temp.'/'.$original_file;
1827
		$original_file='';
1828
	}
1829
	// Wrapping pour les icones de background des mailings
1830
	elseif ($modulepart == 'iconmailing' && !empty($conf->mailing->dir_temp))
1831
	{
1832
		$accessallowed=1;
1833
		$original_file=$conf->mailing->dir_temp.'/'.$original_file;
1834
	}
1835
	// Wrapping pour le scanner
1836
	elseif ($modulepart == 'scanner_user_temp' && !empty($conf->scanner->dir_temp))
1837
	{
1838
		$accessallowed=1;
1839
		$original_file=$conf->scanner->dir_temp.'/'.$fuser->id.'/'.$original_file;
1840
	}
1841
	// Wrapping pour les images fckeditor
1842
	elseif ($modulepart == 'fckeditor' && !empty($conf->fckeditor->dir_output))
1843
	{
1844
		$accessallowed=1;
1845
		$original_file=$conf->fckeditor->dir_output.'/'.$original_file;
1846
	}
1847
1848
	// Wrapping for users
1849
	else if ($modulepart == 'user' && !empty($conf->user->dir_output))
1850
	{
1851
        $canreaduser=(! empty($fuser->admin) || $fuser->rights->user->user->lire);
1852
        if ($fuser->id == (int) $refname) { $canreaduser=1; } // A user can always read its own card
1853
        if ($canreaduser || preg_match('/^specimen/i',$original_file))
1854
	    {
1855
	        $accessallowed=1;
1856
	    }
1857
	    $original_file=$conf->user->dir_output.'/'.$original_file;
1858
	}
1859
	
1860
	// Wrapping for third parties
1861
	else if (($modulepart == 'company' || $modulepart == 'societe') && !empty($conf->societe->dir_output))
1862
	{
1863
		if ($fuser->rights->societe->lire || preg_match('/^specimen/i',$original_file))
1864
		{
1865
			$accessallowed=1;
1866
		}
1867
		$original_file=$conf->societe->multidir_output[$entity].'/'.$original_file;
1868
		$sqlprotectagainstexternals = "SELECT rowid as fk_soc FROM ".MAIN_DB_PREFIX."societe WHERE rowid='".$db->escape($refname)."' AND entity IN (".getEntity('societe', 1).")";
1869
	}
1870
1871
	// Wrapping for contact
1872
	else if ($modulepart == 'contact' && !empty($conf->societe->dir_output))
1873
	{
1874
		if ($fuser->rights->societe->lire)
1875
		{
1876
			$accessallowed=1;
1877
		}
1878
		$original_file=$conf->societe->multidir_output[$entity].'/contact/'.$original_file;
1879
	}
1880
1881
	// Wrapping for invoices
1882
	else if (($modulepart == 'facture' || $modulepart == 'invoice') && !empty($conf->facture->dir_output))
1883
	{
1884
		if ($fuser->rights->facture->lire || preg_match('/^specimen/i',$original_file))
1885
		{
1886
			$accessallowed=1;
1887
		}
1888
		$original_file=$conf->facture->dir_output.'/'.$original_file;
1889
		$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
1890
	}
1891
	// Wrapping for mass actions
1892
	else if ($modulepart == 'massfilesarea_proposals' && !empty($conf->propal->dir_output))
1893
	{
1894
	    if ($fuser->rights->propal->lire || preg_match('/^specimen/i',$original_file))
1895
	    {
1896
	        $accessallowed=1;
1897
	    }
1898
	    $original_file=$conf->propal->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
1899
	}
1900
	else if ($modulepart == 'massfilesarea_orders')
1901
	{
1902
	    if ($fuser->rights->commande->lire || preg_match('/^specimen/i',$original_file))
1903
	    {
1904
	        $accessallowed=1;
1905
	    }
1906
	    $original_file=$conf->commande->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
1907
	}
1908
	else if ($modulepart == 'massfilesarea_invoices')
1909
	{
1910
	    if ($fuser->rights->facture->lire || preg_match('/^specimen/i',$original_file))
1911
	    {
1912
	        $accessallowed=1;
1913
	    }
1914
	    $original_file=$conf->facture->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
1915
	}
1916
	else if ($modulepart == 'massfilesarea_expensereport')
1917
	{
1918
	    if ($fuser->rights->facture->lire || preg_match('/^specimen/i',$original_file))
1919
	    {
1920
	        $accessallowed=1;
1921
	    }
1922
	    $original_file=$conf->expensereport->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
1923
	}
1924
	else if ($modulepart == 'massfilesarea_interventions')
1925
	{
1926
	    if ($fuser->rights->ficheinter->lire || preg_match('/^specimen/i',$original_file))
1927
	    {
1928
	        $accessallowed=1;
1929
	    }
1930
	    $original_file=$conf->ficheinter->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
1931
	}
1932
	else if ($modulepart == 'massfilesarea_supplier_proposal' && !empty($conf->propal->dir_output))
1933
	{
1934
	    if ($fuser->rights->supplier_proposal->lire || preg_match('/^specimen/i',$original_file))
1935
	    {
1936
	        $accessallowed=1;
1937
	    }
1938
	    $original_file=$conf->supplier_proposal->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
1939
	}
1940
	else if ($modulepart == 'massfilesarea_supplier_order')
1941
	{
1942
	    if ($fuser->rights->fournisseur->commande->lire || preg_match('/^specimen/i',$original_file))
1943
	    {
1944
	        $accessallowed=1;
1945
	    }
1946
	    $original_file=$conf->fournisseur->commande->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
1947
	}
1948
	else if ($modulepart == 'massfilesarea_supplier_invoice')
1949
	{
1950
	    if ($fuser->rights->fournisseur->facture->lire || preg_match('/^specimen/i',$original_file))
1951
	    {
1952
	        $accessallowed=1;
1953
	    }
1954
	    $original_file=$conf->fournisseur->facture->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file;
1955
	}
1956
	
1957
	// Wrapping for interventions
1958
	else if (($modulepart == 'fichinter' || $modulepart == 'ficheinter') && !empty($conf->ficheinter->dir_output))
1959
	{
1960
		if ($fuser->rights->ficheinter->lire || preg_match('/^specimen/i',$original_file))
1961
		{
1962
			$accessallowed=1;
1963
		}
1964
		$original_file=$conf->ficheinter->dir_output.'/'.$original_file;
1965
		$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
1966
	}
1967
1968
	// Wrapping pour les deplacements et notes de frais
1969
	else if ($modulepart == 'deplacement' && !empty($conf->deplacement->dir_output))
1970
	{
1971
		if ($fuser->rights->deplacement->lire || preg_match('/^specimen/i',$original_file))
1972
		{
1973
			$accessallowed=1;
1974
		}
1975
		$original_file=$conf->deplacement->dir_output.'/'.$original_file;
1976
		//$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
1977
	}
1978
	// Wrapping pour les propales
1979
	else if ($modulepart == 'propal' && !empty($conf->propal->dir_output))
1980
	{
1981
		if ($fuser->rights->propale->lire || preg_match('/^specimen/i',$original_file))
1982
		{
1983
			$accessallowed=1;
1984
		}
1985
1986
		$original_file=$conf->propal->dir_output.'/'.$original_file;
1987
		$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."propal WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
1988
	}
1989
1990
	// Wrapping pour les commandes
1991
	else if (($modulepart == 'commande' || $modulepart == 'order') && !empty($conf->commande->dir_output))
1992
	{
1993
		if ($fuser->rights->commande->lire || preg_match('/^specimen/i',$original_file))
1994
		{
1995
			$accessallowed=1;
1996
		}
1997
		$original_file=$conf->commande->dir_output.'/'.$original_file;
1998
		$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."commande WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
1999
	}
2000
2001
	// Wrapping pour les projets
2002
	else if ($modulepart == 'project' && !empty($conf->projet->dir_output))
2003
	{
2004
		if ($fuser->rights->projet->lire || preg_match('/^specimen/i',$original_file))
2005
		{
2006
			$accessallowed=1;
2007
		}
2008
		$original_file=$conf->projet->dir_output.'/'.$original_file;
2009
		$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project', 1).")";
2010
	}
2011
	else if ($modulepart == 'project_task' && !empty($conf->projet->dir_output))
2012
	{
2013
		if ($fuser->rights->projet->lire || preg_match('/^specimen/i',$original_file))
2014
		{
2015
			$accessallowed=1;
2016
		}
2017
		$original_file=$conf->projet->dir_output.'/'.$original_file;
2018
		$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project', 1).")";
2019
	}
2020
2021
	// Wrapping pour les commandes fournisseurs
2022
	else if (($modulepart == 'commande_fournisseur' || $modulepart == 'order_supplier') && !empty($conf->fournisseur->commande->dir_output)) 
2023
	{
2024
		if ($fuser->rights->fournisseur->commande->lire || preg_match('/^specimen/i',$original_file))
2025
		{
2026
			$accessallowed=1;
2027
		}
2028
		$original_file=$conf->fournisseur->commande->dir_output.'/'.$original_file;
2029
		$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."commande_fournisseur WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
2030
	}
2031
2032
	// Wrapping pour les factures fournisseurs
2033
	else if (($modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier') && !empty($conf->fournisseur->facture->dir_output))
2034
	{
2035
		if ($fuser->rights->fournisseur->facture->lire || preg_match('/^specimen/i',$original_file))
2036
		{
2037
			$accessallowed=1;
2038
		}
2039
		$original_file=$conf->fournisseur->facture->dir_output.'/'.$original_file;
2040
		$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture_fourn WHERE facnumber='".$db->escape($refname)."' AND entity=".$conf->entity;
2041
	}
2042
	// Wrapping pour les rapport de paiements
2043
	else if ($modulepart == 'supplier_payment')
2044
	{
2045
		if ($fuser->rights->fournisseur->facture->lire || preg_match('/^specimen/i',$original_file))
2046
		{
2047
			$accessallowed=1;
2048
		}
2049
		$original_file=$conf->fournisseur->payment->dir_output.'/'.$original_file;
2050
		$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."paiementfournisseur WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
2051
	}
2052
2053
	// Wrapping pour les rapport de paiements
2054
	else if ($modulepart == 'facture_paiement' && !empty($conf->facture->dir_output))
2055
	{
2056
		if ($fuser->rights->facture->lire || preg_match('/^specimen/i',$original_file))
2057
		{
2058
			$accessallowed=1;
2059
		}
2060
		if ($fuser->societe_id > 0) $original_file=$conf->facture->dir_output.'/payments/private/'.$fuser->id.'/'.$original_file;
2061
		else $original_file=$conf->facture->dir_output.'/payments/'.$original_file;
2062
	}
2063
2064
	// Wrapping for accounting exports
2065
	else if ($modulepart == 'export_compta' && !empty($conf->accounting->dir_output))
2066
	{
2067
		if ($fuser->rights->accounting->bind->write || preg_match('/^specimen/i',$original_file))
2068
		{
2069
			$accessallowed=1;
2070
		}
2071
		$original_file=$conf->accounting->dir_output.'/'.$original_file;
2072
	}
2073
2074
	// Wrapping pour les expedition
2075
	else if ($modulepart == 'expedition' && !empty($conf->expedition->dir_output))
2076
	{
2077
		if ($fuser->rights->expedition->lire || preg_match('/^specimen/i',$original_file))
2078
		{
2079
			$accessallowed=1;
2080
		}
2081
		$original_file=$conf->expedition->dir_output."/sending/".$original_file;
2082
	}
2083
	// Wrapping pour les bons de livraison
2084
	else if ($modulepart == 'livraison' && !empty($conf->expedition->dir_output))
2085
	{
2086
		if ($fuser->rights->expedition->livraison->lire || preg_match('/^specimen/i',$original_file))
2087
		{
2088
			$accessallowed=1;
2089
		}
2090
		$original_file=$conf->expedition->dir_output."/receipt/".$original_file;
2091
	}
2092
2093
	// Wrapping pour les actions
2094
	else if ($modulepart == 'actions' && !empty($conf->agenda->dir_output))
2095
	{
2096
		if ($fuser->rights->agenda->myactions->read || preg_match('/^specimen/i',$original_file))
2097
		{
2098
			$accessallowed=1;
2099
		}
2100
		$original_file=$conf->agenda->dir_output.'/'.$original_file;
2101
	}
2102
2103
	// Wrapping pour les actions
2104
	else if ($modulepart == 'actionsreport' && !empty($conf->agenda->dir_temp))
2105
	{
2106
		if ($fuser->rights->agenda->allactions->read || preg_match('/^specimen/i',$original_file))
2107
		{
2108
			$accessallowed=1;
2109
		}
2110
		$original_file = $conf->agenda->dir_temp."/".$original_file;
2111
	}
2112
2113
	// Wrapping pour les produits et services
2114
	else if ($modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service')
2115
	{
2116
		if (($fuser->rights->produit->lire || $fuser->rights->service->lire) || preg_match('/^specimen/i',$original_file))
2117
		{
2118
			$accessallowed=1;
2119
		}
2120
		if (! empty($conf->product->enabled)) $original_file=$conf->product->multidir_output[$entity].'/'.$original_file;
2121
		elseif (! empty($conf->service->enabled)) $original_file=$conf->service->multidir_output[$entity].'/'.$original_file;
2122
	}
2123
2124
	// Wrapping pour les contrats
2125
	else if ($modulepart == 'contract' && !empty($conf->contrat->dir_output))
2126
	{
2127
		if ($fuser->rights->contrat->lire || preg_match('/^specimen/i',$original_file))
2128
		{
2129
			$accessallowed=1;
2130
		}
2131
		$original_file=$conf->contrat->dir_output.'/'.$original_file;
2132
		$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."contrat WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('contract', 1).")";
2133
	}
2134
2135
	// Wrapping pour les dons
2136
	else if ($modulepart == 'donation' && !empty($conf->don->dir_output))
2137
	{
2138
		if ($fuser->rights->don->lire || preg_match('/^specimen/i',$original_file))
2139
		{
2140
			$accessallowed=1;
2141
		}
2142
		$original_file=$conf->don->dir_output.'/'.$original_file;
2143
	}
2144
2145
	// Wrapping pour les remises de cheques
2146
	else if ($modulepart == 'remisecheque' && !empty($conf->banque->dir_output))
2147
	{
2148
		if ($fuser->rights->banque->lire || preg_match('/^specimen/i',$original_file))
2149
		{
2150
			$accessallowed=1;
2151
		}
2152
2153
		$original_file=$conf->bank->dir_output.'/checkdeposits/'.$original_file;		// original_file should contains relative path so include the get_exdir result
2154
	}
2155
2156
	// Wrapping for bank
2157
	else if ($modulepart == 'bank' && !empty($conf->bank->dir_output))
2158
	{
2159
		if ($fuser->rights->banque->lire)
2160
		{
2161
			$accessallowed=1;
2162
		}
2163
		$original_file=$conf->bank->dir_output.'/'.$original_file;
2164
	}
2165
2166
	// Wrapping for export module
2167
	else if ($modulepart == 'export' && !empty($conf->export->dir_temp))
2168
	{
2169
		// Aucun test necessaire car on force le rep de download sur
2170
		// le rep export qui est propre a l'utilisateur
2171
		$accessallowed=1;
2172
		$original_file=$conf->export->dir_temp.'/'.$fuser->id.'/'.$original_file;
2173
	}
2174
2175
	// Wrapping for import module
2176
	else if ($modulepart == 'import' && !empty($conf->import->dir_temp))
2177
	{
2178
		$accessallowed=1;
2179
		$original_file=$conf->import->dir_temp.'/'.$original_file;
2180
	}
2181
2182
	// Wrapping pour l'editeur wysiwyg
2183
	else if ($modulepart == 'editor' && !empty($conf->fckeditor->dir_output))
2184
	{
2185
		$accessallowed=1;
2186
		$original_file=$conf->fckeditor->dir_output.'/'.$original_file;
2187
	}
2188
	
2189
	// Wrapping for miscellaneous medias files
2190
	elseif ($modulepart == 'medias' && !empty($dolibarr_main_data_root))
2191
	{
2192
	    $accessallowed=1;
2193
	    $original_file=$dolibarr_main_data_root.'/medias/'.$original_file;
2194
	}
2195
	
2196
	// Wrapping for backups
2197
	else if ($modulepart == 'systemtools' && !empty($conf->admin->dir_output))
2198
	{
2199
		if ($fuser->admin) $accessallowed=1;
2200
		$original_file=$conf->admin->dir_output.'/'.$original_file;
2201
	}
2202
2203
	// Wrapping for upload file test
2204
	else if ($modulepart == 'admin_temp' && !empty($conf->admin->dir_temp))
2205
	{
2206
		if ($fuser->admin) $accessallowed=1;
2207
		$original_file=$conf->admin->dir_temp.'/'.$original_file;
2208
	}
2209
2210
	// Wrapping pour BitTorrent
2211
	else if ($modulepart == 'bittorrent' && !empty($conf->bittorrent->dir_output))
2212
	{
2213
		$accessallowed=1;
2214
		$dir='files';
2215
		if (dol_mimetype($original_file) == 'application/x-bittorrent') $dir='torrents';
2216
		$original_file=$conf->bittorrent->dir_output.'/'.$dir.'/'.$original_file;
2217
	}
2218
2219
	// Wrapping pour Foundation module
2220
	else if ($modulepart == 'member' && !empty($conf->adherent->dir_output))
2221
	{
2222
		if ($fuser->rights->adherent->lire || preg_match('/^specimen/i',$original_file))
2223
		{
2224
			$accessallowed=1;
2225
		}
2226
		$original_file=$conf->adherent->dir_output.'/'.$original_file;
2227
	}
2228
2229
	// Wrapping for Scanner
2230
	else if ($modulepart == 'scanner_user_temp' && !empty($conf->scanner->dir_temp))
2231
	{
2232
		$accessallowed=1;
2233
		$original_file=$conf->scanner->dir_temp.'/'.$fuser->id.'/'.$original_file;
2234
	}
2235
2236
    // GENERIC Wrapping
2237
    // If modulepart=module_user_temp	Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/temp/iduser
2238
    // If modulepart=module_temp		Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/temp
2239
    // If modulepart=module_user		Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart/iduser
2240
    // If modulepart=module				Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart
2241
    else
2242
	{
2243
	    if (preg_match('/^specimen/i',$original_file))	$accessallowed=1;    // If link to a file called specimen. Test must be done before changing $original_file int full path. 
2244
	    if ($fuser->admin) $accessallowed=1;    // If user is admin
2245
2246
		// Define $accessallowed
2247
		if (preg_match('/^([a-z]+)_user_temp$/i',$modulepart,$reg))
2248
		{
2249
			if (empty($conf->{$reg[1]}->dir_temp))	// modulepart not supported
2250
			{
2251
				dol_print_error('','Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
2252
				exit;
2253
			}
2254
		    if ($fuser->rights->{$reg[1]}->lire || $fuser->rights->{$reg[1]}->read || ($fuser->rights->{$reg[1]}->download)) $accessallowed=1;
2255
			$original_file=$conf->{$reg[1]}->dir_temp.'/'.$fuser->id.'/'.$original_file;
2256
		}
2257
		else if (preg_match('/^([a-z]+)_temp$/i',$modulepart,$reg))
2258
		{
2259
			if (empty($conf->{$reg[1]}->dir_temp))	// modulepart not supported
2260
			{
2261
				dol_print_error('','Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
2262
				exit;
2263
			}
2264
		    if ($fuser->rights->{$reg[1]}->lire || $fuser->rights->{$reg[1]}->read || ($fuser->rights->{$reg[1]}->download)) $accessallowed=1;
2265
			$original_file=$conf->{$reg[1]}->dir_temp.'/'.$original_file;
2266
		}
2267
		else if (preg_match('/^([a-z]+)_user$/i',$modulepart,$reg))
2268
		{
2269
			if (empty($conf->{$reg[1]}->dir_output))	// modulepart not supported
2270
			{
2271
				dol_print_error('','Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
2272
				exit;
2273
			}
2274
		    if ($fuser->rights->{$reg[1]}->lire || $fuser->rights->{$reg[1]}->read || ($fuser->rights->{$reg[1]}->download)) $accessallowed=1;
2275
			$original_file=$conf->{$reg[1]}->dir_output.'/'.$fuser->id.'/'.$original_file;
2276
		}
2277
		else
2278
		{
2279
			if (empty($conf->$modulepart->dir_output))	// modulepart not supported
2280
			{
2281
				dol_print_error('','Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')');
2282
				exit;
2283
			}
2284
2285
			$perm=GETPOST('perm');
2286
			$subperm=GETPOST('subperm');
2287
			if ($perm || $subperm)
2288
			{
2289
				if (($perm && ! $subperm && $fuser->rights->$modulepart->$perm) || ($perm && $subperm && $fuser->rights->$modulepart->$perm->$subperm)) $accessallowed=1;
2290
				$original_file=$conf->$modulepart->dir_output.'/'.$original_file;
2291
			}
2292
			else
2293
			{
2294
				if ($fuser->rights->$modulepart->lire || $fuser->rights->$modulepart->read) $accessallowed=1;
2295
				$original_file=$conf->$modulepart->dir_output.'/'.$original_file;
2296
			}
2297
		}
2298
2299
		// For modules who wants to manage different levels of permissions for documents
2300
		$subPermCategoryConstName = strtoupper($modulepart).'_SUBPERMCATEGORY_FOR_DOCUMENTS';
2301
		if (! empty($conf->global->$subPermCategoryConstName))
2302
		{
2303
			$subPermCategory = $conf->global->$subPermCategoryConstName;
2304
			if (! empty($subPermCategory) && (($fuser->rights->$modulepart->$subPermCategory->lire) || ($fuser->rights->$modulepart->$subPermCategory->read) || ($fuser->rights->$modulepart->$subPermCategory->download)))
2305
			{
2306
				$accessallowed=1;
2307
			}
2308
		}
2309
2310
		// Define $sqlprotectagainstexternals for modules who want to protect access using a SQL query.
2311
		$sqlProtectConstName = strtoupper($modulepart).'_SQLPROTECTAGAINSTEXTERNALS_FOR_DOCUMENTS';
2312
		if (! empty($conf->global->$sqlProtectConstName))	// If module want to define its own $sqlprotectagainstexternals
2313
		{
2314
			// Example: mymodule__SQLPROTECTAGAINSTEXTERNALS_FOR_DOCUMENTS = "SELECT fk_soc FROM ".MAIN_DB_PREFIX.$modulepart." WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
2315
			eval('$sqlprotectagainstexternals = "'.$conf->global->$sqlProtectConstName.'";');
0 ignored issues
show
Coding Style introduced by
The function dol_check_secure_access_document() contains an eval expression.

On one hand, eval might be exploited by malicious users if they somehow manage to inject dynamic content. On the other hand, with the emergence of faster PHP runtimes like the HHVM, eval prevents some optimization that they perform.

Loading history...
2316
		}
2317
	}
2318
2319
	$ret = array(
2320
		'accessallowed' => $accessallowed,
2321
		'sqlprotectagainstexternals'=>$sqlprotectagainstexternals,
2322
		'original_file'=>$original_file
2323
	);
2324
2325
	return $ret;
2326
}
2327
2328
/**
2329
 * Store object in file.
2330
 *
2331
 * @param string $directory Directory of cache
2332
 * @param string $filename Name of filecache
2333
 * @param mixed $object Object to store in cachefile
2334
 * @return void
2335
 */
2336
function dol_filecache($directory, $filename, $object)
2337
{
2338
    if (! dol_is_dir($directory)) dol_mkdir($directory);
2339
    $cachefile = $directory . $filename;
2340
    file_put_contents($cachefile, serialize($object), LOCK_EX);
2341
    @chmod($cachefile, 0644);
2342
}
2343
2344
/**
2345
 * Test if Refresh needed.
2346
 *
2347
 * @param string $directory Directory of cache
2348
 * @param string $filename Name of filecache
2349
 * @param int $cachetime Cachetime delay
2350
 * @return boolean 0 no refresh 1 if refresh needed
2351
 */
2352
function dol_cache_refresh($directory, $filename, $cachetime)
2353
{
2354
    $now = dol_now();
2355
    $cachefile = $directory . $filename;
2356
    $refresh = !file_exists($cachefile) || ($now-$cachetime) > dol_filemtime($cachefile);
2357
    return $refresh;
2358
}
2359
2360
/**
2361
 * Read object from cachefile.
2362
 *
2363
 * @param string $directory Directory of cache
2364
 * @param string $filename Name of filecache
2365
 * @return mixed Unserialise from file
2366
 */
2367
function dol_readcachefile($directory, $filename)
2368
{
2369
    $cachefile = $directory . $filename;
2370
    $object = unserialize(file_get_contents($cachefile));
2371
    return $object;
2372
}
2373