Les déclarations préparées n'échappent à rien. Lorsque vous préparez une instruction, votre requête est précompilée, de sorte qu'elle n'a besoin que des espaces réservés ( ? ) à remplir. Puisqu'il n'y a aucun moyen de changer le SQL de la requête précompilée, aucun échappement n'est nécessaire.
Pour résoudre ce problème, échappez % et _ manuellement.
Ajout :
Un peu de bon sens :dans votre cas, lorsqu'un utilisateur saisit % dans une boîte de recherche, votre $search la variable contient la chaîne %%% . Comment MySQL saurait-il quel % il doit s'échapper, et lequel doit-il laisser tranquille ?