One function cannot fully protect you from script injection. Consider the following program:
<?php
if(isset($_POST['height']))
$height=htmlspecialchars($_POST['height'], ENT_QUOTES, 'UTF-8');
else $height=200;
if(isset($_POST['width']))
$height=htmlspecialchars($_POST['width'], ENT_QUOTES, 'UTF-8');
else $width=300;
echo("
<!DOCTYPE html>
<html>
<body>
<iframe src='whatever' height=$height width=$width>
</iframe>
</body>
</html>
");
The input is sanitized, but javascript will still be executed through a simple injection vector like:
300 onload=alert(String.fromCharCode(88)+String.fromCharCode(83)+String.fromCharCode(83))
You still need to quote your attributes or you are vulnerable like this example.
Another semi-common injection vector exists when user input is echoed into javascript comments, and you can inject new lines or close the comment. I blame it on the 'this shit doesn't work as it should, but let's keep it around in a comment'-style of development.
Note: The XSS protection of many browsers will not run my simple example. If you want to try it use one without protection, or find a vector that defeats it (not sure if there is one for e.g. Chrome).