Passed
Pull Request — 4.8 (#10059)
by
unknown
06:13
created

testWeWillDefaultToPHPMaxUploadSizingForValidation()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 6
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 11
rs 10
1
<?php
2
3
namespace SilverStripe\Forms\Tests;
4
5
use ReflectionMethod;
6
use SilverStripe\Assets\File;
7
use SilverStripe\Assets\Upload_Validator;
8
use SilverStripe\Dev\FunctionalTest;
9
use SilverStripe\Control\Controller;
10
use SilverStripe\Forms\FileField;
11
use SilverStripe\Forms\FieldList;
12
use SilverStripe\Forms\Form;
13
use SilverStripe\Forms\RequiredFields;
14
15
class FileFieldTest extends FunctionalTest
16
{
17
    /**
18
     * Test a valid upload of a required file in a form. Error is set to 0, as the upload went well
19
     *
20
     * @skipUpgrade
21
     */
22
    public function testUploadRequiredFile()
23
    {
24
        $form = new Form(
25
            Controller::curr(),
26
            'Form',
27
            new FieldList(
28
                $fileField = new FileField('cv', 'Upload your CV')
29
            ),
30
            new FieldList()
31
        );
32
        $fileFieldValue = [
33
            'name' => 'aCV.txt',
34
            'type' => 'application/octet-stream',
35
            'tmp_name' => '/private/var/tmp/phpzTQbqP',
36
            'error' => 0,
37
            'size' => 3471
38
        ];
39
        $fileField->setValue($fileFieldValue);
40
41
        $this->assertTrue($form->validationResult()->isValid());
42
    }
43
44
    /**
45
     * Test that FileField::validate() is run on FileFields with both single and multi-file syntax
46
     * By default FileField::validate() will return true early if the $_FILES super-global does not contain the
47
     * corresponding FileField::name. This early return means the files was not fully run through FileField::validate()
48
     * So for this test we create an invalid file upload on purpose and test that false was returned which means that
49
     * the file was run through FileField::validate() function
50
     */
51
    public function testMultiFileSyntaxUploadIsValidated()
52
    {
53
        $names = [
54
            'single_file_syntax',
55
            'multi_file_syntax_a[]',
56
            'multi_file_syntax_b[0]',
57
            'multi_file_syntax_c[key]'
58
        ];
59
        foreach ($names as $name) {
60
            $form = new Form(
61
                Controller::curr(),
62
                'Form',
63
                new FieldList($fileField = new FileField($name, 'My desc')),
64
                new FieldList()
65
            );
66
            $fileData = $this->createInvalidUploadedFileData($name, "FileFieldTest.txt");
67
            // FileFields with multi_file_syntax[] files will appear in the $_FILES super-global
68
            // with the [] brackets trimmed e.g. $_FILES[multi_file_syntax]
69
            $_FILES = [preg_replace('#\[(.*?)\]#', '', $name) => $fileData];
70
            $fileField->setValue($fileData);
71
            $validator = $form->getValidator();
72
            $isValid = $fileField->validate($validator);
73
            $this->assertFalse($isValid, "$name was run through the validate() function");
74
        }
75
    }
76
77
    protected function createInvalidUploadedFileData($name, $tmpFileName): array
78
    {
79
        $tmpFilePath = TEMP_PATH . DIRECTORY_SEPARATOR . $tmpFileName;
80
81
        // multi_file_syntax
82
        if (strpos($name, '[') !== false) {
83
            $key = 0;
84
            if (preg_match('#\[(.+?)\]#', $name, $m)) {
85
                $key = $m[1];
86
            }
87
            return [
88
                'name' => [$key => $tmpFileName],
89
                'type' => [$key => 'text/plaintext'],
90
                'size' => [$key => 0],
91
                'tmp_name' => [$key => $tmpFilePath],
92
                'error' => [$key => UPLOAD_ERR_NO_FILE],
93
            ];
94
        }
95
        // single_file_syntax
96
        return [
97
            'name' => $tmpFileName,
98
            'type' => 'text/plaintext',
99
            'size' => 0,
100
            'tmp_name' => $tmpFilePath,
101
            'error' => UPLOAD_ERR_NO_FILE,
102
        ];
103
    }
104
105
    /**
106
     * @skipUpgrade
107
     */
108
    public function testGetAcceptFileTypes()
109
    {
110
        $field = new FileField('image', 'Image');
111
        $field->setAllowedExtensions('jpg', 'png');
0 ignored issues
show
Unused Code introduced by
The call to SilverStripe\Forms\FileF...:setAllowedExtensions() has too many arguments starting with 'png'. ( Ignorable by Annotation )

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

111
        $field->/** @scrutinizer ignore-call */ 
112
                setAllowedExtensions('jpg', 'png');

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
Bug introduced by
'jpg' of type string is incompatible with the type array expected by parameter $rules of SilverStripe\Forms\FileF...:setAllowedExtensions(). ( Ignorable by Annotation )

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

111
        $field->setAllowedExtensions(/** @scrutinizer ignore-type */ 'jpg', 'png');
Loading history...
112
113
        $method = new ReflectionMethod($field, 'getAcceptFileTypes');
114
        $method->setAccessible(true);
115
        $allowed = $method->invoke($field);
116
117
        $expected = ['.jpg', '.png', 'image/jpeg', 'image/png'];
118
        foreach ($expected as $extensionOrMime) {
119
            $this->assertContains($extensionOrMime, $allowed);
120
        }
121
    }
122
123
    /**
124
     * Test different scenarii for a failed upload : an error occured, no files where provided
125
     * @skipUpgrade
126
     */
127
    public function testUploadMissingRequiredFile()
128
    {
129
        $form = new Form(
130
            Controller::curr(),
131
            'Form',
132
            new FieldList(
133
                $fileField = new FileField('cv', 'Upload your CV')
134
            ),
135
            new FieldList(),
136
            new RequiredFields('cv')
137
        );
138
        // All fields are filled but for some reason an error occured when uploading the file => fails
139
        $fileFieldValue = [
140
            'name' => 'aCV.txt',
141
            'type' => 'application/octet-stream',
142
            'tmp_name' => '/private/var/tmp/phpzTQbqP',
143
            'error' => 1,
144
            'size' => 3471
145
        ];
146
        $fileField->setValue($fileFieldValue);
147
148
        $this->assertFalse(
149
            $form->validationResult()->isValid(),
150
            'An error occured when uploading a file, but the validator returned true'
151
        );
152
153
        // We pass an empty set of parameters for the uploaded file => fails
154
        $fileFieldValue = [];
155
        $fileField->setValue($fileFieldValue);
156
157
        $this->assertFalse(
158
            $form->validationResult()->isValid(),
159
            'An empty array was passed as parameter for an uploaded file, but the validator returned true'
160
        );
161
162
        // We pass an null value for the uploaded file => fails
163
        $fileFieldValue = null;
164
        $fileField->setValue($fileFieldValue);
165
166
        $this->assertFalse(
167
            $form->validationResult()->isValid(),
168
            'A null value was passed as parameter for an uploaded file, but the validator returned true'
169
        );
170
    }
171
    
172
    /**
173
     * Test the file size validation will use the PHP max size setting if 
174
     * no config for the Upload_Validator::default_max_file_size has been defined
175
     */
176
    public function testWeWillDefaultToPHPMaxUploadSizingForValidation()
177
    {
178
        // These 3 lines are how SilverStripe works out the default max upload size as defined in Upload_Validator
179
        $phpMaxUpload = File::ini2bytes(ini_get('upload_max_filesize'));
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Assets\File::ini2bytes() has been deprecated: 5.0 Use Convert::memstring2bytes() instead ( Ignorable by Annotation )

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

179
        $phpMaxUpload = /** @scrutinizer ignore-deprecated */ File::ini2bytes(ini_get('upload_max_filesize'));

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
180
        $maxPost = File::ini2bytes(ini_get('post_max_size'));
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Assets\File::ini2bytes() has been deprecated: 5.0 Use Convert::memstring2bytes() instead ( Ignorable by Annotation )

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

180
        $maxPost = /** @scrutinizer ignore-deprecated */ File::ini2bytes(ini_get('post_max_size'));

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
181
        $defaultUploadSize = min($phpMaxUpload, $maxPost);
182
183
        $fileField = new FileField('DemoField');
0 ignored issues
show
Unused Code introduced by
The assignment to $fileField is dead and can be removed.
Loading history...
184
185
        $this->assertEquals($defaultUploadSize, $fieldField->getValidator()->getAllowedMaxFileSize('jpg'));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $fieldField seems to be never defined.
Loading history...
186
        $this->assertEquals($defaultUploadSize, $fieldField->getValidator()->getAllowedMaxFileSize('png'));
187
    }
188
189
    /**
190
     * Test the file size validation will use the default_max_file_size validation config if defined
191
     */
192
    public function testWeUseConfigForSizingIfDefined()
193
    {
194
        $configMaxFileSizes = [
195
            'jpg' => $jpgSize = '2m',
196
            '*' => $defaultSize = '1m',
197
        ];
198
199
        Upload_Validator::config()->set('default_max_file_size', $configMaxFileSizes);
200
201
        $fileField = new FileField('DemoField');
0 ignored issues
show
Unused Code introduced by
The assignment to $fileField is dead and can be removed.
Loading history...
202
203
        $this->assertEquals(File::ini2bytes($jpgSize), $fieldField->getValidator()->getAllowedMaxFileSize('jpg'));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $fieldField seems to be never defined.
Loading history...
Deprecated Code introduced by
The function SilverStripe\Assets\File::ini2bytes() has been deprecated: 5.0 Use Convert::memstring2bytes() instead ( Ignorable by Annotation )

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

203
        $this->assertEquals(/** @scrutinizer ignore-deprecated */ File::ini2bytes($jpgSize), $fieldField->getValidator()->getAllowedMaxFileSize('jpg'));

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
204
        
205
        // PNG is not explicitly defined in config, so would fall back to *
206
        $this->assertEquals(File::ini2bytes($defaultSize), $fieldField->getValidator()->getAllowedMaxFileSize('png'));
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Assets\File::ini2bytes() has been deprecated: 5.0 Use Convert::memstring2bytes() instead ( Ignorable by Annotation )

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

206
        $this->assertEquals(/** @scrutinizer ignore-deprecated */ File::ini2bytes($defaultSize), $fieldField->getValidator()->getAllowedMaxFileSize('png'));

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
207
    }
208
}
209