In order to avoid having to do your own escaping, the stuff that needs to be escaped has to be part of the data that pdo protects, namely the bound arguments. It doesn't protect you from anything in the hard coded query.
$sql = "SELECT count(*) ".
"FROM avs_souscript ".
"WHERE num_certif =\"\" ".
"AND date_annul=\"\" ".
"AND user=:sess_user ".
"AND user!=\"\" ".
"AND num_certif LIKE :num_certif_search";
$valeur = 'azert'; //I assume this actually came from some user input
$stmt = $pdo->prepare($sql);
$stmt->bindValue(':num_certif_search', '%'.$valeur.'%');
(or alternately you could put them in the $valuer = "%{$userInput}%"; assignment, either way, they should be in the bound argument, not in the sql.
Moving this bit of silly string concat from the sql out to the php is also good practice for making a scalable application. It's much easier to scale a farm of web servers than it is to scale the database server.
new code : prepare("select * from xx where t=:tmp") then bindValue(':tmp', $val). using your suggestion this would give : bindValue(':tmp', str_replace('%', '\%', $val)). This is not clean code to me. We shouldn't use str_replace() here. There has to be another way, because this way is the principle of "escaping unwanted characters", which is a principle that **should** not exist anymore thanks to prepare() and bindValue(). I hope I've been more clear this time :) – Olivier Pons Apr 30 '10 at 09:33