Completed
Pull Request — master (#5)
by Michael
01:39
created

SwUploadHandler::get()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 4
nop 0
dl 0
loc 12
rs 9.8666
c 0
b 0
f 0
1
<?php namespace XoopsModules\Smallworld;
2
3
/**
4
 * You may not change or alter any portion of this comment or credits
5
 * of supporting developers from this source code or any supporting source code
6
 * which is considered copyrighted (c) material of the original comment or credit authors.
7
 *
8
 * This program is distributed in the hope that it will be useful,
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
 */
12
13
/**
14
 * SmallWorld
15
 *
16
 * @copyright    The XOOPS Project (https://xoops.org)
17
 * @copyright    2011 Culex
18
 * @license      GNU GPL (http://www.gnu.org/licenses/gpl-2.0.html/)
19
 * @package      SmallWorld
20
 * @since        1.0
21
 * @author       Michael Albertsen (http://culex.dk) <[email protected]>
22
 */
23
24
class SwUploadHandler
25
{
26
    private $upload_dir;
27
    private $upload_url;
28
    private $thumbnails_dir;
29
    private $thumbnails_url;
30
    private $thumbnail_max_width;
31
    private $thumbnail_max_height;
32
    private $field_name;
33
34
    /**
35
     * SwUploadHandler constructor.
36
     * @param $options
37
     */
38
    public function __construct($options)
39
    {
40
        $this->upload_dir           = $options['upload_dir'];
41
        $this->upload_url           = $options['upload_url'];
42
        $this->thumbnails_dir       = $options['thumbnails_dir'];
43
        $this->thumbnails_url       = $options['thumbnails_url'];
44
        $this->thumbnail_max_width  = $options['thumbnail_max_width'];
45
        $this->thumbnail_max_height = $options['thumbnail_max_height'];
46
        $this->field_name           = $options['field_name'];
47
    }
48
49
    /**
50
     * @param $file_name
51
     * @return null|\stdClass
52
     */
53
    private function get_file_object($file_name)
54
    {
55
        $file_path = $this->upload_dir . $file_name;
56
        if (is_file($file_path) && '.' !== $file_name[0] && 'index.html' !== $file_name && 'Thumbs.db' !== $file_name) {
57
            $file            = new \stdClass();
58
            $file->name      = $file_name;
59
            $file->size      = filesize($file_path);
60
            $file->url       = $this->upload_url . rawurlencode($file->name);
61
            $file->thumbnail = is_file($this->thumbnails_dir . $file_name) ? $this->thumbnails_url . rawurlencode($file->name) : null;
62
            return $file;
63
        }
64
        return null;
65
    }
66
67
    /**
68
     * @param $file_name
69
     * @return bool
70
     */
71
    private function create_thumbnail($file_name)
72
    {
73
        $file_path      = $this->upload_dir . $file_name;
74
        $thumbnail_path = $this->thumbnails_dir . $file_name;
75
        list($img_width, $img_height) = @getimagesize($file_path);
76
        if (!$img_width || !$img_height) {
77
            return false;
78
        }
79
        $scale = min($this->thumbnail_max_width / $img_width, $this->thumbnail_max_height / $img_height);
80
        if ($scale > 1) {
81
            $scale = 1;
82
        }
83
        $thumbnail_width  = $img_width * $scale;
84
        $thumbnail_height = $img_height * $scale;
85
        $thumbnail_img    = @imagecreatetruecolor($thumbnail_width, $thumbnail_height);
86
        switch (strtolower(substr(strrchr($file_name, '.'), 1))) {
87
            case 'jpg':
88
            case 'jpeg':
89
                $src_img         = @imagecreatefromjpeg($file_path);
90
                $write_thumbnail = 'imagejpeg';
91
                break;
92
            case 'gif':
93
                $src_img         = @imagecreatefromgif($file_path);
94
                $write_thumbnail = 'imagegif';
95
                break;
96
            case 'png':
97
                $src_img         = @imagecreatefrompng($file_path);
98
                $write_thumbnail = 'imagepng';
99
                break;
100
            default:
101
                $src_img = $write_thumbnail = null;
102
        }
103
        $success = $src_img && @imagecopyresampled($thumbnail_img, $src_img, 0, 0, 0, 0, $thumbnail_width, $thumbnail_height, $img_width, $img_height)
104
                   && $write_thumbnail($thumbnail_img, $thumbnail_path);
105
        // Free up memory (imagedestroy does not delete files):
106
        @imagedestroy($src_img);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
107
        @imagedestroy($thumbnail_img);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
108
        return $success;
109
    }
110
111
    //function to return file extension from a path or file name
112
113
    /**
114
     * @param $path
115
     * @return mixed
116
     */
117
    public function getFileExtension($path)
118
    {
119
        $parts = pathinfo($path);
120
        return $parts['extension'];
121
    }
122
123
    /**
124
     * @param $uploaded_file
125
     * @param $name
126
     * @param $size
127
     * @param $type
128
     * @param $error
129
     * @return stdClass
0 ignored issues
show
Documentation introduced by
Should the return type not be \stdClass?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
130
     */
131
    private function handle_file_upload($uploaded_file, $name, $size, $type, $error)
132
    {
133
        global $xoopsUser;
134
        $file   = new \stdClass();
135
        $db     = new SwDatabase();
136
        $userid = $xoopsUser->getVar('uid');
137
138
        // Generate new name for file
139
        //$file->name = basename(stripslashes($name));
140
        $file->name = time() . mt_rand(0, 99999) . '.' . $this->getFileExtension($name);
141
        $file->size = (int)$size;
142
        $file->type = $type;
143
        $img        = XOOPS_URL . '/uploads/albums_smallworld/' . $userid . '/' . $file->name;
144
145
        // Save to database for later use
146
        $db->saveImage("'', '" . $userid . "', '" . $file->name . "', '" . addslashes($img) . "', '" . time() . "', ''");
147
148
        if (!$error && $file->name) {
149
            if ('.' === $file->name[0]) {
150
                $file->name = substr($file->name, 1);
151
            }
152
            $file_path   = $this->upload_dir . $file->name;
153
            $append_file = is_file($file_path) && $file->size > filesize($file_path);
154
            clearstatcache();
155 View Code Duplication
            if ($uploaded_file && is_uploaded_file($uploaded_file)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
156
                // multipart/formdata uploads (POST method uploads)
157
                if ($append_file) {
158
                    file_put_contents($file_path, fopen($uploaded_file, 'r'), FILE_APPEND);
159
                } else {
160
                    move_uploaded_file($uploaded_file, $file_path);
161
                }
162
            } else {
163
                // Non-multipart uploads (PUT method support)
164
                file_put_contents($file_path, fopen('php://input', 'r'), $append_file ? FILE_APPEND : 0);
165
            }
166
            $file_size = filesize($file_path);
167
            if ($file_size === $file->size) {
168
                $file->url       = $this->upload_url . rawurlencode($file->name);
169
                $file->thumbnail = $this->create_thumbnail($file->name) ? $this->thumbnails_url . rawurlencode($file->name) : null;
170
            }
171
            $file->size = $file_size;
172
        } else {
173
            $file->error = $error;
174
        }
175
        return $file;
176
    }
177
178
    public function get()
179
    {
180
        $file_name = isset($_REQUEST['file']) ? basename(stripslashes($_REQUEST['file'])) : null;
181
        if (null !== $file_name) {
182
            $info = $this->get_file_object($file_name);
183
        } else {
184
            $info = array_values(array_filter(array_map([$this, 'get_file_object'], scandir($this->upload_dir, SCANDIR_SORT_NONE))));
185
        }
186
        header('Cache-Control: no-cache, must-revalidate');
187
        header('Content-type: application/json');
188
        echo json_encode($info);
189
    }
190
191
    public function post()
192
    {
193
        $upload = isset($_FILES[$this->field_name]) ? $_FILES[$this->field_name] : [
194
            'tmp_name' => null,
195
            'name'     => null,
196
            'size'     => null,
197
            'type'     => null,
198
            'error'    => null,
199
        ];
200
        if (is_array($upload['tmp_name']) && count($upload['tmp_name']) > 1) {
201
            $info = [];
202
            foreach ($upload['tmp_name'] as $index => $value) {
203
                $info[] = $this->handle_file_upload($upload['tmp_name'][$index], $upload['name'][$index], $upload['size'][$index], $upload['type'][$index], $upload['error'][$index]);
204
            }
205
        } else {
206
            if (is_array($upload['tmp_name'])) {
207
                $upload = [
208
                    'tmp_name' => $upload['tmp_name'][0],
209
                    'name'     => $upload['name'][0],
210
                    'size'     => $upload['size'][0],
211
                    'type'     => $upload['type'][0],
212
                    'error'    => $upload['error'][0],
213
                ];
214
            }
215
            $info = $this->handle_file_upload(
216
                $upload['tmp_name'],
217
                isset($_SERVER['HTTP_X_FILE_NAME']) ? $_SERVER['HTTP_X_FILE_NAME'] : $upload['name'],
218
                isset($_SERVER['HTTP_X_FILE_SIZE']) ? $_SERVER['HTTP_X_FILE_SIZE'] : $upload['size'],
219
                isset($_SERVER['HTTP_X_FILE_TYPE']) ? $_SERVER['HTTP_X_FILE_TYPE'] : $upload['type'],
220
                $upload['error']
221
            );
222
        }
223
        if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 'XMLHttpRequest' === $_SERVER['HTTP_X_REQUESTED_WITH']) {
224
            header('Content-type: application/json');
225
        } else {
226
            header('Content-type: text/plain');
227
        }
228
        echo json_encode($info);
229
    }
230
231
    public function delete()
232
    {
233
        global $xoopsUser;
234
        $userid    = $xoopsUser->getVar('uid');
235
        $db        = new SwDatabase();
236
        $file_name = isset($_REQUEST['file']) ? basename(stripslashes($_REQUEST['file'])) : null;
237
        $file_path = $this->upload_dir . $file_name;
238
        $img       = XOOPS_URL . '/uploads/albums_smallworld/' . $userid . '/' . $file_name;
0 ignored issues
show
Unused Code introduced by
$img is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
239
240
        // Delete file based on user and filename
241
        $db->DeleteImage($userid, $file_name);
242
        $db->DeleteImage($userid, 'Thumbs.db');
243
        $thumbnail_path = $this->thumbnails_dir . $file_name;
244
        $success        = is_file($file_path) && '.' !== $file_name[0] && unlink($file_path);
245
        if ($success && is_file($thumbnail_path)) {
246
            unlink($thumbnail_path);
247
        }
248
        header('Content-type: application/json');
249
        echo json_encode($success);
250
    }
251
}
252