постой.
я туплю.
если ромбики - то страница действительно утф, а вот текст приходит в однобайтной кодировке.
Такое ощущение что ты данные перекодируешь перед отправкой.
Да, и никаких Location: /error.php
По стандарту скрипт который завершился с оибкой, не должен никуда перенаправлять.
Если хочется показать кастомную страницу, то пишешь опять же один раз функцию set_exception_handler и внутри неё делаешь include своей страницв ошибок, а не локейшен.
про заголовки
http заголовок выставлял - выставить мало. надо проверить, выставилось ли оно в итоге.
все остальное - бессмысленная ерунда, не надо ей заниматься
в консоли браузера во вкладке сеть смотришь реальный заголовок. там будет никакой не UTF-8
про ошибку
ты сам не понимаешь что твое "Database connection error" - это полная бессмыслица? Когда у тебя происходит ошибка, база данных тебе пишет, какая именно и в чем конкретно проблема. А ты эту бесценную информацию выкидываешь на помойку.
Кроме того, писать file_put_contents('errors_log') это еще одна бессмыслица. пхп САМ умеет логировать ошибки. Надо ОДИН раз написать в коде ini_set('log_errors',1); и все ошибк будут логироваться САМИ. и выкинуть свой бессмысленный errorHandler туда же на помойку.
При подготовке запроса mysqli_prepare никакого экранирования не происходит.
Экранирование добавляет какой-то левый говнокод, который ты зачем-то добавил в свой скрипт. Надо найти этот код и выкинуть на помойку. И все сразу начнет работать нормально.
я же написал, без отсебятины
в чарсет надо писать не то что тебе в голову ударило, а то что там должно быть.
Вот тебе пример, тренируйся копипастить.
Как только получится скопировать его в свой код без ошибок, все заработает