Passed
Push — 5.x ( 65a76f...3a1e20 )
by Enjoys
59s queued 13s
created

Upload   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 173
Duplicated Lines 0 %

Test Coverage

Coverage 98.57%

Importance

Changes 9
Bugs 1 Features 1
Metric Value
wmc 26
eloc 74
c 9
b 1
f 1
dl 0
loc 173
ccs 69
cts 70
cp 0.9857
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A checkRequired() 0 13 4
A checkSystem() 0 12 3
A validate() 0 9 2
A checkMaxsize() 0 24 4
A checkExtensions() 0 23 4
A check() 0 14 5
A parseRuleOpts() 0 13 2
A getSystemMessage() 0 6 2
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...
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
     */
65 19
    private function check($value, Ruleable $element): bool
66
    {
67 19
        foreach ($this->getParams() as $rule => $ruleOpts) {
68 18
            if (is_int($rule) && is_string($ruleOpts)) {
69 9
                $rule = $ruleOpts;
70 9
                $ruleOpts = null;
71
            }
72 18
            $method = 'check' . $rule;
73 18
            if (!method_exists(Upload::class, $method)) {
74 1
                throw new ExceptionRule(\sprintf('Unknown Upload Rule [%s]', $method));
75
            }
76 17
            return $this->$method($value, $ruleOpts, $element);
77
        }
78 1
        return true;
79
    }
80
81
    /**
82
     * @param false|UploadedFileInterface $value
83
     */
84 4
    private function checkSystem($value, $message, Ruleable $element): bool
85
    {
86 4
        if ($value === false) {
87 1
            return true;
88
        }
89
90 3
        if (!in_array($value->getError(), array(\UPLOAD_ERR_OK, \UPLOAD_ERR_NO_FILE))) {
91 1
            $this->setMessage($this->getSystemMessage($value->getError()));
92 1
            $element->setRuleError($this->getMessage());
93 1
            return false;
94
        }
95 2
        return true;
96
    }
97
98
    /**
99
     * @param false|UploadedFileInterface $value
100
     */
101 5
    private function checkRequired($value, ?string $message, Ruleable $element): bool
102
    {
103 5
        if (is_null($message)) {
104 4
            $message = 'Выберите файл для загрузки';
105
        }
106 5
        $this->setMessage($message);
107
108 5
        if ($value === false || $value->getError() == \UPLOAD_ERR_NO_FILE) {
109 3
            $element->setRuleError($this->getMessage());
110 3
            return false;
111
        }
112
113 2
        return true;
114
    }
115
116
    /**
117
     * @param false|UploadedFileInterface $value
118
     */
119 5
    private function checkMaxsize($value, int|array|string $ruleOpts, Ruleable $element): bool
120
    {
121 5
        if ($value === false) {
122 1
            return true;
123
        }
124
125 4
        $parsed = $this->parseRuleOpts($ruleOpts);
126
127 4
        $threshold_size = $parsed['param'];
128
       // Assert::in($threshold_size);
129
130 4
        $message = $parsed['message'];
131
132 4
        if (is_null($message)) {
133 3
            $message = 'Размер файла (' . Binary::bytes($value->getSize())->format(null, " ") . ')'
134 3
                . ' превышает допустимый размер: ' . Binary::bytes($threshold_size)->format(null, " ");
135
        }
136 3
        $this->setMessage($message);
137
138 3
        if ($value->getSize() > $threshold_size) {
139 2
            $element->setRuleError($this->getMessage());
140 2
            return false;
141
        }
142 1
        return true;
143
    }
144
145
146
    /**
147
     * @param false|UploadedFileInterface $value
148
     */
149 4
    private function checkExtensions($value, string|array $ruleOpts, Ruleable $element): bool
150
    {
151 4
        if ($value === false) {
152 1
            return true;
153
        }
154
155 3
        $parsed = $this->parseRuleOpts($ruleOpts);
156
157 3
        $expected_extensions = \array_map('trim', \explode(",", $parsed['param']));
158 3
        $message = $parsed['message'];
159
160 3
        $extension = pathinfo($value->getClientFilename(), PATHINFO_EXTENSION);
0 ignored issues
show
Bug introduced by
It seems like $value->getClientFilename() can also be of type null; however, parameter $path of pathinfo() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

160
        $extension = pathinfo(/** @scrutinizer ignore-type */ $value->getClientFilename(), PATHINFO_EXTENSION);
Loading history...
161
162 3
        if (is_null($message)) {
163 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

163
            $message = 'Загрузка файлов с расширением .' . /** @scrutinizer ignore-type */ $extension . ' запрещена';
Loading history...
164
        }
165 3
        $this->setMessage($message);
166
167 3
        if (!in_array($extension, $expected_extensions)) {
168 2
            $element->setRuleError($this->getMessage());
169 2
            return false;
170
        }
171 1
        return true;
172
    }
173
174
175 11
    private function parseRuleOpts($opts): array
176
    {
177 11
        if (!is_array($opts)) {
178 5
            $opts = (array)$opts;
179 5
            $opts[1] = null;
180
        }
181 11
        list($param, $message) = $opts;
182
183 11
        Assert::nullOrString($message);
184
185
        return [
186 10
            'param' => $param,
187
            'message' => $message
188
        ];
189
    }
190
}
191