Test Failed
Push — main ( 4244ba...f56735 )
by Paul
10:05 queued 12s
created

UploadedFile::getMimeType()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
c 1
b 0
f 0
dl 0
loc 8
rs 10
cc 3
nc 3
nop 0
1
<?php
2
3
namespace GeminiLabs\SiteReviews;
4
5
use GeminiLabs\SiteReviews\Defaults\UploadedFileDefaults;
6
use GeminiLabs\SiteReviews\Exceptions\FileException;
7
use GeminiLabs\SiteReviews\Exceptions\FileNotFoundException;
8
9
class UploadedFile extends \SplFileInfo
10
{
11
    private int $error;
12
    private string $mimeType;
13
    private string $originalName;
14
    private int $size;
15
16
    /**
17
     * @throws FileNotFoundException
18
     */
19
    public function __construct(array $filedata)
20
    {
21
        $data = glsr(UploadedFileDefaults::class)->restrict($filedata);
22
        $this->error = $data['error'] ?: \UPLOAD_ERR_OK;
23
        $this->mimeType = $data['type'] ?: 'application/octet-stream';
24
        $this->originalName = $this->getName($data['name']);
25
        $this->size = $data['size'];
26
        if (\UPLOAD_ERR_OK !== $this->error && !is_file($data['tmp_name'])) {
27
            throw new FileNotFoundException($data['tmp_name']);
28
        }
29
        parent::__construct($data['tmp_name']);
30
    }
31
32
    /**
33
     * Returns the file mime type extracted from the file upload request.
34
     * This should not be considered as a safe value.
35
     */
36
    public function getClientMimeType(): string
37
    {
38
        return $this->mimeType;
39
    }
40
41
    /**
42
     * Returns the original file name extracted from the file upload request.
43
     * This should not be considered as a safe value to use for a file name on your servers.
44
     */
45
    public function getClientOriginalName(): string
46
    {
47
        return $this->originalName;
48
    }
49
50
    /**
51
     * Returns the original file extension extracted from the file upload request.
52
     * This should not be considered as a safe value to use for a file name on your servers.
53
     */
54
    public function getClientOriginalExtension(): string
55
    {
56
        return pathinfo($this->originalName, \PATHINFO_EXTENSION);
57
    }
58
59
    /**
60
     * Returns the file size extracted from the file upload request.
61
     * This should not be considered as a safe value.
62
     */
63
    public function getClientSize(): int
64
    {
65
        return $this->size;
66
    }
67
68
    /**
69
     * @throws FileException
70
     */
71
    public function getContent(): string
72
    {
73
        $content = file_get_contents($this->getPathname());
74
        if (false === $content) {
75
            throw new FileException(sprintf('Could not get the content of the file "%s".', $this->getPathname()));
76
        }
77
        return $content;
78
    }
79
80
    /**
81
     * If the upload was successful, the constant UPLOAD_ERR_OK is returned.
82
     * Otherwise one of the other UPLOAD_ERR_XXX constants is returned.
83
     */
84
    public function getError(): int
85
    {
86
        return $this->error;
87
    }
88
89
    public function getErrorMessage(): string
90
    {
91
        $errors = [
92
            \UPLOAD_ERR_INI_SIZE => _x('The file "%s" exceeds the upload_max_filesize ini directive (limit is %d KiB).', 'file error (admin-text)', 'site-reviews'),
93
            \UPLOAD_ERR_FORM_SIZE => _x('The file "%s" exceeds the upload limit defined in your form.', 'file error (admin-text)', 'site-reviews'),
94
            \UPLOAD_ERR_PARTIAL => _x('The file "%s" was only partially uploaded.', 'file error (admin-text)', 'site-reviews'),
95
            \UPLOAD_ERR_NO_FILE => _x('No file was uploaded.', 'file error (admin-text)', 'site-reviews'),
96
            \UPLOAD_ERR_CANT_WRITE => _x('The file "%s" could not be written on disk.', 'file error (admin-text)', 'site-reviews'),
97
            \UPLOAD_ERR_NO_TMP_DIR => _x('File could not be uploaded: missing temporary directory.', 'file error (admin-text)', 'site-reviews'),
98
            \UPLOAD_ERR_EXTENSION => _x('File upload was stopped by a PHP extension.', 'file error (admin-text)', 'site-reviews'),
99
        ];
100
        $errorCode = $this->error;
101
        $maxFilesize = \UPLOAD_ERR_INI_SIZE === $errorCode ? wp_max_upload_size() / 1024 : 0;
102
        $message = $errors[$errorCode] ?? 'The file "%s" was not uploaded due to an unknown error.';
103
        return sprintf($message, $this->getClientOriginalName(), $maxFilesize);
104
    }
105
106
    public function getExtensionFromMimeType(): string
107
    {
108
        $mimetypes = wp_parse_args(get_allowed_mime_types(), [
109
            'json' => 'application/json',
110
        ]);
111
        $extensions = explode('|', array_search($this->getMimeType(), $mimetypes, true));
112
        return $extensions[0] ?? $this->getExtension() ?? $this->getClientOriginalExtension();
113
    }
114
115
    /**
116
     * This should not be considered a safe value.
117
     */
118
    public function getMimeType(): string
119
    {
120
        if (function_exists('mime_content_type')) {
121
            if ($mimeType = mime_content_type($this->getPathname())) {
122
                return $mimeType;
123
            }
124
        }
125
        return $this->getClientMimeType();
126
    }
127
128
    /**
129
     * Checks against the file mime type extracted from the file upload request.
130
     * This should not be considered a safe check.
131
     */
132
    public function hasMimeType(string $mimeType): bool
133
    {
134
        $detectedMimeType = $this->getMimeType();
135
        if ('text/csv' === $mimeType && 'application/vnd.ms-excel' === $detectedMimeType) {
136
            return 'csv' === ($this->getExtension() ?? $this->getClientOriginalExtension());
137
        }
138
        $inconclusiveMimeTypes = [
139
            'application/octet-stream',
140
            'application/x-empty',
141
            'text/plain',
142
        ];
143
        if (in_array($detectedMimeType, $inconclusiveMimeTypes)) {
144
            return true;
145
        }
146
        return $mimeType === $detectedMimeType;
147
    }
148
149
    /**
150
     * Returns whether the file has been uploaded with HTTP and no error occurred.
151
     */
152
    public function isValid(): bool
153
    {
154
        $isOk = \UPLOAD_ERR_OK === $this->error;
155
        return $isOk && is_uploaded_file($this->getPathname());
156
    }
157
158
    /**
159
     * Returns locale independent base name of the given path.
160
     */
161
    protected function getName(string $name): string
162
    {
163
        $originalName = str_replace('\\', '/', $name);
164
        $pos = strrpos($originalName, '/');
165
        $originalName = false === $pos ? $originalName : substr($originalName, $pos + 1);
166
        return $originalName;
167
    }
168
}
169