Hello there. Its my first post here and yes, Im a newbie, so bear with me. I've been searching for over a week over the internet the solution for this problem and I just don't get it: I have a webpage where anyone can upload a picture for a profile. I tried to make a safety upload with the following "secure" methods:
- Checking extension
- Checking type with $_FILE['file'][type]
- Cleaning the name
- Renaming it randomly on upload
- Storing it in an "outside of the wwwroot" folder
- Adding an .htaccess file with this code inside:
<Directory /_1co-ma--vi1_n/>
deny from all
<Files ~ "\w+.(gif|jpe?g|png)$">
order deny,allow
allow from all
</Files>
<Directory>
The random name of the file stores in MYSQL database and from there I pretend take it as a reference to display the picture. I know I should make some "mime validation" but I just cant get magic.mime working in my shared server. My questions in short are:
- Is this validation enough to avoid malicious code injection?
- How can I display that picture stored in an "outside wwwroot" folder? (The files names are something like 1dwe3402349f09830239098402938089422 with out any extenuation)
- In case that some picture passed all this validation with a comment on it or a hidden malicious code, will be executed when i display it?
Thank you and any help will be very much appreciate!
Here is the code:
$foto=$_POST['archivo'];
// Check post_max_size (http://us3.php.net/manual/en/features.file-upload.php#73762)
$POST_MAX_SIZE = ini_get('post_max_size');
$unit = strtoupper(substr($POST_MAX_SIZE, -1));
$multiplier = ($unit == 'M' ? 1048576 : ($unit == 'K' ? 1024 : ($unit == 'G' ? 1073741824 : 1)));
if ((int)$_SERVER['CONTENT_LENGTH'] > $multiplier*(int)$POST_MAX_SIZE && $POST_MAX_SIZE)
HandleError('POST exceeded maximum allowed size.');
// Settings
$save_path = chdir('../MyFolder/');
$upload_name = 'archivo'; // change this accordingly
$max_file_size_in_bytes = 1048576; // 1MB in bytes
$whitelist = array('jpg', 'png', 'gif'); // Allowed file extensions
$backlist = array('php', 'php3', 'php4', 'phtml','exe'); // Restrict file extensions
$valid_chars_regex = 'A-Za-z0-9_-s ';// Characters allowed in the file name (in a Regular Expression format)
// Other variables
$MAX_FILENAME_LENGTH = 260;
$file_name = $_FILES['archivo']['name'];
$file_extension = '';
$uploadErrors = array(
0=>'There is no error, the file uploaded with success',
1=>'Ha excedido el tamaño máximo permitido por el servidor <A HREF="javascript:history.go(-1)">Volver</a>',
2=>'Ha excedido el tamaño máximo permitido por la forma <A HREF="javascript:history.go(-1)">Volver</a>',
3=>'El archivo se ha salvado sólo parcialmente <A HREF="javascript:history.go(-1)">Volver</a>',
4=>'Debe adjuntar una foto para continuar <A HREF="javascript:history.go(-1)">Volver</a>',
6=>'No se ha encontrado el archivo temporal <A HREF="javascript:history.go(-1)">Volver</a>'
);
// Validate the upload
if (!isset($_FILES[$upload_name]))
HandleError('No upload found in $_FILES for ' . $upload_name);
else if (isset($_FILES[$upload_name]['error']) && $_FILES[$upload_name]['error'] != 0)
HandleError($uploadErrors[$_FILES[$upload_name]['error']]);
else if (!isset($_FILES[$upload_name]['tmp_name']) || !@is_uploaded_file($_FILES[$upload_name]['tmp_name']))
HandleError('Upload failed is_uploaded_file test.');
else if (!isset($_FILES[$upload_name]['name']))
HandleError('File has no name.');
// Validate the file size (Warning: the largest files supported by this code is 2GB)
$file_size = @filesize($_FILES[$upload_name]['tmp_name']);
if (!$file_size || $file_size > $max_file_size_in_bytes)
HandleError('El archivo excede el límite máximo <A HREF="javascript:history.go(-1)">Volver</a>');
if ($file_size <= 0)
HandleError('El archivo es demasiado pequeño');
// Validate its a MIME Images (Take note that not all MIME is the same across different browser, especially when its zip file)
if(!eregi('image/', $_FILES[$upload_name]['type']))
HandleError('Por favor suba un archivo válido <A HREF="javascript:history.go(-1)">Volver</a>');
// Validate that it is an image
$imageinfo = getimagesize($_FILES[$upload_name]['tmp_name']);
if($imageinfo['mime'] != 'image/gif' && $imageinfo['mime'] != 'image/jpeg' && $imageinfo['mime'] != 'image/png' && isset($imageinfo))
HandleError('Lo sentimos, solo se aceptan archivos JPG, PNG y GIFF <A HREF="javascript:history.go(-1)">Volver</a>');
// Validate file name (for our purposes we'll just remove invalid characters)
$fname = $_FILES[$upload_name]['name'];
$file_name_cleaned = preg_replace("/[^a-zA-Z0-9\.]/", "", strtolower($fname));
if (strlen($file_name_cleaned) == 0 || strlen($file_name_cleaned) > $MAX_FILENAME_LENGTH)
HandleError('El nombre del archivo es inválido <A HREF="javascript:history.go(-1)">Volver</a>');
// Validate that we won't over-write an existing file
if (file_exists($save_path . $file_name_cleaned))
HandleError('Un archivo con ese nombre ya existe <A HREF="javascript:history.go(-1)">Volver</a>');
// Validate file extension
$ext = strtolower(end(explode('.', $_FILES['archivo']['name'])));
if (in_array($ext, $whitelist) === false){
HandleError('La extención del archivo que intenta subir no esta permitida <A HREF="javascript:history.go(-1)">Volver</a>');
}
// Rename the file to be saved
$file_name_random = md5($file_name_cleaned. time());
// Verify! Upload the file
if (!@move_uploaded_file($_FILES[$upload_name]['tmp_name'], $save_path.$file_name_random)) {
HandleError('El archivo no ha podido ser guardado');
}
/* Handles the error output. */
$message='Este archivo parece corrupto. No es posible guardarlo <A HREF="javascript:history.go(-1)">Volver</a>';
function HandleError($message) {
echo $message;
exit(0);
}
/*
*********************************************
*************Mysqul conection****************
*********************************************
*/
include('database_connection.php');
/*
*********************************************
**************User validation****************
*********************************************
*/
$result = mysql_query("select * from MyTable WHERE user LIKE '%$user%'");
$num_rows = mysql_num_rows($result);
if($num_rows > 0)
{
HandleError('The user name you choose already exist <A HREF="javascript:history.go(-1)">Volver</a>');
}
/*
*********************************************
***********Curriculum validation*************
*********************************************
*/
$curriculum_lenght = strlen($curriculum);
if ($curriculum_lenght > 600) {
HandleError('Your curriculum lenght exide 600 characters <A HREF="javascript:history.go(-1)">Volver</a>');
}