За последние 24 часа нас посетили 30182 программиста и 1815 роботов. Сейчас ищут 835 программистов ...

Экранирование слешей для вставки в LIKE

Тема в разделе "Прочие вопросы по PHP", создана пользователем vb, 16 ноя 2006.

  1. vb

    vb Активный пользователь

    С нами с:
    6 июн 2006
    Сообщения:
    911
    Симпатии:
    0
    Адрес:
    Saint-Petersburg
    Добрый день,

    Сегодня столкнулся, как мне кажется, с совершенно идиотской проблемой, но чувствую что начал "пробуксовывать"...

    Топик можно одновременно отнести к базам регуляркам и блондинкам, поэтому вычислив среднее решил запостить сюда :)

    Суть следующая:
    1. Windows Server 2000 :)
    2. Адреса вида C:\test\ - обратите внимание на слеши
    3. Адреса нужно записать в базу.
    4. Нужно делать выборку из базы по LIKE

    А теперь попорядку:
    Очень хочется писать адреса в базу "как есть", то есть именно C:\test\, а не c:/test/ или /test/ или еще как.

    Допустим в базе имеется три записи в колонке path:
    c:\test\
    c:\test\1\
    c:\test\test\

    вставка нормально проходит после обработки mysql_escape_string();

    Далее нам нужно переименовать C:\test\ следовательно и все под дирректории, то есть C:\test\1\ и C:\test\test\
    Для этого нужно сделать выборку записей, где теоретически в WHERE можем записать, то же что и при вставке:
    Код (Text):
    1. "SELECT path FROM table WHERE path LIKE '".mysql_escape_string($path)."%' GROUP BY path"
    Тут баг №1
    при $path == 'C:\test\'; количество записей в результате = 0
    при этом запрос
    Код (Text):
    1. "SELECT path FROM table WHERE path = '".mysql_escape_string($path)."' GROUP BY path"
    вернет 1 запись.
    Объясняется он тем что,
    \test обрабатывается как \t и строка est

    Следовательно нам нужно сделать экранирование этого слеша:
    после mysql_escape_string адрес уже имеет вид C:\\test\\,
    теперь нам нужно еще его преобразовать в C:\\\\test\\, и так подставлять по два слеша перед каждым символом после слеша.

    Собственно место, где я начал подбуксовывать - до запроса делаем обработку:
    $path = preg_replace ("'(\\)([^\\]+)'", '\\1\\1\\2', mysql_escape_path($path));
    По логике регулярка должна найти \ после которого стоит не \ и дописать еще один \.
    Вопрос 1:
    [^\\]+ - конструкция не работает, как она будет работать?
    Вопрос 2:
    Более человечески можно записать в '\\1\\1\\2' вместо \\1 просто \ ?

    Вариантов для обхода этих вопросов масса, но хочется пройти по прямой, потому и задаю этот вопрос.

    С уважением, vb
     
  2. vb

    vb Активный пользователь

    С нами с:
    6 июн 2006
    Сообщения:
    911
    Симпатии:
    0
    Адрес:
    Saint-Petersburg
    Чтобы не извращаться со слешами сделал так:
    Код (Text):
    1. SELECT path FROM table WHERE LOCATE('C:\\test\\', path) = 1 GROUP BY path
    то есть просто $path = mysql_escape_string($path);
     
  3. vb

    vb Активный пользователь

    С нами с:
    6 июн 2006
    Сообщения:
    911
    Симпатии:
    0
    Адрес:
    Saint-Petersburg
    Нет, по ссылке повторяют то что было написано во введении, причем
    то есть str_replace в сочетании c addslashes - лишнее.

    У меня проблема немного глубже - в получении строки вида:
    C:\\\\test\\\\vb\\

    бррр, вернее это не проблема, меня уже интересуют ответы на 2-а вопроса:
    Собственно расписал все так наврное больше от желания поделиться инфой нежели узнать ответ на основной ответ о экранировании.
     
  4. По ссылке не повторяют то что было написано во введении.
     
  5. simpson

    simpson Активный пользователь

    С нами с:
    11 фев 2006
    Сообщения:
    1.650
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    кажется, так:
    PHP:
    1. <?php
    2. $path = 'C:\\test\\vb\\';
    3. echo preg_replace('~(\\\\)([^\\\\])~', '\\\\\\1\\1\\2', mysql_escape_string($path));
    4. ?>
    но лучше бы здесь подошел способ с str_replace.
     
  6. vb

    vb Активный пользователь

    С нами с:
    6 июн 2006
    Сообщения:
    911
    Симпатии:
    0
    Адрес:
    Saint-Petersburg
    simpson, спасибо, из Вашего ответа вывел ответ и на второй вопрос
    :
    PHP:
    1. <?php
    2. $path = 'C:\\test\\vb\\';
    3. echo preg_replace('~\\\\([^\\\\])~', '\\\\\\\\\\\\\\1', mysql_escape_string($path));
    4. ?>
    ИМХО жесть :)
     
  7. при том, что нужен-то был, всего лишь, примитивный str_replace
     
  8. vb

    vb Активный пользователь

    С нами с:
    6 июн 2006
    Сообщения:
    911
    Симпатии:
    0
    Адрес:
    Saint-Petersburg
    Чебурген, в контексте названия темы "Экранирование слешей для(в) mysql-запросе" - да, Вы правы.
     
  9. отлично.
    только разберём этот случай по пунктам, для возможных будущих читателей.
    Заблуждение номер 1. Поскольку в документации ясно написано, что в строках, которые подставляются в оператор LIKE должны быть удвоены слеши.
    Отсюда выходит, что
    Это на самом деле не баг, а фича.
    И, следовательно, задача
    - это заблуждение номер 2.
    Поскольку преобразовывать надо в C:\\\\test\\\\, то регулярка, как следствие, не нужна.

    Что и требовалось доказать.
     
  10. Anonymous

    Anonymous Guest

    Мой код который я вам пытался покозать записывает в базу

    c:\test

    После чего делали запрос

    SQL-запрос:
    SELECT *
    FROM `table`
    WHERE `path` LIKE 'c:\\\\test%'
    LIMIT 0 , 30

    И данный запрос прекрасно сработал – так почему на данный код была такая реакция