mysql_escape_string() is an alright method of preventing SQL injection, parameterized queries are a much better approach.
mysql_escape_string() is still not perfect; for example the following is vulnerable to SQL injection:
$q="select * from user where uid=".mysql_real_escape_string($_GET[uid]);
The PoC is simple:
Use parameterized queries!
htmlspecialchars() will prevent some types of XSS. They won't prevent XSS in DOM events. This method won't prevent injecting events for example:
htmlspecialchars($var,ENT_QUOTES) is a little better, because it prevents DOM event injection, but you can still hijack an event (see the "it's a DOM event" blog post).
So these two functions will partially mitigate two vulnerabilities out of a couple thousand. To call out some of the big offenders that will not be mitigated by
htmlentites() we have: Directory traversal (and LFI/RFI for PHP), LDAP injection, XPATH injection, HTTP Response Splitting, Log file injection... and the list goes on.
Escaping input has nothing to do with removing "forbidden characters". It's about converting escape characters (or sequences of characters) into their "character literal" such that attacker controlled data is still interpreted as data, and not executable code.