|
|
|
| Ответ 006 на задачу N 21.
С условиями задачи можно ознакомится по ссылке.
Немного подправил:
<?php
session_name('sid');
session_id(isset($_REQUEST['sid'])?preg_replace('~[^\d]~','',$_REQUEST['sid']):random_digits(9));
session_start();
mysql_connect('localhost','root');
mysql_select_db('guests');
$acts=array('show','reg','search','delete');
$act=isset($_REQUEST['act'])&&in_array($_REQUEST['act'],$acts)?$_REQUEST['act']:'show';
function random_digits($len){
$rnd='';
while(strlen($rnd)<$len)$rnd.=str_repeat('0',5-strlen($r=rand(0,99999))).$r;
return str_shuffle(substr($rnd,0,$len));
}
function show_page($msg=null){
$page=
'<html>
<body>
'.($msg!==null?'Сообщение:<br />'.$msg.'<br />':'').
'<form method="post">
<input name="nm" type="text" value="">
<input name="protect" type="hidden" value="'.($_SESSION['protect']=random_digits(9)).'">
<input name="act" type="hidden" value="reg">
<input type="submit" value="Отметиться">
</form>
<br />
';
if(mysql_num_rows($r=mysql_query('SELECT * FROM `guests` ORDER BY `id`;'))===0)$page.='Нет пользователей.<br />';
else{
$page.='<table border="1"><tr><td>Номер</td><td>Имя</td><td>Количество визитов</td><td>Удалить</td></tr>';
while(($d=mysql_fetch_assoc($r))!==false)$page.='<tr><td>'.$d['id'].'</td><td>'.htmlspecialchars($d['guestname']).'</td><td>'.$d['visits'].'</td><td><a href="?act=delete&id='.$d['id'].'" onclick="return confirm(\''.htmlspecialchars($d['guestname']).'! Вы действительно хотите вычеркнуть себя?\')">x</a></td></tr>';
$page.='</table>';
}
$page.=
'<form method="get">
Найти посетителя:<br />
<input name="nm" type="text" value="">
<input name="act" type="hidden" value="search">
<input type="submit" value="Искать">
</form>
</body>
</html>';
echo $page;
}
switch($act){
case 'show':
show_page();
break;
case 'reg':
if(isset($_POST['nm'])&&strlen($_POST['nm'])>0&&isset($_POST['protect'])&&isset($_SESSION['protect'])&&$_POST['protect']===$_SESSION['protect']){
$nm=mysql_escape_string($_POST['nm']);
if(mysql_query('UPDATE `guests` SET `visits`=`visits`+1 WHERE `guestname`="'.$nm.'" LIMIT 1;')&&mysql_affected_rows()==0)mysql_query('INSERT INTO `guests` (`guestname`,`visits`) VALUES ("'.$nm.'",0);');
show_page('Привет, '.htmlspecialchars($_POST['nm']).'! Вы знаете, что в Вашем имени '.strlen($_POST['nm']).' символов?');
}else show_page();
break;
case 'search':
if(isset($_REQUEST['nm'])&&strlen($_REQUEST['nm'])>0){
if(mysql_num_rows($r=mysql_query('SELECT * FROM `guests` WHERE `guestname`="'.mysql_escape_string($_REQUEST['nm']).'";'))==1){
$d=mysql_fetch_assoc($r);
show_page('Порядковый номер пользователя "'.htmlspecialchars($d['guestname']).'": '.$d['id'].'<br />Количество посещений: '.$d['visits'].'<br />');
}else show_page('Пользователь не найден.');
}else show_page();
break;
case 'delete':
show_page(isset($_REQUEST['id'])&&mysql_query('DELETE FROM `guests` WHERE `id`='.intval($_REQUEST['id']).';')&&mysql_affected_rows()>0?'Успешно удалено.':'Ошибка при удалении.');
}
?>
|
http://www.softtime.ru/info/task.php?id_article=110 | |
|
|
|
|
|
|
|
для: SoftTime
(31.05.2007 в 23:48)
| | 1) 70 строк, средняя читабельность, комментарии отсуствуют.
2) Не правильно обрабатывается ввод пользователя при помощи функции mysql_escape_string(). Если включён режим магических кавычек, то войти под пользователем "I don't know" уже не получится - будет создано новый пользователь "I don\'t know". Конструкцию
<?php
$_REQUEST['nm'] = mysql_escape_string($_REQUEST['nm']);
?>
|
следует заменить на
<?php
if (!get_magic_quotes_gpc())
{
$name = mysql_escape_string($name);
}
?>
|
А собственно одна из главных особенностей этого задания - корректная вставка текста в СУБД.
3) Нет обработки ошибок SQL-запросов - плохо.
4) Нет привязки к названию файла - хорошо.
5) Перед удалением пользователя спрашивает подтверждение - хорошо. | |
|
|
|
|
|
|
|
для: cheops
(01.06.2007 в 12:18)
| | >> 1) 70 строк, средняя читабельность, комментарии отсуствуют.
Что же тогда плохая читабельность? скрипт в одну строчку? :) | |
|
|
|
|
|
|
|
для: cheops
(01.06.2007 в 12:18)
| | дубль | |
|
|
|
|
|
|
|
для: Artem S.
(01.06.2007 в 18:00)
| | Может на форуме на Д.Р. появится возможность удаления "своих" постов? | |
|
|
|
|
|
|
|
для: cheops
(01.06.2007 в 12:18)
| | >1) 70 строк, средняя читабельность, комментарии отсуствуют.
Скрипт писался за 20 минут, о комментах и не думал.
>2) Не правильно обрабатывается ввод пользователя при помощи функции >mysql_escape_string(). Если включён режим магических кавычек, то войти под пользователем "I >don't know" уже не получится - будет создано новый пользователь "I don\'t know". Конструкцию ><?php
> $_REQUEST['nm'] = mysql_escape_string($_REQUEST['nm']);
>?>
>
>
>следует заменить на <?php
> if (!get_magic_quotes_gpc())
> {
> $name = mysql_escape_string($name);
> }
>?>
>
>
>А собственно одна из главных особенностей этого задания - корректная вставка текста в СУБД.
Для меня проще выключить magic_quotes_gpc. Вообще очень раздражает такая автоматика, проще самому обработать спецсимволы, где это нужно.
Очень интересно, почему для пользователя "' "(одинарная кавычка) не выдаётся вопрос об удалении?
<update>Разобрался, для htmlspecialchars нужен параметр ENT_QUOTES</update>
>3) Нет обработки ошибок SQL-запросов - плохо.
Трудно представляю себе, как можно добиться ошибки sql в этом скрипте (только если база/таблица не существуют или неверные server/username/password, но это относится к части установки, а не к работе скрипта). | |
|
|
|
|
|
|
|
для: sms-send
(01.06.2007 в 19:47)
| | >Для меня проще выключить magic_quotes_gpc. Вообще очень раздражает такая автоматика, проще самому обработать спецсимволы, где это нужно.
Закрыв глаза на то, что бывают ситуации, когда php.ini недоступен, а .htaccess не воспользоваться (например на IIS-сервере)... та вот, закрыв на это глаза, я бы принял Ваши возражения, если б Вы потрудились к решению задачи приложить еще две строки следующего содержания:
#.htaccess
php-flag magic_quotes_gpc off
|
Я бы честно засунул в этот файл эту строку, и всем было бы цветочно.
Но Вы это сделать поленились... Так почему было не полениться мне?
>Очень интересно, почему для пользователя "' "(одинарная кавычка) не выдаётся вопрос об удалении?
><update>Разобрался, для htmlspecialchars нужен параметр ENT_QUOTES</update>
нет. дело не в ent_quotes.... | |
|
|
|
|
|
|
|
для: SoftTime
(31.05.2007 в 23:48)
| | Этот скрипт удивил меня тем, что сразу вывалил окно ошибок JS
Пришлось эксплорер в этом плане заткнуть.
Минимализм (я о размере кода) - это достойно, но лишь в том случае, если при этом не страдает логика.
Кроме упомянутого выше, автор очень странно воспринял идею нумерации посетителей.
Первичный ключ - не нумератор!
Двузначные числа в первом столбике рядом с указанимем "порядковый номер" смотрятся забавно.
Немного скриншотов процесса проверки см. в аттаче | |
|
|
|
|
|
|
|
для: Trianon
(01.06.2007 в 19:19)
| | >Этот скрипт удивил меня тем, что сразу вывалил окно ошибок JS
>Пришлось эксплорер в этом плане заткнуть.
У меня IE 6.0 и Opera 9.02 молчат.
>Минимализм (я о размере кода) - это достойно, но лишь в том случае, если при этом не страдает логика.
Логика пострадала?
>Кроме упомянутого выше, автор очень странно воспринял идею нумерации посетителей.
>
>Первичный ключ - не нумератор!
>Двузначные числа в первом столбике рядом с указанимем "порядковый номер" смотрятся забавно.
Насчёт "порядкового номера", никто не сможет однозначно сказать, что я имел ввиду )) может это инфа для юзера под каким номером он отметился в базе, первым или пятьдесят первым?
>Немного скриншотов процесса проверки см. в аттаче
Очень интересно. Не нашёл аттача. | |
|
|
|
|
|
|
|
для: sms-send
(01.06.2007 в 19:31)
| | >>Этот скрипт удивил меня тем, что сразу вывалил окно ошибок JS
>>Пришлось эксплорер в этом плане заткнуть.
>У меня IE 6.0 и Opera 9.02 молчат.
>
>
>>Минимализм (я о размере кода) - это достойно, но лишь в том случае, если при этом не страдает логика.
>Логика пострадала?
Конечно :(
О логических ошибках написал cheops .
Ну и кроме того, количество посещений 0 у посетителя, которого нашли в таблице - это по меньшей мере странно. Раз нашли, значит хоть один раз да был.
>
>>Кроме упомянутого выше, автор очень странно воспринял идею нумерации посетителей.
>>
>>Первичный ключ - не нумератор!
>>Двузначные числа в первом столбике рядом с указанимем "порядковый номер" смотрятся забавно.
>Насчёт "порядкового номера", никто не сможет однозначно сказать, что я имел ввиду ))
Имел в виду - я. Имеемое в виду, я изложил в условиях:
первое число (N) - просто графа для нумерации строк в списке. Последовательной непрерывной нумерации.
Вы уже не могли иметь другого.
может это инфа для юзера под каким номером он отметился в базе, первым или пятьдесят первым?
Может быть. Но в первую очередь - в реальной жизни - это сочли бы нарушением ТЗ.
>
>>Немного скриншотов процесса проверки см. в аттаче
>Очень интересно. Не нашёл аттача.
Не берут у меня архивы.
Глядите здесь. | |
|
|
|
|
|
|
|
для: Trianon
(01.06.2007 в 21:07)
| | Такое решение вас устроит?
<?php
// устанавливаем имя сессии
session_name('sid');
// проверяем переданный идентификатор сессии или устанавливаем новый
session_id(isset($_REQUEST['sid'])?preg_replace('~[^\d]~','',$_REQUEST['sid']):random_digits(9));
session_start(); // стартуем сессию
mysql_connect('localhost','root') or mysql_err(); // соединяемся с сервером MySQL
mysql_select_db('guests') or mysql_err(); // выбираем базу
$acts=array('show','reg','search','delete'); // допустимые значения параметра "act"
// если параметр "act" не в области допустимых значений, устанавливаем действие "show"
$act=isset($_REQUEST['act'])&&in_array($_REQUEST['act'],$acts)?$_REQUEST['act']:'show';
$self=$_SERVER['PHP_SELF']; // адрес скрипта
/*
*
* ~ mysql_err ~ (return null)
* Вспомогательная функция для вывода сообщений об ошибках MySQL
*
*/
function mysql_err(){
die('MySQL Error: '.mysql_error());
}
/*
*
* ~ random_digits ~ (return string)
* Функция генерации строки, состоящей из определённого количества случайных цифр
* $len (int) - количество цифр
*
*/
function random_digits($len){
$rnd='';
while(strlen($rnd)<$len)$rnd.=str_repeat('0',5-strlen($r=rand(0,99999))).$r;
return str_shuffle(substr($rnd,0,$len));
}
/*
*
* ~ show_page ~ (null)
* Функция вывода html кода страницы
* $msg (string) - сообщение, выводимое на страницу
*
*/
function show_page($msg=null){
$self=&$GLOBALS['self'];
$page= // устанавливаем шапку
'<html>
<body>
'.($msg!==null?'Сообщение:<br />'.$msg.'<br />':''). // если передано сообщение, выводим его
'<form action="'.$self.'" method="post">
<input name="nm" type="text" value="">
<input name="protect" type="hidden" value="'.($_SESSION['protect']=random_digits(9)).'">' // записываем в сессию значение "protect"
.'
<input name="act" type="hidden" value="reg">
<input type="submit" value="Отметиться">
</form>
<br />
';
$r=mysql_query('SELECT * FROM `guests` ORDER BY `id`;') or mysql_err(); // выбираем все записи из таблицы
if(mysql_num_rows($r)===0)$page.='Нет пользователей.<br />'; // если MySQL вернула пустой результат
else{
$page.='<table border="1"><tr><td>Номер</td><td>Имя</td><td>Количество визитов</td><td>Удалить</td></tr>'; // шапка таблицы
for($i=1;($d=mysql_fetch_assoc($r))!==false;$i++) // построчно добавляем все записи
$page.='<tr><td>'.$i.'</td><td>'.htmlspecialchars($d['guestname'],ENT_QUOTES).'</td><td>'.$d['visits'].'</td><td><a href="?act=delete&id='.$d['id'].'" onclick="javascript:return confirm(\''.htmlspecialchars(addslashes($d['guestname'])).'! Вы действительно хотите вычеркнуть себя?\')">x</a></td></tr>';
$page.='</table>'; // footer of the table
}
$page.= // footer of the page
'<form action="'.$self.'" method="get">
Найти посетителя:<br />
<input name="nm" type="text" value="">
<input name="act" type="hidden" value="search">
<input type="submit" value="Искать">
</form>
</body>
</html>';
echo $page; // вывод страницы
}
switch($act){ // выполнение действия, в зависимости от значения параметра "act"
case 'show': // просто вывод страницы (по умолчанию)
show_page();
break;
case 'reg': // добавление новой записи или увеличение количества посещений
if( // если ...
isset($_POST['nm'])&& // передана переменная "nm" методом "post" и
strlen($_POST['nm'])>0&& // "nm" не пустая строка и
isset($_POST['protect'])&& // передана переменная "protect" методом "post" и
isset($_SESSION['protect'])&& // ранее в сессию было записано значение переменной "protect" и
$_POST['protect']===$_SESSION['protect'] // значение "protect", принятое от пользователя, равно значению "protect", записанному ранее в сессии
){
$nm=get_magic_quotes_gpc()?$_POST['nm']:mysql_escape_string($_POST['nm']); // разбираемся с magic_quotes_gpc
if(
(
mysql_query('UPDATE `guests` SET `visits`=`visits`+1 WHERE `guestname`="'.$nm.'" LIMIT 1;') // увеличиваем количество посещений на 1
or
mysql_err() // если ошибка - умираем
)&&
mysql_affected_rows()==0 // если такого имени в базе нет ->
)mysql_query('INSERT INTO `guests` (`guestname`,`visits`) VALUES ("'.$nm.'",1);')/* добавляем соответствующую запись */ or mysql_err();
session_unregister('protect'); // удаляем "protect" из сессии, чтобы избежать накрутки по F5 (вообще это не обязательно, "protect" всё равно обновится в функции show_page)
show_page('Привет, '.htmlspecialchars($_POST['nm']).'! Вы знаете, что в Вашем имени '.strlen($_POST['nm']).' символов?'); // выводим приветствие
}else show_page();
break;
case 'search': // поиск пользователя по имени
if( // если ...
isset($_REQUEST['nm'])&& // передана переменная "nm" и
strlen($_REQUEST['nm'])>0 // "nm" не пустая строка
){
$r=mysql_query('SELECT * FROM `guests` WHERE `guestname`="'.(get_magic_quotes_gpc()?$_REQUEST['nm']:mysql_escape_string($_REQUEST['nm'])).'";') or mysql_err(); // выполняем поиск
if(mysql_num_rows($r)==1){ // если нашли
$d=mysql_fetch_assoc($r);
show_page('Количество посещений пользователя "'.htmlspecialchars($d['guestname']).'": '.$d['visits'].'<br />');
}else show_page('Пользователь не найден.'); // если не нашли
}else show_page();
break;
case 'delete': // удаление записи
show_page( // если ...
isset($_REQUEST['id'])&& // передана переменная "id" и
(
mysql_query('DELETE FROM `guests` WHERE `id`='.intval($_REQUEST['id']).';') // удаление проходит успешно
or
mysql_err() // если ошибка при выполнении запроса - умираем
)&& // и
mysql_affected_rows()>0 // удалена хотябы одна запись
?
'Успешно удалено.' // говорим, что все O'K
:
'Ошибка при удалении.' // сообщаем об ошибке
);
}
?>
|
| |
|
|
|
|
|
|
|
для: sms-send
(01.06.2007 в 22:04)
| | В любом случае, спасибо, что Вы отреагировали на критику конструктивно, то есть представив следующую версию. Это меня радует куда больше, чем даже изначально решенная задача.
Версию я обязательно проверю. | |
|
|
|
|
|
|
|
для: sms-send
(01.06.2007 в 22:04)
| | Увы. К сожалению, ошибки остались, в том числе и значимая
- искажение имени, которое содержит апострофы и т.п.
По требованию исключения побочных эффектов тоже незачет:
Попытка нажать F5 после регистрации имени
приводит к выводу предупреждения браузера
о повторной отправке данных.
Попытка нажать Go Back после регистрации имени
приводит к выводу диагностики браузера
о том, что страница устарела, и необходима
повторная отправка данных для её просмотра.
Попытка нажать F5 после удаления имени
приводит к сообщению "Ошибка при удалении"
Попытка нажать Go Back, Go Forward после удаления имени
также приводит к сообщению "Ошибка при удалении"
И алерта при удалении все так же нет. | |
|
|
|
|
|
|
|
для: Trianon
(05.06.2007 в 14:13)
| | >Увы. К сожалению, ошибки остались, в том числе и значимая
>- искажение имени, которое содержит апострофы и т.п.
http://www.sms-send.mobi/zadacha/ конкретный пример, пожалуйста
>По требованию исключения побочных эффектов тоже незачет:
>
>Попытка нажать F5 после регистрации имени
>приводит к выводу предупреждения браузера
>о повторной отправке данных.
Если нажать "Отправить", то данные не будут занесены в базу.
>Попытка нажать F5 после удаления имени
>приводит к сообщению "Ошибка при удалении"
>
>Попытка нажать Go Back, Go Forward после удаления имени
>также приводит к сообщению "Ошибка при удалении"
Всё верно, ведь пользователь уже удалён.
>И алерта при удалении все так же нет.
Как же нет, когда есть.
Пожалуйста по первому и последнему пункту тестировать здесь. | |
|
|
|
|
|
|
|
для: sms-send
(05.06.2007 в 15:16)
| | Откуда я знаю, что у Вас там на сайте?
И в каком виде оно попадает в базу?
Насчет алерта - был неправ. Прошу прощения. Остальное осталось.
PS.
>Если нажать "Отправить", то данные не будут занесены в базу.
Окно с "Отправить" не должно появляться в принципе.
По F5 обновляют страницы, а не действия.
>Попытка нажать F5 после удаления имени
>приводит к сообщению "Ошибка при удалении"
>
>Попытка нажать Go Back, Go Forward после удаления имени
>также приводит к сообщению "Ошибка при удалении"
>Всё верно, ведь пользователь уже удалён.
Пользователь не нажимал на del повторно - пользователь не производил действий с контентом. Только с отображением документов. Нет причин ни производить удаление, ни фиксировать ошибку. | |
|
|
|
|
|
|
|
для: Trianon
(05.06.2007 в 15:37)
| | Приведите пример имени, которое некорректно обрабатывается. | |
|
|
|
|
|
|
|
для: sms-send
(05.06.2007 в 15:43)
| | Да пожалуйста :)
Ввожу в форму
Привет, Mc\'robbins! Вы знаете, что в Вашем имени 11 символов? | |
|
|
|
|
|
|
|
для: Trianon
(05.06.2007 в 15:45)
| | Увидел. Каюсь. Учту на будущее. Это проявляется при включенном magic_quotes_gpc.
А приложенный .htaccess со следующим содержанием мог бы быть учтён как решение проблемы?
php_value magic_quotes_gpc off
|
----------
Всё-таки в базу всё добавляется верно, слеши вылезают только на вывод в сообщении, т.к. я выпускаю необработанный $_POST['nm']. | |
|
|
|
|
|
|
|
для: sms-send
(05.06.2007 в 15:57)
| | PHP может быть запущен и не как модуль Apache. Неужели трудно обращаться к функции get_magic_quotes_gpc()? | |
|
|
|
|
|
|
|
для: Unkind
(05.06.2007 в 16:01)
| | Просто был в некотором замешательстве, пока не увидел, что я обработал переменную только для ввода в базу. На вывод пускал без обработки. Пытался быстрее избавиться от ошибки простым и понятным решением. | |
|
|
|
|
|
|
|
для: sms-send
(05.06.2007 в 16:03)
| | Я поставил этот файл. Правда, наличие вызовов get_magic_quotes_gpc() наводит на мысль, что где-то Вы пересолили. :) | |
|
|
|
|
|
|
|
для: Trianon
(05.06.2007 в 16:11)
| | Это правда, я и не хотел изначально использовать .htaccess. Просто решение задачи уже перешло в написание отмазок на притензии. Давайте уже другую задачу. | |
|
|
|
|
|
|
|
для: sms-send
(01.06.2007 в 22:04)
| | Этот зараза не хочет искать гостя с именем "<script>" :-E | |
|
|
|
|
|
|
|
для: kasmanaft
(05.06.2007 в 19:28)
| | Кто-нибуть мне объяснит почему? | |
|
|
|
|
|
|
|
для: sms-send
(05.06.2007 в 19:43)
| | Кто-нибуть мне объяснит почему?
На сервере Вашего хостера стоит mod_security. Защита от XSS. | |
|
|
|
|
|
|
|
для: Unkind
(05.06.2007 в 21:12)
| | Тогда как эта строка вообще оказалась в таблице? | |
|
|
|
|
|
|
|
для: Trianon
(05.06.2007 в 21:15)
| | В данном случае проверяется только GET. | |
|
|
|
|
|
|
|
для: Unkind
(05.06.2007 в 21:22)
| | Админу, который этот модуль настраивал, нужно оторвать яйцо.
И другое , впрочем, тоже. За то что в принципе его (mod_security) поставил. | |
|
|
|
|
|
|
|
для: Trianon
(05.06.2007 в 21:34)
| | >Админу, который этот модуль настраивал, нужно оторвать яйцо.
>И другое , впрочем, тоже. За то что в принципе его (mod_security) поставил.
Пока нет такой возможности ))) | |
|
|
|
|
|
|
|
для: Unkind
(05.06.2007 в 21:12)
| | . | |
|
|
|
|
|
|
|
для: Unkind
(05.06.2007 в 21:12)
| | >Кто-нибуть мне объяснит почему?
>На сервере Вашего хостера стоит mod_security. Защита от XSS.
В первый раз сталкиваюсь. | |
|
|
|
|
|
|
|
для: sms-send
(05.06.2007 в 21:27)
| | Коль ты что ли? :)) | |
|
|
|