upload_Core::valid()   B
last analyzed

Complexity

Conditions 6
Paths 6

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 6
eloc 7
c 2
b 1
f 0
nc 6
nop 1
dl 0
loc 9
rs 8.8571
1
<?php defined('SYSPATH') or die('No direct access allowed.');
2
/**
3
 * Upload helper class for working with the global $_FILES
4
 * array and Validation library.
5
 *
6
 * $Id: upload.php 3769 2008-12-15 00:48:56Z zombor $
7
 *
8
 * @package    Core
9
 * @author     Kohana Team
10
 * @copyright  (c) 2007-2008 Kohana Team
11
 * @license    http://kohanaphp.com/license.html
12
 */
13
class upload_Core
14
{
15
16
    /**
17
     * Save an uploaded file to a new location.
18
     *
19
     * @param   mixed    name of $_FILE input or array of upload data
20
     * @param   string   new filename
21
     * @param   string   new directory
22
     * @param   integer  chmod mask
23
     * @return  string   full path to new file
0 ignored issues
show
Documentation introduced by
Should the return type not be string|false?

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...
24
     */
25
    public static function save($file, $filename = null, $directory = null, $chmod = 0644)
0 ignored issues
show
Coding Style introduced by
save uses the super-global variable $_FILES which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
26
    {
27
        // Load file data from FILES if not passed as array
28
        $file = is_array($file) ? $file : $_FILES[$file];
29
30
        if ($filename === null) {
31
            // Use the default filename, with a timestamp pre-pended
32
            $filename = time().$file['name'];
33
        }
34
35
        if (Kohana::config('upload.remove_spaces') === true) {
36
            // Remove spaces from the filename
37
            $filename = preg_replace('/\s+/', '_', $filename);
38
        }
39
40
        if ($directory === null) {
41
            // Use the pre-configured upload directory
42
            $directory = Kohana::config('upload.directory', true);
43
        }
44
45
        // Make sure the directory ends with a slash
46
        $directory = rtrim($directory, '/').'/';
47
48
        if (! is_dir($directory) and Kohana::config('upload.create_directories') === true) {
49
            // Create the upload directory
50
            mkdir($directory, 0777, true);
51
        }
52
53
        if (! is_writable($directory)) {
54
            throw new Kohana_Exception('upload.not_writable', $directory);
55
        }
56
57
        if (is_uploaded_file($file['tmp_name']) and move_uploaded_file($file['tmp_name'], $filename = $directory.$filename)) {
58
            if ($chmod !== false) {
59
                // Set permissions on filename
60
                chmod($filename, $chmod);
61
            }
62
63
            // Return new file path
64
            return $filename;
65
        }
66
67
        return false;
68
    }
69
70
    /* Validation Rules */
71
72
    /**
73
     * Tests if input data is valid file type, even if no upload is present.
74
     *
75
     * @return  bool
76
     */
77
    public static function valid($file)
78
    {
79
        return (is_array($file)
80
            and isset($file['error'])
81
            and isset($file['name'])
82
            and isset($file['type'])
83
            and isset($file['tmp_name'])
84
            and isset($file['size']));
85
    }
86
87
    /**
88
     * Tests if input data has valid upload data.
89
     *
90
     * @return  bool
91
     */
92
    public static function required(array $file)
93
    {
94
        return (isset($file['tmp_name'])
95
            and isset($file['error'])
96
            and is_uploaded_file($file['tmp_name'])
97
            and (int) $file['error'] === UPLOAD_ERR_OK);
98
    }
99
100
    /**
101
     * Validation rule to test if an uploaded file is allowed by extension.
102
     *
103
     * @param   array    allowed file extensions
104
     * @return  bool
105
     */
106
    public static function type(array $file, array $allowed_types)
107
    {
108
        if ((int) $file['error'] !== UPLOAD_ERR_OK) {
109
            return true;
110
        }
111
112
        // Get the default extension of the file
113
        $extension = strtolower(substr(strrchr($file['name'], '.'), 1));
114
115
        // Get the mime types for the extension
116
        $mime_types = Kohana::config('mimes.'.$extension);
117
118
        // Make sure there is an extension, that the extension is allowed, and that mime types exist
119
        return (! empty($extension) and in_array($extension, $allowed_types) and is_array($mime_types));
120
    }
121
122
    /**
123
     * Validation rule to test if an uploaded file is allowed by file size.
124
     * File sizes are defined as: SB, where S is the size (1, 15, 300, etc) and
125
     * B is the byte modifier: (B)ytes, (K)ilobytes, (M)egabytes, (G)igabytes.
126
     * Eg: to limit the size to 1MB or less, you would use "1M".
127
     *
128
     * @param   array    maximum file size
129
     * @return  bool
130
     */
131
    public static function size(array $file, array $size)
132
    {
133
        if ((int) $file['error'] !== UPLOAD_ERR_OK) {
134
            return true;
135
        }
136
137
        // Only one size is allowed
138
        $size = strtoupper($size[0]);
139
140
        if (! preg_match('/[0-9]++[BKMG]/', $size)) {
141
            return false;
142
        }
143
144
        // Make the size into a power of 1024
145
        switch (substr($size, -1)) {
146
            case 'G': $size = intval($size) * pow(1024, 3); break;
147
            case 'M': $size = intval($size) * pow(1024, 2); break;
148
            case 'K': $size = intval($size) * pow(1024, 1); break;
149
            default:  $size = intval($size);                break;
150
        }
151
152
        // Test that the file is under or equal to the max size
153
        return ($file['size'] <= $size);
154
    }
155
} // End upload
156