Создание предложений WHERE из нескольких $ _GET

В настоящее время я пытаюсь написать сложные предложения MySQL WHERE, которые генерируются из переменных $ _GET (которые сами поступают из выпадающих списков выбора). Во-первых, немного кода, чтобы вы понимали, о чем я говорю:

    if(!isset($_GET['order'])){
        $order= 'start asc';
    } elseif ($_GET['order'] == "dateasc") {
        $order= 'start asc';
    } elseif ($_GET['order'] == "titleasc") {
        $order= 'title asc';
    } elseif ($_GET['order'] == "titledesc") {
        $order= 'title desc';
    };


    if(!isset($_GET['cat'])){
        $cat= '0';
    } else  {
        $cat = $_GET['cat'];
    };


    if(!isset($_GET['loc'])){
        $loc= '0';
    } else  {
        $loc = $_GET['loc'];
    };


    if (isset($_GET['sd']) || isset($_GET['ed']) || isset($_GET['cat']) || isset($_GET['loc']) || isset($_GET['order']) ) {
        $where = 'WHERE ';

        if (isset($_GET['sd'])) {
            $where .= "start = " . $_GET['sd'];
        };

        if (isset($_GET['ed'])) {
            $where .= "AND end = " . $_GET['ed'];
        };

        if (isset($_GET['cat'])) {
            $where .= "AND category = " . $_GET['cat'];
        };

        if (isset($_GET['loc'])) {
            $where .= "AND location = " . $_GET['loc'];
        };
    };


    $result = mysql_query("SELECT * FROM " . TABLE . $where . " ORDER BY " . $order);

Очевидно, это не работает, иначе меня бы здесь не было. :) По сути, у меня есть 4 переменные, которые я хочу условно использовать для сортировки в моем запросе: дата начала и дата окончания, категория и местоположение. Моя проблема в том, что все 4 из них не всегда могут использоваться ... поэтому, учитывая приведенный выше пример, может быть случай, когда кто-то выберет категорию ($ cat), но НЕ дату начала ($ sd) ... что означает мой Предложение WHERE должно начинаться с 'AND', что, очевидно, недопустимо. Итак, как мне создать запрос на основе переменных, которые могут или не могут использоваться?

Мне кажется, что я слишком много над этим думаю, и я боюсь писать 9000 строк тестов isset для учета каждой комбинации использования переменной $ _GET. Несомненно, существует простой способ создать предложение WHERE из нескольких $ _GET, которые могут или не могут использоваться каждый раз ..? Я пробовал поискать в Google, но могу найти только решения, предлагающие использовать фреймворк для построения сложных запросов, и это кажется слишком ... неуклюжим ... для такой простой проблемы.


person Kane Ford    schedule 12.09.2013    source источник
comment
Самый простой способ сделать это - поместить каждый из ваших условных операторов в массив по мере прохождения, вместо того, чтобы строить SQL напрямую. Затем, в конце, вы можете просто implode() ваш массив, используя AND в качестве клея.   -  person andrewsi    schedule 12.09.2013
comment
Вы не должны вставлять свои GET-переменные прямо в свой SQL таким образом. Это небезопасно. Посмотрите на php.net/manual/en/book.mysqli.php   -  person Vlad    schedule 12.09.2013
comment
Предложение: я думаю, что для сложных условных операторов вы должны использовать switch-statement. stackoverflow.com/questions/2158759/   -  person John Harper    schedule 12.09.2013
comment
Пожалуйста, прежде чем писать какой-либо код взаимодействия с SQL, вы должны ознакомиться с правильным экранированием SQL, чтобы избежать серьезных ошибок внедрения SQL. Кроме того, mysql_query не следует использовать в новых приложениях. Это устаревший интерфейс, который будет удален из будущих версий PHP. Современная замена, например PDO несложно выучить и упростит разработку кода базы данных.   -  person tadman    schedule 12.09.2013
comment
Спасибо за советы! Я занимаюсь интерфейсом и пользовательским интерфейсом почти исключительно по большей части, поэтому я определенно ценю все указатели.   -  person Kane Ford    schedule 17.09.2013


Ответы (2)


Если вас просто беспокоит предложение where, которое начинается с AND, вы можете добавить 1 = 1, чтобы учесть отсутствие фильтров.

WHERE 1=1

Тогда, если у вас есть фильтры, это будет выглядеть так:

WHERE 1=1 AND col1=? AND col2=?
person Vlad    schedule 12.09.2013

Возможно, это не самое чистое решение, но оно должно быть довольно простым для понимания и реализации.

if (isset($_GET['sd']) || isset($_GET['ed']) || isset($_GET['cat']) || isset($_GET['loc']) || isset($_GET['order']) ) {
    $where = 'WHERE ';

    if (isset($_GET['sd'])) {
        if(strlen($where) > 6) {
           $where .= " AND ";
        }
        $where .= "start = " . $_GET['sd'];
    }

    if (isset($_GET['ed'])) {
        if(strlen($where) > 6) {
           $where .= " AND ";
        }
        $where .= "end = " . $_GET['ed'];
    }

    if (isset($_GET['cat'])) {
        if(strlen($where) > 6) {
           $where .= " AND ";
        }
        $where .= "category = " . $_GET['cat'];
    }

    if (isset($_GET['loc'])) {
        if(strlen($where) > 6) {
           $where .= " AND ";
        }
        $where .= "location = " . $_GET['loc'];
    }
}
person Lumberjack    schedule 12.09.2013
comment
НЕТ. Это безумие. Вы не можете просто указать произвольное $_GET содержимое в своем запросе. Это не чисто ни по какому определению. - person tadman; 12.09.2013
comment
Я добавил if(strlen($where) > 6) { $where .= " AND "; } в код OPs. OP не просил нас защитить его код. Он просил помощи с уменьшением опережения AND в определенных случаях. Насколько важно защитить ваш код от SQL-инъекций? да. Это ВСЕГДА важно? Нет. Иногда я пишу приложения, в которых единственный пользователь - Я. - person Lumberjack; 12.09.2013
comment
Это всегда важно, даже если пользователь - это вы. Однажды вы будете искать категорию O'Malley и тогда станете жертвой своего небрежного программирования. Серьезно, неужели это слишком много - просить влезть туда mysql_real_escape_string и навсегда решить проблему? Ошибки SQL-инъекций - не шутки. Не отмахивайтесь от них, считая, что это не проблема. Сообществу PHP нужно избавиться от этого. Со мной такого отношения не случится. - person tadman; 12.09.2013