Войти

Показать полную графическую версию : [решено] MySQL error при поисковом запросе


qurbanoff@vk
02-02-2014, 23:06
Есть сайт. Сайт работает на движке DataLife Engine 10.1
На сайте установлен модуль "поиск по дополнительным полям" называется "SearchXField v5.0"
Модуль поддерживает сортировку по одному полю содержащему только числовые значения (Цена, количество, год рождения и т.д.)

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


<form action="/" name="search_xf" method="GET">
<input type="hidden" name="do" value="search_xf" />
<input type="hidden" name="loc" value="1" />
Диапазон цен:
От <input type="text" name="int_start_price" />
До <input type="text" name="int_end_price" />
</form>


Если значение полей между 100 и 200 то URL выглядет так:

_http://site.ru//sf/int_start_price:100/int_end_price:200
Проблем нет!

Проблема в том что если в поле диапазона цен в место цифр написать текс например:Москва при этом URL выглядет так:
_http://site.ru//sf/int_start_price:Москва/int_end_price:200
то запрос выдает MySQL error
Код ошибки такой:


MySQL error in file: /engine/modules/show.short.php at line 64
Error Number: 1054
The Error returned was:
Unknown column 'Москва' in 'where clause'
SQL query:

SELECT id, autor, date, short_story, SUBSTRING(full_story, 1, 15) as full_story, xfields, title, category, alt_name, comm_num, allow_comm, approve, tags FROM ad_post where SUBSTRING_INDEX( SUBSTRING_INDEX( xfields, 'price|', -1 ) , '||', 1 )>Москва AND SUBSTRING_INDEX( SUBSTRING_INDEX( xfields, 'price|', -1 ) , '||', 1 )<200 AND approve AND date < '2014-02-02 13:53:54' ORDER BY date+0 DESC LIMIT 0,10


Помогите решить проблему..

Заранее огромное спасибо.

PHP код который обрабатыват данные:


<?php

if (!defined('DATALIFEENGINE')) {
die("Hacking attempt!");
}

$disables = array( 'do', 'cstart', 'page', 'loc', 'news_direction_by', 'news_sort_by' );
$request = $_SERVER['REQUEST_URI'];
$query_string = $_SERVER['QUERY_STRING'];

if ($config['allow_alt_url'] == 'yes')
{
if ($_GET['loc'])
{
$location = '';
foreach ($_GET as $key => $value)
{
if ( $key != 'do' && $key != 'loc' && !is_array($value)){
$location .= $key . ':' . $value . '/';
}else if(is_array($value)){
$location .= $key . ':' . implode(";", $value) . '/';
}
}

header ("Location: $config[http_home_url]sf/$location");
}

$tmp_array = explode('/', $_GET['q']);
$in_array = '';

unset($_GET);
$_GET['do'] = 'search_xf';
$request = substr($request, 1);

foreach($tmp_array as $value)
{
if ($value != '')
{
$in_array = explode(":", $value);
$_GET[$in_array[0]] = $in_array[1];
if($in_array[0] == 'page')
$cstart = $in_array[1];
}
}
}

$url_page = $config['http_home_url'] . $request;

if($_GET['page'] > 1){
$url_page = preg_replace( "/(page:[0-9]+\\/|cstart:[0-9]+)/", "", $url_page );
}else{
$url_page = preg_replace( "/(\\/page:[0-9]+\\/|\\/cstart:[0-9]+)/", "", $url_page );
}

if(strpos($query_string, 'cstart') !== false)
{
$query_string = preg_replace( '/cstart=[0-9]+/', "", $query_string );
$query_string = substr($query_string, 1);
}
$user_query = str_replace("&","&amp;",$query_string);

if ($cstart) {
$cstart = $cstart - 1;
$cstart = $cstart * $config['news_number'];
}

$newsmodule = true;

if (isset($_GET['news_sort_by'])) $news_sort_by = $_GET['news_sort_by'];
else $news_sort_by = 'date';

if (isset($_GET['news_direction_by'])) $news_direction_by = $_GET['news_direction_by'];
else $news_direction_by = 'DESC';

if ($news_sort_by != 'date')
$select = ", SUBSTRING_INDEX( SUBSTRING_INDEX( xfields, '{$news_sort_by}|', -1 ) , '||', 1 ) as $news_sort_by";


$searchQuery = array();
$searchEngine = $_GET;

foreach ($searchEngine as $key => $value)
{
if (!in_array($key, $disables) and $value !="" and $value != NULL)
{
preg_match_all('#int_(.*)_(.*)#', $key, $matches, PREG_SET_ORDER);
if($matches)
{
if($matches[0][1]=='start')
{
$searchQuery[] = "SUBSTRING_INDEX( SUBSTRING_INDEX( xfields, '{$matches[0][2]}|', -1 ) , '||', 1 )>$value";
}
else
{
$searchQuery[] = "SUBSTRING_INDEX( SUBSTRING_INDEX( xfields, '{$matches[0][2]}|', -1 ) , '||', 1 )<$value";
}
}
else
{
// if(strpos($_SERVER['REQUEST_URI'], "?do=searchfields") || strpos($_SERVER['REQUEST_URI'], '/sf/'))
// {
// $value = $db->safesql(htmlspecialchars(stripslashes($value)));
// }
// else
// {
// $value = iconv("utf-8","windows-1251",$db->safesql(htmlspecialchars(stripslashes($value))));
// }
if ($key != 'category')
{
if(strpos($value, ";") === false)
{
$searchArr = array($key, $value);
$searchQuery[] = "xfields LIKE '%" . implode('|', $searchArr) . "%'";
}else{
$searchRes = explode(";", $value);
foreach($searchRes as $kent){
$searchArr = array($key, $kent);
$searchLS[] = "xfields LIKE '%" . implode('|', $searchArr) . "%'";
}
$searchRes = implode(" OR ", $searchLS);
$searchQuery[] = '(' .$searchRes. ')';

}

}
else
{
if ($config['allow_multi_category'] == 'yes')
{
$searchQuery[] = "category regexp '[[:<:]]( $value )[[:>:]]'";
}
else
{
$searchQuery[] = "category = '$value'";
}
}
}
}
}

unset($matches);
if($searchQuery)
$where .= implode(' AND ',$searchQuery)." AND";

$sql_select = "SELECT id, autor, date, short_story, SUBSTRING(full_story, 1, 15) as full_story, xfields, title, category, alt_name, comm_num, allow_comm $select FROM " . PREFIX . "_post where {$where} approve" . $where_date . " ORDER BY " . $news_sort_by . "+0 " . $news_direction_by . " LIMIT " . $cstart . "," . $config['news_number'];
$sql_count = "SELECT COUNT(*) as count FROM " . PREFIX . "_post where {$where} approve" . $where_date;
$allow_active_news = true;

?>

Sham
03-02-2014, 11:44
это уязвимость на sql-injection.
подразумевается (вроде бы), что $value число, но не проверяется и не приводится к типу int. Сделайте хотя бы intval($value) или в условии and is_numeric($value).
$searchEngine = $_GET;
foreach ($searchEngine as $key => $value)
{
if (!in_array($key, $disables) and $value !="" and $value != NULL)
{
preg_match_all('#int_(.*)_(.*)#', $key, $matches, PREG_SET_ORDER);
if($matches)
{
if($matches[0][1]=='start')
{
$searchQuery[] = "SUBSTRING_INDEX( SUBSTRING_INDEX( xfields, '{$matches[0][2]}|', -1 ) , '||', 1 )>$value";
}
else
{
$searchQuery[] = "SUBSTRING_INDEX( SUBSTRING_INDEX( xfields, '{$matches[0][2]}|', -1 ) , '||', 1 )<$value";
}
}
else »

qurbanoff@vk
03-02-2014, 12:00
is_numeric($value) »

А что делать если форма поиска такой?
в БД и есть текстовые значении которые производится поиск

<form action="/" name="search_xf" method="GET">
<input type="hidden" name="do" value="search_xf" />
<input type="hidden" name="loc" value="1" />
Диапазон цен:
От <input type="text" name="int_start_price" />
До <input type="text" name="int_end_price" />

<select name="cat" class="find3">
<option value=""></option>
<option value="Продажа">Продажа</option>
<option value="Покупка">Покупка</option>
</select>
</form>

Sham
03-02-2014, 14:25
повторюсь, приведённый код уязвимый, поскольку не вижу, чтобы данные экранировались перед вставкой в запрос.
А что делать если форма поиска такой?
в БД и есть текстовые значении которые производится поиск »
очевидно, там где name="int_* подразумевается числовой тип. В остальных случаях вставляется как строка. То бишь пробуйте разные name. Например name="category" ищет по полю category
if ($config['allow_multi_category'] == 'yes')
{
$searchQuery[] = "category regexp '[[:<:]]( $value )[[:>:]]'";
}
else
{
$searchQuery[] = "category = '$value'";
} »
по движку конкретно ничего не могу сказать.

qurbanoff@vk
03-02-2014, 14:51
Sham,
Проблему решил с помошью добавлением сторк

! is_numeric ( $value ) && $value = ( (int) $value );

над

$searchQuery[] = "SUBSTRING_INDEX( SUBSTRING_INDEX( xfields, '{$matches[0][2]}|', -1 ) , '||', 1 )>$value";

и

$searchQuery[] = "SUBSTRING_INDEX( SUBSTRING_INDEX( xfields, '{$matches[0][2]}|', -1 ) , '||', 1 )<$value";

это безопасно ?

Sham
03-02-2014, 15:36
после if($matches)
{ »
$value = (int) $value;

в остальных случаях $value обработайте этим (http://docs.php.net/manual/ru/mysqli.real-escape-string.php) (или подобным, что используется в движке).

qurbanoff@vk
03-02-2014, 16:09
Спасибо вам огромное.
Еще один вопрос.
Если в диапазоне цен указать от 100 до 200 тогда товары с ценой 100 и 200 не отображается... отображается интервал с 101 до 199.
В чем может быть проблема?

Sham
03-02-2014, 16:19
>$value »
>=$value и ниже <=$value в запросах

{$matches[0][2]} »
это тоже не обработано. лучше всё переделать с нуля, так не годится...




© OSzone.net 2001-2012