Completed
Push — master ( 79e63b...a5181c )
by Daniel
05:26 queued 02:19
created

code/MimeUploadValidator.php (1 issue)

mismatching argument types.

Documentation Minor

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Adds an additional validation rule to Upload_Validator that attempts to detect
4
 * the file extension of an uploaded file matches it's contents, which is done
5
 * by detecting the MIME type and doing a fuzzy match.
6
 */
7
class MimeUploadValidator extends Upload_Validator
8
{
9
    /**
10
     * The preg_replace() pattern to use against MIME types. Used to strip out
11
     * useless characters so matching of MIME types can be fuzzy.
12
     *
13
     * @var string Regexp pattern
14
     */
15
    protected $filterPattern = '/.*[\/\.\-\+]/i';
16
17
    public function setFilterPattern($pattern)
18
    {
19
        $this->filterPattern = $pattern;
20
    }
21
22
    public function getFilterPattern()
23
    {
24
        return $this->filterPattern;
25
    }
26
27
    /**
28
     * Check if the temporary file has a valid MIME type for it's extension.
29
     *
30
     * @uses finfo php extension
31
     * @return boolean|null
32
     */
33
    public function isValidMime()
34
    {
35
        $extension = strtolower(pathinfo($this->tmpFile['name'], PATHINFO_EXTENSION));
36
37
                // we can't check filenames without an extension or no temp file path, let them pass validation.
38
                if (!$extension || !$this->tmpFile['tmp_name']) {
39
                    return true;
40
                }
41
42
        $expectedMimes = $this->getExpectedMimeTypes($this->tmpFile);
43
        if (empty($expectedMimes)) {
44
            throw new MimeUploadValidator_Exception(
45
                sprintf('Could not find a MIME type for extension %s', $extension)
46
            );
47
        }
48
49
        $finfo = new finfo(FILEINFO_MIME_TYPE);
50
        $foundMime = $finfo->file($this->tmpFile['tmp_name']);
51
        if (!$foundMime) {
52
            throw new MimeUploadValidator_Exception(
53
                sprintf('Could not find a MIME type for file %s', $this->tmpFile['tmp_name'])
54
            );
55
        }
56
57
        foreach ($expectedMimes as $expected) {
58
            if ($this->compareMime($foundMime, $expected)) {
59
                return true;
60
            }
61
        }
62
        return false;
63
    }
64
65
    /**
66
     * Fetches an array of valid mimetypes.
67
     *
68
     * @return array
69
     */
70
    public function getExpectedMimeTypes($tmpFile)
71
    {
72
        $extension = strtolower(pathinfo($tmpFile['name'], PATHINFO_EXTENSION));
73
74
        // if the finfo php extension isn't loaded, we can't complete this check.
75
        if (!class_exists('finfo')) {
76
            throw new MimeUploadValidator_Exception('PHP extension finfo is not loaded');
77
        }
78
79
        // Attempt to figure out which mime types are expected/acceptable here.
80
        $expectedMimes = array();
81
82
        // Get the mime types set in framework core
83
        $knownMimes = Config::inst()->get('HTTP', 'MimeTypes');
84
        if (isset($knownMimes[$extension])) {
85
            $expectedMimes[] = $knownMimes[$extension];
86
        }
87
88
        // Get the mime types and their variations from mimevalidator
89
        $knownMimes = Config::inst()->get(get_class($this), 'MimeTypes');
90
        if (isset($knownMimes[$extension])) {
91
            if (is_array($knownMimes[$extension])) {
92
                $expectedMimes += $knownMimes[$extension];
93
            } else {
94
                $expectedMimes[] = $knownMimes[$extension];
95
            }
96
        }
97
        return $expectedMimes;
98
    }
99
100
    /**
101
     * Check two MIME types roughly match eachother.
102
     *
103
     * Before we check MIME types, remove known prefixes "vnd.", "x-" etc.
104
     * If there is a suffix, we'll use that to compare. Examples:
105
     *
106
     * application/x-json = json
107
     * application/json = json
108
     * application/xhtml+xml = xml
109
     * application/xml = xml
110
     *
111
     * @param string $first The first MIME type to compare to the second
112
     * @param string $second The second MIME type to compare to the first
113
     * @return boolean
114
     */
115
    public function compareMime($first, $second)
116
    {
117
        return preg_replace($this->filterPattern, '', $first) === preg_replace($this->filterPattern, '', $second);
118
    }
119
120
    public function validate()
121
    {
122
        if (parent::validate() === false) {
123
            return false;
124
        }
125
126
        try {
127
            $result = $this->isValidMime();
128
            if ($result === false) {
129
                $this->errors[] = _t(
130
                    'File.INVALIDMIME',
131
                    'File extension does not match known MIME type'
132
                );
133
                return false;
134
            }
135
        } catch (MimeUploadValidator_Exception $e) {
136
            $this->errors[] = _t(
137
                'File.FAILEDMIMECHECK',
138
                'MIME validation failed: {message}',
139
                'Argument 1: Message about why MIME type detection failed',
140
                array('message' => $e->getMessage())
0 ignored issues
show
array('message' => $e->getMessage()) is of type array<string,string,{"message":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
141
            );
142
            return false;
143
        }
144
145
        return true;
146
    }
147
}
148
149
class MimeUploadValidator_Exception extends Exception
150
{
151
}
152