FileUpload()   F
last analyzed

Complexity

Conditions 29
Paths 2820

Size

Total Lines 131
Code Lines 73

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 29
eloc 73
nc 2820
nop 4
dl 0
loc 131
rs 0
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
3
/*
4
 * FCKeditor - The text editor for Internet - http://www.fckeditor.net
5
 * Copyright (C) 2003-2010 Frederico Caldeira Knabben
6
 * Copyright (C) 2024		MDW							<[email protected]>
7
 *
8
 * == BEGIN LICENSE ==
9
 *
10
 * Licensed under the terms of any of the following licenses at your
11
 * choice:
12
 *
13
 *  - GNU General Public License Version 2 or later (the "GPL")
14
 *    https://www.gnu.org/licenses/gpl.html
15
 *
16
 *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
17
 *    https://www.gnu.org/licenses/lgpl.html
18
 *
19
 *  - Mozilla Public License Version 1.1 or later (the "MPL")
20
 *    http://www.mozilla.org/MPL/MPL-1.1.html
21
 *
22
 * == END LICENSE ==
23
 *
24
 * These functions are used by the connector.php script.
25
 */
26
27
/**
28
 * SetXmlHeaders
29
 *
30
 * @return  void
31
 */
32
function SetXmlHeaders()
33
{
34
    ob_end_clean();
35
36
    // Prevent the browser from caching the result.
37
    // Date in the past
38
    header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
39
    // always modified
40
    header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
41
    // HTTP/1.1
42
    header('Cache-Control: no-store, no-cache, must-revalidate');
43
    header('Cache-Control: post-check=0, pre-check=0', false);
44
    // HTTP/1.0
45
    header('Pragma: no-cache');
46
47
    // Set the response format.
48
    header('Content-Type: text/xml; charset=utf-8');
49
}
50
51
/**
52
 * CreateXmlHeader
53
 *
54
 * @param string $command Command
55
 * @param string $resourceType Resource type
56
 * @param string $currentFolder Current folder
57
 * @return void
58
 */
59
function CreateXmlHeader($command, $resourceType, $currentFolder)
60
{
61
    SetXmlHeaders();
62
63
    // Create the XML document header.
64
    echo '<?xml version="1.0" encoding="utf-8" ?>';
65
66
    // Create the main "Connector" node.
67
    echo '<Connector command="' . $command . '" resourceType="' . $resourceType . '">';
68
69
    // Add the current folder node.
70
    echo '<CurrentFolder path="' . ConvertToXmlAttribute($currentFolder) . '" url="' . ConvertToXmlAttribute(GetUrlFromPath($resourceType, $currentFolder, $command)) . '" />';
71
72
    $GLOBALS['HeaderSent'] = true;
73
}
74
75
/**
76
 * CreateXmlFooter
77
 *
78
 * @return void
79
 */
80
function CreateXmlFooter()
81
{
82
    echo '</Connector>';
83
}
84
85
/**
86
 * SendError
87
 *
88
 * @param integer $number Number
89
 * @param string $text Text
90
 * @return  void
91
 */
92
function SendError($number, $text)
93
{
94
    if ($_GET['Command'] == 'FileUpload') {
95
        SendUploadResults($number, "", "", $text);
96
    }
97
98
    if (isset($GLOBALS['HeaderSent']) && $GLOBALS['HeaderSent']) {
99
        SendErrorNode($number, $text);
100
        CreateXmlFooter();
101
    } else {
102
        SetXmlHeaders();
103
104
        dol_syslog('Error: ' . $number . ' ' . $text, LOG_ERR);
105
106
        // Create the XML document header
107
        echo '<?xml version="1.0" encoding="utf-8" ?>';
108
109
        echo '<Connector>';
110
111
        SendErrorNode($number, $text);
112
113
        echo '</Connector>';
114
    }
115
    exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
116
}
117
118
/**
119
 * SendErrorNode
120
 *
121
 * @param integer $number Number
122
 * @param string $text Text of error
123
 * @return  string              Error node
124
 */
125
function SendErrorNode($number, $text)
126
{
127
    if ($text) {
128
        echo '<Error number="' . $number . '" text="' . htmlspecialchars($text) . '" />';
129
    } else {
130
        echo '<Error number="' . $number . '" />';
131
    }
132
    return '';
133
}
134
135
136
/**
137
 * GetFolders
138
 *
139
 * @param string $resourceType Resource type
140
 * @param string $currentFolder Current folder
141
 * @return  void
142
 */
143
function GetFolders($resourceType, $currentFolder)
144
{
145
    // Map the virtual path to the local server path.
146
    $sServerDir = ServerMapFolder($resourceType, $currentFolder, 'GetFolders');
147
148
    // Array that will hold the folders names.
149
    $aFolders = array();
150
151
    $oCurrentFolder = @opendir($sServerDir);
152
153
    if ($oCurrentFolder !== false) {
154
        while ($sFile = readdir($oCurrentFolder)) {
155
            if ($sFile != '.' && $sFile != '..' && is_dir($sServerDir . $sFile)) {
156
                $aFolders[] = '<Folder name="' . ConvertToXmlAttribute($sFile) . '" />';
157
            }
158
        }
159
        closedir($oCurrentFolder);
160
    }
161
162
    // Open the "Folders" node.
163
    echo "<Folders>";
164
165
    natcasesort($aFolders);
166
    foreach ($aFolders as $sFolder) {
167
        echo $sFolder;
168
    }
169
170
    // Close the "Folders" node.
171
    echo "</Folders>";
172
}
173
174
/**
175
 * GetFoldersAndFiles
176
 *
177
 * @param string $resourceType Resource type
178
 * @param string $currentFolder Current folder
179
 * @return void
180
 */
181
function GetFoldersAndFiles($resourceType, $currentFolder)
182
{
183
    // Map the virtual path to the local server path.
184
    $sServerDir = ServerMapFolder($resourceType, $currentFolder, 'GetFoldersAndFiles');
185
186
    // Arrays that will hold the folders and files names.
187
    $aFolders = array();
188
    $aFiles = array();
189
190
    $oCurrentFolder = @opendir($sServerDir);
191
192
    if ($oCurrentFolder !== false) {
193
        while ($sFile = readdir($oCurrentFolder)) {
194
            if ($sFile != '.' && $sFile != '..') {
195
                if (is_dir($sServerDir . $sFile)) {
196
                    $aFolders[] = '<Folder name="' . ConvertToXmlAttribute($sFile) . '" />';
197
                } else {
198
                    $iFileSize = @filesize($sServerDir . $sFile);
199
                    if (!$iFileSize) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $iFileSize of type false|integer is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === false 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...
200
                        $iFileSize = 0;
201
                    }
202
                    if ($iFileSize > 0) {
203
                        $iFileSize = round($iFileSize / 1024);
204
                        if ($iFileSize < 1) {
205
                            $iFileSize = 1;
206
                        }
207
                    }
208
209
                    $aFiles[] = '<File name="' . ConvertToXmlAttribute($sFile) . '" size="' . $iFileSize . '" />';
210
                }
211
            }
212
        }
213
        closedir($oCurrentFolder);
214
    }
215
216
    // Send the folders
217
    natcasesort($aFolders);
218
    echo '<Folders>';
219
220
    foreach ($aFolders as $sFolder) {
221
        echo $sFolder;
222
    }
223
224
    echo '</Folders>';
225
226
    // Send the files
227
    natcasesort($aFiles);
228
    echo '<Files>';
229
230
    foreach ($aFiles as $sFiles) {
231
        echo $sFiles;
232
    }
233
234
    echo '</Files>';
235
}
236
237
/**
238
 * Create folder
239
 *
240
 * @param string $resourceType Resource type
241
 * @param string $currentFolder Current folder
242
 * @return void
243
 */
244
function CreateFolder($resourceType, $currentFolder)
245
{
246
    $sErrorNumber = '0';
247
    $sErrorMsg = '';
248
249
    if (isset($_GET['NewFolderName'])) {
250
        $sNewFolderName = GETPOST('NewFolderName');
251
        $sNewFolderName = SanitizeFolderName($sNewFolderName);
252
253
        if (strpos($sNewFolderName, '..') !== false) {
254
            $sErrorNumber = '102'; // Invalid folder name.
255
        } else {
256
            // Map the virtual path to the local server path of the current folder.
257
            $sServerDir = ServerMapFolder($resourceType, $currentFolder, 'CreateFolder');
258
259
            if (is_writable($sServerDir)) {
260
                $sServerDir .= $sNewFolderName;
261
262
                $sErrorMsg = CreateServerFolder($sServerDir);
263
264
                switch ($sErrorMsg) {
265
                    case '':
266
                        $sErrorNumber = '0';
267
                        break;
268
                    case 'Invalid argument':
269
                    case 'No such file or directory':
270
                        $sErrorNumber = '102'; // Path too long.
271
                        break;
272
                    default:
273
                        $sErrorNumber = '110';
274
                        break;
275
                }
276
            } else {
277
                $sErrorNumber = '103';
278
            }
279
        }
280
    } else {
281
        $sErrorNumber = '102';
282
    }
283
284
    // Create the "Error" node.
285
    echo '<Error number="' . $sErrorNumber . '" />';
286
}
287
288
/**
289
 * FileUpload
290
 *
291
 * @param string $resourceType Resource type
292
 * @param string $currentFolder Current folder
293
 * @param string $sCommand Command
294
 * @param string $CKEcallback Callback
295
 * @return  null
296
 */
297
function FileUpload($resourceType, $currentFolder, $sCommand, $CKEcallback = '')
298
{
299
    global $user;
300
301
    if (!isset($_FILES)) {
302
        global $_FILES;
303
    }
304
    $sErrorNumber = '0';
305
    $sFileName = '';
306
307
    if (isset($_FILES['NewFile']) && !is_null($_FILES['NewFile']['tmp_name']) || (isset($_FILES['upload']) && !is_null($_FILES['upload']['tmp_name']))) {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: (IssetNode && ! is_null(...['upload']['tmp_name']), Probably Intended Meaning: IssetNode && (! is_null(...'upload']['tmp_name']))
Loading history...
308
        global $Config;
309
310
        $oFile = isset($_FILES['NewFile']) ? $_FILES['NewFile'] : $_FILES['upload'];
311
312
        // $resourceType should be 'Image';
313
        $detectHtml = 0;
314
315
        // Map the virtual path to the local server path.
316
        $sServerDir = ServerMapFolder($resourceType, $currentFolder, $sCommand);
317
318
        // Get the uploaded file name.
319
        $sFileName = $oFile['name'];
320
321
        //$sFileName = SanitizeFileName($sFileName);
322
        $sFileName = dol_sanitizeFileName($sFileName);
323
324
        $sOriginalFileName = $sFileName;
325
326
        // Get the extension.
327
        $sExtension = substr($sFileName, (strrpos($sFileName, '.') + 1));
328
        $sExtension = strtolower($sExtension);
329
330
        // Check permission
331
        $permissiontouploadmediaisok = 1;
332
        if (!empty($user->socid)) {
333
            $permissiontouploadmediaisok = 0;
334
        }
335
        /*if (!$user->hasRight('website', 'write') && !$user->hasRight('mailing', 'write')) {
336
            $permissiontouploadmediaisok = 0;
337
        }*/
338
        if (!$permissiontouploadmediaisok) {
339
            dol_syslog("connector.lib.php Try to upload a file with no permission");
340
            $sErrorNumber = '202';
341
        }
342
343
        include_once DOL_DOCUMENT_ROOT . '/core/lib/images.lib.php';
344
        //var_dump($sFileName); var_dump(image_format_supported($sFileName));exit;
345
        $imgsupported = image_format_supported($sFileName);
346
        $isImageValid = ($imgsupported >= 0 ? true : false);
347
        if (!$isImageValid) {
348
            $sErrorNumber = '202';
349
        }
350
351
352
        // Check if it is an allowed extension.
353
        if (!$sErrorNumber) {
354
            if (IsAllowedExt($sExtension, $resourceType)) {
355
                $iCounter = 0;
356
357
                while (true) {
358
                    $sFilePath = $sServerDir . $sFileName;
359
360
                    if (is_file($sFilePath)) {
361
                        $iCounter++;
362
                        $sFileName = RemoveExtension($sOriginalFileName) . '(' . $iCounter . ').' . $sExtension;
363
                        $sErrorNumber = '201';
364
                    } else {
365
                        include_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php';
366
                        dol_move_uploaded_file($oFile['tmp_name'], $sFilePath, 0, 0);
367
368
                        if (is_file($sFilePath)) {
369
                            if (isset($Config['ChmodOnUpload']) && !$Config['ChmodOnUpload']) {
370
                                break;
371
                            }
372
373
                            $permissions = '0777';
374
                            if (isset($Config['ChmodOnUpload']) && $Config['ChmodOnUpload']) {
375
                                $permissions = (string)$Config['ChmodOnUpload'];
376
                            }
377
                            $permissionsdec = octdec($permissions);
378
                            dol_syslog("connector.lib.php permission = " . $permissions . " " . $permissionsdec . " " . decoct($permissionsdec));
379
                            $oldumask = umask(0);
380
                            chmod($sFilePath, $permissionsdec);
381
                            umask($oldumask);
382
                        }
383
384
                        break;
385
                    }
386
                }
387
388
                if (file_exists($sFilePath)) {
389
                    //previous checks failed, try once again
390
                    if (isset($isImageValid) && $imgsupported === -1 && IsImageValid($sFilePath, $sExtension) === false) {
391
                        dol_syslog("connector.lib.php IsImageValid is ko");
392
                        @unlink($sFilePath);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

392
                        /** @scrutinizer ignore-unhandled */ @unlink($sFilePath);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
393
                        $sErrorNumber = '202';
394
                    } elseif (isset($detectHtml) && $detectHtml === -1 && DetectHtml($sFilePath) === true) {
395
                        dol_syslog("connector.lib.php DetectHtml is ko");
396
                        @unlink($sFilePath);
397
                        $sErrorNumber = '202';
398
                    }
399
                }
400
            } else {
401
                $sErrorNumber = '202';
402
            }
403
        }
404
    } else {
405
        $sErrorNumber = '203';
406
    }
407
408
409
    $sFileUrl = CombinePaths(GetResourceTypePath($resourceType, $sCommand), $currentFolder);
410
    $sFileUrl = CombinePaths($sFileUrl, $sFileName);
411
412
413
    // @CHANGE
414
    //SendUploadResults( $sErrorNumber, $sFileUrl, $sFileName );
415
    if ($CKEcallback == '') {
416
        // this line already exists so wrap the if block around it
417
        SendUploadResults($sErrorNumber, $sFileUrl, $sFileName);
418
    } else {
419
        //issue the CKEditor Callback
420
        SendCKEditorResults(
421
            $CKEcallback,
422
            $sFileUrl,
423
            ($sErrorNumber != 0 ? 'Error ' . $sErrorNumber . ' upload failed.' : 'Upload Successful')
424
        );
425
    }
426
427
    exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
428
}
429
430
431
/**
432
 * CombinePaths
433
 *
434
 * @param string $sBasePath sBasePath
435
 * @param string $sFolder sFolder
436
 * @return  string                Combined path
437
 */
438
function CombinePaths($sBasePath, $sFolder)
439
{
440
    return RemoveFromEnd($sBasePath, '/') . '/' . RemoveFromStart($sFolder, '/');
441
}
442
443
/**
444
 * GetResourceTypePath
445
 *
446
 * @param string $resourceType Resource type
447
 * @param string $sCommand Command
448
 * @return  string                      Config
449
 */
450
function GetResourceTypePath($resourceType, $sCommand)
451
{
452
    global $Config;
453
454
    if ($sCommand == "QuickUpload") {
455
        return $Config['QuickUploadPath'][$resourceType];
456
    } else {
457
        return $Config['FileTypesPath'][$resourceType];
458
    }
459
}
460
461
/**
462
 * GetResourceTypeDirectory
463
 *
464
 * @param string $resourceType Resource type
465
 * @param string $sCommand Command
466
 * @return string
467
 */
468
function GetResourceTypeDirectory($resourceType, $sCommand)
469
{
470
    global $Config;
471
    if ($sCommand == "QuickUpload") {
472
        if (strlen($Config['QuickUploadAbsolutePath'][$resourceType]) > 0) {
473
            return $Config['QuickUploadAbsolutePath'][$resourceType];
474
        }
475
476
        // Map the "UserFiles" path to a local directory.
477
        return Server_MapPath($Config['QuickUploadPath'][$resourceType]);
478
    } else {
479
        if (strlen($Config['FileTypesAbsolutePath'][$resourceType]) > 0) {
480
            return $Config['FileTypesAbsolutePath'][$resourceType];
481
        }
482
483
        // Map the "UserFiles" path to a local directory.
484
        return Server_MapPath($Config['FileTypesPath'][$resourceType]);
485
    }
486
}
487
488
/**
489
 * GetUrlFromPath
490
 *
491
 * @param string $resourceType Resource type
492
 * @param string $folderPath Path
493
 * @param string $sCommand Command
494
 * @return  string                  Full url
495
 */
496
function GetUrlFromPath($resourceType, $folderPath, $sCommand)
497
{
498
    return CombinePaths(GetResourceTypePath($resourceType, $sCommand), $folderPath);
499
}
500
501
/**
502
 * RemoveExtension
503
 *
504
 * @param string $fileName Filename
505
 * @return  string                  String without extension
506
 */
507
function RemoveExtension($fileName)
508
{
509
    return substr($fileName, 0, strrpos($fileName, '.'));
510
}
511
512
/**
513
 * ServerMapFolder
514
 *
515
 * @param string $resourceType Resource type
516
 * @param string $folderPath Folder
517
 * @param string $sCommand Command
518
 * @return  string
519
 */
520
function ServerMapFolder($resourceType, $folderPath, $sCommand)
521
{
522
    // Get the resource type directory.
523
    $sResourceTypePath = GetResourceTypeDirectory($resourceType, $sCommand);
524
525
    // Ensure that the directory exists.
526
    $sErrorMsg = CreateServerFolder($sResourceTypePath);
527
    if ($sErrorMsg != '') {
528
        SendError(1, "Error creating folder \"$sResourceTypePath\" ($sErrorMsg)");
529
    }
530
531
    // Return the resource type directory combined with the required path.
532
    return CombinePaths($sResourceTypePath, $folderPath);
533
}
534
535
/**
536
 * GetParentFolder
537
 *
538
 * @param string $folderPath Folder path
539
 * @return  string                  Parent folder
540
 */
541
function GetParentFolder($folderPath)
542
{
543
    $sPattern = "-[/\\\\][^/\\\\]+[/\\\\]?$-";
544
    return preg_replace($sPattern, '', $folderPath);
545
}
546
547
/**
548
 * CreateServerFolder
549
 *
550
 * @param string $folderPath Folder - Folder to create (recursively)
551
 * @param   ?string $lastFolder Internal - Child Folder we are creating, prevents recursion
552
 * @return  string                  ''=success, error message otherwise
553
 */
554
function CreateServerFolder($folderPath, $lastFolder = null)
555
{
556
    global $user;
557
    global $Config;
558
559
    $sParent = GetParentFolder($folderPath);
560
561
    // Ensure the folder path has no double-slashes, or mkdir may fail on certain platforms
562
    while (strpos($folderPath, '//') !== false) {
563
        $folderPath = str_replace('//', '/', $folderPath);
564
    }
565
566
    $permissiontouploadmediaisok = 1;
567
    if (!empty($user->socid)) {
568
        $permissiontouploadmediaisok = 0;
569
    }
570
    /*if (!$user->hasRight('website', 'write') && !$user->hasRight('mailing', 'write')) {
571
     $permissiontouploadmediaisok = 0;
572
     }*/
573
    if (!$permissiontouploadmediaisok) {
574
        return 'Bad permissions to create a folder in media directory';
575
    }
576
577
    // Check if the parent exists, or create it.
578
    if (!empty($sParent) && !file_exists($sParent)) {
579
        //prevents against infinite loop when we can't create root folder
580
        if (!is_null($lastFolder) && $lastFolder === $sParent) {
581
            return "Can't create $folderPath directory";
582
        }
583
584
        // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
585
        $sErrorMsg = CreateServerFolder($sParent, $folderPath);
586
        if ($sErrorMsg != '') {
587
            return $sErrorMsg;
588
        }
589
    }
590
591
    if (!file_exists($folderPath)) {
592
        // Turn off all error reporting.
593
        error_reporting(0);
594
595
        $php_errormsg = '';
596
        // Enable error tracking to catch the error.
597
        ini_set('track_errors', '1');
598
599
        if (isset($Config['ChmodOnFolderCreate']) && !$Config['ChmodOnFolderCreate']) {
600
            mkdir($folderPath);
601
        } else {
602
            $permissions = '0777';
603
            if (isset($Config['ChmodOnFolderCreate']) && $Config['ChmodOnFolderCreate']) {
604
                $permissions = (string)$Config['ChmodOnFolderCreate'];
605
            }
606
            $permissionsdec = octdec($permissions);
607
            $permissionsdec |= octdec('0111'); // Set x bit required for directories
608
            dol_syslog("connector.lib.php permission = " . $permissions . " " . $permissionsdec . " " . decoct($permissionsdec));
609
            // To create the folder with 0777 permissions, we need to set umask to zero.
610
            $oldumask = umask(0);
611
            mkdir($folderPath, $permissionsdec);
612
            umask($oldumask);
613
        }
614
615
        $sErrorMsg = $php_errormsg;
616
617
        // Restore the configurations.
618
        ini_restore('track_errors');
619
        ini_restore('error_reporting');
620
621
        return $sErrorMsg;
622
    } else {
623
        return '';
624
    }
625
}
626
627
/**
628
 * Get Root Path
629
 *
630
 * @return  string              real path
631
 */
632
function GetRootPath()
633
{
634
    if (!isset($_SERVER)) {
635
        global $_SERVER;
636
    }
637
    $sRealPath = realpath('./');
638
    // #2124 ensure that no slash is at the end
639
    $sRealPath = rtrim($sRealPath, "\\/");
640
641
    $sSelfPath = $_SERVER['PHP_SELF'];
642
    $sSelfPath = substr($sSelfPath, 0, strrpos($sSelfPath, '/'));
643
644
    $sSelfPath = str_replace('/', DIRECTORY_SEPARATOR, $sSelfPath);
645
646
    $position = strpos($sRealPath, $sSelfPath);
647
648
    // This can check only that this script isn't run from a virtual dir
649
    // But it avoids the problems that arise if it isn't checked
650
    if ($position === false || $position != strlen($sRealPath) - strlen($sSelfPath)) {
651
        SendError(1, 'Sorry, can\'t map "UserFilesPath" to a physical path. You must set the "UserFilesAbsolutePath" value in "editor/filemanager/connectors/php/config.inc.php".');
652
    }
653
654
    return substr($sRealPath, 0, $position);
655
}
656
657
/**
658
 *  Emulate the asp Server.mapPath function.
659
 * @param string $path given an url path return the physical directory that it corresponds to
660
 * @return string                  Path
661
 */
662
function Server_MapPath($path)
663
{
664
    // This function is available only for Apache
665
    if (function_exists('apache_lookup_uri')) {
666
        $info = apache_lookup_uri($path);
667
        return $info->filename . $info->path_info;
668
    }
669
670
    // This isn't correct but for the moment there's no other solution
671
    // If this script is under a virtual directory or symlink it will detect the problem and stop
672
    return GetRootPath() . $path;
673
}
674
675
/**
676
 * Is Allowed Extension
677
 *
678
 * @param string $sExtension File extension
679
 * @param string $resourceType resource type
680
 * @return  boolean                 true or false
681
 */
682
function IsAllowedExt($sExtension, $resourceType)
683
{
684
    global $Config;
685
    // Get the allowed and denied extensions arrays.
686
    $arAllowed = $Config['AllowedExtensions'][$resourceType];
687
    $arDenied = $Config['DeniedExtensions'][$resourceType];
688
689
    if (count($arAllowed) > 0 && !in_array($sExtension, $arAllowed)) {
690
        return false;
691
    }
692
693
    if (count($arDenied) > 0 && in_array($sExtension, $arDenied)) {
694
        return false;
695
    }
696
697
    return true;
698
}
699
700
/**
701
 * Is Allowed Type
702
 *
703
 * @param string $resourceType resource type
704
 * @return  boolean                 true or false
705
 */
706
function IsAllowedType($resourceType)
707
{
708
    global $Config;
709
    if (!in_array($resourceType, $Config['ConfigAllowedTypes'])) {
710
        return false;
711
    }
712
713
    return true;
714
}
715
716
/**
717
 * IsAllowedCommand
718
 *
719
 * @param string $sCommand Command
720
 * @return  boolean                     True or false
721
 */
722
function IsAllowedCommand($sCommand)
723
{
724
    global $Config;
725
726
    if (!in_array($sCommand, $Config['ConfigAllowedCommands'])) {
727
        return false;
728
    }
729
730
    return true;
731
}
732
733
/**
734
 * GetCurrentFolder
735
 *
736
 * @return  string      current folder
737
 */
738
function GetCurrentFolder()
739
{
740
    $sCurrentFolder = isset($_GET['CurrentFolder']) ? GETPOST('CurrentFolder', '', 1) : '/';
741
742
    // Check the current folder syntax (must begin and start with a slash).
743
    if (!preg_match('|/$|', $sCurrentFolder)) {
744
        $sCurrentFolder .= '/';
745
    }
746
    if (strpos($sCurrentFolder, '/') !== 0) {
747
        $sCurrentFolder = '/' . $sCurrentFolder;
748
    }
749
750
    // Ensure the folder path has no double-slashes
751
    while (strpos($sCurrentFolder, '//') !== false) {
752
        $sCurrentFolder = str_replace('//', '/', $sCurrentFolder);
753
    }
754
755
    // Check for invalid folder paths (..)
756
    if (strpos($sCurrentFolder, '..') || strpos($sCurrentFolder, "\\")) {
757
        SendError(102, '');
758
    }
759
760
    if (preg_match(",(/\.)|[[:cntrl:]]|(//)|(\\\\)|([\:\*\?\"\<\>\|]),", $sCurrentFolder)) {
761
        SendError(102, '');
762
    }
763
764
    return $sCurrentFolder;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $sCurrentFolder also could return the type array which is incompatible with the documented return type string.
Loading history...
765
}
766
767
/**
768
 * Do a cleanup of the folder name to avoid possible problems
769
 *
770
 * @param string $sNewFolderName Folder
771
 * @return  string                      Folder sanitized
772
 */
773
function SanitizeFolderName($sNewFolderName)
774
{
775
    $sNewFolderName = stripslashes($sNewFolderName);
776
777
    // Remove . \ / | : ? * " < >
778
    $sNewFolderName = preg_replace('/\\.|\\\\|\\/|\\||\\:|\\?|\\*|"|<|>|[[:cntrl:]]/', '_', $sNewFolderName);
779
780
    return $sNewFolderName;
781
}
782
783
/**
784
 * Do a cleanup of the file name to avoid possible problems
785
 *
786
 * @param string $sNewFileName Folder
787
 * @return  string                      Folder sanitized
788
 */
789
function SanitizeFileName($sNewFileName)
790
{
791
    global $Config;
792
793
    $sNewFileName = stripslashes($sNewFileName);
794
795
    // Replace dots in the name with underscores (only one dot can be there... security issue).
796
    if ($Config['ForceSingleExtension']) {
797
        $sNewFileName = preg_replace('/\\.(?![^.]*$)/', '_', $sNewFileName);
798
    }
799
800
    // Remove \ / | : ? * " < >
801
    $sNewFileName = preg_replace('/\\\\|\\/|\\||\\:|\\?|\\*|"|<|>|[[:cntrl:]]/', '_', $sNewFileName);
802
803
    return $sNewFileName;
804
}
805
806
/**
807
 * This is the function that sends the results of the uploading process.
808
 *
809
 * @param string $errorNumber errorNumber
810
 * @param string $fileUrl fileUrl
811
 * @param string $fileName fileName
812
 * @param string $customMsg customMsg
813
 * @return  void
814
 */
815
function SendUploadResults($errorNumber, $fileUrl = '', $fileName = '', $customMsg = '')
816
{
817
    // Minified version of the document.domain automatic fix script (#1919).
818
    // The original script can be found at _dev/domain_fix_template.js
819
    echo <<<EOF
820
<script type="text/javascript">
821
(function(){var d=document.domain;while (true){try{var A=window.parent.document.domain;break;}catch(e) {};d=d.replace(/.*?(?:\.|$)/,'');if (d.length==0) break;try{document.domain=d;}catch (e){break;}}})();
822
EOF;
823
824
    if ($errorNumber && $errorNumber != 201) {
825
        $fileUrl = "";
826
        $fileName = "";
827
    }
828
829
    $rpl = array('\\' => '\\\\', '"' => '\\"');
830
    echo 'console.log(' . $errorNumber . ');';
831
    echo 'window.parent.OnUploadCompleted(' . $errorNumber . ', "' . strtr($fileUrl, $rpl) . '", "' . strtr($fileName, $rpl) . '", "' . strtr($customMsg, $rpl) . '");';
832
    echo '</script>';
833
    exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
834
}
835
836
837
// @CHANGE
838
839
// This is the function that sends the results of the uploading process to CKE.
840
/**
841
 * SendCKEditorResults
842
 *
843
 * @param string $callback callback
844
 * @param string $sFileUrl sFileUrl
845
 * @param string $customMsg customMsg
846
 * @return  void
847
 */
848
function SendCKEditorResults($callback, $sFileUrl, $customMsg = '')
849
{
850
    echo '<script type="text/javascript">';
851
852
    $rpl = array('\\' => '\\\\', '"' => '\\"');
853
854
    echo 'window.parent.CKEDITOR.tools.callFunction("' . $callback . '","' . strtr($sFileUrl, $rpl) . '", "' . strtr($customMsg, $rpl) . '");';
855
856
    echo '</script>';
857
}
858
859
860
/**
861
 * RemoveFromStart
862
 *
863
 * @param string $sourceString Source
864
 * @param string $charToRemove Char to remove
865
 * @return  string      Result
866
 */
867
function RemoveFromStart($sourceString, $charToRemove)
868
{
869
    $sPattern = '|^' . $charToRemove . '+|';
870
    return preg_replace($sPattern, '', $sourceString);
871
}
872
873
/**
874
 * RemoveFromEnd
875
 *
876
 * @param string $sourceString Source
877
 * @param string $charToRemove Rhar to remove
878
 * @return  string      Result
879
 */
880
function RemoveFromEnd($sourceString, $charToRemove)
881
{
882
    $sPattern = '|' . $charToRemove . '+$|';
883
    return preg_replace($sPattern, '', $sourceString);
884
}
885
886
/**
887
 * FindBadUtf8
888
 *
889
 * @param string $string String
890
 * @return  boolean
891
 */
892
function FindBadUtf8($string)
893
{
894
    $regex = '([\x00-\x7F]|[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]';
895
    $regex .= '|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2}|(.{1}))';
896
897
    $matches = array();
898
    while (preg_match('/' . $regex . '/S', $string, $matches)) {
899
        if (isset($matches[2])) {
900
            return true;
901
        }
902
        $string = substr($string, strlen($matches[0]));
903
    }
904
905
    return false;
906
}
907
908
/**
909
 * ConvertToXmlAttribute
910
 *
911
 * @param string $value Value
912
 * @return  string
913
 */
914
function ConvertToXmlAttribute($value)
915
{
916
    if (defined('PHP_OS')) {
917
        $os = PHP_OS;
918
    } else {
919
        $os = php_uname();
920
    }
921
922
    if (strtoupper(substr($os, 0, 3)) === 'WIN' || FindBadUtf8($value)) {
923
        return (mb_convert_encoding(htmlspecialchars($value), 'UTF-8', 'ISO-8859-1'));
0 ignored issues
show
Bug Best Practice introduced by
The expression return mb_convert_encodi... 'UTF-8', 'ISO-8859-1') also could return the type array which is incompatible with the documented return type string.
Loading history...
924
    } else {
925
        return (htmlspecialchars($value));
926
    }
927
}
928
929
/**
930
 * Check whether given extension is in html extensions list
931
 *
932
 * @param string $ext Extension
933
 * @param array $formExtensions Array of extensions
934
 * @return  boolean
935
 */
936
function IsHtmlExtension($ext, $formExtensions)
937
{
938
    if (!$formExtensions || !is_array($formExtensions)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $formExtensions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
939
        return false;
940
    }
941
    $lcaseHtmlExtensions = array();
942
    foreach ($formExtensions as $key => $val) {
943
        $lcaseHtmlExtensions[$key] = strtolower($val);
944
    }
945
    return in_array($ext, $lcaseHtmlExtensions);
946
}
947
948
/**
949
 * Detect HTML in the first KB to prevent against potential security issue with
950
 * IE/Safari/Opera file type auto detection bug.
951
 *
952
 * @param string $filePath absolute path to file
953
 * @return bool|-1      Returns true if the file contains insecure HTML code at the beginning, or -1 if error
0 ignored issues
show
Documentation Bug introduced by
The doc comment bool|-1 at position 2 could not be parsed: Unknown type name '-1' at position 2 in bool|-1.
Loading history...
954
 */
955
function DetectHtml($filePath)
956
{
957
    $fp = @fopen($filePath, 'rb');
958
959
    //open_basedir restriction, see #1906
960
    if ($fp === false || !flock($fp, LOCK_SH)) {
961
        return -1;
962
    }
963
964
    $chunk = fread($fp, 1024);
965
    flock($fp, LOCK_UN);
966
    fclose($fp);
967
968
    $chunk = strtolower($chunk);
969
970
    if (!$chunk) {
971
        return false;
972
    }
973
974
    $chunk = trim($chunk);
975
976
    if (preg_match("/<!DOCTYPE\W*X?HTML/sim", $chunk)) {
977
        return true;
978
    }
979
980
    $tags = array('<body', '<head', '<html', '<img', '<pre', '<script', '<table', '<title');
981
982
    foreach ($tags as $tag) {
983
        if (false !== strpos($chunk, $tag)) {
984
            return true;
985
        }
986
    }
987
988
    //type = javascript
989
    if (preg_match('!type\s*=\s*[\'"]?\s*(?:\w*/)?(?:ecma|java)!sim', $chunk)) {
990
        return true;
991
    }
992
993
    //href = javascript
994
    //src = javascript
995
    //data = javascript
996
    if (preg_match('!(?:href|src|data)\s*=\s*[\'"]?\s*(?:ecma|java)script:!sim', $chunk)) {
997
        return true;
998
    }
999
1000
    //url(javascript
1001
    if (preg_match('!url\s*\(\s*[\'"]?\s*(?:ecma|java)script:!sim', $chunk)) {
1002
        return true;
1003
    }
1004
1005
    return false;
1006
}
1007
1008
/**
1009
 * Check file content.
1010
 * Currently this function validates only image files.
1011
 *
1012
 * @param string $filePath Absolute path to file
1013
 * @param string $extension File extension
1014
 * @return  bool|-1                 Returns true if the file is valid, false if the file is invalid, -1 if error.
0 ignored issues
show
Documentation Bug introduced by
The doc comment bool|-1 at position 2 could not be parsed: Unknown type name '-1' at position 2 in bool|-1.
Loading history...
1015
 */
1016
function IsImageValid($filePath, $extension)
1017
{
1018
    if (!@is_readable($filePath)) {
1019
        return -1;
1020
    }
1021
1022
    $imageCheckExtensions = array(
1023
        'gif',
1024
        'jpeg',
1025
        'jpg',
1026
        'png',
1027
        'swf',
1028
        'psd',
1029
        'bmp',
1030
        'iff',
1031
        'tiff',
1032
        'tif',
1033
        'swc',
1034
        'jpc',
1035
        'jp2',
1036
        'jpx',
1037
        'jb2',
1038
        'xbm',
1039
        'wbmp'
1040
    );
1041
1042
    if (!in_array($extension, $imageCheckExtensions)) {
1043
        return true;
1044
    }
1045
1046
    if (@getimagesize($filePath) === false) {
1047
        return false;
1048
    }
1049
1050
    return true;
1051
}
1052