phpBB
Statistics
| Revision:

root / trunk / phpBB / includes / functions_upload.php

History | View | Annotate | Download (24.8 kB)

1
<?php
2
/**
3
*
4
* @package phpBB3
5
* @copyright (c) 2005 phpBB Group
6
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
7
*
8
*/
9
10
/**
11
* @ignore
12
*/
13
if (!defined('IN_PHPBB'))
14
{
15
        exit;
16
}
17
18
/**
19
* Responsible for holding all file relevant information, as well as doing file-specific operations.
20
* The {@link fileupload fileupload class} can be used to upload several files, each of them being this object to operate further on.
21
* @package phpBB3
22
*/
23
class filespec
24
{
25
        var $filename = '';
26
        var $realname = '';
27
        var $uploadname = '';
28
        var $mimetype = '';
29
        var $extension = '';
30
        var $filesize = 0;
31
        var $width = 0;
32
        var $height = 0;
33
        var $image_info = array();
34
35
        var $destination_file = '';
36
        var $destination_path = '';
37
38
        var $file_moved = false;
39
        var $init_error = false;
40
        var $local = false;
41
42
        var $error = array();
43
44
        var $upload = '';
45
46
        /**
47
        * File Class
48
        * @access private
49
        */
50
        function filespec($upload_ary, $upload_namespace)
51
        {
52
                if (!isset($upload_ary))
53
                {
54
                        $this->init_error = true;
55
                        return;
56
                }
57
58
                $this->filename = $upload_ary['tmp_name'];
59
                $this->filesize = $upload_ary['size'];
60
                $name = (STRIP) ? stripslashes($upload_ary['name']) : $upload_ary['name'];
61
                $name = trim(utf8_htmlspecialchars(utf8_basename($name)));
62
                $this->realname = $this->uploadname = $name;
63
                $this->mimetype = $upload_ary['type'];
64
65
                // Opera adds the name to the mime type
66
                $this->mimetype        = (strpos($this->mimetype, '; name') !== false) ? str_replace(strstr($this->mimetype, '; name'), '', $this->mimetype) : $this->mimetype;
67
68
                if (!$this->mimetype)
69
                {
70
                        $this->mimetype = 'application/octetstream';
71
                }
72
73
                $this->extension = strtolower($this->get_extension($this->realname));
74
75
                // Try to get real filesize from temporary folder (not always working) ;)
76
                $this->filesize = (@filesize($this->filename)) ? @filesize($this->filename) : $this->filesize;
77
78
                $this->width = $this->height = 0;
79
                $this->file_moved = false;
80
81
                $this->local = (isset($upload_ary['local_mode'])) ? true : false;
82
                $this->upload = $upload_namespace;
83
        }
84
85
        /**
86
        * Cleans destination filename
87
        *
88
        * @param real|unique|unique_ext $mode real creates a realname, filtering some characters, lowering every character. Unique creates an unique filename
89
        * @param string $prefix Prefix applied to filename
90
        * @access public
91
        */
92
        function clean_filename($mode = 'unique', $prefix = '', $user_id = '')
93
        {
94
                if ($this->init_error)
95
                {
96
                        return;
97
                }
98
99
                switch ($mode)
100
                {
101
                        case 'real':
102
                                // Remove every extension from filename (to not let the mime bug being exposed)
103
                                if (strpos($this->realname, '.') !== false)
104
                                {
105
                                        $this->realname = substr($this->realname, 0, strpos($this->realname, '.'));
106
                                }
107
108
                                // Replace any chars which may cause us problems with _
109
                                $bad_chars = array("'", "\\", ' ', '/', ':', '*', '?', '"', '<', '>', '|');
110
111
                                $this->realname = rawurlencode(str_replace($bad_chars, '_', strtolower($this->realname)));
112
                                $this->realname = preg_replace("/%(\w{2})/", '_', $this->realname);
113
114
                                $this->realname = $prefix . $this->realname . '.' . $this->extension;
115
                        break;
116
117
                        case 'unique':
118
                                $this->realname = $prefix . md5(unique_id());
119
                        break;
120
121
                        case 'avatar':
122
                                $this->extension = strtolower($this->extension);
123
                                $this->realname = $prefix . $user_id . '.' . $this->extension;
124
125
                        break;
126
127
                        case 'unique_ext':
128
                        default:
129
                                $this->realname = $prefix . md5(unique_id()) . '.' . $this->extension;
130
                        break;
131
                }
132
        }
133
134
        /**
135
        * Get property from file object
136
        */
137
        function get($property)
138
        {
139
                if ($this->init_error || !isset($this->$property))
140
                {
141
                        return false;
142
                }
143
144
                return $this->$property;
145
        }
146
147
        /**
148
        * Check if file is an image (mimetype)
149
        *
150
        * @return true if it is an image, false if not
151
        */
152
        function is_image()
153
        {
154
                return (strpos($this->mimetype, 'image/') !== false) ? true : false;
155
        }
156
157
        /**
158
        * Check if the file got correctly uploaded
159
        *
160
        * @return true if it is a valid upload, false if not
161
        */
162
        function is_uploaded()
163
        {
164
                if (!$this->local && !is_uploaded_file($this->filename))
165
                {
166
                        return false;
167
                }
168
169
                if ($this->local && !file_exists($this->filename))
170
                {
171
                        return false;
172
                }
173
174
                return true;
175
        }
176
177
        /**
178
        * Remove file
179
        */
180
        function remove()
181
        {
182
                if ($this->file_moved)
183
                {
184
                        @unlink($this->destination_file);
185
                }
186
        }
187
188
        /**
189
        * Get file extension
190
        */
191
        function get_extension($filename)
192
        {
193
                if (strpos($filename, '.') === false)
194
                {
195
                        return '';
196
                }
197
198
                $filename = explode('.', $filename);
199
                return array_pop($filename);
200
        }
201
202
        /**
203
        * Get mimetype. Utilize mime_content_type if the function exist.
204
        * Not used at the moment...
205
        */
206
        function get_mimetype($filename)
207
        {
208
                $mimetype = '';
209
210
                if (function_exists('mime_content_type'))
211
                {
212
                        $mimetype = mime_content_type($filename);
213
                }
214
215
                // Some browsers choke on a mimetype of application/octet-stream
216
                if (!$mimetype || $mimetype == 'application/octet-stream')
217
                {
218
                        $mimetype = 'application/octetstream';
219
                }
220
221
                return $mimetype;
222
        }
223
224
        /**
225
        * Get filesize
226
        */
227
        function get_filesize($filename)
228
        {
229
                return @filesize($filename);
230
        }
231
232
233
        /**
234
        * Check the first 256 bytes for forbidden content
235
        */
236
        function check_content($disallowed_content)
237
        {
238
                if (empty($disallowed_content))
239
                {
240
                        return true;
241
                }
242
243
                $fp = @fopen($this->filename, 'rb');
244
245
                if ($fp !== false)
246
                {
247
                        $ie_mime_relevant = fread($fp, 256);
248
                        fclose($fp);
249
                        foreach ($disallowed_content as $forbidden)
250
                        {
251
                                if (stripos($ie_mime_relevant, '<' . $forbidden) !== false)
252
                                {
253
                                        return false;
254
                                }
255
                        }
256
                }
257
                return true;
258
        }
259
260
        /**
261
        * Move file to destination folder
262
        * The phpbb_root_path variable will be applied to the destination path
263
        *
264
        * @param string $destination_path Destination path, for example $config['avatar_path']
265
        * @param bool $overwrite If set to true, an already existing file will be overwritten
266
        * @param string $chmod Permission mask for chmodding the file after a successful move. The mode entered here reflects the mode defined by {@link phpbb_chmod()}
267
        *
268
        * @access public
269
        */
270
        function move_file($destination, $overwrite = false, $skip_image_check = false, $chmod = false)
271
        {
272
                global $user, $phpbb_root_path;
273
274
                if (sizeof($this->error))
275
                {
276
                        return false;
277
                }
278
279
                $chmod = ($chmod === false) ? CHMOD_READ | CHMOD_WRITE : $chmod;
280
281
                // We need to trust the admin in specifying valid upload directories and an attacker not being able to overwrite it...
282
                $this->destination_path = $phpbb_root_path . $destination;
283
284
                // Check if the destination path exist...
285
                if (!file_exists($this->destination_path))
286
                {
287
                        @unlink($this->filename);
288
                        return false;
289
                }
290
291
                $upload_mode = (@ini_get('open_basedir') || @ini_get('safe_mode') || strtolower(@ini_get('safe_mode')) == 'on') ? 'move' : 'copy';
292
                $upload_mode = ($this->local) ? 'local' : $upload_mode;
293
                $this->destination_file = $this->destination_path . '/' . utf8_basename($this->realname);
294
295
                // Check if the file already exist, else there is something wrong...
296
                if (file_exists($this->destination_file) && !$overwrite)
297
                {
298
                        @unlink($this->filename);
299
                }
300
                else
301
                {
302
                        if (file_exists($this->destination_file))
303
                        {
304
                                @unlink($this->destination_file);
305
                        }
306
307
                        switch ($upload_mode)
308
                        {
309
                                case 'copy':
310
311
                                        if (!@copy($this->filename, $this->destination_file))
312
                                        {
313
                                                if (!@move_uploaded_file($this->filename, $this->destination_file))
314
                                                {
315
                                                        $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR'], $this->destination_file);
316
                                                }
317
                                        }
318
319
                                break;
320
321
                                case 'move':
322
323
                                        if (!@move_uploaded_file($this->filename, $this->destination_file))
324
                                        {
325
                                                if (!@copy($this->filename, $this->destination_file))
326
                                                {
327
                                                        $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR'], $this->destination_file);
328
                                                }
329
                                        }
330
331
                                break;
332
333
                                case 'local':
334
335
                                        if (!@copy($this->filename, $this->destination_file))
336
                                        {
337
                                                $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR'], $this->destination_file);
338
                                        }
339
340
                                break;
341
                        }
342
343
                        // Remove temporary filename
344
                        @unlink($this->filename);
345
346
                        if (sizeof($this->error))
347
                        {
348
                                return false;
349
                        }
350
351
                        phpbb_chmod($this->destination_file, $chmod);
352
                }
353
354
                // Try to get real filesize from destination folder
355
                $this->filesize = (@filesize($this->destination_file)) ? @filesize($this->destination_file) : $this->filesize;
356
357
                if ($this->is_image() && !$skip_image_check)
358
                {
359
                        $this->width = $this->height = 0;
360
361
                        if (($this->image_info = @getimagesize($this->destination_file)) !== false)
362
                        {
363
                                $this->width = $this->image_info[0];
364
                                $this->height = $this->image_info[1];
365
366
                                if (!empty($this->image_info['mime']))
367
                                {
368
                                        $this->mimetype = $this->image_info['mime'];
369
                                }
370
371
                                // Check image type
372
                                $types = $this->upload->image_types();
373
374
                                if (!isset($types[$this->image_info[2]]) || !in_array($this->extension, $types[$this->image_info[2]]))
375
                                {
376
                                        if (!isset($types[$this->image_info[2]]))
377
                                        {
378
                                                $this->error[] = sprintf($user->lang['IMAGE_FILETYPE_INVALID'], $this->image_info[2], $this->mimetype);
379
                                        }
380
                                        else
381
                                        {
382
                                                $this->error[] = sprintf($user->lang['IMAGE_FILETYPE_MISMATCH'], $types[$this->image_info[2]][0], $this->extension);
383
                                        }
384
                                }
385
386
                                // Make sure the dimensions match a valid image
387
                                if (empty($this->width) || empty($this->height))
388
                                {
389
                                        $this->error[] = $user->lang['ATTACHED_IMAGE_NOT_IMAGE'];
390
                                }
391
                        }
392
                        else
393
                        {
394
                                $this->error[] = $user->lang['UNABLE_GET_IMAGE_SIZE'];
395
                        }
396
                }
397
398
                $this->file_moved = true;
399
                $this->additional_checks();
400
                unset($this->upload);
401
402
                return true;
403
        }
404
405
        /**
406
        * Performing additional checks
407
        */
408
        function additional_checks()
409
        {
410
                global $user;
411
412
                if (!$this->file_moved)
413
                {
414
                        return false;
415
                }
416
417
                // Filesize is too big or it's 0 if it was larger than the maxsize in the upload form
418
                if ($this->upload->max_filesize && ($this->get('filesize') > $this->upload->max_filesize || $this->filesize == 0))
419
                {
420
                        $max_filesize = get_formatted_filesize($this->upload->max_filesize, false);
421
422
                        $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'WRONG_FILESIZE'], $max_filesize['value'], $max_filesize['unit']);
423
424
                        return false;
425
                }
426
427
                if (!$this->upload->valid_dimensions($this))
428
                {
429
                        $this->error[] = $user->lang($this->upload->error_prefix . 'WRONG_SIZE',
430
                                $user->lang('PIXELS', (int) $this->upload->min_width),
431
                                $user->lang('PIXELS', (int) $this->upload->min_height),
432
                                $user->lang('PIXELS', (int) $this->upload->max_width),
433
                                $user->lang('PIXELS', (int) $this->upload->max_height),
434
                                $user->lang('PIXELS', (int) $this->width),
435
                                $user->lang('PIXELS', (int) $this->height));
436
437
                        return false;
438
                }
439
440
                return true;
441
        }
442
}
443
444
/**
445
* Class for assigning error messages before a real filespec class can be assigned
446
*
447
* @package phpBB3
448
*/
449
class fileerror extends filespec
450
{
451
        function fileerror($error_msg)
452
        {
453
                $this->error[] = $error_msg;
454
        }
455
}
456
457
/**
458
* File upload class
459
* Init class (all parameters optional and able to be set/overwritten separately) - scope is global and valid for all uploads
460
*
461
* @package phpBB3
462
*/
463
class fileupload
464
{
465
        var $allowed_extensions = array();
466
        var $disallowed_content = array('body', 'head', 'html', 'img', 'plaintext', 'a href', 'pre', 'script', 'table', 'title'); 
467
        var $max_filesize = 0;
468
        var $min_width = 0;
469
        var $min_height = 0;
470
        var $max_width = 0;
471
        var $max_height = 0;
472
        var $error_prefix = '';
473
474
        /**
475
        * Init file upload class.
476
        *
477
        * @param string $error_prefix Used error messages will get prefixed by this string
478
        * @param array $allowed_extensions Array of allowed extensions, for example array('jpg', 'jpeg', 'gif', 'png')
479
        * @param int $max_filesize Maximum filesize
480
        * @param int $min_width Minimum image width (only checked for images)
481
        * @param int $min_height Minimum image height (only checked for images)
482
        * @param int $max_width Maximum image width (only checked for images)
483
        * @param int $max_height Maximum image height (only checked for images)
484
        *
485
        */
486
        function fileupload($error_prefix = '', $allowed_extensions = false, $max_filesize = false, $min_width = false, $min_height = false, $max_width = false, $max_height = false, $disallowed_content = false)
487
        {
488
                $this->set_allowed_extensions($allowed_extensions);
489
                $this->set_max_filesize($max_filesize);
490
                $this->set_allowed_dimensions($min_width, $min_height, $max_width, $max_height);
491
                $this->set_error_prefix($error_prefix);
492
                $this->set_disallowed_content($disallowed_content);
493
        }
494
495
        /**
496
        * Reset vars
497
        */
498
        function reset_vars()
499
        {
500
                $this->max_filesize = 0;
501
                $this->min_width = $this->min_height = $this->max_width = $this->max_height = 0;
502
                $this->error_prefix = '';
503
                $this->allowed_extensions = array();
504
                $this->disallowed_content = array();
505
        }
506
507
        /**
508
        * Set allowed extensions
509
        */
510
        function set_allowed_extensions($allowed_extensions)
511
        {
512
                if ($allowed_extensions !== false && is_array($allowed_extensions))
513
                {
514
                        $this->allowed_extensions = $allowed_extensions;
515
                }
516
        }
517
518
        /**
519
        * Set allowed dimensions
520
        */
521
        function set_allowed_dimensions($min_width, $min_height, $max_width, $max_height)
522
        {
523
                $this->min_width = (int) $min_width;
524
                $this->min_height = (int) $min_height;
525
                $this->max_width = (int) $max_width;
526
                $this->max_height = (int) $max_height;
527
        }
528
529
        /**
530
        * Set maximum allowed filesize
531
        */
532
        function set_max_filesize($max_filesize)
533
        {
534
                if ($max_filesize !== false && (int) $max_filesize)
535
                {
536
                        $this->max_filesize = (int) $max_filesize;
537
                }
538
        }
539
540
        /**
541
        * Set disallowed strings
542
        */
543
        function set_disallowed_content($disallowed_content)
544
        {
545
                if ($disallowed_content !== false && is_array($disallowed_content))
546
                {
547
                        $this->disallowed_content = array_diff($disallowed_content, array(''));
548
                }
549
        }
550
551
        /**
552
        * Set error prefix
553
        */
554
        function set_error_prefix($error_prefix)
555
        {
556
                $this->error_prefix = $error_prefix;
557
        }
558
559
        /**
560
        * Form upload method
561
        * Upload file from users harddisk
562
        *
563
        * @param string $form_name Form name assigned to the file input field (if it is an array, the key has to be specified)
564
        * @return object $file Object "filespec" is returned, all further operations can be done with this object
565
        * @access public
566
        */
567
        function form_upload($form_name)
568
        {
569
                global $user;
570
571
                unset($_FILES[$form_name]['local_mode']);
572
                $file = new filespec($_FILES[$form_name], $this);
573
574
                if ($file->init_error)
575
                {
576
                        $file->error[] = '';
577
                        return $file;
578
                }
579
580
                // Error array filled?
581
                if (isset($_FILES[$form_name]['error']))
582
                {
583
                        $error = $this->assign_internal_error($_FILES[$form_name]['error']);
584
585
                        if ($error !== false)
586
                        {
587
                                $file->error[] = $error;
588
                                return $file;
589
                        }
590
                }
591
592
                // Check if empty file got uploaded (not catched by is_uploaded_file)
593
                if (isset($_FILES[$form_name]['size']) && $_FILES[$form_name]['size'] == 0)
594
                {
595
                        $file->error[] = $user->lang[$this->error_prefix . 'EMPTY_FILEUPLOAD'];
596
                        return $file;
597
                }
598
599
                // PHP Upload filesize exceeded
600
                if ($file->get('filename') == 'none')
601
                {
602
                        $max_filesize = @ini_get('upload_max_filesize');
603
                        $unit = 'MB';
604
605
                        if (!empty($max_filesize))
606
                        {
607
                                $unit = strtolower(substr($max_filesize, -1, 1));
608
                                $max_filesize = (int) $max_filesize;
609
610
                                $unit = ($unit == 'k') ? 'KB' : (($unit == 'g') ? 'GB' : 'MB');
611
                        }
612
613
                        $file->error[] = (empty($max_filesize)) ? $user->lang[$this->error_prefix . 'PHP_SIZE_NA'] : sprintf($user->lang[$this->error_prefix . 'PHP_SIZE_OVERRUN'], $max_filesize, $user->lang[$unit]);
614
                        return $file;
615
                }
616
617
                // Not correctly uploaded
618
                if (!$file->is_uploaded())
619
                {
620
                        $file->error[] = $user->lang[$this->error_prefix . 'NOT_UPLOADED'];
621
                        return $file;
622
                }
623
624
                $this->common_checks($file);
625
626
                return $file;
627
        }
628
629
        /**
630
        * Move file from another location to phpBB
631
        */
632
        function local_upload($source_file, $filedata = false)
633
        {
634
                global $user;
635
636
                $form_name = 'local';
637
638
                $_FILES[$form_name]['local_mode'] = true;
639
                $_FILES[$form_name]['tmp_name'] = $source_file;
640
641
                if ($filedata === false)
642
                {
643
                        $_FILES[$form_name]['name'] = utf8_basename($source_file);
644
                        $_FILES[$form_name]['size'] = 0;
645
                        $mimetype = '';
646
647
                        if (function_exists('mime_content_type'))
648
                        {
649
                                $mimetype = mime_content_type($source_file);
650
                        }
651
652
                        // Some browsers choke on a mimetype of application/octet-stream
653
                        if (!$mimetype || $mimetype == 'application/octet-stream')
654
                        {
655
                                $mimetype = 'application/octetstream';
656
                        }
657
658
                        $_FILES[$form_name]['type'] = $mimetype;
659
                }
660
                else
661
                {
662
                        $_FILES[$form_name]['name'] = $filedata['realname'];
663
                        $_FILES[$form_name]['size'] = $filedata['size'];
664
                        $_FILES[$form_name]['type'] = $filedata['type'];
665
                }
666
667
                $file = new filespec($_FILES[$form_name], $this);
668
669
                if ($file->init_error)
670
                {
671
                        $file->error[] = '';
672
                        return $file;
673
                }
674
675
                if (isset($_FILES[$form_name]['error']))
676
                {
677
                        $error = $this->assign_internal_error($_FILES[$form_name]['error']);
678
679
                        if ($error !== false)
680
                        {
681
                                $file->error[] = $error;
682
                                return $file;
683
                        }
684
                }
685
686
                // PHP Upload filesize exceeded
687
                if ($file->get('filename') == 'none')
688
                {
689
                        $max_filesize = @ini_get('upload_max_filesize');
690
                        $unit = 'MB';
691
692
                        if (!empty($max_filesize))
693
                        {
694
                                $unit = strtolower(substr($max_filesize, -1, 1));
695
                                $max_filesize = (int) $max_filesize;
696
697
                                $unit = ($unit == 'k') ? 'KB' : (($unit == 'g') ? 'GB' : 'MB');
698
                        }
699
700
                        $file->error[] = (empty($max_filesize)) ? $user->lang[$this->error_prefix . 'PHP_SIZE_NA'] : sprintf($user->lang[$this->error_prefix . 'PHP_SIZE_OVERRUN'], $max_filesize, $user->lang[$unit]);
701
                        return $file;
702
                }
703
704
                // Not correctly uploaded
705
                if (!$file->is_uploaded())
706
                {
707
                        $file->error[] = $user->lang[$this->error_prefix . 'NOT_UPLOADED'];
708
                        return $file;
709
                }
710
711
                $this->common_checks($file);
712
713
                return $file;
714
        }
715
716
        /**
717
        * Remote upload method
718
        * Uploads file from given url
719
        *
720
        * @param string $upload_url URL pointing to file to upload, for example http://www.foobar.com/example.gif
721
        * @return object $file Object "filespec" is returned, all further operations can be done with this object
722
        * @access public
723
        */
724
        function remote_upload($upload_url)
725
        {
726
                global $user, $phpbb_root_path;
727
728
                $upload_ary = array();
729
                $upload_ary['local_mode'] = true;
730
731
                if (!preg_match('#^(https?://).*?\.(' . implode('|', $this->allowed_extensions) . ')$#i', $upload_url, $match))
732
                {
733
                        $file = new fileerror($user->lang[$this->error_prefix . 'URL_INVALID']);
734
                        return $file;
735
                }
736
737
                if (empty($match[2]))
738
                {
739
                        $file = new fileerror($user->lang[$this->error_prefix . 'URL_INVALID']);
740
                        return $file;
741
                }
742
743
                $url = parse_url($upload_url);
744
745
                $host = $url['host'];
746
                $path = $url['path'];
747
                $port = (!empty($url['port'])) ? (int) $url['port'] : 80;
748
749
                $upload_ary['type'] = 'application/octet-stream';
750
751
                $url['path'] = explode('.', $url['path']);
752
                $ext = array_pop($url['path']);
753
754
                $url['path'] = implode('', $url['path']);
755
                $upload_ary['name'] = utf8_basename($url['path']) . (($ext) ? '.' . $ext : '');
756
                $filename = $url['path'];
757
                $filesize = 0;
758
759
                $errno = 0;
760
                $errstr = '';
761
762
                if (!($fsock = @fsockopen($host, $port, $errno, $errstr)))
763
                {
764
                        $file = new fileerror($user->lang[$this->error_prefix . 'NOT_UPLOADED']);
765
                        return $file;
766
                }
767
768
                // Make sure $path not beginning with /
769
                if (strpos($path, '/') === 0)
770
                {
771
                        $path = substr($path, 1);
772
                }
773
774
                fputs($fsock, 'GET /' . $path . " HTTP/1.1\r\n");
775
                fputs($fsock, "HOST: " . $host . "\r\n");
776
                fputs($fsock, "Connection: close\r\n\r\n");
777
778
                $get_info = false;
779
                $data = '';
780
                while (!@feof($fsock))
781
                {
782
                        if ($get_info)
783
                        {
784
                                $block = @fread($fsock, 1024);
785
                                $filesize += strlen($block);
786
787
                                if ($this->max_filesize && $filesize > $this->max_filesize)
788
                                {
789
                                        $max_filesize = get_formatted_filesize($this->max_filesize, false);
790
791
                                        $file = new fileerror(sprintf($user->lang[$this->error_prefix . 'WRONG_FILESIZE'], $max_filesize['value'], $max_filesize['unit']));
792
                                        return $file;
793
                                }
794
795
                                $data .= $block;
796
                        }
797
                        else
798
                        {
799
                                $line = @fgets($fsock, 1024);
800
801
                                if ($line == "\r\n")
802
                                {
803
                                        $get_info = true;
804
                                }
805
                                else
806
                                {
807
                                        if (stripos($line, 'content-type: ') !== false)
808
                                        {
809
                                                $upload_ary['type'] = rtrim(str_replace('content-type: ', '', strtolower($line)));
810
                                        }
811
                                        else if ($this->max_filesize && stripos($line, 'content-length: ') !== false)
812
                                        {
813
                                                $length = (int) str_replace('content-length: ', '', strtolower($line));
814
815
                                                if ($length && $length > $this->max_filesize)
816
                                                {
817
                                                        $max_filesize = get_formatted_filesize($this->max_filesize, false);
818
819
                                                        $file = new fileerror(sprintf($user->lang[$this->error_prefix . 'WRONG_FILESIZE'], $max_filesize['value'], $max_filesize['unit']));
820
                                                        return $file;
821
                                                }
822
                                        }
823
                                        else if (stripos($line, '404 not found') !== false)
824
                                        {
825
                                                $file = new fileerror($user->lang[$this->error_prefix . 'URL_NOT_FOUND']);
826
                                                return $file;
827
                                        }
828
                                }
829
                        }
830
                }
831
                @fclose($fsock);
832
833
                if (empty($data))
834
                {
835
                        $file = new fileerror($user->lang[$this->error_prefix . 'EMPTY_REMOTE_DATA']);
836
                        return $file;
837
                }
838
839
                $tmp_path = (!@ini_get('safe_mode') || strtolower(@ini_get('safe_mode')) == 'off') ? false : $phpbb_root_path . 'cache';
840
                $filename = tempnam($tmp_path, unique_id() . '-');
841
842
                if (!($fp = @fopen($filename, 'wb')))
843
                {
844
                        $file = new fileerror($user->lang[$this->error_prefix . 'NOT_UPLOADED']);
845
                        return $file;
846
                }
847
848
                $upload_ary['size'] = fwrite($fp, $data);
849
                fclose($fp);
850
                unset($data);
851
852
                $upload_ary['tmp_name'] = $filename;
853
854
                $file = new filespec($upload_ary, $this);
855
                $this->common_checks($file);
856
857
                return $file;
858
        }
859
860
        /**
861
        * Assign internal error
862
        * @access private
863
        */
864
        function assign_internal_error($errorcode)
865
        {
866
                global $user;
867
868
                switch ($errorcode)
869
                {
870
                        case 1:
871
                                $max_filesize = @ini_get('upload_max_filesize');
872
                                $unit = 'MB';
873
874
                                if (!empty($max_filesize))
875
                                {
876
                                        $unit = strtolower(substr($max_filesize, -1, 1));
877
                                        $max_filesize = (int) $max_filesize;
878
879
                                        $unit = ($unit == 'k') ? 'KB' : (($unit == 'g') ? 'GB' : 'MB');
880
                                }
881
882
                                $error = (empty($max_filesize)) ? $user->lang[$this->error_prefix . 'PHP_SIZE_NA'] : sprintf($user->lang[$this->error_prefix . 'PHP_SIZE_OVERRUN'], $max_filesize, $user->lang[$unit]);
883
                        break;
884
885
                        case 2:
886
                                $max_filesize = get_formatted_filesize($this->max_filesize, false);
887
888
                                $error = sprintf($user->lang[$this->error_prefix . 'WRONG_FILESIZE'], $max_filesize['value'], $max_filesize['unit']);
889
                        break;
890
891
                        case 3:
892
                                $error = $user->lang[$this->error_prefix . 'PARTIAL_UPLOAD'];
893
                        break;
894
895
                        case 4:
896
                                $error = $user->lang[$this->error_prefix . 'NOT_UPLOADED'];
897
                        break;
898
899
                        case 6:
900
                                $error = 'Temporary folder could not be found. Please check your PHP installation.';
901
                        break;
902
903
                        default:
904
                                $error = false;
905
                        break;
906
                }
907
908
                return $error;
909
        }
910
911
        /**
912
        * Perform common checks
913
        */
914
        function common_checks(&$file)
915
        {
916
                global $user;
917
918
                // Filesize is too big or it's 0 if it was larger than the maxsize in the upload form
919
                if ($this->max_filesize && ($file->get('filesize') > $this->max_filesize || $file->get('filesize') == 0))
920
                {
921
                        $max_filesize = get_formatted_filesize($this->max_filesize, false);
922
923
                        $file->error[] = sprintf($user->lang[$this->error_prefix . 'WRONG_FILESIZE'], $max_filesize['value'], $max_filesize['unit']);
924
                }
925
926
                // check Filename
927
                if (preg_match("#[\\/:*?\"<>|]#i", $file->get('realname')))
928
                {
929
                        $file->error[] = sprintf($user->lang[$this->error_prefix . 'INVALID_FILENAME'], $file->get('realname'));
930
                }
931
932
                // Invalid Extension
933
                if (!$this->valid_extension($file))
934
                {
935
                        $file->error[] = sprintf($user->lang[$this->error_prefix . 'DISALLOWED_EXTENSION'], $file->get('extension'));
936
                }
937
938
                // MIME Sniffing
939
                if (!$this->valid_content($file))
940
                {
941
                        $file->error[] = sprintf($user->lang[$this->error_prefix . 'DISALLOWED_CONTENT']);
942
                }
943
        }
944
945
        /**
946
        * Check for allowed extension
947
        */
948
        function valid_extension(&$file)
949
        {
950
                return (in_array($file->get('extension'), $this->allowed_extensions)) ? true : false;
951
        }
952
953
        /**
954
        * Check for allowed dimension
955
        */
956
        function valid_dimensions(&$file)
957
        {
958
                if (!$this->max_width && !$this->max_height && !$this->min_width && !$this->min_height)
959
                {
960
                        return true;
961
                }
962
963
                if (($file->get('width') > $this->max_width && $this->max_width) ||
964
                        ($file->get('height') > $this->max_height && $this->max_height) ||
965
                        ($file->get('width') < $this->min_width && $this->min_width) ||
966
                        ($file->get('height') < $this->min_height && $this->min_height))
967
                {
968
                        return false;
969
                }
970
971
                return true;
972
        }
973
974
        /**
975
        * Check if form upload is valid
976
        */
977
        function is_valid($form_name)
978
        {
979
                return (isset($_FILES[$form_name]) && $_FILES[$form_name]['name'] != 'none') ? true : false;
980
        }
981
982
983
        /**
984
        * Check for bad content (IE mime-sniffing)
985
        */
986
        function valid_content(&$file)
987
        {
988
                return ($file->check_content($this->disallowed_content));
989
        }
990
991
        /**
992
        * Return image type/extension mapping
993
        */
994
        function image_types()
995
        {
996
                return array(
997
                        IMAGETYPE_GIF                => array('gif'),
998
                        IMAGETYPE_JPEG                => array('jpg', 'jpeg'),
999
                        IMAGETYPE_PNG                => array('png'),
1000
                        IMAGETYPE_SWF                => array('swf'),
1001
                        IMAGETYPE_PSD                => array('psd'),
1002
                        IMAGETYPE_BMP                => array('bmp'),
1003
                        IMAGETYPE_TIFF_II        => array('tif', 'tiff'),
1004
                        IMAGETYPE_TIFF_MM        => array('tif', 'tiff'),
1005
                        IMAGETYPE_JPC                => array('jpg', 'jpeg'),
1006
                        IMAGETYPE_JP2                => array('jpg', 'jpeg'),
1007
                        IMAGETYPE_JPX                => array('jpg', 'jpeg'),
1008
                        IMAGETYPE_JB2                => array('jpg', 'jpeg'),
1009
                        IMAGETYPE_SWC                => array('swc'),
1010
                        IMAGETYPE_IFF                => array('iff'),
1011
                        IMAGETYPE_WBMP                => array('wbmp'),
1012
                        IMAGETYPE_XBM                => array('xbm'),
1013
                );
1014
        }
1015
}