Completed
Push — master ( e7d60a...f2d2e3 )
by Michael
02:44
created

JUpload::__construct()   F

Complexity

Conditions 52
Paths > 20000

Size

Total Lines 172

Duplication

Lines 172
Ratio 100 %

Importance

Changes 0
Metric Value
cc 52
nc 4294967295
nop 2
dl 172
loc 172
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * This class manage upload, with use of the JUpload applet. It's both a sample to show how to use the applet, and
5
 * a class you can use directly into your own application.
6
 *
7
 * Recommandation: Don't update its code !
8
 *
9
 * By doing this, you'll be able to reuse directly any update coming from the JUpload project, instead of reporting your
10
 * modifications into any new version of this class. This guarantees you that your project can use the last version of
11
 * JUpload, without any code modification. We work so that the applet behavior remains unchanged, but from time to time,
12
 * a change can appear.
13
 *
14
 * Sample:
15
 * - See the index.php samples, in the same folder.
16
 *
17
 * Notes:
18
 * - maxChunkSize: this class use a default maxChunkSize of 500K (or less, depending on the script max size). This allows
19
 * upload of FILES OF ANY SIZE on quite all ISP hosting. If it's too big for you (the max upload size of your ISP is less
20
 * than 500K), or if you want no chunk at all, you can, of course, override this default value.
21
 *
22
 *
23
 *
24
 * Parameters:
25
 * - $appletparams contains a map for applet parameters: key is the applet parameter name. The value is the value to transmit
26
 *      to the applet. See the applet documentation for information on all applet parameters.
27
 * - $classparams contains the parameter specific for the JUpload class below. Here are the main class parameters:
28
 *      - demo_mode. Files are uploaded to the server, but not stored on its hard drive. That is: you can simulate the global
29
 *      behavior, but won't consume hard drive space. This mode is used on sourceforge web site.
30
 *
31
 *
32
 * Output generated for uploaded files:
33
 * - $files is an array of array. This can be managed by (a) the function given in the callbackAfterUploadManagement class
34
 *      parameter, or (b) within the page whose URL is given in the afterUploadURL applet parameter, or (c) you can Extend the
35
 *      class and redeclare defaultAfterUploadManagement() to your needs.
36
 *  See the defaultAfterUploadManagement() for a sample on howto manage this array.
37
 *
38
 *   This array contains:
39
 *     - One entry per file. Each entry is an array, that contains all files properties, stored as $key=>$value.
40
 *      The available keys are:
41
 *        - name: the filename, as it is now stored on the system.
42
 *        - size: the file size
43
 *        - path: the absolute path, where the file has been stored.
44
 *          - fullName: the canonical file name (i.e. including the absolute path)
45
 *        - md5sum: the md5sum of the file, if further control is needed.
46
 *          - mimetype: the calculated mime type of the file
47
 *        - If the formData applet parameter is used: all attributes (key and value) uploaded by the applet, are put here,
48
 *          repeated for each file.
49
 *
50
 *      Note: if you are using a callback function (i.e. callbackAfterUploadManagement) and you do not see a global 'object' you
51
 *                  are expecting then it might have been destroyed by PHP - c.f. http://bugs.php.net/bug.php?id=39693
52
 *
53
 */
54
55 View Code Duplication
class JUpload
0 ignored issues
show
Duplication introduced by
This class seems to be duplicated in 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...
56
{
57
58
    public $appletparams;
59
    public $classparams;
60
    public $files;
61
62
    public function __construct($appletparams = [], $classparams = [])
63
    {
64
        if ('array' !== gettype($classparams)) {
65
            $this->abort('Invalid type of parameter classparams: Expecting an array');
66
        }
67
        if ('array' !== gettype($appletparams)) {
68
            $this->abort('Invalid type of parameter appletparams: Expecting an array');
69
        }
70
71
        // set some defaults for the applet params
72
        if (!isset($appletparams['afterUploadURL'])) {
73
            $appletparams['afterUploadURL'] = $_SERVER['PHP_SELF'] . '?afterupload=1';
74
        }
75
        if (!isset($appletparams['name'])) {
76
            $appletparams['name'] = 'JUpload';
77
        }
78
        if (!isset($appletparams['archive'])) {
79
            $appletparams['archive'] = 'wjhk.jupload.jar';
80
        }
81
        if (!isset($appletparams['code'])) {
82
            $appletparams['code'] = 'wjhk.jupload2.JUploadApplet';
83
        }
84
        if (!isset($appletparams['debugLevel'])) {
85
            $appletparams['debugLevel'] = 0;
86
        }
87
        if (!isset($appletparams['httpUploadParameterType'])) {
88
            $appletparams['httpUploadParameterType'] = 'array';
89
        }
90
        if (!isset($appletparams['showLogWindow'])) {
91
            $appletparams['showLogWindow'] = ($appletparams['debugLevel'] > 0) ? 'true' : 'false';
92
        }
93
        if (!isset($appletparams['width'])) {
94
            $appletparams['width'] = 640;
95
        }
96
        if (!isset($appletparams['height'])) {
97
            $appletparams['height'] = ('true' === $appletparams['showLogWindow']) ? 500 : 300;
98
        }
99
        if (!isset($appletparams['mayscript'])) {
100
            $appletparams['mayscript'] = 'true';
101
        }
102
        if (!isset($appletparams['scriptable'])) {
103
            $appletparams['scriptable'] = 'false';
104
        }
105
        //if (!isset($appletparams['stringUploadSuccess']))
106
        $appletparams['stringUploadSuccess'] = 'SUCCESS';
107
        //if (!isset($appletparams['stringUploadError']))
108
        $appletparams['stringUploadError'] = 'ERROR: (.*)';
109
        $maxpost                           = $this->tobytes(ini_get('post_max_size'));
110
        $maxmem                            = $this->tobytes(ini_get('memory_limit'));
111
        $maxfs                             = $this->tobytes(ini_get('upload_max_filesize'));
112
        $obd                               = ini_get('open_basedir');
113
        if (!isset($appletparams['maxChunkSize'])) {
114
            $maxchunk                     = ($maxpost < $maxmem) ? $maxpost : $maxmem;
115
            $maxchunk                     = ($maxchunk < $maxfs) ? $maxchunk : $maxfs;
116
            $maxchunk                     /= 4;
117
            $optchunk                     = (500000 > $maxchunk) ? $maxchunk : 500000;
118
            $appletparams['maxChunkSize'] = $optchunk;
119
        }
120
        $appletparams['maxChunkSize'] = $this->tobytes($appletparams['maxChunkSize']);
121
        if (!isset($appletparams['maxFileSize'])) {
122
            $appletparams['maxFileSize'] = $maxfs;
123
        }
124
        $appletparams['maxFileSize'] = $this->tobytes($appletparams['maxFileSize']);
125
        if (isset($classparams['errormail'])) {
126
            $appletparams['urlToSendErrorTo'] = $_SERVER['PHP_SELF'] . '?errormail';
127
        }
128
129
        // Same for class parameters
130
        if (!isset($classparams['demo_mode'])) {
131
            $classparams['demo_mode'] = false;
132
        }
133
        if ($classparams['demo_mode']) {
134
            $classparams['create_destdir']  = false;
135
            $classparams['allow_subdirs']   = true;
136
            $classparams['allow_zerosized'] = true;
137
            $classparams['duplicate']       = 'overwrite';
138
        }
139
        if (!isset($classparams['debug_php']))                                            // set true to log some messages in PHP log
140
        {
141
            $classparams['debug_php'] = false;
142
        }
143
        if (!isset($this->classparams['allowed_mime_types']))                // array of allowed MIME type
144
        {
145
            $classparams['allowed_mime_types'] = 'all';
146
        }
147
        if (!isset($this->classparams['allowed_file_extensions']))    // array of allowed file extensions
148
        {
149
            $classparams['allowed_file_extensions'] = 'all';
150
        }
151
        if (!isset($classparams['verbose_errors']))                        // shouldn't display server info on a production site!
152
        {
153
            $classparams['verbose_errors'] = true;
154
        }
155
        if (!isset($classparams['session_regenerate'])) {
156
            $classparams['session_regenerate'] = false;
157
        }
158
        if (!isset($classparams['create_destdir'])) {
159
            $classparams['create_destdir'] = true;
160
        }
161
        if (!isset($classparams['allow_subdirs'])) {
162
            $classparams['allow_subdirs'] = false;
163
        }
164
        if (!isset($classparams['spaces_in_subdirs'])) {
165
            $classparams['spaces_in_subdirs'] = false;
166
        }
167
        if (!isset($classparams['allow_zerosized'])) {
168
            $classparams['allow_zerosized'] = false;
169
        }
170
        if (!isset($classparams['duplicate'])) {
171
            $classparams['duplicate'] = 'rename';
172
        }
173
        if (!isset($classparams['dirperm'])) {
174
            $classparams['dirperm'] = 0755;
175
        }
176
        if (!isset($classparams['fileperm'])) {
177
            $classparams['fileperm'] = 0644;
178
        }
179
        if (!isset($classparams['destdir'])) {
180
            if ('' != $obd) {
181
                $classparams['destdir'] = $obd;
182
            } else {
183
                $classparams['destdir'] = '/var/tmp/jupload_test';
184
            }
185
        } else {
186
            $classparams['destdir'] = str_replace('~', ' ', $classparams['destdir']);
187
        }
188
        if ($classparams['create_destdir']) {
189
            $_umask = umask(0);    // override the system mask
190
            @mkdir($classparams['destdir'], $classparams['dirperm']);
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...
191
            umask($_umask);
192
        }
193
        if (!is_dir($classparams['destdir']) && is_writable($classparams['destdir'])) {
194
            $this->abort('Destination dir not accessible');
195
        }
196
        if (!isset($classparams['tmp_prefix'])) {
197
            $classparams['tmp_prefix'] = 'jutmp.';
198
        }
199
        if (!isset($classparams['var_prefix'])) {
200
            $classparams['var_prefix'] = 'juvar.';
201
        }
202
        if (!isset($classparams['jscript_wrapper'])) {
203
            $classparams['jscript_wrapper'] = 'JUploadSetProperty';
204
        }
205
        if (!isset($classparams['tag_jscript'])) {
206
            $classparams['tag_jscript'] = '<!--JUPLOAD_JSCRIPT-->';
207
        }
208
        if (!isset($classparams['tag_applet'])) {
209
            $classparams['tag_applet'] = '<!--JUPLOAD_APPLET-->';
210
        }
211
        if (!isset($classparams['tag_flist'])) {
212
            $classparams['tag_flist'] = '<!--JUPLOAD_FILES-->';
213
        }
214
        if (!isset($classparams['http_flist_start'])) {
215
            $classparams['http_flist_start'] = "<table border='1'><TR><TH>Filename</TH><TH>file size</TH><TH>Relative path</TH><TH>Full name</TH><TH>md5sum</TH><TH>Specific parameters</TH></TR>";
216
        }
217
        if (!isset($classparams['http_flist_end'])) {
218
            $classparams['http_flist_end'] = "</table>\n";
219
        }
220
        if (!isset($classparams['http_flist_file_before'])) {
221
            $classparams['http_flist_file_before'] = '<tr><td>';
222
        }
223
        if (!isset($classparams['http_flist_file_between'])) {
224
            $classparams['http_flist_file_between'] = '</td><td>';
225
        }
226
        if (!isset($classparams['http_flist_file_after'])) {
227
            $classparams['http_flist_file_after'] = "</td></tr>\n";
228
        }
229
230
        $this->appletparams = $appletparams;
231
        $this->classparams  = $classparams;
232
        $this->page_start();
233
    }
234
235
    /**
236
     * Return an array of uploaded files * The array contains: name, size, tmp_name, error,
237
     * relativePath, md5sum, mimetype, fullName, path
238
     */
239
    public function uploadedfiles()
240
    {
241
        return $this->files;
242
    }
243
244
    /**
245
     * Log a message on the current output, as a HTML comment.
246
     * @param      $function
247
     * @param      $msg
248
     * @param bool $htmlComment
249
     */
250
    protected function logDebug($function, $msg, $htmlComment = true)
251
    {
252
        $output = "[DEBUG] [$function] $msg";
253
        if ($htmlComment) {
254
            echo("<!-- $output -->\r\n");
255
        } else {
256
            echo("$output\r\n");
257
        }
258
    }
259
260
    /**
261
     * Log a message to the PHP log.
262
     * Declared "protected" so it may be Extended if you require customised logging (e.g. particular log file location).
263
     * @param $function
264
     * @param $msg
265
     */
266
    protected function logPHPDebug($function, $msg)
267
    {
268
        if (true === $this->classparams['debug_php']) {
269
            $output = "[DEBUG] [$function] " . $this->arrayexpand($msg);
270
            error_log($output);
271
        }
272
    }
273
274
    private function arrayexpand($array)
275
    {
276
        $output = '';
277
        if (is_array($array)) {
278
            foreach ($array as $key => $value) {
279
                $output .= "\n " . $key . ' => ' . $this->arrayexpand($value);
280
            }
281
        } else {
282
            $output .= $array;
283
        }
284
285
        return $output;
286
    }
287
288
    /**
289
     * Convert a value ending in 'G','M' or 'K' to bytes
290
     * @param $val
291
     * @return int|string
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|double|string?

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...
292
     */
293
    private function tobytes($val)
294
    {
295
        $val  = trim($val);
296
        $last = fix_strtolower($val{strlen($val) - 1});
297
        switch ($last) {
298
            case 'g':
299
                $val *= 1024;
300
            case 'm':
301
                $val *= 1024;
302
            case 'k':
303
                $val *= 1024;
304
        }
305
306
        return $val;
307
    }
308
309
    /**
310
     * Build a string, containing a javascript wrapper function
311
     * for setting applet properties via JavaScript. This is necessary,
312
     * because we use the "modern" method of including the applet (using
313
     * <object> resp. <embed> tags) in order to trigger automatic JRE downloading.
314
     * Therefore, in Netscape-like browsers, the applet is accessible via
315
     * the document.embeds[] array while in others, it is accessible via the
316
     * document.applets[] array.
317
     *
318
     * @return A string, containing the necessary wrapper function (named JUploadSetProperty)
0 ignored issues
show
Documentation introduced by
Should the return type not be string?

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...
319
     */
320
    private function str_jsinit()
321
    {
322
        $N    = "\n";
323
        $name = $this->appletparams['name'];
324
        $ret  = '<script type="text/javascript">' . $N;
325
        $ret  .= '<!--' . $N;
326
        $ret  .= 'function ' . $this->classparams['jscript_wrapper'] . '(name, value) {' . $N;
327
        $ret  .= '  document.applets["' . $name . '"] == null || document.applets["' . $name . '"].setProperty(name,value);' . $N;
328
        $ret  .= '  document.embeds["' . $name . '"] == null || document.embeds["' . $name . '"].setProperty(name,value);' . $N;
329
        $ret  .= '}' . $N;
330
        $ret  .= '//-->' . $N;
331
        $ret  .= '</script>';
332
333
        return $ret;
334
    }
335
336
    /**
337
     * Build a string, containing the applet tag with all parameters.
338
     *
339
     * @return A string, containing the applet tag
0 ignored issues
show
Documentation introduced by
Should the return type not be string?

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...
340
     */
341
    private function str_applet()
342
    {
343
        $N      = "\n";
344
        $params = $this->appletparams;
345
        // return the actual applet tag
346
        $ret = '<object classid = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"' . $N;
347
        $ret .= '  codebase = "http://java.sun.com/update/1.5.0/jinstall-1_5-windows-i586.cab#Version=5,0,0,3"' . $N;
348
        $ret .= '  width = "' . $params['width'] . '"' . $N;
349
        $ret .= '  height = "' . $params['height'] . '"' . $N;
350
        $ret .= '  name = "' . $params['name'] . '">' . $N;
351
        foreach ($params as $key => $val) {
352
            if ('width' !== $key && 'height' !== $key) {
353
                $ret .= '  <param name = "' . $key . '" value = "' . $val . '" />' . $N;
354
            }
355
        }
356
        $ret .= '  <comment>' . $N;
357
        $ret .= '    <embed' . $N;
358
        $ret .= '      type = "application/x-java-applet;version=1.5"' . $N;
359
        foreach ($params as $key => $val) {
360
            $ret .= '      ' . $key . ' = "' . $val . '"' . $N;
361
        }
362
        $ret .= '      pluginspage = "http://java.sun.com/products/plugin/index.html#download">' . $N;
363
        $ret .= '      <noembed>' . $N;
364
        $ret .= '        Java 1.5 or higher plugin required.' . $N;
365
        $ret .= '      </noembed>' . $N;
366
        $ret .= '    </embed>' . $N;
367
        $ret .= '  </comment>' . $N;
368
        $ret .= '</object>';
369
370
        return $ret;
371
    }
372
373
    private function abort($msg = '')
374
    {
375
        $this->cleanup();
376
        if ('' != $msg) {
377
            die(str_replace('(.*)', $msg, $this->appletparams['stringUploadError']) . "\n");
378
        }
379
        exit;
380
    }
381
382
    private function warning($msg = '')
383
    {
384
        $this->cleanup();
385
        if ('' != $msg) {
386
            echo('WARNING: ' . $msg . "\n");
387
        }
388
        echo $this->appletparams['stringUploadSuccess'] . "\n";
389
        exit;
390
    }
391
392
    private function cleanup()
393
    {
394
        // remove all uploaded files of *this* request
395
        if (isset($_FILES)) {
396
            foreach ($_FILES as $key => $val) {
397
                @unlink($val['tmp_name']);
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...
398
            }
399
        }
400
        // remove accumulated file, if any.
401
        @unlink($this->classparams['destdir'] . '/' . $this->classparams['tmp_prefix'] . session_id());
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...
402
        @unlink($this->classparams['destdir'] . '/' . $this->classparams['tmp_prefix'] . 'tmp' . session_id());
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...
403
        // reset session var
404
        $_SESSION[$this->classparams['var_prefix'] . 'size'] = 0;
405
406
        return;
407
    }
408
409
    private function mkdirp($path)
410
    {
411
        // create subdir (hierary) below destdir;
412
        $dirs = explode('/', $path);
413
        $path = $this->classparams['destdir'];
414
        foreach ($dirs as $dir) {
415
            $path .= '/' . $dir;
416
            if (!file_exists($path)) {  // @ does NOT always supress the error!
417
                $_umask = umask(0);    // override the system mask
418
                @mkdir($path, $this->classparams['dirperm']);
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...
419
                umask($_umask);
420
            }
421
        }
422
        if (!is_dir($path) && is_writable($path)) {
423
            $this->abort('Destination dir not accessible');
424
        }
425
    }
426
427
    /**
428
     * This method:
429
     * - Replaces some potentially dangerous characters by '_' (in the given name an relative path)
430
     * - Checks if a files of the same name already exists.
431
     *      - If no: no problem.
432
     *      - If yes, and the duplicate class param is set to rename, the file is renamed.
433
     *      - If yes, and the duplicate class param is set to overwrite, the file is not renamed. The existing one will be erased.
434
     *      - If yes, and the duplicate class param is set to reject, an error is thrown.
435
     * @param $name
436
     * @param $subdir
437
     * @return string
438
     */
439
    private function dstfinal(&$name, &$subdir)
440
    {
441
        $name = preg_replace('![`$\\\\/|]!', '_', $name);
442
        if ($this->classparams['allow_subdirs'] && ('' != $subdir)) {
443
            $subdir = trim(preg_replace('!\\\\!', '/', $subdir), '/');
444
            $subdir = preg_replace('![`$|]!', '_', $subdir);
445
            if (!$this->classparams['spaces_in_subdirs']) {
446
                $subdir = str_replace(' ', '_', $subdir);
447
            }
448
            // recursively create subdir
449
            if (!$this->classparams['demo_mode']) {
450
                $this->mkdirp($subdir);
451
            }
452
            // append a slash
453
            $subdir .= '/';
454
        } else {
455
            $subdir = '';
456
        }
457
        $ret = $this->classparams['destdir'] . '/' . $subdir . $name;
458
        if (file_exists($ret)) {
459
            if ('overwrite' === $this->classparams['duplicate']) {
460
                return $ret;
461
            }
462
            if ('reject' === $this->classparams['duplicate']) {
463
                $this->abort('A file with the same name already exists');
464
            }
465
            if ('warning' === $this->classparams['duplicate']) {
466
                $this->warning("File $name already exists - rejected");
467
            }
468
            if ('rename' === $this->classparams['duplicate']) {
469
                $cnt = 1;
470
                $dir = $this->classparams['destdir'] . '/' . $subdir;
471
                $ext = strrchr($name, '.');
472
                if ($ext) {
473
                    $nameWithoutExtension = substr($name, 0, strlen($name) - strlen($ext));
474
                } else {
475
                    $ext                  = '';
476
                    $nameWithoutExtension = $name;
477
                }
478
479
                $rtry = $dir . $nameWithoutExtension . '_' . $cnt . $ext;
480
                while (file_exists($rtry)) {
481
                    ++$cnt;
482
                    $rtry = $dir . $nameWithoutExtension . '._' . $cnt . $ext;
483
                }
484
                //We store the result name in the byReference name parameter.
485
                $name = $nameWithoutExtension . '_' . $cnt . $ext;
486
                $ret  = $rtry;
487
            }
488
        }
489
490
        return $ret;
491
    }
492
493
    /**
494
     * Example function to process the files uploaded.  This one simply displays the files' data.
495
     *
496
     */
497
    public function defaultAfterUploadManagement()
498
    {
499
        $flist = '[defaultAfterUploadManagement] Nb uploaded files is: ' . count($this->files);
0 ignored issues
show
Unused Code introduced by
$flist 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...
500
        $flist = $this->classparams['http_flist_start'];
501
        foreach ($this->files as $f) {
502
            //$f is an array, that contains all info about the uploaded file.
503
            $this->logDebug('defaultAfterUploadManagement', "  Reading file ${f['name']}");
504
            $flist .= $this->classparams['http_flist_file_before'];
505
            $flist .= $f['name'];
506
            $flist .= $this->classparams['http_flist_file_between'];
507
            $flist .= $f['size'];
508
            $flist .= $this->classparams['http_flist_file_between'];
509
            $flist .= $f['relativePath'];
510
            $flist .= $this->classparams['http_flist_file_between'];
511
            $flist .= $f['fullName'];
512
            $flist .= $this->classparams['http_flist_file_between'];
513
            $flist .= $f['md5sum'];
514
            $addBR = false;
515
            foreach ($f as $key => $value) {
516
                //If it's a specific key, let's display it:
517
                if ('name' !== $key && 'size' !== $key && 'relativePath' !== $key && 'fullName' !== $key && 'md5sum' !== $key) {
518
                    if ($addBR) {
519
                        $flist .= '<br>';
520
                    } else {
521
                        // First line. We must add a new 'official' list separator.
522
                        $flist .= $this->classparams['http_flist_file_between'];
523
                        $addBR = true;
524
                    }
525
                    $flist .= "$key => $value";
526
                }
527
            }
528
            $flist .= $this->classparams['http_flist_file_after'];
529
        }
530
        $flist .= $this->classparams['http_flist_end'];
531
532
        return $flist;
533
    }
534
535
    /**
536
     * Generation of the applet tag, and necessary things around (js content). Insertion of this into the content of the
537
     * page.
538
     * See the tag_jscript and tag_applet class parameters.
539
     * @param $str
540
     * @return string|string[]|null
541
     */
542
    private function generateAppletTag($str)
543
    {
544
        $this->logDebug('generateAppletTag', 'Entering function');
545
        $str = preg_replace('/' . $this->classparams['tag_jscript'] . '/', $this->str_jsinit(), $str);
546
547
        return preg_replace('/' . $this->classparams['tag_applet'] . '/', $this->str_applet(), $str);
548
    }
549
550
    /**
551
     * This function is called when constructing the page, when we're not reveiving uploaded files. It 'just' construct
552
     * the applet tag, by calling the relevant function.
553
     *
554
     * This *must* be public, because it is called from PHP's output buffering
555
     * @param $str
556
     * @return string|string[]|null
557
     */
558
    public function interceptBeforeUpload($str)
559
    {
560
        $this->logDebug('interceptBeforeUpload', 'Entering function');
561
562
        return $this->generateAppletTag($str);
563
    }
564
565
    /**
566
     * This function displays the uploaded files description in the current page (see tag_flist class parameter)
567
     *
568
     * This *must* be public, because it is called from PHP's output buffering.
569
     * @param $str
570
     * @return string|string[]|null
571
     */
572
    public function interceptAfterUpload($str)
573
    {
574
        $this->logDebug('interceptAfterUpload', 'Entering function');
575
        $this->logPHPDebug('interceptAfterUpload', $this->files);
576
577
        if (count($this->files) > 0) {
578
            if (isset($this->classparams['callbackAfterUploadManagement'])) {
579
                $this->logDebug('interceptAfterUpload', 'Before call of ' . $this->classparams['callbackAfterUploadManagement']);
580
                $strForFListContent = call_user_func($this->classparams['callbackAfterUploadManagement'], $this, $this->files);
581
            } else {
582
                $strForFListContent = $this->defaultAfterUploadManagement();
583
            }
584
            $str = preg_replace('/' . $this->classparams['tag_flist'] . '/', $strForFListContent, $str);
585
        }
586
587
        return $this->generateAppletTag($str);
588
    }
589
590
    /**
591
     * This method manages the receiving of the debug log, when an error occurs.
592
     */
593
    private function receive_debug_log()
594
    {
595
        // handle error report
596
        if (isset($_POST['description']) && isset($_POST['log'])) {
597
            $msg = $_POST['log'];
598
            mail($this->classparams['errormail'], $_POST['description'], $msg);
599
        } else {
600
            if (isset($_SERVER['SERVER_ADMIN'])) {
601
                mail(
602
                    $_SERVER['SERVER_ADMIN'],
603
                    'Empty jupload error log',
604
                    'An empty log has just been posted.'
605
                );
606
            }
607
            $this->logPHPDebug('receive_debug_log', 'Empty error log received');
608
        }
609
        exit;
610
    }
611
612
    /**
613
     * This method is the heart of the system. It manage the files sent by the applet, check the incoming parameters (md5sum) and
614
     * reconstruct the files sent in chunk mode.
615
     *
616
     * The result is stored in the $files array, and can then be managed by the function given in the callbackAfterUploadManagement
617
     * class parameter, or within the page whose URL is given in the afterUploadURL applet parameter.
618
     * Or you can Extend the class and redeclare defaultAfterUploadManagement() to your needs.
619
     */
620
    private function receive_uploaded_files()
621
    {
622
        $this->logDebug('receive_uploaded_files', 'Entering POST management');
623
624
        if ('' == session_id()) {
625
            session_start();
626
        }
627
        // we check for the session *after* handling possible error log
628
        // because an error could have happened because the session-id is missing.
629
        if (!isset($_SESSION[$this->classparams['var_prefix'] . 'size'])) {
630
            $this->abort('Invalid session (in afterupload, POST, check of size)');
631
        }
632
        if (!isset($_SESSION[$this->classparams['var_prefix'] . 'files'])) {
633
            $this->abort('Invalid session (in afterupload, POST, check of files)');
634
        }
635
        $this->files = $_SESSION[$this->classparams['var_prefix'] . 'files'];
636
        if (!is_array($this->files)) {
637
            $this->abort('Invalid session (in afterupload, POST, is_array(files))');
638
        }
639
        if ('true' === $this->appletparams['sendMD5Sum'] && !isset($_POST['md5sum'])) {
640
            $this->abort('Required POST variable md5sum is missing');
641
        }
642
        $cnt = 0;
643
        foreach ($_FILES as $key => $value) {
644
            //Let's read the $_FILES data
645
            if (isset($files_data)) {
646
                unset($files_data);
647
            }
648
            $jupart    = (isset($_POST['jupart'])) ? (int)$_POST['jupart'] : 0;
649
            $jufinal   = (isset($_POST['jufinal'])) ? (int)$_POST['jufinal'] : 1;
650
            $relpaths  = (isset($_POST['relpathinfo'])) ? $_POST['relpathinfo'] : null;
651
            $md5sums   = (isset($_POST['md5sum'])) ? $_POST['md5sum'] : null;
652
            $mimetypes = (isset($_POST['mimetype'])) ? $_POST['mimetype'] : null;
653
            //$relpaths = (isset($_POST["relpathinfo$cnt"])) ? $_POST["relpathinfo$cnt"] : null;
654
            //$md5sums = (isset($_POST["md5sum$cnt"])) ? $_POST["md5sum$cnt"] : null;
655
656
            if ('string' === gettype($relpaths)) {
657
                $relpaths = [$relpaths];
658
            }
659
            if ('string' === gettype($md5sums)) {
660
                $md5sums = [$md5sums];
661
            }
662
            if ('true' === $this->appletparams['sendMD5Sum'] && !is_array($md5sums)) {
663
                $this->abort('Expecting an array of MD5 checksums');
664
            }
665
            if (!is_array($relpaths)) {
666
                $this->abort('Expecting an array of relative paths');
667
            }
668
            if (!is_array($mimetypes)) {
669
                $this->abort('Expecting an array of MIME types');
670
            }
671
            // Check the MIME type (note: this is easily forged!)
672
            if (isset($this->classparams['allowed_mime_types']) && is_array($this->classparams['allowed_mime_types'])) {
673
                if (!in_array($mimetypes[$cnt], $this->classparams['allowed_mime_types'])) {
674
                    $this->abort('MIME type ' . $mimetypes[$cnt] . ' not allowed');
675
                }
676
            }
677
            if (isset($this->classparams['allowed_file_extensions']) && is_array($this->classparams['allowed_file_extensions'])) {
678
                $fileExtension = substr(strrchr($value['name'][$cnt], '.'), 1);
679
                if (!in_array($fileExtension, $this->classparams['allowed_file_extensions'])) {
680
                    $this->abort('File extension ' . $fileExtension . ' not allowed');
681
                }
682
            }
683
684
            $dstdir  = $this->classparams['destdir'];
685
            $dstname = $dstdir . '/' . $this->classparams['tmp_prefix'] . session_id();
686
            $tmpname = $dstdir . '/' . $this->classparams['tmp_prefix'] . 'tmp' . session_id();
687
688
            // Controls are now done. Let's store the current uploaded files properties in an array, for future use.
689
            $files_data['name']         = $value['name'][$cnt];
0 ignored issues
show
Bug introduced by
The variable $files_data does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
690
            $files_data['size']         = 'not calculated yet';
691
            $files_data['tmp_name']     = $value['tmp_name'][$cnt];
692
            $files_data['error']        = $value['error'][$cnt];
693
            $files_data['relativePath'] = $relpaths[$cnt];
694
            $files_data['md5sum']       = $md5sums[$cnt];
695
            $files_data['mimetype']     = $mimetypes[$cnt];
696
697
            if (!move_uploaded_file($files_data['tmp_name'], $tmpname)) {
698
                if ($classparams['verbose_errors']) {
0 ignored issues
show
Bug introduced by
The variable $classparams does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
699
                    $this->abort("Unable to move uploaded file (from ${files_data['tmp_name']} to $tmpname)");
700
                } else {
701
                    trigger_error("Unable to move uploaded file (from ${files_data['tmp_name']} to $tmpname)", E_USER_WARNING);
702
                    $this->abort('Unable to move uploaded file');
703
                }
704
            }
705
706
            // In demo mode, no file storing is done. We just delete the newly uploaded file.
707
            if ($this->classparams['demo_mode']) {
708
                if ($jufinal || (!$jupart)) {
709
                    if ($jupart) {
710
                        $files_data['size'] = ($jupart - 1) * $this->appletparams['maxChunkSize'] + filesize($tmpname);
711
                    } else {
712
                        $files_data['size'] = filesize($tmpname);
713
                    }
714
                    $files_data['fullName'] = 'Demo mode<BR>No file storing';
715
                    array_push($this->files, $files_data);
716
                }
717
                unlink($tmpname);
718
                ++$cnt;
719
                continue;
720
            }
721
            //If we get here, the upload is a real one (no demo)
722
            if ($jupart) {
723
                // got a chunk of a multi-part upload
724
                $len                                                 = filesize($tmpname);
725
                $_SESSION[$this->classparams['var_prefix'] . 'size'] += $len;
726
                if ($len > 0) {
727
                    $src = fopen($tmpname, 'rb');
728
                    $dst = fopen($dstname, (1 == $jupart) ? 'wb' : 'ab');
729
                    while ($len > 0) {
730
                        $rlen = ($len > 8192) ? 8192 : $len;
731
                        $buf  = fread($src, $rlen);
732
                        if (!$buf) {
733
                            fclose($src);
734
                            fclose($dst);
735
                            unlink($dstname);
736
                            $this->abort('read IO error');
737
                        }
738
                        if (!fwrite($dst, $buf, $rlen)) {
739
                            fclose($src);
740
                            fclose($dst);
741
                            unlink($dstname);
742
                            $this->abort('write IO error');
743
                        }
744
                        $len -= $rlen;
745
                    }
746
                    fclose($src);
747
                    fclose($dst);
748
                    unlink($tmpname);
749
                }
750
                if ($jufinal) {
751
                    // This is the last chunk. Check total lenght and
752
                    // rename it to it's final name.
753
                    $dlen = filesize($dstname);
754
                    if ($dlen != $_SESSION[$this->classparams['var_prefix'] . 'size']) {
755
                        $this->abort('file size mismatch');
756
                    }
757
                    if ('true' === $this->appletparams['sendMD5Sum']) {
758
                        if ($md5sums[$cnt] != md5_file($dstname)) {
759
                            $this->abort('MD5 checksum mismatch');
760
                        }
761
                    }
762
                    // remove zero sized files
763
                    if (($dlen > 0) || $this->classparams['allow_zerosized']) {
764
                        $dstfinal = $this->dstfinal($files_data['name'], $files_data['relativePath']);
765
                        if (!rename($dstname, $dstfinal)) {
766
                            $this->abort('rename IO error');
767
                        }
768
                        $_umask = umask(0);    // override the system mask
769
                        if (!chmod($dstfinal, $this->classparams['fileperm'])) {
770
                            $this->abort('chmod IO error');
771
                        }
772
                        umask($_umask);
773
                        $files_data['size']     = filesize($dstfinal);
774
                        $files_data['fullName'] = $dstfinal;
775
                        $files_data['path']     = fix_dirname($dstfinal);
776
                        array_push($this->files, $files_data);
777
                    } else {
778
                        unlink($dstname);
779
                    }
780
                    // reset session var
781
                    $_SESSION[$this->classparams['var_prefix'] . 'size'] = 0;
782
                }
783
            } else {
784
                // Got a single file upload. Trivial.
785
                if ('true' === $this->appletparams['sendMD5Sum']) {
786
                    if ($md5sums[$cnt] != md5_file($tmpname)) {
787
                        $this->abort('MD5 checksum mismatch');
788
                    }
789
                }
790
                $dstfinal = $this->dstfinal($files_data['name'], $files_data['relativePath']);
791
                if (!rename($tmpname, $dstfinal)) {
792
                    $this->abort('rename IO error');
793
                }
794
                $_umask = umask(0);    // override the system mask
795
                if (!chmod($dstfinal, $this->classparams['fileperm'])) {
796
                    $this->abort('chmod IO error');
797
                }
798
                umask($_umask);
799
                $files_data['size']     = filesize($dstfinal);
800
                $files_data['fullName'] = $dstfinal;
801
                $files_data['path']     = fix_dirname($dstfinal);
802
                array_push($this->files, $files_data);
803
            }
804
            ++$cnt;
805
        }
806
807
        echo $this->appletparams['stringUploadSuccess'] . "\n";
808
        $_SESSION[$this->classparams['var_prefix'] . 'files'] = $this->files;
809
        session_write_close();
810
        exit;
811
    }
812
813
    /**
814
     *
815
     *
816
     */
817
    private function page_start()
818
    {
819
        $this->logDebug('page_start', 'Entering function');
820
821
        // If the applet checks for the serverProtocol, it issues a HEAD request
822
        // -> Simply return an empty doc.
823
        if ('HEAD' === $_SERVER['REQUEST_METHOD']) {
824
            // Nothing to do
825
826
        } elseif ('GET' === $_SERVER['REQUEST_METHOD']) {
827
            // A GET request means: return upload page
828
            $this->logDebug('page_start', 'Entering GET management');
829
830
            if ('' == session_id()) {
831
                session_start();
832
            }
833
            if (isset($_GET['afterupload'])) {
834
                $this->logDebug('page_start', 'afterupload is set');
835
                if (!isset($_SESSION[$this->classparams['var_prefix'] . 'files'])) {
836
                    $this->abort('Invalid session (in afterupload, GET, check of $_SESSION): files array is not set');
837
                }
838
                $this->files = $_SESSION[$this->classparams['var_prefix'] . 'files'];
839
                if (!is_array($this->files)) {
840
                    $this->abort('Invalid session (in afterupload, GET, check of is_array(files)): files is not an array');
841
                }
842
                // clear session data ready for new upload
843
                $_SESSION[$this->classparams['var_prefix'] . 'files'] = [];
844
845
                // start intercepting the content of the calling page, to display the upload result.
846
                ob_start([& $this, 'interceptAfterUpload']);
847
            } else {
848
                $this->logDebug('page_start', 'afterupload is not set');
849
                if ($this->classparams['session_regenerate']) {
850
                    session_regenerate_id(true);
851
                }
852
                $this->files                                          = [];
853
                $_SESSION[$this->classparams['var_prefix'] . 'size']  = 0;
854
                $_SESSION[$this->classparams['var_prefix'] . 'files'] = $this->files;
855
                // start intercepting the content of the calling page, to display the applet tag.
856
                ob_start([& $this, 'interceptBeforeUpload']);
857
            }
858
        } elseif ('POST' === $_SERVER['REQUEST_METHOD']) {
859
            // If we got a POST request, this is the real work.
860
            if (isset($_GET['errormail'])) {
861
                //Hum, an error occurs on server side. Let's manage the debug log, that we just received.
862
                $this->receive_debug_log();
863
            } else {
864
                $this->receive_uploaded_files();
865
            }
866
        }
867
    }
868
}
869
870
// PHP end tag omitted intentionally!!
871