2010-04-28 1 views
3

Я уже проверил ответы на такие вопросы, как this one (How do I create a PDO parameterized query with a LIKE statement in PHP). я в конечном итоге к этому решению:PDO/Php Проблема с инструкцией LIKE и специальными символами

$sql = "SELECT count(*) ". 
     "FROM mytable ". 
     "WHERE num_certif LIKE CONCAT('%',:val,'%')"; 
$valeur = 'azert'; 
$stmt = $pdo->prepare($sql); 
$stmt->bindValue(':val', $val); 

Это работает, но вот моя проблема: как я могу справиться с «%» символ? (т. е. $ valeur = '%'; возвращает все строки)?

ответ

4

Вам нужно бежать символ%,

$valeur = '\%'; 
+0

Yep. Я знал это. Но если вы подумайте о принципе: prepare() и bindValue() были созданы для оптимизации * и *, избегая таких функций, как mysql_real_escape(), escape() и т. д. Поэтому, если мне нужно сделать str_replace ('%', ' \% '...) это означало бы, что одна (важная) цель была упущена. Именно поэтому я искал элегантное решение, вместо того, чтобы чувствовать себя как возвращение к старым временам «php safe_mode». –

+0

Я не получил ваш Подготовленный оператор не имеет ничего общего с семантикой подстановочного знака. Символ подстановки не должен изменять его значение при использовании в качестве аргументов для подготовленных операторов. –

+0

Я имею в виду: old code = "select * from xx where t =". Mysql_real_escape (blabla). "
новый код: prepare ("select * from xx where t =: tmp") then bindValue (': tmp', $ val). используя ваше предложение, это даст: bindValue (': tmp', str_replace ('%', '\%', $ val)). Для меня это не чистый код. Мы не должны использовать str_replace() здесь. Должен быть другой путь, потому что этот способ - это принцип «избежания нежелательных символов», который является принципом, который ** должен быть ** не существовать больше благодаря prepare() и bindValue(). Надеюсь, на этот раз я был более ясен :) –

-1

Для того, чтобы избежать того, чтобы сделать свое собственное вытекание, материал, который должен быть экранирован должен быть частью данных, PDO защищает, а именно связанных аргументов. Он не защищает вас от чего-либо в жестко закодированном запросе.

$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.'%'); 

(или альтернативно вы можете поместить их в $valuer = "%{$userInput}%"; задания, так или иначе, они должны быть в связанном аргументе, а не в SQL.

Moving этот бит серпантин CONCAT из SQL из на PHP является хорошей практикой для создания масштабируемых приложений это гораздо проще масштабировать ферму веб-серверов, чем масштабировать сервер базы данных

+0

Большое спасибо за ответ, человек, но ... Я сделал это, поэтому мне просто не нужно больше заботиться о том, что находится в $ valeur. С вашим кодом мне нужно заботиться о том, что в $ valeur. Предположим, что $ valeur считывается из POST, и это только символ «*». Угадайте, что произойдет? Все строки вернулись. (Это то, что происходит в моем примере кода, так что ваш ответ не подходит). С вашим кодом мне придется скрывать символы, и мой вопрос таков: «Как избегать ** быть вынужденным избегать символов в коде php? Я не хочу изменять, что происходит. Pdo должен справиться с этим сам». –

+0

PDO защищает вас только от пользовательского ввода. Он предполагает, что SQL является безопасным/разумным. Если вы хотите защитить (что происходит в случае необходимости), то значения, подлежащие защите, должны пройти через параметры. Он не собирается догадываться о синтаксисе переменных подстановки и о том, как интерпретировать то, что вы хотели сделать. Вам нужно это сделать. Кажется, вы думаете, что PDO - это то, чего нет. – cabbey

+0

Из руководства: «PDO обеспечивает уровень абстракции доступа к данным, что означает, что независимо от используемой вами базы данных вы используете одни и те же функции для выдачи запросов и получения данных. PDO не обеспечивает абстракцию базы данных; он не переписывает SQL или не эмулирует отсутствующие функции. Вы должны использовать полномасштабный слой абстракции, если вам нужно это средство. ' – cabbey

0

Я добился того, что с помощью функции сравнения строк:..

WHERE INSTR(LCASE(num_certif),LCASE(:val))>0 

Я подозреваю, что производительность пострадает.

+1

Ваш комментарий правильно: производительность страдает * много *. ** ': /' ** –

+0

@Olivier Pons Спасибо за подтверждение этого. В моем случае это не имеет большого значения, и я предпочел бы использовать более элегантное решение. –

2

Примечание для пользователей PostgreSQL ... вместо функции CONCAT можно использовать

SELECT count(*) 
    FROM mytable 
    WHERE num_certif LIKE '%' || :val || '%' 
+0

Отличный совет! Благодаря! –

0

я использую что-то очень простое, как это:

$select_str = "SELECT * FROM table_x WHERE text_field LIKE '%".$value."%'"; 

    $StHandler = $this->dbHandler->prepare($select_str); 
    $StHandler->execute(); 

Вы можете использовать только один% в зависимости от того, что вы ищете. Например, если вы хотите, чтобы начать с ценностями и иметь любые символы позже, вы будете использовать». $ Значения.«% '»

Надеется, что это помогает

Смежные вопросы