PDO将错误的日文字符插入数据库

Background


I'm currently writing a small web application for myself to test my Japanese. It consists of getting to see a Japanese word, and then giving the correct translation in Dutch. I have a small set-up where I can specify a Japanese word with the Dutch translation, and it will get inserted in the database.

Problem


When inserting certain Japanese characters, such as "お" (or "O" for those wondering) it gets inserted in the database as "ず" (or "Zu"). There are more characters which also get transformed, but I forgot which (I cleared the database to see if certain solutions worked).

What have I tried


I've made sure that all the things I think need to be UTF-8 are set to UTF-8. I've set the following to UTF-8:
  • HTML page header:
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  • PHP header (very first line):
    header('Content-Type: text/html; charset=utf-8');
  • The MySQL table japanese_words:
    ALTER TABLE japanese_words CONVERT TO CHARACTER SET utf8;
  • PDO encoding:
    $db = new PDO('mysql:host=localhost;dbname=japanese;charset=utf8', '****', '****');
    And tried:
    $db->exec("set names utf8");

Specifying the Japanese word works in PHP. I can dump, and regularly show, the Japanese words in my webpage. This means my HTML and PHP are set up correctly. So there are no errors before inserting it in the database.

When I insert the Japanese words manually in the database it works.

The characters get "transformed" when I try to insert it in to the database using PDO.

Trying to show the query PDO generates doesn't work. I get the query with the bound parameter and not the actual word.

Code


add_word.php (this all works fine):
$japanese_word = $_POST['japanese_word'];
$dutch_word = $_POST['dutch_word'];

$word = new Word();
$word->setDutchWord($dutch_word);
$word->setJapaneseWord($japanese_word);

$wordDAO = new WordDAO($db);
$success = $wordDAO->addWord($word);

WordDAO method, where I think the problem is (or somewhere between there and the actual MySQL database):

$query = "insert into `japanese_words` (`word`) values(:word)";
$stmt = $this->db->prepare($query);
$stmt->bindParam(':word', strtolower($word->getJapaneseWord()));
$stmt->execute();
$japanese_word_id = $this->db->lastInsertId();

Question


What am I doing wrong here? Did I forget to set up more encodings, or specify a particular PDO setting? Any help is appreciated.

The problem is I was using strtolower() in my bindParam. This changed the values of the Japanese words. Changing the code to the following worked:

$query = "insert into `japanese_words` (`word`) values(:word)";
$stmt = $this->db->prepare($query);
$stmt->bindParam(':word', $word->getJapaneseWord());
$stmt->execute();
$japanese_word_id = $this->db->lastInsertId();

Damn my blatant copy/pasting (of course I found out as soon as I posted the question).

PDO

mb_internal_encoding('UTF-8');

$dbh = new PDO("mysql:host=localhost;dbname=japanese;charset=utf8");
$dbh->exec("set names utf8");

$query = "insert into `japanese_words` (`word`) values(:word)";
$stmt = $this->db->prepare($query);

// use mb_* function for japanese string 
$stmt->bindParam(':word', mb_strtolower($word->getJapaneseWord()));

$stmt->execute();

$japanese_word_id = $this->db->lastInsertId();

Change Charset and Collation of a Database and Table

ALTER DATABASE japanese CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE japanese_words CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci; 

Set the charset of your page

<?php
ini_set("default_charset", "UTF-8");
header('Content-type: text/html; charset=UTF-8');
?>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
...

You may have to check that your files are saved with the right charset!