Handling file types - safely
Posted: Sat Mar 18, 2006 4:32 am
Is it just me, or does file handling take quite a lot of effort? What I'm after is some sort of functionality that will tell me what file has just been uploaded. I have put up a couple of posts about this and had some great responses. With those responses and some other info I've searched for, I have cobbled together a class that determines what file type has just been uploaded.
I haven't tested it much, but it seems to work ok.
And here's some example usage
You can also add file types to check:
Are there any scripts that do this better out there? There are a few floors with this, but it works at the moment - suggestions / ideas welcome
I haven't tested it much, but it seems to work ok.
Code: Select all
/*
THIS CLASS IS DESIGNED TO CHECK THE FILE TYPE OF AN UPLOADED FILE
WITHOUT DEPENDING ON THE INFORMATION SENT BY THE BROWSER.
THIS CLASS HAS NOT BEEN TESTED VERY MUCH - SO DON'T USE IT FOR REAL... YET
*/
class file_type{
# ADD MORE OF THESE FROM http://filext.com/ #
var $idents = array(
"application/pdf"=>"25 50 44 46 2D 31 2E",
"application/msword"=>"D0 CF 11 E0 A1 B1 1A E1",
"application/zip"=>"50 4B 03 04"
);
#####################################################
# DETERMINES THE FILE TYPE
#####################################################
function get_file_type ($file){
# IS THE FILE AN IMAGE FILE #
if($file_info = getimagesize($file)){
return $file_info['mime'];
# IS THE FILE TYPE LISTED IN OUR CATALOGUED TYPES $this->idents #
}else if($file_type = $this->get_ident($file,$this->idents)){
return $file_type;
# IS THE UPLOADED FILE A TEXT FILE #
}else if($this->is_text_file($file)){
return "text/plain";
# NOT A RECOGNISED FILE TYPE BY THIS CLASS #
}else{
return false;
}
}
#####################################################
# GET OTHER FILE TYPES FROM $this->idents
#####################################################
# Check post http://forums.devnetwork.net/viewtopic. ... 028#246028 #
function get_ident($file,$hex_idents){
# OPEN THE FILE FOR READING (BINARY) #
$fp=fopen($file, 'rb');
if(!$fp){
return null;
}
# GET THE (converted to bin) HEX IDENTIFIER LENGTH TO EXTRACT THAT AMOUNT OF BYTES FROM OUR UPLOADED FILE #
$bin_idents = array_map(array($this, 'condense'), $hex_idents);
$size = array_map('strlen', $bin_idents);
$read = max($size);
# STORE THE READ DATA #
$data = fread($fp, $read);
fclose($fp);
# CHECK OUR DATA AGAINST THE ARRAY OF CATALOGUED FILE TYPES $this->idents #
foreach($bin_idents as $type => $signature){
$found = (substr($data, 0, strlen($signature)) === $signature);
if($found){
break;
}
}
return($found ? $type : false);
}
function condense($value){
return pack('H*',str_replace(' ','',$value));
}
#####################################################
# CHECKS WHETHER THE FILE IS A PLAIN TEXT FILE
#####################################################
# Check http://forums.devnetwork.net/viewtopic.php?t=23517 #
function is_text_file($filename){
if(!is_readable($filename)) return false;
$data = file_get_contents($filename);
$bad = false;
for( $x = 0 , $y = strlen($data); !$bad && $x < $y; $x++){
$bad = ( ord($data{$x}) > 127 );
}
return!$bad;
}
#####################################################
# CREATES NEW FILE NAME WITH ONLY ALPHA NUMERIC CHARS
#####################################################
function websafe_rename($string, $mime_type){
// remove the current extenion
$chop_to = strlen(strrchr($string, "."));
$string = substr($string,0,(strlen($string)-$chop_to));
// remove non-alpha characters
$new_string=ereg_replace("[^A-Za-z0-9]","_",$string);
$final_string=ereg_replace("[_]+","_",$new_string);
// get the correct extension type for the file
$extension=$this->get_mime_extension($mime_type);
return $final_string.$extension;
}
#####################################################
# GETS THE CORRECT EXTENSION FOR FILE TYPES
#####################################################
function get_mime_extension($mime_type){
$mime = array('application/msword'=>'.doc','image/gif'=>'.gif','image/jpeg'=>'.jpg','application/pdf'=>'.pdf','image/png'=>'.png','application/zip'=>'.zip','text/plain'=>'.txt');
return $mime[$mime_type];
}
}//end classAnd here's some example usage
Code: Select all
$uploaded_file_type = new file_type;
# GET THE MIME TYPE #
$mime_type = $uploaded_file_type->get_file_type($_FILES['formfile']['tmp_name']);
if(!$mime_type){
echo "Sorry, not really sure what you've uploaded.";
}else{
# CREATE A NEAT NEW NAME + EXTENSION #
$new_file_name = $uploaded_file_type->websafe_rename($_FILES['formfile']['name'], $mime_type);
echo "Your file ( ".$new_file_name." ) is ".$mime_type."<br />";
}Code: Select all
$uploaded_file_type->idents["application/zip"] = "50 4B 03 04";Are there any scripts that do this better out there? There are a few floors with this, but it works at the moment - suggestions / ideas welcome