Мое окончательное решение, которое, похоже, работает во всех случаях, состоит в замене всех специальных символов по мере их ввода.
public function xmlEntities($text)
{
$search = array('&','<','>','"','\'', chr(163), chr(128), chr(165));
$replace = array('&', '<', '>', '"', ''', '£', '€', '¥');
$text = str_replace($search, $replace, $text);
return $text;
}