Helpful Information
 
 
Category: Post a PHP snippet
file upload class

drive crashed on a forum I run, gave me the opportunity to re-write some old slop code.

The class:

<?php

define('FILE_UPLOAD_ERR_PATH', 10);
define('FILE_UPLOAD_ERR_SIZE', 11);
define('FILE_UPLOAD_ERR_TYPE', 12);
define('FILE_UPLOAD_ERR_INVALID', 13);

class File_upload {

var $path;

var $_allowed;
var $_max_size;

var $_is_error; //(bool)
var $_errno;

function File_upload() {
$this->_allowed_mime = array();
$this->_allowed_ext = array();
$this->_is_error = false;
$this->_errno = 0;
$this->path = '';
$this->_max_size = 100000;
}

function allow($type) {

switch ($type) {
case 'images' :
$this->_allowed['image/gif'] = array('gif');
$this->_allowed['image/png'] = array('png');
$this->_allowed['image/jpeg'] = array('jpg', 'jpeg');
$this->_allowed['image/pjpeg'] = $this->_allowed['image/jpeg'];
break;
}
}

function add_allowed($mime, $ext) {
$this->_allowed[$mime] = $ext;
}
function get_extensions() {
$all_ext = array();
foreach ($this->_allowed as $exts)
foreach($exts as $ext)
$all_ext[] = $ext;
return $all_ext;
}

function upload($file) {
extract($file);
// $type, $name, $tmp_name, $size, $error

if (UPLOAD_ERR_OK!=$error) {
$this->_is_error = true;
$this->_errno = $error;
return false;
}
$path = $this->get_path();
if (!is_dir($path) || $path=='') {
$this->_is_error = true;
$this->_errno = FILE_UPLOAD_ERR_PATH;
return false;
}
if ($size>$this->get_max_size()) {
$this->_is_error = true;
$this->_errno = FILE_UPLOAD_ERR_SIZE;
return false;
}

if (!isset($this->_allowed[$type])) {
$this->_is_error = true;
$this->_errno = FILE_UPLOAD_ERR_TYPE;
return false;
}

$ext = strtolower(File_upload::file_extension($name));
if (!$ext || !in_array($ext, $this->_allowed[$type])) {
$this->_is_error = true;
$this->_errno = FILE_UPLOAD_ERR_TYPE;
return false;
}

if (!is_uploaded_file($tmp_name)) {
$this->_is_error = true;
$this->_errno = FILE_UPLOAD_ERR_INVALID;
return false;
}


// cleanup file name to be cool
$name = preg_replace('/[^a-zA-Z0-9. ]+/','_',$name);

// auto rename
$name = File_upload::unique_filename($path, $name);

move_uploaded_file($tmp_name, $path.$name);

// extra paranoid to prevent any execution ever
chmod($path.$name, 0644);

return $name;
}

function upload_multiple($files) {
$total = count($files['name']);
$filenames = array();
for ($x=0; $x<$total; $x++) {
$filenames[] = $this->upload( array(
'name' => $files['name'][$x],
'type' => $files['type'][$x],
'tmp_name' => $files['tmp_name'][$x],
'error' => $files['error'][$x],
'size' => $files['size'][$x],
));
}
return $filenames;
}

function file_extension($file) {
$ext = array_pop(explode(".", $file));
if ($ext==$file)
return false;
return $ext;
}

function set_max_size($size=0) { $this->_max_size = $size; }
function get_max_size() { return $this->_max_size; }

function get_error() {
switch ($this->_errno) {
case UPLOAD_ERR_INI_SIZE :
return 'The uploaded file exceeds the upload_max_filesize directive in php.ini.';
case UPLOAD_ERR_FORM_SIZE :
return ' The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.';
case UPLOAD_ERR_PARTIAL :
return 'The uploaded file was only partially uploaded.';
case UPLOAD_ERR_NO_FILE :
return 'No file was uploaded.';
case UPLOAD_ERR_NO_TMP_DIR :
return 'Missing a temporary folder.';
case UPLOAD_ERR_CANT_WRITE :
return 'Failed to write file to disk.';
case FILE_UPLOAD_ERR_PATH :
return 'Upload path is not a directory.';
case FILE_UPLOAD_ERR_SIZE :
return 'The uploaded file exceeds the max file size.';
case FILE_UPLOAD_ERR_TYPE:
return 'The uploaded file type is invalid.';
case FILE_UPLOAD_ERR_INVALID:
return 'The file is not an actual uploaded file.';
}
return 'Unknown error ('.intval($this->errno).')';
}

function is_error() { return $this->_is_error; }
function set_path($path) { $this->path = $path; }
function get_path() { return $this->path; }

function unique_filename($path, $name) {

if (!file_exists($path.$name))
return $name;

return File_upload::unique_filename($path, md5(time().rand()).$name);
}

}

?>


example code usage for actually uploading the file:

<?php

$is_upload = $_GET['upload'] && !empty($_FILES);
if ($is_upload) {
$upload = new File_upload();
$upload->allow('images');
$upload->set_path('/home/user/public_html/uploads/');
$upload->set_max_size(500000);
$filename = $upload->upload($_FILES['file']);
$error = false;
if ($upload->is_error()) {
$error = true;
$errstr= $upload->get_error();
}
}

?>


example code needed for uploading a single file:

<h1>Image Upload</h1><br />
<form enctype="multipart/form-data" method="POST" action="?mode=upload&upload=1">
<input type="hidden" name="MAX_FILE_SIZE" value="500000" />
<table width="300" cellpadding="3" cellspacing="0" border="0">
<tr>
<td><input name="file" type="file" size="50"></td>
</tr>
<tr>
<td align="right">
<input type="submit" value="Upload Image">
</td>
</tr>
</table>
</form>
<p style="font-size:8pt;">
Allowed file extensions are JPG, JPEG PNG, GIF and max file size is 500kb
</p>
<?php
if ($is_upload && $error) {
print '<strong>Error: '.$errstr.'</strong><br />';
} else if ($is_upload) {
$image = _URL_.'uploads/'.$filename;
print '<input type="text" size="'.strlen($image).'" value="'.$image.'"><br />';
print '<img src="'.$image.'">';
}
?>


it will need to be modified to allow other file types.. so hopefully someone can reply to this thread for whatever their need is and I can update it ... it is currently used for uploading images.

Multiple files by request:
I had to revise the main class to accept multiple files (upload_multiple method). copy and paste the updated class.

example usage php for doing the actual upload:

<?php
$is_upload = $_GET['upload'] && !empty($_FILES);
$max_size = 250000;
$max_uploads = 5;
if ($is_upload) {
if (count($_FILES['file']['name'])<=$max_uploads) {
$upload = new File_upload();
$upload->allow('images');
$upload->set_path('/home/ecnet/public_html/uploads/');
$upload->set_max_size($max_size);

$files = $upload->upload_multiple($_FILES['file']);
$error = false;
if ($upload->is_error()) {
$error = true;
$errstr= $upload->get_error();
}
} else {
$error = true;
$errstr= 'Trying to upload to many files';
}
}
?>


example usage as far as HTML etc


<h1>Image Upload</h1><br />
<script type="text/javascript"><!--
var gFiles = 0;
function addFile() {
var tr = document.createElement('tr');
tr.setAttribute('id', 'file-' + gFiles);
var td = document.createElement('td');
td.innerHTML = '<input type="file" size="30" name="file[]"><span onclick="removeFile(\'file-' + gFiles + '\')" style="cursor:pointer;">Remove</span>';
tr.appendChild(td);
document.getElementById('files-root').appendChild(tr);
gFiles++;
}
function removeFile(aId) {
var obj = document.getElementById(aId);
obj.parentNode.removeChild(obj);
}

--></script>
<form enctype="multipart/form-data" method="POST" action="?mode=misc&action=upload&upload=1">
<span onclick="addFile()" style="cursor:pointer;cursor:hand;">Add</span>
<input type="hidden" name="MAX_FILE_SIZE" value="<?php echo $max_size; ?>" />
<table><tbody id="files-root">
<tr><td><input type="file" name="file[]" size="30"></td></tr>
</table>
<input type="submit" value="Upload Image">
</form>
<p style="font-size:8pt;">
allowed extensions are: <strong>JPG, JPEG PNG, GIF</strong>; max size per file: <strong>250kb</strong>; max number of files per upload <strong><?php echo $max_uploads; ?>
</p>
<?php
if ($is_upload && $error) {
print '<strong>Error: '.$errstr.'</strong><br />';
} else if ($is_upload) {
foreach ($files as $file) {
$image = _URL_.'uploads/'.$file;
print '<input type="text" size="'.strlen($image).'" value="'.$image.'"><br />';
print '<img src="'.$image.'">';
}
}


?>

js code for file add/remove located here:
http://www.codingforums.com/showthread.php?t=65390

edit:
Thu Feb 16 18:11:12 CST 2006 - bug fix on images, missing image/pjpeg mime

can this be used to upload multiple files?

can this be used to upload multiple files?

yes, it could, I'll write up an example later today when I have time

ok, refer to top post

to do(or to not do, depending on how it goes ;)):
- make sure filename is completely unique by checking if file_exists again and again until it passes
- better way to set allowed file types and a get method to return them as an array.
- use is_uploaded_file http://us3.php.net/manual/en/function.is-uploaded-file.php
edit, i just felt like doing it tonight (updated top post again)

some minor updates.. passes E_ALL now.. and E_STRICT eventually.

<?php

if (!defined('UPLOAD_ERR_OK'))
define('UPLOAD_ERR_OK', 0);

if (!defined('UPLOAD_ERR_INI_SIZE'))
define('UPLOAD_ERR_INI_SIZE', 1);

if (!defined('UPLOAD_ERR_FORM_SIZE'))
define('UPLOAD_ERR_FORM_SIZE', 2);

if (!defined('UPLOAD_ERR_PARTIAL'))
define('UPLOAD_ERR_PARTIAL', 3);

if (!defined('UPLOAD_ERR_NO_FILE'))
define('UPLOAD_ERR_NO_FILE', 4);

if (!defined('UPLOAD_ERR_NO_TMP_DIR'))
define('UPLOAD_ERR_NO_TMP_DIR', 6);

if (!defined('UPLOAD_ERR_CANT_WRITE'))
define('UPLOAD_ERR_CANT_WRITE', 7);

define('FILE_UPLOAD_ERR_PATH', 10);
define('FILE_UPLOAD_ERR_SIZE', 11);
define('FILE_UPLOAD_ERR_TYPE', 12);
define('FILE_UPLOAD_ERR_INVALID', 13);

class File_upload {

var $path;

var $_allowed;
var $_max_size;

var $_is_error; //(bool)
var $_errno;

function File_upload() {
$this->_allowed_mime = array();
$this->_allowed_ext = array();
$this->_is_error = false;
$this->_errno = 0;
$this->path = '';
$this->_max_size = 100000;
}

function allow($type) {

switch ($type) {
case 'images' :
$this->_allowed['image/gif'] = array('gif');
$this->_allowed['image/png'] = array('png');
$this->_allowed['image/jpeg'] = array('jpg', 'jpeg');
$this->_allowed['image/pjpeg'] = $this->_allowed['image/jpeg'];
break;
case 'text' :
$this->_allowed['plain/text'] = array('txt');
$this->_allowed['text/plain'] = $this->_allowed['plain/text'];
break;
}
}

function add_allowed($mime, $ext) {
$this->_allowed[$mime] = $ext;
}
function get_extensions() {
$all_ext = array();
foreach ($this->_allowed as $exts)
foreach($exts as $ext)
$all_ext[] = $ext;
return $all_ext;
}

function upload($file) {
extract($file);
// $type, $name, $tmp_name, $size, $error

if (UPLOAD_ERR_OK!=$error) {
$this->_is_error = true;
$this->_errno = $error;
return false;
}
$path = $this->get_path();
if (!is_dir($path) || $path=='') {
$this->_is_error = true;
$this->_errno = FILE_UPLOAD_ERR_PATH;
return false;
}
if ($size>$this->get_max_size()) {
$this->_is_error = true;
$this->_errno = FILE_UPLOAD_ERR_SIZE;
return false;
}

if (!isset($this->_allowed[$type])) {
$this->_is_error = true;
$this->_errno = FILE_UPLOAD_ERR_TYPE;
return false;
}

$ext = strtolower(File_upload::file_extension($name));
if (!$ext || !in_array($ext, $this->_allowed[$type])) {
$this->_is_error = true;
$this->_errno = FILE_UPLOAD_ERR_TYPE;
return false;
}

if (!is_uploaded_file($tmp_name)) {
$this->_is_error = true;
$this->_errno = FILE_UPLOAD_ERR_INVALID;
return false;
}


// cleanup file name to be cool
$name = preg_replace('/[^a-zA-Z0-9. ]+/','_',$name);

// auto rename
$name = File_upload::unique_filename($path, $name);

move_uploaded_file($tmp_name, $path.$name);

// extra paranoid to prevent any execution ever
chmod($path.$name, 0644);

return $name;
}

function upload_multiple($files) {
$total = count($files['name']);
$filenames = array();
for ($x=0; $x<$total; $x++) {
$filenames[] = $this->upload( array(
'name' => $files['name'][$x],
'type' => $files['type'][$x],
'tmp_name' => $files['tmp_name'][$x],
'error' => $files['error'][$x],
'size' => $files['size'][$x],
));
}
return $filenames;
}

function file_extension($file) {
$ext = array_pop(explode(".", $file));
if ($ext==$file)
return false;
return $ext;
}

function set_max_size($size=0) { $this->_max_size = $size; }
function get_max_size() { return $this->_max_size; }

function get_error() {
switch ($this->_errno) {
case UPLOAD_ERR_INI_SIZE :
return 'The uploaded file exceeds the upload_max_filesize directive in php.ini.';
case UPLOAD_ERR_FORM_SIZE :
return ' The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.';
case UPLOAD_ERR_PARTIAL :
return 'The uploaded file was only partially uploaded.';
case UPLOAD_ERR_NO_FILE :
return 'No file was uploaded.';
case UPLOAD_ERR_NO_TMP_DIR :
return 'Missing a temporary folder.';
case UPLOAD_ERR_CANT_WRITE :
return 'Failed to write file to disk.';
case FILE_UPLOAD_ERR_PATH :
return 'Upload path is not a directory.';
case FILE_UPLOAD_ERR_SIZE :
return 'The uploaded file exceeds the max file size.';
case FILE_UPLOAD_ERR_TYPE:
return 'The uploaded file type is invalid.';
case FILE_UPLOAD_ERR_INVALID:
return 'The file is not an actual uploaded file.';
}
return 'Unknown error ('.intval($this->errno).')';
}

function is_error() { return $this->_is_error; }
function set_path($path) { $this->path = $path; }
function get_path() { return $this->path; }

function unique_filename($path, $name) {

if (!file_exists($path.$name))
return $name;

return File_upload::unique_filename($path, md5(time().rand()).$name);
}

}


?>










privacy (GDPR)