2

最好的问候,对不起我的英语不好,我有ajax perl 聊天脚本

索引页是incoming.cgi

use strict;
use warnings;
use CGI;
use Fcntl qw(:DEFAULT :flock);
use File::Basename;

#DEBUG
    #use Carp qw( confess );
    #$SIG{__DIE__} =  \&confess;


# Not so elegant... to be improved
my ($scriptname,$scriptdir,$scriptsuffix) = fileparse($ENV{SCRIPT_FILENAME});
my %config = (do $scriptdir.'config.pl');

my $query = new CGI;

my $text = $query->param('text');
my $user = $query->param('user');

if ( !defined $text || !defined $user) { print $query->header('text/plain; charset="UTF-8"',401); exit; }   # Bad formed request

# Check for unwanted clients
my $badipfilename = $config{pathonserver}."banlist.dat";
open(my $badipfile,  "<:encoding(UTF-8)", $badipfilename )  or die "Unable to load file $badipfilename: $!";
my $ban = <$badipfile> || "";
if( $ban ne "" && $ENV{'REMOTE_ADDR'} =~ /$ban/ ) { print $query->header('text/plain; charset="UTF-8"',403); exit; }    # Banned IP
close($badipfile);

# OK Well formed request && accepted client
print $query->header('text/plain; charset="UTF-8"');

if ( length($text) > 1024  || length($text) == 0) { print "TEXTSIZE"; exit; }
if ( length($user) > 32 || length($text) == 0) { print "USERSIZE"; exit; }

# check for HTML
if ( $user =~ /<(?:.|\s)*?>/i ) { print "HTMLUSER|$&"; exit; }
if ( $text =~ /<(?:.|\s)*?>/i ) { print "HTMLTEXT|$&"; exit; }

# check for unwanted words
my $badwordsfilename = $config{pathonserver}."badwords.dat";
open(my $badwordsfile,  "<:encoding(UTF-8)", $badwordsfilename )  or die "Unable to load file $badwordsfilename: $!";
my $bw = <$badwordsfile> || "";
close($badwordsfile);
my $bwregex = '(^|\s)('.$bw.')($|\s)';

if ( $bw ne "" && $user =~ /$bwregex/i ) { print "BADUSER|$&"; exit; }
if ( $bw ne "" && $text =~ /$bwregex/i ) { print "BADTEXT|$&"; exit; }

# OK all test passed
my $lidfilename = $config{pathonserver}."lastid.dat";
my $chatfilename = $config{pathonserver}."chat.dat";

open(LASTIDFILE,  "+<:encoding(UTF-8)", $lidfilename )  or die "Unable to load file $lidfilename: $!";

# We use lock on this file to sync with other actions
# START OF CRITICAL SECTION
flock( LASTIDFILE, LOCK_EX ) or die "Cannot gain FLOCK on file $lidfilename: $!";

# Open this INTO critical section or other access will cause errors
open(my $chatfile,  "+<:encoding(UTF-8)", $chatfilename )  or die "Unable to open file $chatfilename: $!";

my $newid;

if( -s $chatfile > 150000 )
{   
    # The file is too big, let's prune
    my $newchatfilename = $config{pathonserver}."newchat.dat";
    open( my $newchatfile, ">:encoding(UTF-8)", $newchatfilename) or die "Unable to create file $newchatfilename: $!";

    my $i = 0;
    while( <$chatfile> )
    {   
        # Roll the file rows until we reach 75 K
        if( tell($chatfile) > 75000 )
        {
            # Ok we can copy the following rows reassigning a new ID
            my @chatfields = split /\|/;
            $chatfields[0] = $i;
            print $newchatfile join( '|' , @chatfields);
            $i ++;
        }
    }
    $newid = $i;

    close $chatfile;
    close $newchatfile;

    # Cleanup deleting old chat.txt and replacing with the new chat.txt
    if (unlink($chatfilename) != 1)
    {
        my $errstr = "Unable to delete file $chatfilename: $!";
        unlink $newchatfilename;
        die $errstr;
    }
    rename $newchatfilename,$chatfilename;

    # Re-open chat.txt as if it was never modified
    open($chatfile,  "+<", $chatfilename )  or die "Unable to open file $chatfilename: $!";
}
else
{
    seek(LASTIDFILE, 0, 0);

    my $lastserverid = <LASTIDFILE>;
    $newid = $lastserverid + 1;
}

# Do some checks on the text the user inserted
# We must do these tests here because we cannot trust the script input
chomp $text;
chomp $user;

$text =~ s/\|//g;
$user =~ s/\|//g;

# Ok let's format our record

my @localtime = localtime();
my @dateformat = ($localtime[3],$localtime[4] + 1,($localtime[5] + 1900)%100);
my $chatrow = $newid . '|' . $ENV{'REMOTE_ADDR'} . '|' . sprintf("%02d/%02d/%02d",$dateformat[$config{dateformat0}],$dateformat[$config{dateformat1}],$dateformat[$config{dateformat2}]) . '|' . 
                sprintf("%02d:%02d:%02d",$localtime[2],$localtime[1],$localtime[0]) . '|' . 
                $user . '|' . $text;

truncate(LASTIDFILE,0);
seek(LASTIDFILE, 0, 0);
print LASTIDFILE $newid;

seek($chatfile, 0, 2);
if( tell($chatfile) > 0 ) 
{
    print $chatfile "\n";
}
print $chatfile $chatrow;

close($chatfile);
#END OF CRITICAL SECTION
close(LASTIDFILE);

print "OK";

这里是 apc.js 的函数

function AJAXPerlChat() 
{
    // Config params
    this.cgiDir = "/cgi-bin/apc/";  // Path to AJAX Perl Chat CGIs
    this.documentDir = "/apc/";     // Path to AJAX Perl Chat JSs & HTMLs
    ///////////////////////////

    this.ajax = false;
    this.chatFrame = null;

    this.lastMsgId = 0;
    this.failedRequests = 0;
    this.timeoutRequests = 0;

    this.stick = true;
    this.started = false;   
    this.resetted = false;

    this.nickInput = null;
    this.textInput = null;
    this.adminLink = null;

    this.refreshAJAXObj = null;
    this.submitAJAXObj = null;
}

AJAXPerlChat.prototype.InstallAJAXObjects = function()
{
    var self = this;

    // The AJAX Objects
    this.refreshAJAXObj = new AJAXObj();
    this.submitAJAXObj = new AJAXObj();



    // Data receive callback for refresh request
    this.refreshAJAXObj.onReceiveResponse = function(status,statusText,responseText)
    {
        switch(status)
        {
            case 200:
                self.failedRequests = 0;
                self.timoeoutRequests = 0;
                if(responseText == 'RESET')
                {
                    self.Reset();
                    break;
                }
                else self.ReceiveChatData(responseText);
                break;
            default:
                // We had some troubles
                self.HandleFailedRequest();             
                break;
        }       
    }

    // Timeout callback for refresh request
    this.refreshAJAXObj.onRequestTimeout = function()
    {
        // We had timeout
        self.refreshAJAXObj.abort();
        self.HandleTimeoutRequest();
    }
    if(this.refreshAJAXObj.CreateRequest())
        this.ajax = true;
    else
        return;


    // Data receive callback for submit request
    this.submitAJAXObj.onReceiveResponse = function(status,statusText,responseText)
    {
        self.nickInput.disabled = false;
        self.textInput.disabled = false;

        if(status != 200)
        {
            // We had some troubles
            self.HandleFailedRequest();
        }
        else
        {
            var splitresponse = responseText.split("|");
            switch(splitresponse[0])
            {
                case "TEXTSIZE":
                    self.ReportError('Testo troppo lungo (o nullo)',4000);
                    break;
                case "USERSIZE":
                    self.ReportError('Nickname troppo lungo (o nullo)',4000);
                    break;
                case "HTMLUSER":
                    self.ReportError('Non &egrave; ammesso codice HTML nel nickname: &quot;' + htmlentities(splitresponse[1],'ENT_NOQUOTES') + '&quot;',4000);
                    break;
                case "HTMLTEXT":
                    self.ReportError('Non &egrave; ammesso codice HTML nel testo: &quot;' + htmlentities(splitresponse[1],'ENT_NOQUOTES') + '&quot;',4000);
                    break;
                case "BADUSER":
                    self.ReportError('Testo non ammesso nel nickname: &quot;' + htmlentities(splitresponse[1],'ENT_NOQUOTES') + '&quot;',4000);
                    break;
                case "BADTEXT":
                    self.ReportError('Testo non ammesso nel messaggio: &quot;' + htmlentities(splitresponse[1],'ENT_NOQUOTES') + '&quot;',4000);
                    break;
                case "OK":
                    self.textInput.value = "";
                    break;
            }
            // SEEMS NOT WORKING IN OPERA 9 AND IN FF3 the cursor caret hides if we had an error to report but the input focuses correctly
            self.textInput.focus();
        }
    }

    // Timeout callback for submit request
    this.submitAJAXObj.onRequestTimeout = function()
    {
        // We had timeout
        self.submitAJAXObj.abort();
        self.HandleFailedRequest();
    }

    this.submitAJAXObj.onRequestAborted = function()
    {
        // Unlock controls to allow new submit
        if( self.nickInput != undefined )
            self.nickInput.disabled = false;
        if( self.nickInput != undefined )
            self.textInput.disabled = false;
    }

    if(this.submitAJAXObj.CreateRequest())
        this.ajax = true;
    else
        return;
}

// This function can be overriden to install different handlers or to use different objects
AJAXPerlChat.prototype.InstallControls = function()
{
    var self = this;

    this.chatFrame = document.getElementById("apc_chatframe");  
    this.chatFrame.onscroll = function(event) 
    { 
        if(self.chatFrame.scrollTop == self.chatFrame.scrollHeight - self.chatFrame.clientHeight)
            self.stick = true;
        else
            self.stick = false;
    }

    // Install handlers for chat controls
    this.nickInput = document.getElementById("apc_nick");
    this.textInput = document.getElementById("apc_text");
    this.adminLink = document.getElementById("apc_adminlink");

    this.nickInput.disabled = true;
    this.textInput.disabled = true;

    this.nickInput.onfocus =    function(event) { if(self.nickInput.value == 'Nickname') self.nickInput.value = ''; }
    this.nickInput.onblur =     function(event) { if(self.nickInput.value == '') self.nickInput.value = 'Nickname'; }
    this.nickInput.onkeydown =  function(event) { if(event == undefined) event = window.event; if(event.keyCode && event.keyCode==13) self.textInput.focus(); }

    this.textInput.onkeydown =  function(event) { if(event == undefined) event = window.event; if(event.keyCode && event.keyCode==13) self.Submit(); }

    this.adminLink.onclick = function(event)
    {
        open(self.documentDir + 'admin.html','AjaxPerlChatADMIN','width=620,height=600,status=yes,resizable=yes');
    }

    this.errorDiv = document.getElementById("apc_errordiv");
    this.errorDiv.style.display = "none";

}



AJAXPerlChat.prototype.Start = function()
{
    var self = this;
    this.interval = setInterval(function(){self.Refresh();},1000);
    this.started = true;

    if( this.nickInput != undefined )
        this.nickInput.disabled = false;
    if( this.textInput != undefined )
        this.textInput.disabled = false;
}

AJAXPerlChat.prototype.Stop = function()
{
    if(this.interval)
        clearInterval(this.interval);
    if(this.overloadTimer)
        clearTimeout(this.overloadTimer);
    this.started = false;

    if( this.nickInput != undefined )
        this.nickInput.disabled = true;
    if( this.textInput != undefined )
        this.textInput.disabled = true;
}

AJAXPerlChat.prototype.Overload = function()
{
    var self = this;
    this.Stop();
    this.ReportError('La chat &egrave; temporaneamente fuori uso. Attendere 10 secondi',10000);

    this.overloadTimer = setTimeout(function(){ self.timeoutRequests = 0; self.Start();},10000);
}

AJAXPerlChat.prototype.Disconnection = function()
{
    var self = this;
    this.Stop();
    this.ReportError('La chat &egrave; temporaneamente fuori uso. Attendere 30 secondi',30000);

    this.overloadTimer = setTimeout(function(){ self.Reset(); self.Start();},30000);
}

AJAXPerlChat.prototype.Refresh = function()
{
    if(!this.ajax || !this.started) return;
    this.refreshAJAXObj.SendRequest(this.cgiDir + "refresh.cgi?lid=" + this.lastMsgId,null,950,false);
}

AJAXPerlChat.prototype.Reset = function()
{
    this.resetted = true;
    this.lastMsgId = 0;
    this.failedRequests = 0;
    this.timeoutRequests = 0;
}

AJAXPerlChat.prototype.ReceiveChatData = function(receivedText)
{
    // Here we format the data
    var lines = receivedText.split('\n');
    var output = "";

    for(var i = 0; i<lines.length;i++)
    {
        var elements = lines[i].split('|');
        if(elements.length < 5) continue;
        if(elements.length < 6) elements[5] = "";
        //0:MSGID 1:IP 2:DATE 3:TIME 4:NICK 5:MESSAGE
        elements[5] = htmlentities(elements[5],'ENT_NOQUOTES');
        output += '<div class="apc_chatentrydiv"><table><tr><td class="apc_littledate">' + elements[2] + '<br />' + elements[3] + '</td><td class="apc_chatentry"><span class = "apc_chatentrynick">' + elements[4] + ':</span> <span class = "apc_chatentrytext">' + elements[5] + '</span></td></tr></table></div>';
        this.lastMsgId = elements[0];
    }
    if(this.resetted)
    {
        this.resetted = false;
        this.ClearChatData();
    }
    this.PushChatData(output);
}

AJAXPerlChat.prototype.PushChatData = function(formatted)
{
    this.chatFrame.innerHTML += formatted;
    if(this.chatFrame.scrollHeight > this.chatFrame.clientHeight && this.stick)
        this.chatFrame.scrollTop = this.chatFrame.scrollHeight - this.chatFrame.clientHeight;
}

AJAXPerlChat.prototype.ClearChatData = function()
{
    this.chatFrame.innerHTML = "";
}

AJAXPerlChat.prototype.ReportError = function(errorstring,timer)
{
    var self = this;

    if(this.errorDivTimer)
        clearTimeout(this.errorDivTimer);
    this.errorDiv.style.display = "";
    this.errorDiv.innerHTML = errorstring;
    this.errorDivTimer = setTimeout(function(){ self.errorDiv.style.display = "none";}, timer);
}

AJAXPerlChat.prototype.Submit = function()
{
    if(!this.ajax) return;
    if(!this.started) return;

    username = encodeURIComponent(this.nickInput.value);
    usertext = encodeURIComponent(this.textInput.value);

    this.submitAJAXObj.SendRequest(this.cgiDir + "incoming.cgi?user=" + username + "&text=" + usertext,null,1500,false);

    if( this.nickInput != undefined )
        this.nickInput.disabled = true;
    if( this.textInput != undefined )
        this.textInput.disabled = true;
}

AJAXPerlChat.prototype.HandleFailedRequest = function()
{       
    this.failedRequests ++;
    if(this.failedRequests > 5) this.Disconnection();
}

AJAXPerlChat.prototype.HandleTimeoutRequest = function()
{       
    this.timeoutRequests ++;
    if(this.timeoutRequests > 5) this.Overload();
}


function htmlentities (string, quote_style) {
    // http://kevin.vanzonneveld.net
    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: nobbler
    // +    tweaked by: Jack
    // +   bugfixed by: Onno Marsman
    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // -    depends on: get_html_translation_table
    // *     example 1: htmlentities('Kevin & van Zonneveld');
    // *     returns 1: 'Kevin &amp; van Zonneveld'

    var histogram = {}, symbol = '', tmp_str = '', entity = '';
    tmp_str = string.toString();

    if (false === (histogram = get_html_translation_table('HTML_ENTITIES', quote_style))) {
        return false;
    }

    for (symbol in histogram) {
        entity = histogram[symbol];
        tmp_str = tmp_str.split(symbol).join(entity);
    }

    return tmp_str;
}

function get_html_translation_table(table, quote_style) {
    // http://kevin.vanzonneveld.net
    // +   original by: Philip Peterson
    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   bugfixed by: noname
    // +   bugfixed by: Alex
    // +   bugfixed by: Marco
    // %          note: It has been decided that we're not going to add global
    // %          note: dependencies to php.js. Meaning the constants are not
    // %          note: real constants, but strings instead. integers are also supported if someone
    // %          note: chooses to create the constants themselves.
    // %          note: Table from http://www.the-art-of-web.com/html/character-codes/
    // *     example 1: get_html_translation_table('HTML_SPECIALCHARS');
    // *     returns 1: {'"': '&quot;', '&': '&amp;', '<': '&lt;', '>': '&gt;'}

    var entities = {}, histogram = {}, decimal = 0, symbol = '';
    var constMappingTable = {}, constMappingQuoteStyle = {};
    var useTable = {}, useQuoteStyle = {};

    useTable      = (table ? table.toUpperCase() : 'HTML_SPECIALCHARS');
    useQuoteStyle = (quote_style ? quote_style.toUpperCase() : 'ENT_COMPAT');

    // Translate arguments
    constMappingTable[0]      = 'HTML_SPECIALCHARS';
    constMappingTable[1]      = 'HTML_ENTITIES';
    constMappingQuoteStyle[0] = 'ENT_NOQUOTES';
    constMappingQuoteStyle[2] = 'ENT_COMPAT';
    constMappingQuoteStyle[3] = 'ENT_QUOTES';

    // Map numbers to strings for compatibilty with PHP constants
    if (!isNaN(useTable)) {
        useTable = constMappingTable[useTable];
    }
    if (!isNaN(useQuoteStyle)) {
        useQuoteStyle = constMappingQuoteStyle[useQuoteStyle];
    }

    if (useQuoteStyle != 'ENT_NOQUOTES') {
        entities['34'] = '&quot;';
    }

    if (useQuoteStyle == 'ENT_QUOTES') {
        entities['39'] = '&#039;';
    }

    if (useTable == 'HTML_SPECIALCHARS') {
        // ascii decimals for better compatibility
        entities['38'] = '&amp;';
        entities['60'] = '&lt;';
        entities['62'] = '&gt;';
    } else if (useTable == 'HTML_ENTITIES') {
        // ascii decimals for better compatibility
      entities['38']  = '&amp;';
      entities['60']  = '&lt;';
      entities['62']  = '&gt;';
      entities['160'] = '&nbsp;';
      entities['161'] = '&iexcl;';
      entities['162'] = '&cent;';
      entities['163'] = '&pound;';
      entities['164'] = '&curren;';
      entities['165'] = '&yen;';
      entities['166'] = '&brvbar;';
      entities['167'] = '&sect;';
      entities['168'] = '&uml;';
      entities['169'] = '&copy;';
      entities['170'] = '&ordf;';
      entities['171'] = '&laquo;';
      entities['172'] = '&not;';
      entities['173'] = '&shy;';
      entities['174'] = '&reg;';
      entities['175'] = '&macr;';
      entities['176'] = '&deg;';
      entities['177'] = '&plusmn;';
      entities['178'] = '&sup2;';
      entities['179'] = '&sup3;';
      entities['180'] = '&acute;';
      entities['181'] = '&micro;';
      entities['182'] = '&para;';
      entities['183'] = '&middot;';
      entities['184'] = '&cedil;';
      entities['185'] = '&sup1;';
      entities['186'] = '&ordm;';
      entities['187'] = '&raquo;';
      entities['188'] = '&frac14;';
      entities['189'] = '&frac12;';
      entities['190'] = '&frac34;';
      entities['191'] = '&iquest;';
      entities['192'] = '&Agrave;';
      entities['193'] = '&Aacute;';
      entities['194'] = '&Acirc;';
      entities['195'] = '&Atilde;';
      entities['196'] = '&Auml;';
      entities['197'] = '&Aring;';
      entities['198'] = '&AElig;';
      entities['199'] = '&Ccedil;';
      entities['200'] = '&Egrave;';
      entities['201'] = '&Eacute;';
      entities['202'] = '&Ecirc;';
      entities['203'] = '&Euml;';
      entities['204'] = '&Igrave;';
      entities['205'] = '&Iacute;';
      entities['206'] = '&Icirc;';
      entities['207'] = '&Iuml;';
      entities['208'] = '&ETH;';
      entities['209'] = '&Ntilde;';
      entities['210'] = '&Ograve;';
      entities['211'] = '&Oacute;';
      entities['212'] = '&Ocirc;';
      entities['213'] = '&Otilde;';
      entities['214'] = '&Ouml;';
      entities['215'] = '&times;';
      entities['216'] = '&Oslash;';
      entities['217'] = '&Ugrave;';
      entities['218'] = '&Uacute;';
      entities['219'] = '&Ucirc;';
      entities['220'] = '&Uuml;';
      entities['221'] = '&Yacute;';
      entities['222'] = '&THORN;';
      entities['223'] = '&szlig;';
      entities['224'] = '&agrave;';
      entities['225'] = '&aacute;';
      entities['226'] = '&acirc;';
      entities['227'] = '&atilde;';
      entities['228'] = '&auml;';
      entities['229'] = '&aring;';
      entities['230'] = '&aelig;';
      entities['231'] = '&ccedil;';
      entities['232'] = '&egrave;';
      entities['233'] = '&eacute;';
      entities['234'] = '&ecirc;';
      entities['235'] = '&euml;';
      entities['236'] = '&igrave;';
      entities['237'] = '&iacute;';
      entities['238'] = '&icirc;';
      entities['239'] = '&iuml;';
      entities['240'] = '&eth;';
      entities['241'] = '&ntilde;';
      entities['242'] = '&ograve;';
      entities['243'] = '&oacute;';
      entities['244'] = '&ocirc;';
      entities['245'] = '&otilde;';
      entities['246'] = '&ouml;';
      entities['247'] = '&divide;';
      entities['248'] = '&oslash;';
      entities['249'] = '&ugrave;';
      entities['250'] = '&uacute;';
      entities['251'] = '&ucirc;';
      entities['252'] = '&uuml;';
      entities['253'] = '&yacute;';
      entities['254'] = '&thorn;';
      entities['255'] = '&yuml;';
    } else {
        throw Error("Table: "+useTable+' not supported');
        return false;
    }

    // ascii decimals to real symbols
    for (decimal in entities) {
        symbol = String.fromCharCode(decimal);
        histogram[symbol] = entities[decimal];
    }

    return histogram;
}

我已经向incoming.cgi 添加了一个提交按钮,以使用参数文本和用户发送

 <input type="submit" value=" POST " name="apc_text">

当我尝试通过按钮(名称和文本)发送它失败并且它(默认情况下)刷新整个页面,这需要很长时间才能响应,我试图使提交按钮仅重新加载内部框架

我怎么了

4

1 回答 1

0

我承认我浏览了您的代码,没有扫描它,但我注意到您正在禁用文本输入,并在其上挂起一个按键事件。

您可能还需要一个单击事件处理程序,并且您可能希望从处理程序返回 false 以便表单不会提交到服务器。

于 2012-12-19T20:20:08.580 回答