As I understand it now the function htmlspecialchars() acts on what is in the database to display it in a HTML textarea. And when this text is submitted htmlspecialchars_decode() reverses the substitution. This indeed should not surreptitiuosly alter untouched text in the database. So I still don't understand how this could have led to corruption: ... It seems like htmlspecialchars_decode() has been acting twice on it
To check on this, I first ran a script that called htmlspecialchars and htmlspecialchars_decode alternately, and then called htmlspecialchars_decode twice in a row. Calling them alternately did no damage, but calling htmlspecial_chars twice in a row did. I then tested the submission scripts with the same text I had used in the test script, and it displayed like it would with two calls to htmlspecialchars_decode.
Through some testing, I determined that submitting a form does an implicit call to htmlspecialchars_decode. So, I removed the explicit calls to that function. I also determined that not calling htmlspecialchars on the text that should be displayed in a TEXTAREA will modify it. So, this is form behavior and not CKEditor-specific behavior. In light of this, I changed the scripts to always call htmlspecialchars before displaying text in a form and to never call htmlspecialchars_decode. With these changes, you should be able to use HTML entities without them getting corrupted.
To check on this, I first ran a script that called htmlspecialchars and htmlspecialchars_decode alternately, and then called htmlspecialchars_decode twice in a row. Calling them alternately did no damage, but calling htmlspecial_chars twice in a row did. I then tested the submission scripts with the same text I had used in the test script, and it displayed like it would with two calls to htmlspecialchars_decode.
Through some testing, I determined that submitting a form does an implicit call to htmlspecialchars_decode. So, I removed the explicit calls to that function. I also determined that not calling htmlspecialchars on the text that should be displayed in a TEXTAREA will modify it. So, this is form behavior and not CKEditor-specific behavior. In light of this, I changed the scripts to always call htmlspecialchars before displaying text in a form and to never call htmlspecialchars_decode. With these changes, you should be able to use HTML entities without them getting corrupted.