I'm doing a copy-pasta from My Answer to a similar question on SO:
Always remember, Filter In, Escape Out for all user supplied (or untrusted) input.
When reading user supplied data, filter it to known values. DO NOT BLACKLIST! Always always always always whitelist what you are expecting to get. If you're expecting a hex number, validate it with a regex like:
^[a-f0-9]+$. Figure out what you expect, and filter towards that. Do none of your filenames have anything but alpha, numeric and
.? Then filter to
^[a-z0-9.]+$. But don't start thinking blacklisting against things. It won't work.
When using user-data, escape it properly for the use at hand. If it's going in a database, either bind it as a parameterized query, or escape it with the database's escape function. If you're calling a shell command, escape it with
escapeshellarg(). If you're using it in a regex pattern, escape it with
preg_quote(). There are more than that, but you get the idea.
When outputting user data, escape it properly for the format you're outputting it as. If you're outputting it to HTML or XML, use
htmlspecialchars(). If you're outputting to raw headers for some reason, escape any linebreaks (
str_replace(array("\r", "\n"), array('\r', '\n'), $string)). Etc, etc, etc.
But always filter using a white-list, and always escape using the correct method for the context. Otherwise there's a significant chance you'll miss something...