Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Updating a record based on cookie retrieval

by Nik (Initiate)
on Dec 07, 2004 at 12:26 UTC ( [id://412892]=perlquestion: print w/replies, xml ) Need Help??

Nik has asked for the wisdom of the Perl Monks concerning the following question:

Why the following code does upadte the visitors hostname in the database bu instead it adds a new row for the same visitor?
What am i missing here?
cookies are setuped correctly though likek this:
%cookie = fetch CGI::Cookie if $ENV{HTTP_COOKIE}; $cookie1 = cookie( -name=>"host", -value=>$host, -expires +=>"+7d" ); $cookie2 = cookie( -name=>"xronos", -value=>$xronos, -expires +=>"+7d" ); $cookie3 = cookie( -name=>"visits", -value=>cookie(visits)+1, -expires +=>"+7d" );
if ( $ENV{HTTP_COOKIE} ) { $st = $db->prepare( 'SELECT * FROM logs' ); $st->execute(); while ( $row = $st->fetchrow_hashref ) { if ( cookie(host) eq $row->{host} ) { $db->do( "UPDATE logs SET visits=visits+1 WHERE host='cookie( +host)'" ) or die $db->errstr; } } } elsif ( !$ENV{HTTP_COOKIE} ) { $db->do( "INSERT INTO logs VALUES (NULL, '$host', '$xronos', '$file +', 1)" ) or die $db->errstr; }
The Devil Is In The Details!

Replies are listed 'Best First'.
Re: Updating a record based on cookie retrieval
by davorg (Chancellor) on Dec 07, 2004 at 13:45 UTC

    Your major problem is that you are trying to interpolate a function call (cookie("host")) into a double-quoted string and Perl doesn't do that.

    However, you are making the logic a lot more complex than it needs to be. I'd do something like this (untested):

    my $host = cookie('host'); unless ($db->do("update logs set visits=visits+1 where host='$host')" +> 1) { $db->do("insert into logs values (null, '$host', '$xronos', '$file', + 1)"); }

    I've omitted error checking for clarity.

    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Updating a record based on cookie retrieval
by sasikumar (Monk) on Dec 07, 2004 at 12:53 UTC
    Hi
    Try using use strict;
    And clear all the errors that should resolve ur problem
    I hope this will not work if ( cookie(host) eq $row->{host} ) {
    Instead try this one  if ( %cookie->{host} eq $row->{host} ) {

    Thanks
    SasiKumar
Re: Updating a record based on cookie retrieval
by Jenda (Abbot) on Dec 07, 2004 at 16:24 UTC

    (mutters incomprehensibly)First, why do you fetch all records from the Logs table if you are only interested in the one with host = ???? This is a terrible waste. Even if there was not an index on the column, it would still be much much quicker to ask the database to find the one row instead of forcing it to send you all.

    Second, function calls are not evaluated within doublequoted strings. Anyway you should NEVER interpolate a variable into some SQL you are gonna execute unless you either quote the variable or make sure it only contains safe characters. If you compute a number or test that the variable only contains a number you are safe, but guess what happens if you blindly interpolate a variable into a SQL like that and the variable contains a singlequote. Search the Net for "SQL injection attack". It's generaly prefered to use placeholders.

    It's not the best idea to use the INSERT INTO TableName VALUES (...). You should always specify the columns into which you are inserting the data. Imagine you add a column to the table later or reorder the columns. Booooooom. If you are lucky. If unlucky it'll still "work" and only several weeks later you find out that the data are bogus, because the columns were mixed up.

    Even if you did use a sensible SELECT statement, used placeholders and specified the columns to insert into there would still be a bug in your code. What if two instances of your script are fired at the same time? With the same host? The first one checks whether there is a row for that host, but before it'll be able to insert a row, the second script gets the CPU, runs the same check, also finds out that there is no record for the host and then both scripts insert a new row for the host. Not too good I guess.

    So what you should do is to set the database so that there is an index on the "host" column and the database doesn't allow duplicates in this column. And then use code that will try to UPDATE the row where "host = ?", if the update does not affect any rows it will try to INSERT new row with that "host" and if this fails with the "Cannot insert duplicate value ..." error, UPDATE the row where "host = ?".

    You might also use transactions (if your database supports them), but that would require table level locks (to make sure no rows are inserted between the UPDATE and the possible INSERT) and that might degrade the performance.

    Also ... if your database supports that you'd better create a stored procedure that would do the UPDATE, INSERT, UPDATE for you. That'd be more efficient than to contact the database up to three times and have it compile the SQL and build the execution plan for each visit.

    Jenda
    We'd like to help you learn to help yourself
    Look around you, all you see are sympathetic eyes
    Stroll around the grounds until you feel at home
       -- P. Simon in Mrs. Robinson

    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Updating a record based on cookie retrieval
by DaWolf (Curate) on Dec 07, 2004 at 19:00 UTC
    Not directly related to the code:

    Your table should have a UNIQUE constraint on the host field. This will avoid some precious time cleaning the table if something goes wrong, wich was the case here.

    Directly related to the code:

    if ( $ENV{HTTP_COOKIE} ) { # # Some code here # } elsif ( !$ENV{HTTP_COOKIE} ) { # # Some code here # }


    Your elsif is rubbish, since your testing only one condition. It should be replaced by a simple else.

    Regards,

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://412892]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (6)
As of 2024-04-19 13:15 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found