2016-04-10 2 views
2

Я пытаюсь внедрить фильтры, которые помогут пользователям улучшить поиск других пользователей. Вот изображение из моих параметров поиска только предоставить вам графическое представление того, что я в скором времени передать:Фильтры не работают (Выполнение различных запросов PHP на основе параметров)

enter image description here

Есть три фильтра:

  1. Пол
  2. Возраст
  3. Сходство в исследованиях

По умолчанию, я хочу чтобы передать всех пользователей в систему. Поэтому, когда пользователь переходит на users.php, каждый пользователь будет отображаться, а затем, когда применяются фильтры, уточните результаты соответственно.

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

Я попытался реализовать разные запросы для каждого сценария, но все пользователи всегда отображаются. Если я укажу, что хочу найти женщину, а затем нажать «Поиск», она ничего не сделает, показывая все пользователи.

Кроме того, я борюсь с параметром similarity in studies. Способ, которым это работает, заключается в том, что в таблице под названием user_bio Я храню данные о том, что изучает пользователь, пользователь может не предоставлять эту информацию, поэтому изучение также может быть пустым в моей таблице.

Способ, которым я хочу, чтобы он работал, - это посмотреть, что изучил пользователь, а затем найти слова, которые соответствуют другим бионам других народов. Например, я в настоящее время зарегистрирован как Конор, а Конор изучает компьютерную науку. В идеале, будет запускаться алгоритм, который ищет другие пользователи из таблицы user_bio и возвращает всех пользователей, у которых есть computer или science в своей биографии. Я уверен, что это относится к статье LIKE, но я никогда не использовал ее раньше, поэтому я не могу быть уверен.

Вот мой текущий подход:

// processing filters 
$refined_gender = htmlentities (strip_tags(@$_POST['gender'])); 
$age_from  = htmlentities (strip_tags(@$_POST['age_from'])); 
$age_to   = htmlentities (strip_tags(@$_POST['age_to'])); 
$studying  = htmlentities (strip_tags(@$_POST['studying'])); 

$get_all_users = mysqli_query ($connect, "SELECT * FROM users"); 

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); 

if (isset($_POST['submit'])){ 
     // if gender parameter is used ... 
     if ($refined_gender){ 
       $gender_statement = mysqli_prepare ($connect, "SELECT * FROM users WHERE gender = ?"); 
       mysqli_stmt_bind_param($gender_statement, "s", $refined_gender); 
       mysqli_stmt_execute ($gender_statement); 
       mysqli_stmt_close($gender_statement); 
     } 
     // if studying parameter used... 
     if ($studying) { 
      // see explanation below... 
     } 
     // if gender and age parameter used... 
     if ($refined_gender && $age_from && $age_to){ 
       $gen_and_age_statement = mysqli_prepare ($connect, "SELECT * FROM users WHERE gender = ? AND age BETWEEN ? AND ?"); 
       mysqli_stmt_bind_param($gen_and_age_statement, "sss", $refined_gender, $age_from, $age_to); 
       mysqli_stmt_execute ($gen_and_age_statement); 
       mysqli_stmt_close($gen_and_age_statement); 
     } 
} 

Резюме, что мне нужно:

  1. SELECT * FROM users запрос будет выполняться по умолчанию users.php. Это покажет всех пользователей в системе.
  2. Для любого применяемого фильтра. Не все фильтры должны применяться для получения результата, пользователь может искать женщину и искать по клику, загружая всех женщин-пользователей в систему.
  3. Мне нужен запрос для изменения в зависимости от того, какие фильтры были применены. Поэтому, если пользователь искал пользователя-пользователя, а остальные два параметра не выбраны, тогда запрос будет "SELECT * FROM users WHERE gender = '$var_here'.
+0

Я бы рекомендовал не подавлять сообщения об ошибках, а обрабатывать их. Большинство из них можно решить с помощью простого isset(); –

+0

'if ($ refined_gender && $ age_from && $ age_to)' почему вы проверяете, являются ли эти переменные истинными? – Black

+0

@EdwardBlack - мой мыслительный процесс позади этого был «если поля имеют данные в них, или опция выбрана, сделайте это ...». – Freddy

ответ

0

Здесь IAM предоставления кода таким образом, что, как вы можете написать несколько вариант фильтра внутри одной query..but здесь я не упомянул о вашем третьем примере выбора фильтра, потому что его о другой таблице, и вы не были упомянуты это явно так, что он связан с этой таблицей с использованием внешних ключей или следующей структуры реляционной базы данных. Каждый способ использования нескольких фильтров выглядит следующим образом. здесь я добавил подключения к базе данных и вывел функции впрыска ... если вам не нужно это пренебрегать этой частью.

function escape($e_string) 
{ 
    global $connect; 
    if(!isset($connect)) 
    { 
     // DATABASE CONNECTION QUERY 
     $connect = mysqli_connect("servername", "username", "password", ""); 
     if (!$connect) 
      die("Connection failed: " . mysqli_connect_error()); 
    } 
    $e_string = trim(utf8_encode($e_string)); 
    $e_string = mysqli_real_escape_string($connect,$e_string); 
    return $e_string; 
} 

// processing filters 
$refined_gender = isset($_POST['gender']) ? escape($_POST['gender']) : ''; 
$age_from  = isset($_POST['age_from']) ? escape($_POST['age_from']) : ''; 
$age_to   = isset($_POST['age_to']) ? escape($_POST['age_to']) : ''; 
$studying  = isset($_POST['studying']) ? escape($_POST['studying']) : ''; 

$query = "SELECT * FROM users WHERE 1=1"; 

if (isset($_POST['submit'])){ 

     $addstring1 = $addstring2 = $addstring3 = $and1 = $and2 = $and3 = ""; 
     $andcnt =3; 

     if($refined_gender != '') 
     $addstring1 = " gender = '$refined_gender'";  

     if($age_from != '') 
     $addstring2 = " age >= '$age_from'";  

     if($age_to != '') 
     $addstring3 = " age <= '$age_to'";  

     for($i=1;$i<=$andcnt;$i++) 
     ${"and".$i} = ${"addstring".$i} != '' ? " AND" : ""; 

     $query .= $and1.$addstring1.$and2.$addstring2.$and3.$addstring3; 

} 
$get_all_users = mysqli_query ($connect, $query); 
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); 
+0

Привет. Я получаю «Неустранимая ошибка: вызывать неопределенные функции escape()« ошибки во всех четырех «фильтрах обработки». Любая идея почему? До тех пор я не могу проверить эту оценку. – Freddy

+0

Вы скопировали и ввели ту же функцию «escape», которую я написал сверху? .. Это должно сделать ваши входы безопасными. Чтобы проверить, работает ли запрос или не удаляет все вызовы функции эвакуации из POST-входов. –

+0

Да, не возражаете ли вы присоединиться к этой чатовой комнате, чтобы я мог задать вам несколько вопросов по вашему подходу? http://chat.stackoverflow.com/rooms/109252/php-filters – Freddy

1

Вместо этого кода:

htmlentities (strip_tags(@$_POST['gender'])); 

вы должны проверить это, например, так:

$gender = filter_input(INPUT_POST, 'gender', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => '/^[mf]$/i']]); 
$ageFrom = filter_input(INPUT_POST, 'age_from', FILTER_VALIDATE_INT, [ 'default' => 1, 'min_range' => 1, 'max_range' => 100]); 
$ageTo = filter_input(INPUT_POST, 'age_to', FILTER_VALIDATE_INT, [ 'default' => 1, 'min_range' => 1, 'max_range' => 100]); 
$studying = filter_input(INPUT_POST, 'gender', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => '/^(similar|different|same)$/i']]); 

Это проще и безопаснее.

Каждый вход должен быть правильно проверен.

Избегайте использования @.

После того, как у вас есть значения, вы можете объединить их в запросе, например, так:

$types = ''; 
$values = []; 
$query = 'SELECT * FROM users'; 
$where = []; 

// empty tests for both null (no data in input) and false (invalid data) 
if (!empty($gender)) { 
    $where[] = 'gender = ?'; 
    $types .= 's'; 
    $values[] = &$gender; 
} 
if (!empty($ageFrom)) { 
    $where[] = 'age >= ?'; 
    $types .= 'i'; 
    $values = &$ageFrom; 
} 
if (!empty($ageTo)) { 
    $where[] = 'age <= ?'; 
    $types .= 'i'; 
    $values = &$ageTo; 
} 
if (!empty($studying)) { 

    $field = 'user_bio'; 

    // Get the $user_bio value of the current user from the database 

    // Change the $user_bio into a regular expression collection of words 
    $regexp = '('.str_replace(' ','|',$user_bio).')'; 

    // Set up the where 
    switch ($studying) { 
     case 'same': 
      $comparison = '= ?'; 
      break; 
     case 'different': 
      $comparison = 'NOT REGEXP (?)'; 
      break; 
     case 'similar': 
      $comparison = 'REGEXP (?)'; 
      break;     
    } 
    $where[] = $field.' '.$comparison; 
    $types .= 's'; 
    $values[] = &$user_bio; 
} 

if (count($where) > 0) { 
    $query .= ' WHERE '.implode(' AND ',$where); 
} 

// new mysqli (host, 
$mysqli = new mysqli('localhost','root','','stuff'); 
$stmt = $mysqli->prepare($query); 

// This allows you to use a variable number of arguments with the prepared statement 
// Note the use of the ampersands on the array assignment, this ensures they are passed by reference 
$params = array_merge([$types],$values); 
call_user_func_array([$stmt,'bind_param'],$params); 

$stmt->execute(); 

// Bind a variable for each column 
$stmt->bind_result($user_name); 

while ($stmt->fetch()) { 
var_dump($result); 
} 
+0

Понял. Где у вас есть 'm' и' f', это просто примеры? т. е. заменить их на «значение» каждого переключателя ('['male', 'female']')? Также жаль позднего ответа, действительно занят, и я ценю вашу помощь :) – Freddy

+0

Да - например и < input type = "radio" name = "gender" value = "m" id = "rb-male"> – user2182349

+0

У меня есть пара вопросов, подтверждающих возраст, используя ваш подход.Видя, как фильтр возраста использует два значения ('$ age_from' и' $ age_to') Как это проверить? В настоящее время у меня есть следующий '$ ageFilter = false; if (isset ($ _ POST ['gender'])) { $ age_from = strtolower ($ _ POST ['age_from']); \t $ age_to = strtolower ($ _ POST ['age_to']); if (! In_array ($ age_from, $ age_to, ['age_from', 'age_to'])) умереть; $ ageFilter = true; } 'и я на 100% сделал ошибку. Кроме того, при обработке '$ ageFilter', как мне установить его' $ value'? У меня есть '$ values ​​[] = & $ age_from, $ age_to;'? – Freddy

0

Эти Html страница:

<form method="POST" action=""> 
    <input type="radio" name="rbo_gender" value="male">Male 
    <input type="radio" name="rbo_gender" value="female">Female 
    Age From<select name="agefrom"> 
     <?php 
     for($i=10;$i<50;$i++): 
     ?> 
     <option value="<?php echo $i?>"><?php echo $i?></option> 
     <?php 
     endfor; 
     ?> 
    </select> 
    Age To<select name="ageto"> 
     <?php 
     for($i=10;$i<50;$i++): 
     ?> 
     <option value="<?php echo $i?>"><?php echo $i?></option> 
     <?php 
     endfor; 
     ?> 
    </select> 
    Studying: 
    <input type="radio" name="rbo_type" value="similar">Similar 
    <input type="radio" name="rbo_type" value="exact">Exactly same 
    <input type="radio" name="rbo_type" value="different">Different 
    <input type="submit" name="btnsearch" value="Search"> 
</form> 

Это PHP часть:

if($_POST["btnsearch"]) 
{ 
    if(!empty($_POST["rbo_gender"])) 
    { 
     $gender = $_POST["rbo_gender"]; 
     $cond .= " and gender = '".$gender."'"; 
    } 
    if(!empty($_POST["agefrom"])) 
    { 
     $agefrom = $_POST["agefrom"]; 
     $cond .= " and age >= '".$agefrom."'"; 
    } 
    if(!empty($_POST["ageto"])) 
    { 
     $ageto = $_POST["ageto"]; 
     $cond .= " and age <= '".$ageto."'"; 
    } 
    if(!empty($_POST["rbo_type"])) 
    { 
     $user_type = $_POST["rbo_type"]; 
     switch($_POST["rbo_type"]) 
     { 
      case "similar": $cond .= " and user_bio like '%".$ageto."%'"; 
       break; 
      case "exact": $cond .= " and user_bio = '".$ageto."'"; 
       break; 
      case "different":$cond .= " and user_bio ! like '%".$ageto."%'"; 
       break;  
     } 
    } 

    $query = "select * from users where 1 ".$cond; 
} 

Пожалуйста, обновите запрос как на MySQLi() & использования связывает пары. Также вместо использования @ попробуйте использовать filter_input вы можете использовать REGEXP вместо подобных тоже. Я создал переменную для использования цели bind_param.

+0

Привет, извините за поздний ответ. Я попробовал свой метод после изменения его требований. Но когда я нажимаю поиск, ничего не происходит, он просто обновляет страницу? На данный момент давайте просто рассмотрим гендерный фильтр. У меня есть '$ query = mysqli_query ($ connect," SELECT * FROM users WHERE account_type = 'user' ". $ Cond);' как мой запрос, и когда я выбираю самец из опции radio, он все еще показывает мне всех пользователей? – Freddy

+0

Код, представленный здесь, представляется уязвимым для SQL Injection. В этот день и в возрасте нет оправдания тому, что вы не можете использовать подготовленные заявления с привязками привязок или, как минимум, правильно избегать потенциально небезопасных значений, включенных в текст SQL. Подход в этом ответе может «работать». Но с точки зрения безопасности, он получает оценку FAIL. – spencer7593

+0

@ spencer7593, здесь я добавил только его концепцию и уже упомянул, что мы должны использовать bind_param и все другие меры предосторожности для безопасности ... –

0

(я не знаю, почему ответы уже представленные не на Ваш вопрос достаточно.)

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

Динамически подготовить текст SQL. Запустите инструкцию с помощью «SELECT ... FROM users». (Мы будем обрабатывать присоединени ORDER BY в качестве последнего шага.

Я бы условно проверить каждый «фильтр», чтобы увидеть, если мне нужно добавить условие к WHERE пункта или нет.

На пусконаладка SQL, мы будем включать «WHERE 1 = 1».

$sql = "SELECT ... FROM users u" 
$sql .= " WHERE 1=1"; 

«где 1 = 1» в основном бесполезна. оптимизатор собирается бросить, что далеко. причина, мы добавим его в просто чтобы сделать наш код более легким позже. Мы можем просто добавить наш следующий фильтр с условием «И» и не беспокоиться о том, является ли это первым, и нам нужно использовать WHERE вместо AND.

Мы инициализируем строку и массив, чтобы удерживать нашу строку привязки «sssis» независимо от того, что она должна быть, и массив ссылок на значения, которые мы хотим передать.

$bind_type = ""; 
    $bind_vals = array(); 

Обработка для каждого фильтра будет нехорошо ... но мы можем это сделать. Проверьте, нужно ли нам добавлять что-либо к SQL. Если да, то выясните, что нужно добавить, включая любые заполнители ссылок. И добавьте тип параметра привязки («i», «s», что угодно) в строку $ bind_type и нажмите (ссылку) на значение в наш массив $ bind_vals.

if ($refined_gender) { 
    // figure out what that SQL text needs to look like 
    // append the string to the SQL text 
    $sql .= " AND u.gender = ?"; 

    // append type to string, and push a reference to the value into array 
    $bind_types .= "s"; 
    $bind_val[] = &$refined_gender; 
} 

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

Повторяем то же самое для каждого фильтра, который, возможно, потребуется добавить. Проверьте, нужно ли это, выяснить, что нам нужно добавить в текст SQL, добавить в строку bind_types и нажать (ссылку) на значение в массив bind_vals.

Для того, чтобы это исправить, я бы начал работать только с одним условием и получить эту работу, чтобы получить изломы. Когда мы добавляем больше фильтров, и все идет не так, я знаю, где искать проблему. (Я знаю, что работало раньше.)

Когда я закончил с предложением WHERE, я добавляю любые ORDER BY и LIMIT, которые мне нужны. Это может быть условным, но в конце концов, мы будем наматывать делать что-то вроде этого:

$sql .= " ORDER BY u.id DESC LIMIT 50"; 

Когда я закончу со всем, что у меня есть строка, содержащая текст SQL, который выглядит как это:.

SELECT ... 
    FROM users u 
    WHERE 1=1 
    AND u.gender = ? 
    AND u.age_from >= ? 
    AND u.age_to <= ? 
    ORDER BY u.id DESC 
    LIMIT 50 

(в данном примере, она содержит три связывания заполнителей Если мы правильно сделали,

мы будем иметь $ bind_types строку, содержащую три символа, например «УСИ»

И у нас будет массив $ bind_vals, содержащий ссылки на три значения.

Теперь мы можем вызвать mysqli_stmt_prepare. Если в нашем SQL нет ошибки, мы должны вернуть дескриптор инструкции.

$stmt = mysqli_prepare($conn,$sql); 

(Проверьте возвращение из подготовки.)

Теперь нам нужно связать наши параметры. И здесь mysqli делает вещи немного волосатыми. Если бы мы использовали PDO (или Perl DBI), вызов «параметра привязки/привязки» был бы простым. Это позволит нам передать массив значений привязки. Но не mysqli. Он не позволит нам вызвать mysqli_stmt_bind_param с массивом в качестве аргумента.

Нам нужно запустить вызов функции вроде этого:

mysqli_stmt_bind_param($stmt, $bind_types, &$refined_gender, &$age_from, ...); 

И наша проблема в том, что у нас есть переменная число аргументов.

Существует обходное решение.

Мы можем использовать функцию call_user_func_array.

Поскольку код использует процедурный стиль, а не объектно-ориентированный стиль, дескриптор подготовленного оператора является первым аргументом, вторым аргументом является строка типов привязок, за которой следуют значения привязки. Значения bind уже находятся в массиве. Нам просто нужно собрать все из них в один массив hugh jass.

Функция array_merge, по-видимому, предназначена для этого.

// array_merge(array($stmt), array($bind_types), $bind_vals) 

Это вернет нам единый массив. Это именно то, что нам нужно для вызова функции call_user_func_array. Нам не понадобится этот массив нигде (если мы не отлаживаем, и мы хотим распечатать его).

Нам нужно только вызвать mysqli_stmt_bind_param, если в нашем заявлении имеется хотя бы один связующий агент. Поэтому мы можем сократить это, если наша строка $ bind_types пуста. (И мы знаем $ bind_types не будет «0», потому что наш код не добавляется «0» к нему.)

if ($bind_types) { 
    call_user_func_array('mysqli_stmt_bind_param', array_merge(array($stmt), array($bind_types), $bind_vals)); 
} 

Первый аргумент (в call_user_func_array) является имя функции, мы хотим, чтобы выполнить , а второй аргумент - массив hugh jass, который мы хотим преобразовать в список.

И все, что нужно сделать, это сделать его динамическим, мы можем передать в один, два, три значения привязки.

На этом этапе мы готовы выполнить инструкцию и получить результаты.

Опять же, важно указать: mysqli_stmt_bind_param ожидает, что значения привязки будут переданы по ссылке, а не по значению. И поэтому мы нажали ссылки на значения в массив bind_vals.

Я не уверен, какой вопрос вы задали.

Но, безусловно, это первый вызов mysqli_query. Это вернет все строки в таблице users.

С одним или двумя условиями подход к статическим типам SQL и статических привязок и вывод значений привязки работоспособны.

Но когда мы получим три, четыре, пять возможных фильтров и все возможные комбинации, это будет нелегко.

Итак, мы идем с более динамичным подходом, динамически создавая запрос и подталкивая наши значения привязки к массиву как go.