• 15 апреля стартует «Курс «SQL-injection Master» ©» от команды The Codeby

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

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

    Запись на курс до 25 апреля. Получить промодоступ ...

Магия кодировок

  • Автор темы vital
  • Дата начала
V

vital

Преамбула.
Надо сделать автодополнение в инпут, типа как в гугле, это стало модно. Не долго думаю выбрал
плагин для джквери, как первый попавшийся.
Була.
Следствие выявило, что русские буквы приходят аякс обработчику(пхп срипту) как хрен знает что. Руками всунул в плагин encodeURIComponent(). Буквы стали приходить нормально, urldecode() возвращает то что надо.

Строки для дополнения берутся из бд. Кодировки всего и везде прописаны как UTF-8.

Беда вот в чем... Русские буквы из урлдекоде!=русским буквам из бд.

Далее таблица и код обработчика, что бы было понятнее..

Код:
--
-- Database: `SPRAVKA`
--

-- --------------------------------------------------------

--
-- Table structure for table `Student`
--

CREATE TABLE IF NOT EXISTS `Student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`fio` varchar(200) COLLATE utf8_bin NOT NULL,
`nomprikzach` int(11) NOT NULL,
`dataprikzach` date NOT NULL,
`passport` varchar(20) COLLATE utf8_bin NOT NULL,
`address` varchar(50) COLLATE utf8_bin NOT NULL,
`phone` varchar(10) COLLATE utf8_bin NOT NULL,
`group` varchar(5) COLLATE utf8_bin NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
PHP:
header("Content-type: text/plain; charset=utf-8");
if (empty($_GET["q"]))exit;
$q=$_GET['q']; 
include_once("../config.php");
$q=urldecode($q);
$handle=mysql_connect($dbhost,$dbuser,$dbpass) or exit;
mysql_select_db($dbname,$handle) or exit;
mysql_query('SET NAMES `utf8`');
$res=mysql_query('SELECT id,fio FROM student',$handle) or exit;
while($row = mysql_fetch_assoc($res))
{	echo $row['fio']."====".$row['id']."===".$q."\n"; //Для дебагу, что бы видеть что сравниваем ниже..
if (strpos(strtolower($row['fio']), $q) !== false) //Не выполняется, возвращает фолс, когда буквы те же. Например строка фамилия, а буква - ф
{
echo $row['fio']."|".$row['id']."\n";
}
}
так вот. ЧТО ЗА БРЕД?
 
K

KoMaTozZz

Возможно Вам поможет "AddDefaultCharset utf8" в .htaccess и COLLATE=utf8_general_ci;

p.s. Зачем каждый раз выбирать ВСЕ записи? чем не подходит вариант запроса
PHP:
$res=mysql_query('SELECT id,fio FROM student where `fio` like '{$q}%';',$handle) or exit;
 
V

vital

Возможно Вам поможет "AddDefaultCharset utf8" в .htaccess и COLLATE=utf8_general_ci;
Проблему решил другим.
.s. Зачем каждый раз выбирать ВСЕ записи?
А они и не выбираются. Результат кешируется, за ненадобностью опущено.

Добавлено: Но спасибо за вариант)
 
K

KoMaTozZz

Проблему решил другим.
Ну так поделитесь решением, авось кто-то на подобную проблему наткнется? ;)

p.s. Кстати, кажется мне, что
PHP:
$encoding = mb_detect_encoding($row['fio'], "auto" );
$q = mb_convert_encoding( $q, "UTF-8", $encoding);
тоже должно сработать. Но это я так.. Мысли :lovecodeby: Для других
 
V

vital

Ну так поделитесь решением
Так я бы поделился если бы понял все точно сам.
Ну суть в том, что для функций работы со строками помогло явное указание что они работают с юникодом(необязательный параметр), что, вобщем-то странно т.к. для работы с юникодом они и выдуманы. Ну.. потом там еще было немного правка конфига сервера, но суть в том, что выше. Ниже рабочий вариант.
PHP:
header("Content-type: text/plain; charset=utf-8");
error_reporting(0);
if (empty($_GET["q"]))exit;
$q=$_GET['q']; 
include_once("../config.php");
$q=mb_strtolower(urldecode($q),'UTF-8'); //вот например как тут
$handle=mysql_connect($dbhost,$dbuser,$dbpass) or exit;
mysql_select_db($dbname,$handle) or exit;
mysql_query('SET NAMES `utf8`');
$res=mysql_query('SELECT id,fio FROM student',$handle) or die(mysql_error($handle));
while($row = mysql_fetch_assoc($res))
{  
if (mb_strpos(mb_strtolower($row['fio'],'UTF-8'), $q,0,'UTF-8') !== false)
{
echo $row['fio']."|".$row['id']."\n";
}
}
 
K

KoMaTozZz

т.к. для работы с юникодом они и выдуманы.
Немного не согласен с Вами, ибо назначение их работы - мультибайтовые строки (UTF-8, UTF-16, UCS2, etc...). Т.е. странного ничего нет в том, что по умолчанию они не работают с UTF-8 (которая нужна Вам), т.к. полная поддержка данной кодировки предусмотрена в php6.

Кстати, я запустил код, который Вы указали в первом посте - у меня все заработало "на ура". Как я и предпологал в своем первом ответе - решение кроется в AddDefaultCharset UTF-8 и collate=utf8_general_ci (эти параметры я бы рекомендовал использовать всегда, и, особенно, если используете ajax). Но если Вам угодно использовать mbstring - пожалуйста :)

И еще дам несколько советов (не думайте, что я пытаюсь Вас учить, нет ;) )

1) При тестировании желательно всегда включать отображение ошибок, warning и notice.
PHP:
Error_Reporting(E_ALL);
Это позволит проще находить и устранять ошибки и неточности в коде :)

2) У Вас есть
PHP:
if (empty($_GET["q"]))exit;
$q=$_GET['q'];
Лучше писать так
PHP:
$q = (isset($_GET['q'])) ? $_GET['q'] : exit();
При отсутствии параметра q в GET в первом случае будет notice, во втором обработается корректно.

3) Ну и, конечно же, проверяйте то, что приходит в GET и POST :) Вот простой пример применения функций addslashes и htmlentities ко всем элементам массива $_GET :
PHP:
$_GET = array_map('addslashes', $_GET);
$_GET = array_map('htmlentities', $_GET);
 
V

vital

При тестировании желательно всегда включать отображение ошибок, warning и notice.
При тестировании так и делаю)
. Т.е. странного ничего нет в том, что по умолчанию они не работают с UTF-8
Ну может быть)
Ну и, конечно же, проверяйте то, что приходит в GET и POST smile.gif Вот простой пример применения функций addslashes и htmlentities ко всем элементам массива $_GET
Это да..)
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!