|
|
|
| Долго же мои руки тянулись к этой задаче =)
<?php
// подключение к бд
$dbHost = "localhost"; // Хост
$dbUser = "root"; // Логин
$dbPasswd = "root"; // Пароль
$dbName = "uses"; // Имя базы
$link = mysql_connect ($dbHost, $dbUser, $dbPasswd);
if (!$link) die ("Не могу установить соединение с базой данных!");
mysql_select_db ($dbName);
mysql_query("SET NAMES 'cp1251'");
error_reporting(E_ALL);
$showEnterForm = true; // флаг на показ формы входа
$error = null; // объявляем переменную ошибки
// функция обработки текстовых строк, приходящих от пользователя
function userTextValid($text)
{
global $error;
$text = trim($text);
// имя не может быть пустым
if ( empty($text) ) {
$error = 'А вы шутник, г-н без имени =) Но все-таки представьтесь.';
return false;
}
if ( get_magic_quotes_gpc() ) {
return $text;
} else {
return mysql_real_escape_string($text);
}
}
if ( isset($_GET['act']) ) {
// форма входа показывается только в отсутствии других действий
$showEnterForm = false;
switch ($_GET['act']):
// вход
case 'enter':
$name = userTextValid($_POST['name']);
if ( !empty($error) ) {
echo $error, '<br>';
$showEnterForm = true; // даем возможность исправить досадную ошибку
break;
}
$queryCheck = mysql_query("SELECT * FROM `guests` WHERE `guestname` = '$name'");
if ( mysql_num_rows($queryCheck) ) { // если пользователь нас уже посещал
$uid = mysql_result($queryCheck, 0, 'id');
mysql_query("UPDATE `guests` SET visits = visits + 1 WHERE id = $uid");
} else {
mysql_query("INSERT INTO `guests` (`guestname`, `visits`) VALUES ('$name', '1')");
$uid = mysql_insert_id();
}
header("location: {$_SERVER['PHP_SELF']}?act=gutenTag&uid={$uid}"); // отправляем на страницу с приветствием
break;
// приветствие
case 'gutenTag':
$uid = intval($_GET['uid']);
$queryUser = mysql_query("SELECT * FROM `guests` WHERE id = $uid");
if ( !mysql_num_rows($queryUser) ) { // если такого id в базе нет - где-то подстава
echo 'А казачок то засланный... Вас нет в базе данных!';
} else {
$user = mysql_fetch_assoc($queryUser);
echo 'Привет, ', htmlSpecialChars($user['guestname']),
'! Вы знаете, что в Вашем имени ', strlen($user['guestname']), ' символов?<br><br>';
}
// сразу переходим к статистике
case 'stat':
$queryAllUsers = mysql_query("SELECT * FROM `guests`");
if ( !mysql_num_rows($queryAllUsers) ) {
echo 'Увы, нас еще никто не посещал.';
} else {
echo 'Нас уже посетили:<br>';
echo '<table border="1"><tr>';
echo '<td>N</td><td>Гость</td><td>Визитов</td><td>X</td></tr>';
$i = 0;
while($user = mysql_fetch_assoc($queryAllUsers)) {
echo '<tr><td>', ++$i, '</td>';
// ссылка и имя гостя
echo '<td><a href="', $_SERVER['PHP_SELF'], '?act=search&q=',
rawUrlEncode($user['guestname']), '">',
htmlSpecialChars($user['guestname']),
'</a></td>';
echo '<td>', $user['visits'], '</td>';
// ссылка на удаление
echo '<td><a href="', $_SERVER['PHP_SELF'], '?act=del&id=', $user['id'], '" ',
'onclick="if (confirm(\'' , mysql_real_escape_string( htmlSpecialChars($user['guestname']) ) ,
'! Вы действительно хотите вычеркнуть себя?\')) { return true } else { return false };">';
echo "X</a></td></tr>";
}
echo '</table>';
}
break;
case 'del':
$id = intval($_GET['id']);
mysql_query("DELETE FROM `guests` WHERE id = $id");
header("location: {$_SERVER['PHP_SELF']}?act=stat");
break;
// поиск пользователей
case 'search':
$name = mysql_real_escape_string(stripslashes($_GET['q']));
$querySearch = mysql_query("SELECT * FROM `guests` WHERE `guestname` = '$name'");
if (!mysql_num_rows($querySearch)) {
echo 'Увы, <i>', htmlSpecialChars($name), '</i> тут и близко не было';
} else {
echo 'Кто-то нашелся:<br>';
echo '<table border="1"><tr>';
echo '<td>N</td><td>Гость</td><td>Визитов</td><td>X</td></tr>';
$i = 0;
while($user = mysql_fetch_assoc($querySearch)) {
echo '<tr><td>', ++$i, '</td>';
echo '<td><a href="', $_SERVER['PHP_SELF'], '?act=search&q=',
rawUrlEncode($user['guestname']), '">',
htmlSpecialChars($user['guestname']),
'</a></td>';
echo '<td>', $user['visits'], '</td>';
echo '<td><a href="', $_SERVER['PHP_SELF'], '?act=del&id=', $user['id'], '" ',
'onclick="if (confirm(\'' , mysql_real_escape_string( htmlSpecialChars($user['guestname']) ) ,
'! Вы действительно хотите вычеркнуть себя?\')) { return true } else { return false };">';
echo "X</a></td></tr>";
}
echo '</table>';
}
break;
endswitch;
}
?>
<?php if ($showEnterForm): ?>
<br><br>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>?act=enter" method="post">
<input type="text" name="name">
<input type="submit" value="Войти">
</form>
<?php endif; ?>
<br><br>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="get">
<input type="hidden" name="act" value="search">
<input type="text" name="q">
<input type="submit" value="Найти">
</form>
<a href="<?php echo $_SERVER['PHP_SELF']; ?>">Войти на сайт</a> |
<a href="<?php echo $_SERVER['PHP_SELF']; ?>?act=stat">Все пользователи</a>
|
| |
|
|
|
|
|
|
|
для: neadekvat
(20.03.2010 в 23:35)
| | $_SERVER['PHP_SELF'] стараюсь поменьше использовать, с учётом того что вдруг потом нужно будет переделывать под mod_rewrite.
>htmlSpecialChars
красивенько :) | |
|
|
|
|
|
|
|
для: heed
(21.03.2010 в 00:14)
| | > $_SERVER['PHP_SELF'] стараюсь поменьше использовать, с учётом того что вдруг потом нужно будет переделывать под mod_rewrite.
Пока не сталкивался с тем, что $_SERVER['PHP_SELF'] с мод_рерайтом бы мне помешало, поэтому использую) Но спасибо, в будущем учту и постараюсь не нарваться на подводный камень)
> красивенько :)
*поклонился*
Порой я обостренно педантичен)) | |
|
|
|
|
|
|
|
для: neadekvat
(20.03.2010 в 23:35)
| | Участок кода:
// имя не может быть пустым
if ( empty($text) ) {
|
Следует заменить на
// имя не может быть пустым
if ( $text == '' ) {
|
, чтобы скрипт пропускал ноль в качестве имени. | |
|
|
|
|
автор: .heed (21.03.2010 в 02:00) |
|
|
для: neadekvat
(21.03.2010 в 00:20)
| | дотянулся посмотреть условия задачи :)
я тут вот чего подумал.
>Имена могут содержать абсолютно любые символы.
>Хранить имена нужно в БД .....
Если под любыми символами понимаются не только 255 байт однобитной кодировки, а например имена например так-же на греческом, то вроде-бы должно быть всё в utf-8 .
Но если я подменю переключу кодировку страницы в браузере с utf-8 на cp1251, а скрипт будет ждать данные в utf-8 , то это вызовет ошибку,
Incorrect string value: '\xFF\xFF\xFF.............
как например если такой скрипт сохранить в cp1251 и выполнить.
<pre><?
//error_reporting(E_ALL);
$link = mysql_connect('localhost', 'root', 'root')
or exit('mysql_connect: '. mysql_error());
mysql_select_db('test')
or exit('mysql_select_db: '. mysql_error());
mysql_query("SET NAMES 'utf8'");
/*
mysql_query('CREATE TABLE guests (
id INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
guestname TINYTEXT NOT NULL,
visits INT(11) NOT NULL
)ENGINE=MyISAM DEFAULT CHARSET=utf8')
or exit('CREATE TABLE: '. mysql_error());
*/
echo $txt = mysql_real_escape_string('яяяяя');
mysql_query("INSERT INTO guests VALUES( NULL, '$txt', 1 )")
or exit('INSERT: '. mysql_error());
?><hr/>
| Или я в чём-то ошибаюсь,
Но всётаки есть шанс получить эти FF FF FF .
Вот теперь и думаю как выход использовать однобайтную кодировку и htmlкодируя всётаки выводить на странице в utf-8, или просто фильтровать, и тем самым проигнорировать это "абсолютно любые символы." :) ? | |
|
|
|
|
|
|
|
для: .heed
(21.03.2010 в 02:00)
| | Абсолютно любые символы в рамках выбранной кодовой страницы, конечно.
А вот вчерашний ляп neadekvat'a вынуждает меня задуматься о том, что следующий пункт в условии был бы ой как полезен:
Имена посетителей, начинающиеся с точки, в БД сохранять не нужно.
Тем не менее таких посетителей нужно приветствовать точно также как и остальных, как будто они ранее ни разу на странице не появлялись. | |
|
|
|
|
|
|
|
для: Trianon
(21.03.2010 в 09:18)
| | Ляп - это то, что ноль не пропускает? Или то, что у меня там id в передаче между страницами участвует?
А в остальном как?
С точкой.. Сейчас на страницу приветствия передается id в базе, но чтобы реализовать дополнение с точкой (да по сути пофиг, с чем, смысл в том, чтобы приветствовать пользователя, не добавляя его в базу) - передавать через url надо будет имя, затем делать запрос в бд, если имя не начинается на ту же точку, или сразу по шаблону выводить приветствие, кол-во символов и то, что посетил нас юзер только один раз. | |
|
|
|
|
|
|
|
для: neadekvat
(21.03.2010 в 11:30)
| | Нет, на ноль я не обратил внимания.
Я по обыкновению обратил внимание на по обыкновению преждевременный, и не тем фактором обусловленный вызов mysql_real_escape_string()
Если имя начинается с точки - зачем делать запрос к БД?
Собственно, идея другими словами - проще.
Приходит человек и называет имя.
Почему, чтобы показать длину этого имени, Вы вынуждены класть его в БД?
Сумеете ли Вы показать длину, не выполняя таких тяжелых операций?
Ваше решение меня в последнем не убедило.
Ну и при поиске тоже ляп был.
Тестовые данные можно проглядеть в темах с ответами других участников этой ежегодной корриды. | |
|
|
|
|
|
|
|
для: Trianon
(21.03.2010 в 17:46)
| | Хм, да, я выбрал иной, более напряжный в плане ресурсоемкости алгоритм.
Но, как я уже выше сказал, вместо id на страницу передавать само имя - тогда запросов не нужно будет. | |
|
|
|
|
|
|
|
для: Trianon
(21.03.2010 в 09:18)
| | тогда задача упрощается :)
я уже полез смотреть какие символы вообще в юникоде http://ru.wikipedia.org/wiki/Символы,_представленные_в_Юникоде чтобы потом посмотреть чего можно в http://ru.wikipedia.org/wiki/UTF-8,
и не понял почему
> последовательностями длиной от 2 до 6 байт (реально только до 4 байт, поскольку использование кодов больше 221 не планируется), в которых первый байт всегда имеет вид 11xxxxxx, а остальные — 10xxxxxx.
а должно быть
>В Юникоде зарезервировано 1 114 112 (= 220 + 216) позиций символов,
Но в utf-8 всётаки интереснее.
>В тексте UTF-8 принципиально не может быть байтов со значениями 254 (0xFE) и 255 (0xFF). Поскольку в Юникоде не определены символы с кодами выше 221, то в UTF-8 оказываются неиспользуемыми также значения байтов от 248 до 253 (0xF8—0xFD). Если запрещены искусственно удлинённые (за счёт добавления ведущих нулей) последовательности UTF-8, то не используются также байтовые значения 192 и 193 (0xC0 и 0xC1).
Буду целый месяц думать чтобы только попробовать понять :)
Вот насчёт
> в) нажать на ссылку в списке, чтобы удалить запись из него.
......
>в) По ссылке удаления должно всплывать alert-окно подтверждения с вопросом
> Name! Вы действительно хотите вычеркнуть себя?
Почему "себя" ? а если кого-то другого ?
// Извиняюсь если такие вопросы уже были, просто решения и обсуждения не читал, много ссылок, и просто интереснее сравнивать после того как делать | |
|
|
|
|
|
|
|
для: heed
(21.03.2010 в 13:12)
| | > Name! Вы действительно хотите вычеркнуть себя?
>Почему "себя" ? а если кого-то другого ?
По ссылке удаления Васи Пупкина выводится сообщение
Вася Пупкин! Вы действительно хотите вычеркнуть себя?
По моему это звучит лучше, чем
Вася Пупкин! Вы действительно хотите вычеркнуть Вася Пупкин?
или
Уважаемый! Вы действительно хотите вычеркнуть Вася Пупкин?
Так мне показалось. | |
|
|
|
|
|
|
|
для: Trianon
(21.03.2010 в 17:50)
| | Звучит конечно, но просто неоднозначность какая-то :) Регистрации с такой таблицей получается что и нет, значит как-бы любой заглянувший администрирует. А ссылки "del" имеются к каждому имени . получается что если пользователь "Вася Пупкин младший" начнёт удалять пользователя "Вася Пупкин старший", то ему буден задан неоднозначный вопрос .
Предлагаю вариант
Уважаемый! Вы действительно хотите вычеркнуть пользователя зарегестрировавшигося как Вася Пупкин?
:) | |
|
|
|
|
 5.6 Кб |
|
|
для: neadekvat
(20.03.2010 в 23:35)
| | Изменил в скрипте кое-что: теперь не идет запрос к бд при подсчете кол-ва символов, убрал ненужные (все, что нашел) mysql_real_escape_string
Тестировал на именах из этой темы:
http://softtime.ru/forum/read.php?id_forum=7&id_theme=38452
|
(пост от 01.06.2007 в 21:41) | |
|
|
|
|
|
|
|
для: neadekvat
(20.03.2010 в 23:35)
| |
echo '<td><a href="', $_SERVER['PHP_SELF'], '?act=del&id=', $user['id'], '" ',
'onclick="if (confirm(\'' , mysql_real_escape_string( htmlSpecialChars($user['guestname']) ) ,
'! Вы действительно хотите вычеркнуть себя?\')) { return true } else { return false };">';
|
Кажется перестарались с обработками. | |
|
|
|
|
|
|
|
для: Рома
(22.03.2010 в 00:19)
| | Хм..ну, во-первых, смотреть следует последнюю версию.
Во-вторых, когда кажется...
Без экранирования попробуйте-ка подставить ' (апостроф) | |
|
|
|
|
|
|
|
для: neadekvat
(22.03.2010 в 01:01)
| | Хотите сказать это правильно?
<?php echo mysql_real_escape_string( htmlSpecialChars($user['guestname']) );
|
| |
|
|
|
|
|
|
|
для: Рома
(22.03.2010 в 01:57)
| | Еще раз говорю, смотреть надо новую версию.
Но смысл в целом остался, да, использование htmlSpecialChars и экранирования.
Первое - для случаев типа & Второе - для того же апострофа. | |
|
|
|
|
|
|
|
для: Рома
(22.03.2010 в 01:57)
| | А что здесь не так - в контексте формирования JS-константы? | |
|
|
|
|
|
|
|
для: Trianon
(22.03.2010 в 08:59)
| | Trianon, вы так и не сказали, как в целом относитесь к такому решению вашей задачи =) | |
|
|
|
|
|
|
|
для: neadekvat
(22.03.2010 в 11:49)
| | Неправда.
Я не раз говорил, что вот к такой логике
if ( get_magic_quotes_gpc() ) {
return $text;
} else {
return mysql_real_escape_string($text);
}
|
отношусь весьма отрицательно. | |
|
|
|
|
|
|
|
|
для: neadekvat
(22.03.2010 в 18:54)
| | По ссылке вариант oliss содержит ошибку (с trim() ), и неясно чем пустые массивы неугодили. А так вообще верный подход. | |
|
|
|
|
|
|
|
для: Тень&
(22.03.2010 в 20:06)
| | Грубо говоря, от моего варианта (парой постов выше его процетировал Trianon) отличается тем, что данные "чистятся" с помощью stripslashes() или я упустил еще какой-то важный момент? | |
|
|
|
|
|
|
|
для: neadekvat
(22.03.2010 в 20:15)
| | дело не в том, чем данные чистятся.
Дело в том, что лежит в переменной.
Если пользователь ввел поле апостроф, а в переменной оказался не апостроф, а какая-то хрень(к примеру \' ) , значит в переменной лежит не то, что ввел пользователь.
Если пользователь ввел поле амперсенд, а в переменной оказался не амперсенд, а какая-то хрень(к примеру & ) , значит в переменной лежит не то, что ввел пользователь.
Если пользователь ввел два обратных слэша, а в переменной оказались не два обратных слэша, а какая-то хрень(к примеру \ ) , значит в переменной лежит не то, что ввел пользователь.
А если в переменной лежит не то, то разбираться в том как устроен скрипт, и как он работает с этим "не тем " - дело трудное и хлопотное.
Зачем?
Так понятно? | |
|
|
|
|
|
|
|
для: Trianon
(22.03.2010 в 20:27)
| | Вот теперь картинка в голове сложилась, понял =)
Подытожив, можно сделать вывод, что
1. Все данные от пользователей надо сохранять в первозданном виде
2. Функции экранирования или преобразования в html-код применять непосредственно перед запросами (или тем же js-кодом, где нужно экранирование) или выводом информации на экран.
// На вопрос ниже нашел ответ в той же теме, куда дал ссылку.
Однако еще кое-что хочу у вас просить.
Почему вы считаете, что лучше делать так:
<?php
$var = "'" . mysql_real_escape_string($var) . "'";
$sql = "... VALUES ($var)";
|
Чем плох такой вариант, когда все кавычки видны в самом запросе:
<?php
$var = mysql_real_escape_string($var);
$sql = "... VALUES ('$var')";
|
| |
|
|
|
|
|
|
|
для: neadekvat
(22.03.2010 в 20:44)
| | 1. Потому что экранирующий слэш и обрамляющий апостроф - символы одной грамматики. И им разумно быть локально близко друг к другу. Так мне кажется.
2. Поотму что значения в SQL-запросе вовсе не обязаны быть строковыми - они могут быть и числовыми. А в режиме совместимости даже MySQL больно бьет по рукам при попытке написать что-то вроде INSERT INTO (id) VALUES('123');
Если мне память не изменяет. А уж другие СУБД и подавно. | |
|
|
|
|
|
|
|
для: Trianon
(22.03.2010 в 23:01)
| | Черт возьми, решение вашей задачи дало мне намного больше ответов и полезных советов, чем я думал =) | |
|
|
|
|
|
|
|
для: neadekvat
(22.03.2010 в 23:15)
| | И тем не менее, первых два слова предпочел бы заменить на спасибо большое. | |
|
|
|
|
|
|
|
для: Trianon
(22.03.2010 в 23:17)
| | Это я собирался сделать как раз-таки этим постом =)
Спасибо больше =) | |
|
|
|
|
|
|
|
для: Тень&
(22.03.2010 в 20:06)
| | trim() там и впрямь ненужен (это был частный случай, где он требовался) | |
|
|
|
|
|
|
|
для: Trianon
(22.03.2010 в 08:59)
| | >А что здесь не так - в контексте формирования JS-константы?
mysql_real_escape_string() вместо addslashes()? в контексте формирования JS-константы может и не имеет значения, но mysql_real_escape_string() в echo пихать - впервые вижу. | |
|
|
|
|
|
|
|
для: Рома
(22.03.2010 в 22:45)
| | >в контексте формирования JS-константы может и не имеет значения
именно что имеет. | |
|
|
|
|
|
|
|
для: Trianon
(22.03.2010 в 23:04)
| | Мда, а что, правила экранирования для JS и MySQL (да ещё и real_escape) совпадают? | |
|
|
|
|
|
|
|
для: Тень&
(23.03.2010 в 09:14)
| | real_escape на utf-8 как раз наиболее близкий аналог из стандартных функций, по-моему.
Не то что бы там совсем всё чисто - меня просто удивил фырк, ничем, кроме новизны, не обусловленный, как оказалось. | |
|
|
|
|
|
|
|
для: Trianon
(23.03.2010 в 10:33)
| | >Не то что бы там совсем всё чисто - меня просто удивил фырк, ничем, кроме новизны, не обусловленный, как оказалось.
Не то что бы там совсем всё чисто - это и есть ключевые слова. Форс-мажерные обстоятельства выведут скрипт из строя. Мало того, вы ставите уклон на то, что можно применять mysql_real_escape_string() вместо addslashes(). А вот и нет, функции разные, выполняют схожие обработки, но одна из них зависимая от подключения, и кодировки. к тому же мы находимся в разделе, где новички определяются как им поступать в процессе написания кода. Вас послушать, (в данной ситуации естественно) все поголовно начнут применять mysql_real_escape_string() вместо addslashes(), естественно у некоторых это вызовет ошибки. Давайте не будем уподобляться Евгению Попову и будем учить людей делать обработки так, как это предусмотрено разработчиками языка.
P.S. Я ни сколько не сомневаюсь ни в Вашем профессионализме, ни в профессионализме neadekvat`a - вы можете применять что хотите, потому что соображаете что делаете. Но не все соображают как вы и не все понимают mysql_real_escape_string() и addslashes(). | |
|
|
|
|
|
|
|
для: Рома
(26.03.2010 в 14:58)
| | > Не то что бы там совсем всё чисто - это и есть ключевые слова. Форс-мажерные обстоятельства выведут скрипт из строя.
Хотелось бы взглянуть на пример такой атаки.
Именно на mysql_real_escape_string(utf-8) для экранирования входных данных JS.
Вас, конекчно же, не затруднит привести? Просто чтобы не уподобляться.
>P.S. Я ни сколько не сомневаюсь ни в Вашем профессионализме, ни в профессионализме neadekvat`a - вы можете применять что хотите, потому что соображаете что делаете. Но не все соображают как вы и не все понимают mysql_real_escape_string() и addslashes().
Окей, замечательно.
Вы не напомните Ваш собственный пример решения? | |
|
|
|
|
|
|
|
для: Trianon
(26.03.2010 в 17:19)
| | >Вы не напомните Ваш собственный пример решения?
Я не решил эту задачу, точнее начал, но так и не закончил, хотя вам и обещал решить. Довольны наверное ответом?)))
>Хотелось бы взглянуть на пример такой атаки.
Я не про атаку вовсе. | |
|
|
|
|
|
|
|
для: Рома
(26.03.2010 в 17:37)
| | нет. Недоволен.
Я просто подумал, что у Вас где-то есть чистый вариант, который я упустил из виду. | |
|
|
|