Things you need to consider and watch out for:
File extensions: Webservers use the file extension to determine the MIME-Type sent to the client. You should use a whitelisting of extensions that you allow. In your case this would be image extensions.
LFI: As already mentioned by Matchu, local file inclusion can be an issue. If your application has dynamic includes that allow you to include an arbitrary file, eg. include($_GET['myfile']);
it can lead to arbitrary PHP execution. So you need to secure such includes by using basename(). This can even happen with images, since they can contain embedded comments.
MIME-Type-Detection: This is actually not very well known, and there's not much information about it. IE<8 has a feature called MIME-Type-Detection which will, if the Content-Type does not match with the content, try to guess the type by looking at the first 256 bytes. This means, if you have a PNG file called image.gif with a comment at the top that reads <script>alert('hello');</script>
, then IE<8 will think it is HTML and execute the JavaScript, leading to an XSS attack.
To prevent this issue for images you can use the approach mentioned by Williham Totland. I would suggest using getimagesize() to detect if the image is valid and to ensure that the extension matches the type.
$image_filename = 'uploaded_image.gif';
$image_extension = substr(strrchr($image_filename, '.'), 1);
$mime_mapping = array('png' => 'image/png', 'gif' => 'image/gif', 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg');
$info = getimagesize($image_filename);
if (!$info) {
exit('not an image');
}
if ($info['mime'] != $mime_mapping[$image_extension]) {
exit('wrong extension given');
}
// all checks passed
// image can be saved now
There is an article written about this issue here.