Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
PathValidator
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
2 / 2
5
100.00% covered (success)
100.00%
1 / 1
 validatePath
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 validateDirectory
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3/**
4 * Karla ImageMagick wrapper library
5 *
6 * PHP Version 8.0<
7 *
8 * @category Utility
9 * @author   Johannes Skov Frandsen <jsf@greenoak.dk>
10 * @license  http://www.opensource.org/licenses/mit-license.php MIT
11 * @link     https://github.com/localgod/karla Karla
12 * @since    2024-01-01
13 */
14
15declare(strict_types=1);
16
17namespace Karla;
18
19/**
20 * Class for validating file system paths to prevent directory traversal attacks
21 *
22 * @category Utility
23 * @author   Johannes Skov Frandsen <jsf@greenoak.dk>
24 * @license  http://www.opensource.org/licenses/mit-license.php MIT
25 * @link     https://github.com/localgod/karla Karla
26 */
27class PathValidator
28{
29    /**
30     * Validate a file path and return its resolved absolute path.
31     *
32     * Prevents directory traversal attacks by resolving the real path and
33     * rejecting paths containing null bytes.
34     *
35     * @param string $path Path to validate
36     *
37     * @throws \InvalidArgumentException If the path contains null bytes or cannot be resolved.
38     */
39    public static function validatePath(string $path): string
40    {
41        if (str_contains($path, "\0")) {
42            throw new \InvalidArgumentException('Path contains null bytes');
43        }
44
45        $realPath = realpath($path);
46
47        if ($realPath === false) {
48            throw new \InvalidArgumentException("Invalid path: {$path}");
49        }
50
51        return $realPath;
52    }
53
54    /**
55     * Validate a directory path and return its resolved absolute path.
56     *
57     * Prevents directory traversal attacks by resolving the real path and
58     * confirming the resolved path is a directory.
59     *
60     * @param string $path Directory path to validate
61     *
62     * @throws \InvalidArgumentException If the path is invalid or not a directory.
63     */
64    public static function validateDirectory(string $path): string
65    {
66        $realPath = self::validatePath($path);
67
68        if (!is_dir($realPath)) {
69            throw new \InvalidArgumentException("Path is not a directory: {$path}");
70        }
71
72        return $realPath;
73    }
74}