Passed
Push — master ( d855a0...34f20f )
by Enjoys
01:02 queued 12s
created

Upload::checkRequired()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

Changes 4
Bugs 0 Features 1
Metric Value
eloc 7
c 4
b 0
f 1
dl 0
loc 13
ccs 8
cts 8
cp 1
rs 10
cc 4
nc 4
nop 3
crap 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Enjoys\Forms\Rule;
6
7
use ByteUnits\Binary;
8
use Enjoys\Forms\Element;
9
use Enjoys\Forms\Exception\ExceptionRule;
10
use Enjoys\Forms\Interfaces\Ruleable;
11
use Enjoys\Forms\Rules;
12
use Psr\Http\Message\UploadedFileInterface;
13
use Webmozart\Assert\Assert;
14
15
class Upload extends Rules implements RuleInterface
16
{
17
    private array $systemErrorMessage = [
18
        'unknown' => "Unknown upload error",
19
        \UPLOAD_ERR_INI_SIZE => "Размер принятого файла превысил максимально допустимый размер,
20
            который задан директивой upload_max_filesize конфигурационного файла php.ini.",
21
        \UPLOAD_ERR_FORM_SIZE => "Размер загружаемого файла превысил значение MAX_FILE_SIZE, указанное в HTML-форме.",
22
        \UPLOAD_ERR_PARTIAL => "Загружаемый файл был получен только частично.",
23
        \UPLOAD_ERR_NO_FILE => "Файл не был загружен",
24
        //Добавлено в PHP 5.0.3.
25
        \UPLOAD_ERR_NO_TMP_DIR => "Отсутствует временная папка.",
26
        //Добавлено в PHP 5.1.0.
27
        \UPLOAD_ERR_CANT_WRITE => "Не удалось записать файл на диск.",
28
        //Добавлено в PHP 5.2.0.
29
        \UPLOAD_ERR_EXTENSION => "File upload stopped by extension",
30
    ];
31
32
33 1
    private function getSystemMessage(int $error): string
34
    {
35 1
        if (isset($this->systemErrorMessage[$error])) {
36 1
            return $this->systemErrorMessage[$error];
37
        }
38
        return $this->systemErrorMessage['unknown'];
39
    }
40
41
    /**
42
     * @psalm-suppress PossiblyNullReference
43
     * @param Ruleable&Element $element
44
     * @return bool
45
     * @throws ExceptionRule
46
     */
47 2
    public function validate(Ruleable $element): bool
48
    {
49
        /** @var UploadedFileInterface|false $value */
50 2
        $value = \getValueByIndexPath($element->getName(), $this->getRequest()->getFilesData()->toArray());
0 ignored issues
show
Bug introduced by
The method getName() does not exist on Enjoys\Forms\Interfaces\Ruleable. Since it exists in all sub-types, consider adding an abstract or default implementation to Enjoys\Forms\Interfaces\Ruleable. ( Ignorable by Annotation )

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

50
        $value = \getValueByIndexPath($element->/** @scrutinizer ignore-call */ getName(), $this->getRequest()->getFilesData()->toArray());
Loading history...
Bug introduced by
The method toArray() does not exist on Psr\Http\Message\UploadedFileInterface. ( Ignorable by Annotation )

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

50
        $value = \getValueByIndexPath($element->getName(), $this->getRequest()->getFilesData()->/** @scrutinizer ignore-call */ toArray());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
51
52 2
        if (false === $this->check($value, $element)) {
53 1
            return false;
54
        }
55 1
        return true;
56
    }
57
58
59
    /**
60
     * @param false|UploadedFileInterface $value
61
     * @param Ruleable $element
62
     * @return bool
63
     * @throws ExceptionRule
64
     * @noinspection PhpMissingParamTypeInspection
65
     */
66 20
    private function check($value, Ruleable $element): bool
67
    {
68 20
        foreach ($this->getParams() as $rule => $ruleOpts) {
69 19
            if (is_int($rule) && is_string($ruleOpts)) {
70 9
                $rule = $ruleOpts;
71 9
                $ruleOpts = null;
72
            }
73 19
            $method = 'check' . $rule;
74 19
            if (!method_exists(Upload::class, $method)) {
75 1
                throw new ExceptionRule(\sprintf('Unknown Upload Rule [%s]', $method));
76
            }
77 18
            return $this->$method($value, $ruleOpts, $element);
78
        }
79 1
        return true;
80
    }
81
82
    /**
83
     * @param false|UploadedFileInterface $value
84
     * @param mixed $message
85
     * @param Ruleable $element
86
     * @return bool
87
     * @noinspection PhpMissingParamTypeInspection
88
     * @noinspection PhpUnusedParameterInspection
89
     * @noinspection PhpUnusedPrivateMethodInspection
90
     * @psalm-suppress UnusedParam     *
91
     */
92 4
    private function checkSystem($value, $message, Ruleable $element): bool
93
    {
94 4
        if ($value === false) {
95 1
            return true;
96
        }
97
98 3
        if (!in_array($value->getError(), array(\UPLOAD_ERR_OK, \UPLOAD_ERR_NO_FILE))) {
99 1
            $this->setMessage($this->getSystemMessage($value->getError()));
100 1
            $element->setRuleError($this->getMessage());
101 1
            return false;
102
        }
103 2
        return true;
104
    }
105
106
    /**
107
     * @param false|UploadedFileInterface $value
108
     * @noinspection PhpMissingParamTypeInspection
109
     * @noinspection PhpUnusedPrivateMethodInspection
110
     */
111 5
    private function checkRequired($value, ?string $message, Ruleable $element): bool
112
    {
113 5
        if (is_null($message)) {
114 4
            $message = 'Выберите файл для загрузки';
115
        }
116 5
        $this->setMessage($message);
117
118 5
        if ($value === false || $value->getError() == \UPLOAD_ERR_NO_FILE) {
119 3
            $element->setRuleError($this->getMessage());
120 3
            return false;
121
        }
122
123 2
        return true;
124
    }
125
126
    /**
127
     * @param false|UploadedFileInterface $value
128
     * @noinspection PhpMissingParamTypeInspection
129
     * @noinspection PhpUnusedPrivateMethodInspection
130
     */
131 6
    private function checkMaxsize($value, int|array|string $ruleOpts, Ruleable $element): bool
132
    {
133 6
        if ($value === false) {
134 1
            return true;
135
        }
136
137 5
        $parsed = $this->parseRuleOpts($ruleOpts);
138
139 5
        $threshold_size = $parsed['param'];
140
141 5
        $message = $parsed['message'];
142
143 5
        $file_size = $value->getSize() ?? 0;
144
145 5
        if (is_null($message)) {
146 4
            $message = 'Размер файла (' . Binary::bytes($file_size)->format(null, " ") . ')'
147 4
                . ' превышает допустимый размер: ' . Binary::bytes($threshold_size)->format(null, " ");
148
        }
149 4
        $this->setMessage($message);
150
151 4
        if ($file_size > $threshold_size) {
152 2
            $element->setRuleError($this->getMessage());
153 2
            return false;
154
        }
155 2
        return true;
156
    }
157
158
159
    /**
160
     * @param false|UploadedFileInterface $value
161
     * @noinspection PhpMissingParamTypeInspection
162
     * @noinspection PhpUnusedPrivateMethodInspection
163
     */
164 4
    private function checkExtensions($value, string|array $ruleOpts, Ruleable $element): bool
165
    {
166 4
        if ($value === false) {
167 1
            return true;
168
        }
169
170 3
        $parsed = $this->parseRuleOpts($ruleOpts);
171
172 3
        $expected_extensions = \array_map('trim', \explode(",", $parsed['param']));
173 3
        $message = $parsed['message'];
174
175 3
        $extension = pathinfo($value->getClientFilename() ?? '', PATHINFO_EXTENSION);
176
177 3
        if (is_null($message)) {
178 1
            $message = 'Загрузка файлов с расширением .' . $extension . ' запрещена';
0 ignored issues
show
Bug introduced by
Are you sure $extension of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

178
            $message = 'Загрузка файлов с расширением .' . /** @scrutinizer ignore-type */ $extension . ' запрещена';
Loading history...
179
        }
180 3
        $this->setMessage($message);
181
182 3
        if (!in_array($extension, $expected_extensions)) {
183 2
            $element->setRuleError($this->getMessage());
184 2
            return false;
185
        }
186 1
        return true;
187
    }
188
189
190 12
    private function parseRuleOpts(mixed $opts): array
191
    {
192 12
        if (!is_array($opts)) {
193 6
            $opts = (array)$opts;
194 6
            $opts[1] = null;
195
        }
196 12
        list($param, $message) = $opts;
197
198 12
        Assert::nullOrString($message);
199
200
        return [
201 11
            'param' => $param,
202
            'message' => $message
203
        ];
204
    }
205
}
206