ultimix
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
78  # ~added
79  $valid_chars_regex = '.A-Z0-9_ !@#$%^&()+={}\[\]\',~`-';
80 
81  // Other variables
83  global $file_name;
84  $file_name = "";
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"]);
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
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"];
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 ?>