Completed
Push — master ( b6ec89...4ebcd0 )
by Bjørn
03:01
created

PathChecker::checkAbsolutePath()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 27
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 5.2596

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 4
eloc 6
c 3
b 0
f 0
nc 4
nop 2
dl 0
loc 27
ccs 4
cts 7
cp 0.5714
crap 5.2596
rs 10
1
<?php
2
3
namespace WebPConvert\Helpers;
4
5
use WebPConvert\Exceptions\InvalidInputException;
6
use WebPConvert\Exceptions\InvalidInput\TargetNotFoundException;
7
8
/**
9
 * Functions for sanitizing.
10
 *
11
 * @package    WebPConvert
12
 * @author     Bjørn Rosell <[email protected]>
13
 * @since      Class available since Release 2.0.6
14
 */
15
class PathChecker
16
{
17
18
     /**
19
      * Check absolute file path to prevent attacks.
20
      *
21
      * - Prevents non printable characters
22
      * - Prevents stream wrappers
23
      * - Prevents directory traversal
24
      *
25
      * Preventing non printable characters is especially done to prevent the NUL character, which can be used
26
      * to bypass other tests. See https://st-g.de/2011/04/doing-filename-checks-securely-in-PHP.
27
      *
28
      * Preventeng stream wrappers is especially done to protect against Phar Deserialization.
29
      * See https://blog.ripstech.com/2018/new-php-exploitation-technique/
30
      *
31
      * @param  string  $absFilePath
32
      * @return string  sanitized file path
33
      */
34 36
    public static function checkAbsolutePath($absFilePath, $text = 'file')
35
    {
36 36
        if (empty($absFilePath)) {
37
            throw new InvalidInputException('Empty filepath for ' . $text);
38
        }
39
40
        // Prevent non printable characters
41
        /*
42
        if (!ctype_print($absFilePath)) {
43
            throw new InvalidInputException('Non-printable characters are not allowed in ' . $text);
44
        }*/
45
46
        // Prevent control characters (at least the first 32 (#0 - #1f)
47 36
        if (preg_match('#[\x{0}-\x{1f}]#', $absFilePath)) {
48
            throw new InvalidInputException('Non-printable characters are not allowed');
49
        }
50
51
        // Prevent directory traversal
52
        /* Disabled. We DO allow it again (#203)
53
        if (preg_match('#\.\.\/#', $absFilePath)) {
54
            throw new InvalidInputException('Directory traversal is not allowed in ' . $text . ' path');
55
        }*/
56
57
        // Prevent stream wrappers ("phar://", "php://" and the like)
58
        // https://www.php.net/manual/en/wrappers.phar.php
59 36
        if (preg_match('#^\\w+://#', $absFilePath)) {
60
            throw new InvalidInputException('Stream wrappers are not allowed in ' . $text . ' path');
61
        }
62 36
    }
63
64 36
    public static function checkAbsolutePathAndExists($absFilePath, $text = 'file')
65
    {
66 36
        if (empty($absFilePath)) {
67
            throw new TargetNotFoundException($text . ' argument missing');
68
        }
69 36
        self::checkAbsolutePath($absFilePath, $text);
70 36
        if (@!file_exists($absFilePath)) {
71 5
            throw new TargetNotFoundException($text . ' file was not found');
72
        }
73 35
        if (@is_dir($absFilePath)) {
74
            throw new InvalidInputException($text . ' is a directory');
75
        }
76 35
    }
77
78
    /**
79
     *  Checks that source path is secure, file exists and it is not a dir.
80
     *
81
     *  To also check mime type, use InputValidator::checkSource
82
     */
83 31
    public static function checkSourcePath($source)
84
    {
85 31
        self::checkAbsolutePathAndExists($source, 'source');
86 30
    }
87
88 30
    public static function checkDestinationPath($destination)
89
    {
90 30
        if (empty($destination)) {
91
            throw new InvalidInputException('Destination argument missing');
92
        }
93 30
        self::checkAbsolutePath($destination, 'destination');
94
95 30
        if (!preg_match('#\.webp$#i', $destination)) {
96
            // Prevent overriding important files.
97
            // Overriding an .htaccess file would lay down the website.
98
            throw new InvalidInputException(
99
                'Destination file must end with ".webp". ' .
100
                'If you deliberately want to store the webp files with another extension, you must rename ' .
101
                'the file after successful conversion'
102
            );
103
        }
104
105 30
        if (@is_dir($destination)) {
106
            throw new InvalidInputException('Destination is a directory');
107
        }
108 30
    }
109
110
    public static function checkSourceAndDestinationPaths($source, $destination)
111
    {
112
        self::checkSourcePath($source);
113
        self::checkDestinationPath($destination);
114
    }
115
}
116