1 <?php
2 /**
3 * Upload.class.php - File Upload Class v1.1 - 02 July 2001
4 * Copyright Darren Beale <mail@bealers.com>
5 *
6 * The contents of this file remain the intellectual property of Darren Beale.
7 * It is free for Personal and non-profit use as long as this
8 * entire comment block remains as-is. (Yes all of it)
9 *
10 * If you're using it commercially, please mail <mail@bealers.com> for a postal
11 * address. You can then get your boss to send me a measly 10 UKP so you can
12 * have unlimited use.
13 *
14 * Either way, If you modify or extend it, please Fw: me on a copy with a
15 * small note on what you've done and why.
16 *
17 * TODO:
18 * Check that source_dir is writeable
19 * Allow for auto-rename option on overwrite
20 * Handle exceptions and notices better
21 * Extend Pear/HTML/Form??
22 * Fix Macintosh Upload issues (it won't work)
23 * 100% Pear Compliant
24 * PHPDoc commenting and bundled docs
25 *
26 * ChangeLog
27 * v1.0 - Initial Release 01/07/01
28 * v1.1 - Allowed for Multiple File uploads 02/07/01
29 *
30 * I WILL PROVIDE SUPPORT FOR THIS SCRIPT!
31 * This script *should* be able to handle the uploading of any file, if it
32 * doesn't as a first port of call please change the settings
33 * UPLOAD_DEBUG_OUTPUT and UPLOAD_ENV_OUTPUT to see what is happening.
34 * If you still have problems, mail
35 * me and I'll see what I can do. Don't expect me to code your app though!
36 * BTW You Need PHP > 4.0.2
37 *
38 * Useage: (bare bones)
39 *
40 <?php
41 require_once("Upload.class.php");
42
43 $upload = new Upload();
44 $upload->printFormStart("index.php");
45
46 // put as many of these in as you want,
47 // pass a string filename, else a default is used.
48 $upload->printFormField();
49 print"<br />";
50 $upload->printFormField();
51
52 $upload->printFormSubmit();
53 $upload->printFormEnd();
54
55 if ($submit) {
56 $upload->setAllowedMimeTypes(array("image/bmp","image/gif","image/pjpeg","image/jpeg","image/x-png"));
57 $upload->setUploadPath("c:\apache\htdocs");
58
59 if ($upload->doUpload()) {
60 print "Files Uploaded!";
61 } else {
62 $errors = $upload->getUploadErrors();
63 print "<strong>::Errors occured::</strong><br />\n";
64 while(list($filename,$values) = each($errors)) {
65 "File: " . print $filename . "<br />";
66 $count = count($values);
67 for($i=0; $i<$count; $i++) {
68 print "==>" . $values[$i] . "<br />";
69 }
70 }
71 }
72 }
73 ?>
74 *
75 * This class is complete re-write of my original code that I used
76 * as a basis for one of my PHPBuilder.com articles.
77 * http://www.phpbuilder.com/columns/bealers20000904.php3
78 *
79 * @author Darren Beale <mail@bealers.com>
80 */
81
82 // CONSTANTS ///////////////////////////////////////////////////////////////////
83
84 /*
85 * Funny one this, during testing I couldn't assertain the dimensions of certain images.
86 * Until I can figure out why, you can set this flag to allow the images
87 * that don't return anything.
88 */
89 if (!defined('UPLOAD_ALLOW_DUBIOUS_IMAGES')) {
90 define('UPLOAD_ALLOW_DUBIOUS_IMAGES', true);
91 }
92
93 /*
94 * Defaults only, they can be overridden using methods.
95 */
96 if (!defined('UPLOAD_MAX_FILE_SIZE')) {
97 define('UPLOAD_MAX_FILE_SIZE', 1048576); // 1MB = 1048576
98 }
99 if (!defined('UPLOAD_IMAGE_MAX_WIDTH')) {
100 define('UPLOAD_IMAGE_MAX_WIDTH', 300);
101 }
102 if (!defined('UPLOAD_IMAGE_MAX_HEIGHT')) {
103 define('UPLOAD_IMAGE_MAX_HEIGHT', 300);
104 }
105 if (!defined('UPLOAD_FIELD_NAME')) {
106 define('UPLOAD_FIELD_NAME', "uploadFile");
107 }
108
109
110 /*
111 * un-essential, only change if in development and you are having problems
112 */
113 if (!defined('UPLOAD_DEBUG_OUTPUT')) {
114 define('UPLOAD_DEBUG_OUTPUT', false);
115 }
116 if (!defined('UPLOAD_ENV_OUTPUT')) {
117 define('UPLOAD_ENV_OUTPUT', false);
118 }
119 if (!defined('UPLOAD_LINE_BREAK')) {
120 define('UPLOAD_LINE_BREAK',"<br />"); // markup specific
121 }
122
123 class Upload
124 {
125
126 // {{{ properties
127
128 // array
129 var $uploadErrors;
130 var $registeredMimeTypes;
131 var $allowedMimeTypes;
132
133 // int
134 var $maxImageWidth;
135 var $maxImageHeight;
136 var $maxFileSize;
137
138 /*
139 * used to track the number of fields created and name them accordingly
140 */
141 var $fieldCounter;
142
143 // string
144 var $uploadPath;
145 var $uploadFieldName;
146 var $fieldName;
147 var $errorType;
148
149 // bool
150 var $imageSizeOk;
151 var $uploadValidated;
152 var $uploadFail;
153
154 //}}}
155 //{{{ constructor
156
157 function Upload()
158 {
159 $this->uploadErrors = array();
160 $this->registeredMimeTypes = array();
161 $this->allowedMimeTypes = array();
162
163 $this->maxImageWidth = 0;
164 $this->maxImageHeight = 0;
165 $this->maxFileSize = 0;
166 $this->fieldCounter = 0;
167
168 $this->uploadFieldName = "";
169 $this->uploadPath = "";
170
171 $this->imageSizeOk = false;
172 $this->uploadValidated = false;
173 $this->uploadFail = false;
174
175 /*
176 * set defaults
177 */
178 if(!$this->registeredMimeTypes) {
179 $this->setRegisteredMimeTypes();
180 }
181
182 if(!$this->maxImageWidth || !$this->maxImageHeight) {
183 $this->setMaxImageSize();
184 }
185
186 if(!$this->maxFileSize) {
187 $this->setMaxFileSize();
188 }
189
190 /*
191 * check to see what our environment is like, nothing happens unless
192 * UPLOAD_ENV_OUTPUT == true
193 */
194 $this->checkLocalEnv();
195 }
196
197 //}}}
198
199 /*
200 * public methods ///////////////////////////////////////////////////////////
201 */
202
203 //{{{ setImageSize()
204
205 function setMaxImageSize($maxImageWidth = UPLOAD_IMAGE_MAX_WIDTH, $maxImageHeight = UPLOAD_IMAGE_MAX_HEIGHT)
206 {
207 $this->maxImageWidth = $maxImageWidth;
208 $this->maxImageHeight = $maxImageHeight;
209 }
210
211 //}}}
212 //{{{ setUploadPath()
213
214 function setUploadPath($uploadPath)
215 {
216 $this->uploadPath = $uploadPath;
217 }
218
219 //}}}
220 //{{{ setDestinationFileName()
221
222 function setDestinationFileName($destinationFileName = "uploadedFile.file")
223 {
224 $this->uploadFieldName = $destinationFileName; //+++
225 }
226
227 //}}}
228 //{{{ setRegisteredMimeTypes()
229
230 function setRegisteredMimeTypes($registeredMimeTypes = array())
231 {
232 if (sizeof($registeredMimeTypes) == 0) {
233 $this->registeredMimeTypes =
234 array(
235 "application/x-gzip-compressed" => ".tar.gz, .tgz",
236 "application/x-zip-compressed" => ".zip",
237 "application/x-tar" => ".tar",
238 "text/plain" => ".php, .txt, .inc (etc)",
239 "text/html" => ".html, .htm (etc)",
240 "image/bmp" => ".bmp, .ico",
241 "image/gif" => ".gif",
242 "image/pjpeg" => ".jpg, .jpeg",
243 "image/jpeg" => ".jpg, .jpeg",
244 "image/x-png" => ".png",
245 "audio/mpeg" => ".mp3 etc",
246 "audio/wav" => ".wav",
247 "application/pdf" => ".pdf",
248 "application/x-shockwave-flash" => ".swf",
249 "application/msword" => ".doc",
250 "application/vnd.ms-excel" => ".xls",
251 "application/octet-stream" => ".exe, .fla, .psd (etc)"
252 );
253 } else {
254 $this->registeredMimeTypes = $registeredMimeTypes;
255 }
256 }
257
258 //}}}
259 //{{{ setAllowedMimeTypes()
260
261 function setAllowedMimeTypes($allowedMimeTypes = array())
262 {
263 $this->allowedMimeTypes = $allowedMimeTypes;
264 }
265
266 //}}}
267 //{{{ setMaxFileSize()
268
269 function setMaxFileSize($maxFileSize = UPLOAD_MAX_FILE_SIZE)
270 {
271 $this->maxFileSize = $maxFileSize;
272 }
273
274 //}}}
275 //{{{ getUploadErrors()
276
277 function getUploadErrors()
278 {
279 return $this->uploadErrors; // array
280 }
281
282 //}}}
283 //{{{ printFormStart() TODO Extend HTML/Form ??
284
285 function printFormStart($formAction = "./", $formMethod = "POST", $formName = "uploadForm", $formTarget = "_self", $formInlineJavaScript="")
286 {
287 print "<FORM ACTION='" . $formAction .
288 "' METHOD='" . $formMethod .
289 "' TARGET='" . $formTarget .
290 "' NAME='" . $formName .
291 "' ENCTYPE='multipart/form-data'" . $formInlineJavaScript . ">\n";
292 }
293
294 //}}}
295 //{{{ printFormField()
296
297 function printFormField($fieldName = "") //+++
298 {
299 if(!$fieldName) {
300 $fieldName = UPLOAD_FIELD_NAME . "_" . $this->fieldCounter;
301 }
302 print "<INPUT TYPE='FILE' NAME='" . $fieldName . "'>\n";
303 print "<INPUT TYPE='HIDDEN' NAME='uploadFileName[" .
304 $this->fieldCounter . "]' VALUE='" . $fieldName . "'>\n";
305 $this->fieldCounter++;
306 }
307
308 //}}}
309 //{{{ printFormSubmit()
310
311 function printFormSubmit($name="submit", $value="Upload", $formInlineJavaScript="")
312 {
313 print "<INPUT TYPE='HIDDEN' NAME='fieldCounter' VALUE='" .
314 $this->fieldCounter . "'>\n";
315 print "<INPUT TYPE='SUBMIT'
316 NAME='" . $name . "' VALUE='" . $value . "'" . $formInlineJavaScript . ">\n";
317 }
318
319 //}}}
320 //{{{ printFormEnd()
321
322 function printFormEnd()
323 {
324 print "</FORM>\n";
325 }
326
327 //}}}
328
329 /*
330 * private methods //////////////////////////////////////////////////////////
331 */
332
333 //{{{ checkLocalEnv()
334
335 function checkLocalEnv()
336 {
337 /*
338 * this is a developer helper method and a pre-emptive strike
339 * towards any support emails ;)
340 */
341 if (UPLOAD_ENV_OUTPUT) {
342 print UPLOAD_LINE_BREAK . "::PHP Environment - php.ini settings::" . UPLOAD_LINE_BREAK;
343
344 print UPLOAD_LINE_BREAK . "(php.ini variable: file_uploads)" . UPLOAD_LINE_BREAK;
345 print "HTTP File Uploads are ";
346 if (ini_get("file_uploads")) {
347 print "[ On ]";
348 } else {
349 print "[ Off ] - This is a *major* issue. This script WILL NOT WORK!";
350 print UPLOAD_LINE_BREAK . "Please check php.ini if you have access to it, if not you cannot use this Script, sorry.";
351 }
352 print UPLOAD_LINE_BREAK . UPLOAD_LINE_BREAK . "(php.ini variable: upload_tmp_dir)";
353 print UPLOAD_LINE_BREAK . "Temp Upload Directory is set to [ " . ini_get("upload_tmp_dir") . " ]";
354 print UPLOAD_LINE_BREAK . "Note, this is a fully qualified path on the *server*";
355
356 print UPLOAD_LINE_BREAK . UPLOAD_LINE_BREAK . "(php.ini variable: upload_max_filesize)";
357 print UPLOAD_LINE_BREAK . "Maximum allowed file size is set to [ " . ini_get("upload_max_filesize") . " ]";
358
359 print UPLOAD_LINE_BREAK . UPLOAD_LINE_BREAK . "(php.ini variable: safe_mode)" . UPLOAD_LINE_BREAK;
360 print "Safe mode is ";
361 if (!ini_get("safe_mode")) {
362 print "[ Off ]";
363 } else {
364 print "[ On ] - This script will almost certainly not work!";
365 print UPLOAD_LINE_BREAK . "Please check php.ini if you have access to it, if not you cannot use this Script, sorry.";
366 }
367 }
368 }
369
370 //}}}
371 //{{{ setError()
372
373 function setError($errorType)
374 {
375 $this->uploadErrors[$this->HTTP_POST_FILES[$this->uploadFieldName]['name']][] = $errorType; //+++
376 }
377
378 //}}}
379 //{{{ getAllowedMimeTypes()
380
381 function getAllowedMimeTypes()
382 {
383 return $this->allowedMimeTypes;
384 }
385
386 //}}}
387 //{{{ getUploadImageSize()
388
389 function getUploadImageSize()
390 {
391 $dimensions = GetImageSize($this->uploadFile); //+++
392
393 /*
394 * I've been having some issues when uploading images with regards
395 * to the array passed back (i.e. No values)
396 */
397 if (UPLOAD_DEBUG_OUTPUT) {
398 print "WIDTH: " . $dimensions[0] . UPLOAD_LINE_BREAK . "HEIGHT: " .
399 $dimensions[1] . UPLOAD_LINE_BREAK;
400 }
401
402 if (!UPLOAD_ALLOW_DUBIOUS_IMAGES) {
403 $this->setError("cannotGetImageSize");
404 }
405 return array($dimensions[0],$dimensions[1]);
406 }
407
408 //}}}
409 //{{{ checkMimeType()
410
411 function checkMimeType()
412 {
413 if (!in_array($this->HTTP_POST_FILES[$this->uploadFieldName]['type'],$this->getAllowedMimeTypes())) {
414 $this->setError("mimeException");
415 return false;
416 } else {
417 return true;
418 }
419 }
420
421 //}}}
422 //{{{ checkImageSize()
423
424 function checkImageSize()
425 {
426 $this->imageSize = $this->getUploadImageSize($this->uploadFile); //+++
427
428 $imageSizeOK = true;
429
430 if ($this->imageSize[0] > $this->maxImageWidth) {
431 $imageSizeOK = false;
432 $this->setError("imageWidthException");
433 }
434
435 if ($this->imageSize[1] > $this->maxImageHeight) {
436 $imageSizeOK= false;
437 $this->setError("imageHeightException");
438 }
439 return $imageSizeOK;
440 }
441
442 //}}}
443 //{{{ copyFile()
444
445 function copyFile() // TODO check for is_writeable()
446 {
447 return move_uploaded_file($this->uploadFile, $this->uploadPath . "/" . $this->HTTP_POST_FILES[$this->uploadFieldName]['name']); //+++
448 }
449
450 //}}}
451 //{{{ checkMaxFileSize()
452
453 function checkMaxFileSize()
454 {
455 if ($this->HTTP_POST_FILES[$this->uploadFieldName]['size'] > $this->maxFileSize) { //+++ ISSUE
456 return false;
457 } else {
458 return true;
459 }
460 }
461
462 //}}}
463 //{{{ setDefaults()
464
465 function setDefaults()
466 {
467 if(!$this->registeredMimeTypes) {
468 $this->setRegisteredMimeTypes();
469 }
470
471 if(!$this->maxImageWidth || !$this->maxImageHeight) {
472 $this->setMaxImageSize();
473 }
474
475 if(!$this->maxFileSize) {
476 $this->setMaxFileSize();
477 }
478 }
479
480 //}}}
481 //{{{ processUpload()
482
483 function processUpload() { //+++
484
485 /*
486 * Some MIME types seem to be rather randomly set, I'm assuming that this
487 * is an OS issue. For example M$ Word documents have been, in my experience,
488 * application/octet-stream, text/richtext or application/msword
489 * <shrug> if UPLOAD_DEBUG_OUTPUT == true, echo the MIME type.
490 * This is arguably useful for a development environment.
491 * Disabled by default.
492 */
493 if (UPLOAD_DEBUG_OUTPUT) {
494 print UPLOAD_LINE_BREAK . "::DEBUG::" . UPLOAD_LINE_BREAK .
495 "Field Name: " . $this->uploadFieldName .
496 UPLOAD_LINE_BREAK .
497 "Mime Type: " . $this->HTTP_POST_FILES[$this->uploadFieldName]['type'] .
498 UPLOAD_LINE_BREAK .
499 "File Name: " . $this->HTTP_POST_FILES[$this->uploadFieldName]['name'] .
500 UPLOAD_LINE_BREAK .
501 "File Size: " . $this->HTTP_POST_FILES[$this->uploadFieldName]['size'] .
502 UPLOAD_LINE_BREAK .
503 "Temp Name: " . $this->HTTP_POST_FILES[$this->uploadFieldName]['tmp_name'] .
504 UPLOAD_LINE_BREAK;
505 }
506
507 $this->uploadFile = $this->HTTP_POST_FILES[$this->uploadFieldName]['tmp_name'];
508 $this->setDefaults();
509
510 if (!$this->uploadPath) {
511 $this->setError("noUploadPathException"