The challenge is to get every piece of the process to "talk" in the same character set. Here's a little script that puts a string into the DB as UTF-8, retrieves it, and outputs it to a HTML page that has UTF-8 defined as its character set:
<?php
// sample text:
$text = <<<END
! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ­ ® ¯ ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ
END;
// convert the text to UTF-8:
$text = mb_convert_encoding($text, 'UTF-8');
// connect to DB and tell it we want to use UTF-8:
$db = new mysqli('localhost','xxxxx','xxxxx','test');
$db->query("SET NAMES 'utf8'");
$db->query("SET CHARACTER SET utf8");
// put data into DB, retrieve it, then delete the row:
$db->query("INSERT INTO test (text) VALUES('" . $db->escape_string($text) . "')");
$res = $db->query('SELECT * FROM test');
$row = $res->fetch_assoc();
$output = $row['text'];
$db->query("DELETE FROM test WHERE 1");
// make sure we're using UTF-8 for our page output:
header('Content-Type: text/html;charset=UTF-8');
?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang='en'>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
<title>Untitled</title>
</head>
<body>
<h3>Before:</h3>
<p>
<?php
// show text before it was sent to DB:
echo htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
?>
</p>
<h3>After:</h3>
<p>
<?php
// show what we got from the DB:
echo htmlspecialchars($output, ENT_QUOTES, 'UTF-8');
?>
</p>
</body>
</html>