Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Общие вопросы > Повторная запись в гостевую книгу при обновлении


Автор: Leshik 6.9.2007, 18:33
Здрасте =)
Помогите пожалуйста.
Написал скрипт простейшей гостевой книги(практически списано из "Изучаем Perl")/
Код

#! perl -w

use strict;
use CGI qw/:standard/;
use CGI::Carp qw( fatalsToBrowser );
use Fcntl qw/:flock/;

#скрипт гостевой книги
sub bail{                          
    my $error = "@_";
    print p(h4("Error:"), $error);
    print end_html;
    die $error;
}

my( 
    $message_file,
    $title,
    $obj,
    $mes,
    @arr,
    $name);

$message_file = "tmp/guestbook";
$title = "Гостевая книга";
$obj = CGI->new();

print header(
    -type => 'text/html',
    -charset => 'windows-1251'),
    start_html($title), h3($title);

    if (param("message")) {
        $obj->param("date", scalar localtime);
        $obj->param("addr", $ENV{REMOTE_ADDR});
            if (!param("name")) {
                $name = "Анонимно";
                $obj->param("name", $name);
            }
        @arr = ($obj)
}

open (FILE_BOOK, "+< $message_file") or bail("cannot open $message_file: $!");
flock(FILE_BOOK, LOCK_EX) or bail("cannot flock $message_file: $!");
    
    while (!eof(FILE_BOOK)) {
        $mes = CGI->new(\*FILE_BOOK);
        push @arr, $mes;
    }

seek(FILE_BOOK, 0, 0) or bail ("cannot rewind $message_file: $!");
    foreach $mes (@arr) {
        $mes->save(\*FILE_BOOK);
    };
close(FILE_BOOK);

print hr(), start_form(),
    p("Ваше имя:", $obj->textfield(
    -NAME => "name",
    -OVERRIDE => 1)),
    p("Ваше сообщение:"), 
    $obj->textarea(
    -NAME => "message",
    -OVERRIDE => 1,
    -ROWS => 10,
    -COLUMNS => 40,
    -MAXLENGTH => 10),
    p(submit(
    -NAME =>"Отправить",
    -onClick =>), reset("Очистить")),
    end_form();
print hr(), h4("Предыдущие сообщения:");
    foreach $mes (@arr) {
        printf "%s\t[%s]:\t%s", $mes->param("date"), $mes->param("name"), $mes->param("message");
        print br();
    }
print end_html();

После того, как я ввожу имя и сообщение и жму на кнопку "отправить", если я обновляю страницу, то те же самые данные записываются ещё раз. И так всё время.
Подскажите, пожалуйста, как от этого можно избавиться.

Прошу извинить меня, за размещение не в ветке "CGI-программирование"( немного промахнулся smile)

Автор: maxim1000 6.9.2007, 18:48
Perl'а я не знаю, но сталкивался с подобной ситуацией
решил её так:
ответом на запрос является перенаправление на страницу completed.html (к примеру), на которой написано что-то в духе "выполнено"
даже если пользователь будет обновлять её, ему просто каждый раз будут писать "выполнено"

Автор: Leshik 6.9.2007, 21:48
Спасибо.
О таком решении я тоже задумывался, но всё же может быть есть ещё какой-нибудь способ?

Автор: comtat 6.9.2007, 22:29
Цитата(Leshik @  6.9.2007,  21:48 Найти цитируемый пост)
но всё же может быть есть ещё какой-нибудь способ? 

ИМХО редирект на другую страницу самый правильный вариант

Автор: StealtH 6.9.2007, 23:11
Имхо, из предложенного выше - самый идельный способ, сам им пользуюсь при любом запросе методом POST.
Как вариант, попробуй в базу писать md5 хеш поста, и потом при новом посте искать по этому ключу, если не найдено - добавляешь пост, если найдено - пишешь об этом пользователю или редиректишь на главную страницу.

Автор: Leshik 6.9.2007, 23:27
Цитата(StealtH @  6.9.2007,  23:11 Найти цитируемый пост)
Как вариант, попробуй в базу писать md5 хеш поста

А не могли бы вы обьяснить как это сделать или где про это можно почитать.
Спасибо

Автор: StealtH 7.9.2007, 09:46
Цитата(Leshik @ 6.9.2007,  23:27)
Цитата(StealtH @  6.9.2007,  23:11 Найти цитируемый пост)
Как вариант, попробуй в базу писать md5 хеш поста

А не могли бы вы обьяснить как это сделать или где про это можно почитать.
Спасибо

Запросто ! 

man Digest::MD5

Там даже примеры есть. 

Если вкратце, то делаешь хэш(md5_hex($post)) и пишешь его в отдельный файл, потом при добавлении поста формируешь md5-сумму поста и ищешь подобную в файле с хэшами. 


Код


#!/usr/bin/perl

use strict;

..................................

my $hash = md5_hex($FORM{'post'});
open FILE, 'hashes';
chomp(my @hashes = <FILE>);
my $flag = 0;
for(0..$#hashes)}{

    if($hash eq $hashes[$_]){
         $flag = 1;
         last;
    }
}

if (!$flag){
    open FILE, ">>hashes";
    print FILE $hash, "\n";
} else {
    &message('Duplicate of record');
}





Примерно так, но такой подход не есть зергуд в плане быстродействия и ресурсов, особенно когда количество записей в гесте будет больше 5-6 тысяч.

Автор: SHAmanovi4 7.9.2007, 14:30
А я делаю self-redirect. То есть, перенаправляю на ту же страницу. Если нужно вывести сообщение, то делаю так:

Код

print qq(Location: $ENV{HTTP_REFERER}&ok=1\n\n);

А при выводе формы и гостевой палю, есть ли этот параметр.

Код

if($ENV{ok})
{
print "<h2 class='ok'>Ваше сообщение добавлено</h2>";
}

Автор: Leshik 7.9.2007, 17:34
Всем спасибо  smile , буду пробовать.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)