Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
Самоучитель PHP 5 / 6 (3 издание). Авторы: Кузнецов М.В., Симдянов И.В. C++. Мастер-класс в задачах и примерах. Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель MySQL 5. Авторы: Кузнецов М.В., Симдянов И.В. PHP Puzzles. Авторы: Кузнецов М.В., Симдянов И.В. MySQL 5. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Решение задачи №21
 
 автор: Лена   (17.07.2010 в 23:55)   письмо автору
 
 


<?php
session_start
();

//подключение к базе
include("db_config.php");

//удаление пользователя
if(isset($_GET['action'])){
$sql "DELETE FROM guests WHERE id=" . (int)$_GET['action'];
  
$del mysql_query($sql);
  if(!
$del) exit("Error in" $sql);
  
header("Location:" $_SERVER['PHP_SELF']);
}

//добавление пользователя
$errors = array();
if(isset(
$_POST['enter'])){
    if(
$_POST['login'] == '' && $_POST['login'] == 0)
          
$errors['name'] = "Введите Ваше имя!";
    if(isset(
$_POST['login']) && mb_strlen($_POST['login'])<3)
          
$errors['lenth'] = "Имя должно содержать не менее 2 символов!";

   if(
$errors){
        foreach(
$errors as $errKey=>$errVal){
            if(
$errVal =='')
                unset(
$errors[$errKey]);
        }
   }

   if(empty(
$errors)){
       
$_POST['login'] = trim($_POST['login']);
    
//проверяем, есть ли уже такой пользователь в списке
    
$q "SELECT * FROM guests
            WHERE guestname ='" 
mysql_real_escape_string($_POST['login']) . "'";
    
$r mysql_query($q);
    if(!
$r)exit("Error in " $q mysql_error());
        if(
mysql_num_rows($r)>0){
        
//пользователь есть в списке
                //защита от F5
                
if(!isset($_SESSION['var'])) exit();
                if(isset(
$_SESSION['var']) && $_SESSION['var'] == 1){
                    
$upd ="UPDATE guests SET visits=visits+1
                            WHERE guestname ='" 
mysql_real_escape_string($_POST['login']) . "'";
                    
$r_upd mysql_query($upd);
                       if(!
$r_upd) exit("Error in " $upd mysql_error());
                       
$_SESSION['var'] = -1;
                   }
        }else{
        
//пользователь зашел первый раз
                
if(isset($_SESSION['var']) && $_SESSION['var'] == 1){
                    
$ins ="INSERT INTO guests(guestname,visits)
                            VALUES('" 
mysql_real_escape_string($_POST['login']) . "',1)";
                    
$r_upd mysql_query($ins);
                    if(!
$r_upd)exit("Error in " $ins mysql_error());
                    
$_SESSION['var'] = -1;
                }
        }
         
//длина имени
        
$nameLenth mb_strlen($_POST['login']);
        
$word "символ";
        
$end "";
        if(
mb_strrchr($nameLenth,1))
           
$end "";
        else if(
mb_strrchr($nameLenth,2) || mb_strrchr($nameLenth,3) || mb_strrchr($nameLenth,4))
          
$end "a";
        else
           
$end "ов";
        
?>
        Привет, <?php print htmlspecialchars($_POST['login']) ?>!
        Вы знаете, что в Вашем имени <?php print $nameLenth  " " $word $end ?>?<br />
<?php
   
}
}

//форма входа
if(!isset($_POST['enter']) || $errors){
    
//если есть ошибки заполнения формы
     
if(isset($errors)){
         foreach(
$errors as $errVal)
             print 
"<div style='color:#F00;'>" $errVal "</div>";
     }
?>

<html>
<head>
  <title>Список посетителей</title>
</head>

<body>
        <form action='' method='post'>
            <input name = "login" type="text"
            value="<?php if(isset($_POST['login'])) print htmlspecialchars($_POST['login']); ?>">
            <input type="submit" value="Войти" name="enter">

        </form>

<?php
$_SESSION
['var'] = 1;
}

//список пользователей
$sql "SELECT * FROM guests ORDER BY guestname";
$res mysql_query($sql);
if(!
$res)exit("Error in " $sql mysql_error());
?>
Нас уже посетили:
<table width=600 cellpadding=0 cellspaacing=0 border=1>
<tr align='center' valign='top'><th>№</th><th>Гость</th><th>Визит</th><th>X</th></tr>
<?php
 
for($i=0;$row=mysql_fetch_assoc($res);$i++){
 
?>
  <tr align='center' valign='top'>
              <td><?php print ($i+1?></td>
              <td width=70%><a href=''><?php print htmlspecialchars($row['guestname']) ?></a></td>
              <td><?php print $row['visits'?></td>
              <td><a href='?action=<?php print $row['id'?>
onclick='return confirm("<?php print htmlspecialchars($row['guestname']);?>,Вы действительно хотите вычеркнуть себя?");'>del</a></td>
          </tr>
<?php
 
}

//поиск пользователя
if(!isset($_GET['search'])){
?>
<tr align="center">
    <td colspan="4">
        <form action=''>
            <input name = "sc_name" type="text"
            value="<?php if(isset($_GET['sc_name'])) print htmlspecialchars($_GET['sc_name']); ?>">
            <input type="submit" value="Поиск" name="search">
        </form>
    </td>
</tr>
<?php
}

if(isset(
$_GET['search'])){
$_GET['sc_name'] = trim($_GET['sc_name']);
$sql "SELECT * FROM guests WHERE guestname='" mysql_real_escape_string($_GET['sc_name']) . "'";
$res mysql_query($sql);
if(!
$res)exit("Error in " $sql mysql_error());
    if(
mysql_num_rows($res)>0){
        
?>

        <tr><td colspan='4'>
         Пользователь <strong><?php print htmlspecialchars($_GET['sc_name']); ?></strong> есть в списке.
         </td></tr>
    <?php
    
}else{ ?>
        <tr><td colspan='4'>
        Пользователя <strong><?php print htmlspecialchars($_GET['sc_name']); ?></strong> в списке нет.
        </td></tr>
    <?php
    
}
}
?>
</table>
</body>

</html>


Из задания не поняла это:
Name - ссылкой на скрипт поиска имени в списке.
Не понятно, куда должна вести ссылка, поэтому адреса в эти ссылки я не вписывала.

  Ответить  
 
 автор: Trianon   (18.07.2010 в 00:06)   письмо автору
 
   для: Лена   (17.07.2010 в 23:55)
 

>Из задания не поняла это:
>Name - ссылкой на скрипт поиска имени в списке.
>Не понятно, куда должна вести ссылка.

У вас есть форма поиска, так?
Поскольку поиск выполняется методом GET (как предписано в условии), по нажатию на кнопку Search, браузер выполняет переход на некоторый URL (инициирующий поиск).
Ссылка с имени должна вести на такой URL (URL поиска этого имени).

По сути. Как-то Вы, по-моему, сильно усложнили и задачу и подход к её решению.
В условии задачи ничего не говорилось о сеансах работы.
Сессии же сами по себе с компьютера на компьютер не перепрыгивают, не говоря уже о том, что сессия может банально устареть.
Собственно, применение сессий никак не запрещается, но вот толк от них здесь врядли будет. Скорее наоборот - вероятен какой-нибудь прокол.

PS. Надеюсь, cheops тоже напишет по традиции что-нибудь о решении...

  Ответить  
 
 автор: Лена   (18.07.2010 в 00:23)   письмо автору
 
   для: Trianon   (18.07.2010 в 00:06)
 

>У вас есть форма поиска, так?
У меня обработчик формы поиска и список - в одном файле, я так понимаю, надо было два скрипта делать, один - выводит список, другой - обработчик поиска. Да? Тогда немного переделаю.

>По сути. Как-то Вы, по-моему, сильно усложнили и задачу и подход к её решению.
Делала, как могу. На решения чужие я не смотрела и к помощи чьей-либо не обращалась, поэтому сложно или просто судить не могу. Честно говоря, в проектах иногда задания попадались намного сложнее :)

>не говоря уже о том, что сессия может банально устареть.
как сессия может устареть именно в моем случае? При выводе формы я устанавливаю сессионную переменную, нажал пользователь на кнопку - и сразу же эта переменная проверяется.
Я на этой защите от F5 как-то споткнулась, кроме сессий ничего не придумалось.

  Ответить  
 
 автор: Trianon   (18.07.2010 в 16:29)   письмо автору
 
   для: Лена   (18.07.2010 в 00:23)
 

>>У вас есть форма поиска, так?
>У меня обработчик формы поиска и список - в одном файле, я так понимаю, надо было два скрипта делать, один - выводит список, другой - обработчик поиска. Да? Тогда немного переделаю.


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


>>По сути. Как-то Вы, по-моему, сильно усложнили и задачу и подход к её решению.
>Делала, как могу. На решения чужие я не смотрела и к помощи чьей-либо не обращалась, поэтому сложно или просто судить не могу. Честно говоря, в проектах иногда задания попадались намного сложнее :)
>
>>не говоря уже о том, что сессия может банально устареть.
>как сессия может устареть именно в моем случае? При выводе формы я устанавливаю сессионную переменную, нажал пользователь на кнопку - и сразу же эта переменная проверяется.
>Я на этой защите от F5 как-то споткнулась, кроме сессий ничего не придумалось.

Тут все очень просто.
Защита от F5 - частный случай обработки POST-запроса.
Дело в том, что практически любой POST-запрос (если Вы не хотите, чтоб он был слепым, то есть обрабатывал данные, ничего не показывая пользователю в ответ на экране браузера) после непосредственно сохранения данных вместо формирования отклика должен выполнить перенаправление - редирект - с целью превратить запрос браузера в GET.
GET-запрос и будет сохранен в истории браузера - он же будет выполнен по нажатии F5. Само собой, никакая POST-обработка при этом повторяться не станет.
Это вобщем-то хрестоматийный материал - и какие-либо других альтернатив тут практически нет.
Немногие исключения в этом плане - специальная серверная обработка данных запросов от других скриптов и от клиентских компонент AJAX. Для них, конечно, после POST редирект не пишут.
Сам же редирект выполняется обычно функцией header("Location: скрипт"); на ту ветвь скрипта, которая и покажет состояние системы после POST-запроса.

  Ответить  
 
 автор: Лена   (18.07.2010 в 18:46)   письмо автору
 
   для: Trianon   (18.07.2010 в 16:29)
 

Ссылка-имя в списке:
<td width=70%><a href='?search=<?php rawurlencode($row['guestname'])?>'><?php print htmlspecialchars($row['guestname']) ?></a></td>


Что касается редиректа. Я его пробовала, мне не понравилось, что возвращает пустую форму.
Сейчас сделала немного по-другому (привожу только кусок, который поменяла):

<?php
                    $ins 
="INSERT INTO guests(guestname,visits)
                            VALUES('" 
mysql_real_escape_string($_POST['login']) . "',1)";
                    
$r_upd mysql_query($ins);
                    if(!
$r_upd)exit("Error in " $ins mysql_error());
        }
        
header("Location:" $_SERVER['PHP_SELF'] . "?res=" rawurlencode($_POST['login']));
        
?>
<?php

   
}
}

if(isset(
$_GET['res'])){
         
//длина имени
        
$nameLenth mb_strlen(rawurldecode($_GET['res']));
        
$word "символ";
        
$end "";
        if(
mb_strrchr($nameLenth,1))
           
$end "";
        else if(
mb_strrchr($nameLenth,2) || mb_strrchr($nameLenth,3) || mb_strrchr($nameLenth,4))
          
$end "a";
        else
           
$end "ов";
    
?>
        Привет, <?php print htmlspecialchars(rawurldecode($_GET['res'])) ?>!
        Вы знаете, что в Вашем имени <?php print $nameLenth  " " $word $end ?>?<br />
<?php
}
?>



Так хотя бы кроме пустой формы входа еще и приветствие появляется...

  Ответить  
 
 автор: Trianon   (19.07.2010 в 00:27)   письмо автору
 
   для: Лена   (18.07.2010 в 18:46)
 

>Что касается редиректа. Я его пробовала, мне не понравилось, что возвращает пустую форму.
Нет уж, извините. Как это пустую форму?
Он должен вернуть ту самую фразу насчет длины логина.
Ну или собщение об ошибке, если что-то пошло не так.

Собственно написать header("Location: .."); exit(); не проблема.
Проблема обычно передать скрипту отклика точку исполнения запроса.
Вы это сделали (или попытались сделать) путем передачи параметра ?res=....


1. rawurldecode наверняка ошибочен.
2. после выброса поля заголовка Location: исполнение скрипта следует останавливать. Обычно.
3. Надо понимать, что редирект выполняется нетолько в ветви INSERT но и в ветви UPDATE также.

  Ответить  
 
 автор: Лена   (19.07.2010 в 12:02)   письмо автору
 
   для: Trianon   (19.07.2010 в 00:27)
 

>Собственно написать header("Location: .."); exit(); не проблема.
>Проблема обычно передать скрипту отклика точку исполнения запроса.
>Вы это сделали (или попытались сделать) путем передачи параметра ?res=....

Изменила, поставила условие, чтобы не показывалась пустая форма, теперь все работает:

<?php
//форма входа
if((!isset($_POST['enter']) || $errors) && !isset($_GET['res'])){
//вывод формы и, если есть, ошибок
}



>1. rawurldecode наверняка ошибочен.

Почему, не пойму.

Как я понимаю, при отправке данных $_GET-методом через форму данные кодируются браузером
без применения rawurlencode и автоматом после декодируются php.
Если мы отправляем данные без формы, их нужно url-кодировать, а после декодировать, что я и сделала.

>2. после выброса поля заголовка Location: исполнение скрипта следует останавливать. Обычно.
>3. Надо понимать, что редирект выполняется нетолько в ветви INSERT но и в ветви UPDATE также.

Да, у меня так и было, я просто не весь кусок показала:

<?php
   
if(empty($errors)){
   
$_POST['login'] = trim($_POST['login']);
    
//проверяем, есть ли уже такой пользователь в списке
$q "SELECT * FROM guests
        WHERE guestname ='" 
mysql_real_escape_string($_POST['login']) . "'";
    
$r mysql_query($q);
    if(!
$r)exit("Error in " $q mysql_error());
        if(
mysql_num_rows($r)>0){
        
//пользователь есть в списке
                
$upd ="UPDATE guests SET visits=visits+1
                    WHERE guestname ='" 
mysql_real_escape_string($_POST['login']) . "'";
                
$r_upd mysql_query($upd);
               if(!
$r_upd) exit("Error in " $upd mysql_error());
        }else{
        
//пользователь зашел первый раз
                
$ins ="INSERT INTO guests(guestname,visits)
                    VALUES('" 
mysql_real_escape_string($_POST['login']) . "',1)";
                
$r_upd mysql_query($ins);
                if(!
$r_upd)exit("Error in " $ins mysql_error());
        }
        
//защита от F5
        
header("Location:" $_SERVER['PHP_SELF'] . "?res=" rawurlencode($_POST['login']));
        exit();
   }
?>

  Ответить  
 
 автор: Trianon   (19.07.2010 в 15:06)   письмо автору
 
   для: Лена   (19.07.2010 в 12:02)
 

>>1. rawurldecode наверняка ошибочен.
>
>Почему, не пойму.
>
>Как я понимаю, при отправке данных $_GET-методом через форму данные кодируются браузером
> без применения rawurlencode и автоматом после декодируются php.
>Если мы отправляем данные без формы, их нужно url-кодировать, а после декодировать, что я и сделала.


Давайте отличать отправку запроса браузером (по ссылке ли, или из формы) и процесс получения, обработки этого запроса и соответствующую выдачу отклика сервером.
Отправка:
Браузер может отправлять GET-запрос на основании данных формы (в этом случае он (браузер) сам составляет целевой URL и сам занимается URL-кодированием) , может отправить его по ссылке (в этом случае URL-кодированием правильной ссылки придется заняться серверу в момент формирования текста ссылки), может отправить его из-за ввода URL руками пользователя (в этом случае за правильное кодирование будет ответственен пользователь... хоть современные браузеры и помогают ему в этом процессе - при наборе нелатинских букв/цифр, они принудительно URL-кодируют таковые.)

Прием и обработка.
Сервер не знает, кто явился инициатором отправки, да ему и не надо.
В QUERY_STRING апач разместит принятый сырой (недекодированный) хвостик URL.
PHP разобьет его на переменные, и декодивав их имена и значения, разместит их в $_GET и $_REQUEST.
Дальше скрипт сделает то, что указал программист. Но в $_GET данные будут уже декодированы. а в $_SERVER['QUERY_STRING'] - еще не декодированы. Независимо от источника данных - поскольку он серверу неизвестен.

  Ответить  
 
 автор: Лена   (19.07.2010 в 17:03)   письмо автору
 
   для: Trianon   (19.07.2010 в 15:06)
 

Спасибо! Теперь все понятно :)
Как обычно, полученные от вас знания не всегда найдешь в такой краткой и понятной форме.
Получается, задача решилась и теперь можно посмотреть, как ее делали другие, оценить и выбрать оптимальный вариант :)

  Ответить  
 
 автор: Trianon   (19.07.2010 в 17:09)   письмо автору
 
   для: Лена   (19.07.2010 в 17:03)
 

Очевидно, полностью решенной задачу можно считать лишь приложив к ней .htaccess со строкой вроде php_value magic_quotes_gpc off

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

  Ответить  
 
 автор: Лена   (20.07.2010 в 17:11)   письмо автору
 
   для: Trianon   (19.07.2010 в 17:09)
 

Посмотрела решения других.
004 - красивый код.
006 тоже понравилась организация структуры, там же тоже защита от F5 через сессию, только
сессионную переменную, по которой проверяют, через скрытое поле формы передают.
И код nneadekvat`а понравился, как идет переключение с ветки на ветку.

В вашем решении задачи понравилось применение LENGTH в запросе для определения длины имени. Это мне даже в голову не пришло :) В моем случае это было бы CHAR_LENGTH().
Не понятно, зачем если мы кладем в базу числа и после их вытягиваем надо пропускать через
intval.
$visits = intval($row['visits']);
$len = intval($row['len']);

И ошибку у себя увидела: если список посетителей пустой, у меня нет вывода соответствующего сообщения.

  Ответить  
 
 автор: Николай2357   (05.10.2010 в 22:46)   письмо автору
 
   для: Лена   (20.07.2010 в 17:11)
 

Вот это
<?
    $nameLenth 
mb_strlen($_POST['login']);
кирилицу неправильно посчитает.
С окончаниями я раньше тоже мудрил... Сейчас позабыл совсем))
Вот, функцию решил подарить... Может пригодится. Довольно полезная штука.
<?
function createEndings($num$sihgl$even$noeven)  

    
$num abs($num) % 100
    
$ten $num 10
     
    if(
$num 10 && $num 20)  
        return 
$num .' '$noeven
    if(
$ten && $ten 5)  
        return 
$num .' '.$even
    if(
$ten == 1)  
        return 
$num .' '.$sihgl
         
    return 
$num .' '.$noeven
}

echo 
createEndings(2'символ''символа''символов');

  Ответить  
 
 автор: Лена   (06.10.2010 в 14:46)   письмо автору
 
   для: Николай2357   (05.10.2010 в 22:46)
 

>Вот это
<?
>    $nameLenth mb_strlen($_POST['login']);
кирилицу неправильно посчитает.

Ну я как бы с самого начала подразумевала, что кодировка utf...

>echo createEndings(2, 'символ', 'символа', 'символов');

echo createEndings(1112, 'символ', 'символа', 'символов');
:)
за функцию спасибо.

  Ответить  
 
 автор: Николай2357   (06.10.2010 в 18:10)   письмо автору
 
   для: Лена   (06.10.2010 в 14:46)
 

>Ну я как бы с самого начала подразумевала, что кодировка utf...
Если подразумевать с самого начала, то нужно ставить кодировку для всего.
<?
mb_internal_encoding
("UTF-8");

я не нашел... Может в конфиге.

Без этого неправильно подсчитает.

  Ответить  
 
 автор: psychomc   (18.07.2010 в 19:22)   письмо автору
 
   для: Лена   (17.07.2010 в 23:55)
 

если не секрет, зачем здесь вот это:

<?php
// .......
if($errors){
        foreach(
$errors as $errKey=>$errVal){
            if(
$errVal =='')
                unset(
$errors[$errKey]);
        }
   } 

// .....


разве в этой программе в массив $errors может попасть элемент с пустым значением?

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования