I've had this issue come up at least once before, and this may do the job without getting too fancy.
I also noticed that you could use str_replace much more effectively, assuming you're using a version of PHP that is new enough to support arrays for parameters 1 and 2 (see the below example). Basically, the $search array has all of the messed-up characters you're searching for and the $replace array has all of the characters you'd like to use to replace those from the $search array - in the same order.
$search = array('“', '”', '“', '”', '’', '–', '’', '“', '”', '&');
$replace = array('"', '"', '"', '"', '\'', '—', '\'', '"', '"', '&');
$result = str_replace($search, $replace, $subject);
The only stupid Microsoft one I didn't include there that is pretty common was the elipsis (...), but I'm sure you can tackle that.
I also noticed that there is a similar discussion taking place here:
http://phpbuilder.com/board/showthread.php?t=10317719
That's somewhat of a more industrial-strength solution, but worth trying if what I suggested doesn't do what you need.