ultimix

- Main Page
- Data Structures
- Files
- Examples

- File List
- Globals

upload.php
Go to the documentation of this file.
1 <?php
2 /*
3 This is an upload script for SWFUpload that attempts to properly handle uploaded files
4 in a secure way.
5
6 Notes:
7
8 SWFUpload doesn't send a MIME-TYPE. In my opinion this is ok since MIME-TYPE is no better than
9 file extension and is probably worse because it can vary from OS to OS and browser to browser
10 (for the same file).
11 The best thing to do is content sniff the file but this can be resource intensive, is difficult, and can
12 still be fooled or inaccurate.
13 Accepting uploads can never be 100% secure.
14
15 You can't guarantee that SWFUpload is really the source of the upload. A malicious user
16 will probably be uploading from a tool that sends invalid or false metadata about the file.
17 The script should properly handle this.
18
19 The script should not over-write existing files.
20
21 The script should strip away invalid characters from the file name or reject the file.
22
23 The script should not allow files to be saved that could then be executed on the webserver
24 (such as .php files). To keep things simple we will use an extension whitelist for allowed file extensions.
25 Which files should be allowed depends on your server configuration. The extension white-list is _not_ tied
26 your SWFUpload file_types setting
27
28 For better security uploaded files should be stored outside the webserver's document root. Downloaded files
29 should be accessed via a download script that proxies from the file system to the webserver. This prevents
30 users from executing malicious uploaded files. It also gives the developer control over the outgoing
31 mime-type, access restrictions, etc. This, however, is outside the scope of this script.
32
33 SWFUpload sends each file as a separate POST rather than several files in a single post. This is a better
34 method in my opinions since it better handles file size limits, e.g., if post_max_size is 100 MB and I post
35 two 60 MB files then the post would fail (2x60MB = 120MB). In SWFupload each 60 MB is posted as separate
36 post and we stay within the limits. This
37 also simplifies the upload script since we only have to handle a single file.
38
39 The script should properly handle situations where the post was too large or the posted file is larger than
40 our defined max. These values are not tied to your SWFUpload file_size_limit setting.
41 */
42
43 # added
44 # no direct call
45 if( defined( 'NO_DIRECT_CALL' ) === false )
46 {
47 exit( 0 );
48 }
49 # ~added
50
51 // Code for Session Cookie workaround
52 if (isset($_POST["PHPSESSID"])) {
53 session_id($_POST["PHPSESSID"]);
54 } else if (isset($_GET["PHPSESSID"])) {
55 session_id($_GET["PHPSESSID"]);
56 }
57
58 @session_start();
59
60 // Check post_max_size (http://us3.php.net/manual/en/features.file-upload.php#73762)
61 $POST_MAX_SIZE = ini_get('post_max_size');
62 $unit = strtoupper(substr($POST_MAX_SIZE, -1));
63 $multiplier = ($unit == 'M' ? 1048576 : ($unit == 'K' ? 1024 : ($unit == 'G' ? 1073741824 : 1)));
64
65 if ((int)@$_SERVER['CONTENT_LENGTH'] > $multiplier*(int)$POST_MAX_SIZE && $POST_MAX_SIZE) {
66 header("HTTP/1.1 500 Internal Server Error"); // This will trigger an uploadError event in SWFUpload
67 echo "POST exceeded maximum allowed size.";
68 exit(0);
69 }
70
71 // Settings
72 // added $save_path = getcwd() . "/data/";
73 global $save_path;
74 $upload_name = "Filedata";
75 $max_file_size_in_bytes = 2147483647; // 2GB in bytes
76 # added $extension_whitelist = array("jpg", "gif", "png"); // Allowed file extensions
77 global $extension_whitelist;
78 # ~added
79 $valid_chars_regex = '.A-Z0-9_ !@#$%^&()+={}\[\]\',~`-';
80
81 // Other variables
82 $MAX_FILENAME_LENGTH = 260;
83 global $file_name;
84 $file_name = "";
85 $file_extension = "";
86 $uploadErrors = array(
87 0=>"There is no error, the file uploaded with success",
88 1=>"The uploaded file exceeds the upload_max_filesize directive in php.ini",
89 2=>"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form",
90 3=>"The uploaded file was only partially uploaded",
91 4=>"No file was uploaded",
92 6=>"Missing a temporary folder"
93 );
94
95 // Validate the upload
96 if (!isset($_FILES[$upload_name])) {
97 HandleError("No upload found in \$_FILES for " . $upload_name);
98 exit(0);
99 } else if (isset($_FILES[$upload_name]["error"]) && $_FILES[$upload_name]["error"] != 0) {
100 HandleError($uploadErrors[$_FILES[$upload_name]["error"]]);
101 exit(0);
102 } else if (!isset($_FILES[$upload_name]["tmp_name"]) || !@is_uploaded_file($_FILES[$upload_name]["tmp_name"])) {
103 HandleError("Upload failed is_uploaded_file test.");
104 exit(0);
105 } else if (!isset($_FILES[$upload_name]['name'])) {
106 HandleError("File has no name.");
107 exit(0);
108 }
109
110 // Validate the file size (Warning: the largest files supported by this code is 2GB)
111 $file_size = @filesize($_FILES[$upload_name]["tmp_name"]);
112 if (!$file_size || $file_size > $max_file_size_in_bytes) {
113 HandleError("File exceeds the maximum allowed size");
114 exit(0);
115 }
116
117 if ($file_size <= 0) {
118 HandleError("File size outside allowed lower bound");
119 exit(0);
120 }
121
122 // Validate file name (for our purposes we'll just remove invalid characters)
123 # added
124 #$file_name = preg_replace('/[^'.$valid_chars_regex.']|\.+$/i', "", basename($_FILES[$upload_name]['name']));
125 $file_name = basename($_FILES[$upload_name]['name']);
126 # ~added
127
128 # added
129 global $original_file_name;
130 $original_file_name = $file_name;
131 $file_name = md5( $file_name.microtime( true ) );
132 # ~added
133
134 if (strlen($file_name) == 0 || strlen($file_name) > $MAX_FILENAME_LENGTH) {
135 HandleError("Invalid file name");
136 exit(0);
137 }
138
139
140 // Validate that we won't over-write an existing file
141 # added
142 #if (file_exists($save_path . $file_name)) {
143 # HandleError("File with this name already exists");
144 # exit(0);
145 #}
146 # ~added
147
148 // Validate file extension
149 $path_info = pathinfo($_FILES[$upload_name]['name']);
150 $file_extension = $path_info["extension"];
151 $is_valid_extension = false;
152 foreach ($extension_whitelist as $extension) {
153 # added
154 if( $extension == '*' ){
155 $is_valid_extension = true;
156 break;
157 }
158 # ~added
159 if (strcasecmp($file_extension, $extension) == 0) {
160 $is_valid_extension = true;
161 break;
162 }
163 }
164 if (!$is_valid_extension) {
165 HandleError("Invalid file extension");
166 exit(0);
167 }
168
169 // Validate file contents (extension and mime-type can't be trusted)
170 /*
171 Validating the file contents is OS and web server configuration dependant. Also, it may not be reliable.
172 See the comments on this page: http://us2.php.net/fileinfo
173
174 which describes how a PHP script can be embedded within a GIF image file.
175
176 Therefore, no sample code will be provided here. Research the issue, decide how much security is
177 needed, and implement a solution that meets the needs.
178 */
179
180
181 // Process the file
182 /*
183 At this point we are ready to process the valid file. This sample code shows how to save the file. Other tasks
184 could be done such as creating an entry in a database or generating a thumbnail.
185
186 Depending on your server OS and needs you may need to set the Security Permissions on the file after it has
187 been saved.
188 */
189 if (!@move_uploaded_file($_FILES[$upload_name]["tmp_name"], $save_path.$file_name)) {
190 HandleError("File could not be saved.");
191 exit(0);
192 }
193
194 /* Handles the error output. This error message will be sent to the uploadSuccess event handler. The event handler
195 will have to check for any error messages and react as needed. */
196 function HandleError($message) {
197 echo $message;
198 }
199 ?>