I've done it with some trick. Firstly I find text between body tags then I change it to html special chars and save it. After that I replace text between body tags with [TO_BE_REPLACED] and in the end I change the text to be replaced with text escaped by htmlspecialchars()
<?php
$str = '<head> <><><>& </head> <body><><>&</body>';
preg_match('/<body>(.*?)<\/body>/', $str, $match);
$special = htmlspecialchars($match[1]); // you can use html entities as well
$str = preg_replace('/<body>(.*?)<\/body>/','<body>[TO_BE_REPLACED]</body>',$str);
echo htmlspecialchars(str_replace('[TO_BE_REPLACED]', $special, $str)); //this one is only to show purpose
echo '<br>----<br>';
echo str_replace('[TO_BE_REPLACED]', $special, $str);
?>
Check demo