Gossamer Forum
Home : Products : Links 2.0 : Customization :

Widgetz MyLinks Bug Fixed

Quote Reply
Widgetz MyLinks Bug Fixed
Hi all,

in my last posting I said that I thought that theres a little bug in mylinks.cgi
Somehow nowbody didn't really figured out what I ment - now my exact explanation. (Eliot - hope you see that this is a bug now Wink)
---
We have two persons and two computers
Person 1: Links Admin and Computer 1: Server
Person 2: Links visitor and Computer 2: HomePC
Now P2 visits page of P1 and thinks that there's a cool link (ID=5). He bookmarks it.
Now C1 sets a cookie on C2.
One week later P1 sees that ID=5 is broken for an unknown reason. He deletes it in Links admin so the link is not longer avaiable.
One week later P2 comes back to the site and wants to view mylinks.cgi
The cookie is stil stored on his computer with link ID=5 in it.
Now when he views mylinks.cgi he don't see the bookmark anymore (because it has been deleted by P1) but instead of this he sees a bookmark with "Unknown Tag: Title" - Instead of the real bookmarked title.
Thats a bug isn't it ? Smile
---
Ok and heres my solution:
change mylinks.cgi to this
Code:
#!/usr/local/bin/perl
#############################################################################
# mylinks.cgi
#
#############################################################################
# Script written by Jerry Su, jsu7785@email.com
#
# -------------------------------------------------------------------------
#
# PROGRAM NAME: MyLinks
#
# VERSION: 1.0
#
# LAST MODIFIED: 11/29/99
#
# =========================================================================
#
# REQUIRED MODULES: CGI.pm, CGI/Carp.pm
#
# =========================================================================
#
# COPYRIGHT NOTICE:
#
#
#
# Copyright (c)1999-2000 Jerry Su. All Rights Reserved.
#
#
#
# MyLinks is redistributed AS-IS, with no guarantees or warrantees of any
#
# kind. The author of the script will not be held liable to any damage,
#
# both direct or indirect, that this script may cause you.
#
#
#
# If you have any questions or comments, please email jsu7785@email.com
#
#############################################################################

# Cookie information.
my %cookie = (
name => 'MyLinks',
expires => '+3y',
path => '/',
domain => '.eurotango.org'
);

# Deliminator (MUST BE A LETTER [no symbols or numbers]!)
my $delim = 'A';

# Links to display per page.
my $per_page = 10;

# Characters used in encoding/decoding.
my @e = qw!0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z!;

# Load required modules and libraries.
# ---------------------------------------------------
use CGI ();
use CGI::Carp qw/fatalsToBrowser/;
require "admin/links.cfg";
require "$db_lib_path/db_utils.pl";
require "$db_lib_path/links.def";
$build_use_templates ?
require "$db_lib_path/site_html_templates.pl" :
require "$db_lib_path/site_html.pl";
$|++;
# ========================================================

&main ();

sub main {
# ---------------------------------------------------
# Determine what to do.
#
my $in = new CGI;

if ($in->param('add')) { &add ($in); }
elsif ($in->param('delete')) { &delete ($in); }
elsif ($in->param('help')) { &help ($in); }
else { &display ($in); }
}
# ==============================================================

sub add {
# --------------------------------------------------------
# Adds an ID from the users cookie.
#
my $in = shift;
my $id = $in->param('add');
my $c = $in->cookie($cookie{'name'});

# Make sure we have a valid ID.
unless ($id =~ m,^\d+$,) {
print $in->header();
&site_html_myadderror ("Invalid Link ID: $id");
return;
}

my (%rec) = &get_record ($id);
if ($rec{$db_key} ne $id) {
print $in->header();
&site_html_myadderror ("Unkown Link ID: $id");
return;
}

my $e = &encode ($id);
my @c = split $delim, $c;
my %c = map { $_ => 1 } @c;

# Check to see if the ID is in the cookie.
if ($c{$e}) {
print $in->header();
&site_html_myadderror ("Already in Cookie: $id $e");
return;
}

# Make the cookie.
my $cookie = $in->cookie (
-name => $cookie{'name'},
-value => (join $delim, @c, $e),
-expires => $cookie{'expires'},
-path => $cookie{'path'},
-domain => $cookie{'domain'}
);

# Set the cookie and print the header.
print $in->header ( -cookie => $cookie );
&site_html_myadd (%rec);
}

sub delete {
# --------------------------------------------------------
# Deletes an ID from the users cookie.
#
my $in = shift;
my $id = $in->param('delete');
my $c = $in->cookie($cookie{'name'});

# If ID equals to 'all', delete all.
if ($id =~ m,^ALL$,i) {
# Make the cookie.
my $cookie = $in->cookie (
-name => $cookie{'name'},
-value => '',
-expires => '-1s',
-path => $cookie{'path'},
-domain => $cookie{'domain'}
);

# Set the cookie and print the header.
print $in->header ( -cookie => $cookie );
&site_html_mydeleteall ( { total => $#c+1 } );
return;
}

# Make sure we have a valid ID.
unless ($id =~ m,^\d+$,) {
print $in->header();
&site_html_mydeleteerror ("Invalid Link ID: $id");
return;
}

my (%rec) = &get_record ($id);
if ($rec{$db_key} ne $id) {
print $in->header();
&site_html_mydeleteerror ("Unkown Link ID: $id");
return;
}

my @c = split $delim, $c;
my %c = map { $_ => 1 } @c;
my $e = &encode ($id);

# Check to see if the id is in the cookie.
if (!$c{$e}) {
print $in->header();
&site_html_mydeleteerror ("Not in Cookie: $id");
return;
}

# Make the cookie.
my $cookie = $in->cookie (
-name => $cookie{'name'},
-value => (join $delim, grep {!/^$e$/} @c),
-expires => $cookie{'expires'},
-path => $cookie{'path'},
-domain => $cookie{'domain'}
);

# Set the cookie and print the header.
print $in->header ( -cookie => $cookie );
&site_html_mydelete (%rec);
}

sub help {
#---------------------------------------------------------
# Help Menu for people to set their Cookies.
my $in = shift;
print $in->header();
&site_html_myhelp;
return;
}

sub display {
# --------------------------------------------------------
# Creates page for links to be displayed.
#

my (%links, %cat, %rec);
foreach (@c) {
last if ($_ eq "");
%rec = &get_record ($_);
%{$links{$_}} = %rec;
push (@{$cat{$rec{Category}}}, $_);
}

CAT: foreach (sort keys %cat) {
$OUT{links} .= qq~<p>$_<br>~;
LINK: foreach (@{$cat{$_}}) {
$OUT{links} .= &site_html_mylink (%{$links{$_}});
}
}

my $in = shift;
my @c = split $delim, $in->cookie($cookie{'name'});
my $p = $in->param('page') | | 1;
my (%OUT, $start);
my $broken = "0";

$OUT{'total'} = $#c+1;
$OUT{'links'} = "";
$OUT{'span'} = "";

if ($OUT{'total'} > 0) {
$tpages = int $OUT{'total'}/$per_page + (($OUT{'total'} % $per_page) ? 1 : 0);
$p = 1 if ($p > $tpages);
my $start = ($p-1) * $per_page;
my $url = $ENV{'SCRIPT_NAME'};

# Builds the span pages.
if ($tpages > 1) {
my $prev = $p-1;
my $next = $p+1;

if ($p > 1) {
$OUT{'span'} .= qq~<a href="$url~;
$OUT{'span'} .= qq~?page=$prev~ if ($prev > 1);
$OUT{'span'} .= qq~"><b>< Previous</b></a> <a href="$url">1</a> ~;
if ($prev > 1) {
for (2 .. $prev) { $OUT{'span'} .= qq~<a href="$url?page=$_">$_</a> ~; }
}
}
else { $OUT{'span'} .= qq~< Previous ~; }
$OUT{'span'} .= qq~<b>$p</b> ~;
if ($p < $tpages) {
for ($next .. $tpages) { $OUT{'span'} .= qq~<a href="$url?page=$_">$_</a> ~; }
$OUT{'span'} .= qq~<a href="$url?page=$next"><b>Next ></b></a>~;
}
else { $OUT{'span'} .= qq~Next >~; }
}

# Builds the links.
foreach (@c[$start .. ($start + $per_page - 1)]) {
last if ($_ eq "");
my @exist = &get_record (&decode ($_));
my $ex = @exist;
if ($ex > 1) {
$OUT{'links'} .= &site_html_mylink (@exist);
}
else {
$broken++;
next;
}
}
}
$OUT{'totallinks'} = $OUT{'total'}-$broken;

# Builds the MyLinks page.
print $in->header();
&site_html_myhome ( { %OUT } );
}

sub encode {
# --------------------------------------------------------
# Encodes ID into a alphanumeric smaller value.
#
my $in = shift;
my ($out);

while ($in >= ($#e+1)) {
$out = $e[$in % ($#e+1)] . $out;
$in = int $in/($#e+1);
}
$out = $e[$in] . $out;
return $out;
}

sub decode {
# --------------------------------------------------------
# Decodes ID from an alphanumeric smaller value.
#
my $in = shift;
my ($y, $out);
my $x = 0;
my %e = map { $_ => $x++; } @e;

for ($x = 0; $x < length($in); $x++) {
$y = substr ($in, $x, 1);
$out = $out * ($#e+1) + $e{$y};
}
return $out;
}
and replace the <%total%> - tag in your mylinks templates to <%totallinks%> - if you have.
Then replace this eurotango.org/links/site_html_templates.txt with your subs in site_html_templaes.pl
Then rename your templates to the templatenames in my site_html_templates.txt if they differ.
That should be all.
Here's the whole mylinks.cgi to download
eurotango.org/links/mylinks.txt
Don't forget to change the domain to yours.

---

Now what I wanna know is whether someone can make a better code out of my modification. I don't think that I have chosen the best solution to fix this bug - but it works Smile
I thought about adding a routine here
Code:
else {
$broken++;
next;
}
which deletes the entry of the deleted Link in the cookie but I don't know how to do that right now.
Maybe there is anyone who could do some better coding...
cya all,

nikolai

[This message has been edited by DigitalFusion (edited April 02, 2000).]
Quote Reply
Re: Widgetz MyLinks Bug Fixed In reply to
Hey all,

just wanted to bring to top Wink since I gfot no feedback yet...
Did anyone else than Jimmy tried out the code ?
cya,

nikolai
Quote Reply
Re: Widgetz MyLinks Bug Fixed In reply to
No comments ?

Eliot Smile I really would like to hear what you say since I am really doing a lot to learn perl now - and it is always good to hear whether a written code is good or not.
And I really would like to know whether you understand what i mean (what the bug is) now Wink
cya,

nikolai
Quote Reply
Re: Widgetz MyLinks Bug Fixed In reply to
Codes look fine to me...

Regards,

------------------
Eliot Lee....
Former Handle: Eliot
* Check Resource Center
* Search Forums
* Thinking out of the box (codes) is not only fun, but effective.
Quote Reply
Re: Widgetz MyLinks Bug Fixed In reply to
Actually working perfectly, DigitalFusion! You made my day! ;-)

Thomas
www.japanreference.com/
Quote Reply
Re: Widgetz MyLinks Bug Fixed In reply to
is everyone having the same problem?
do i really need to make these changes or depends on the server i'm on?
Quote Reply
Re: Widgetz MyLinks Bug Fixed In reply to
theguy,

yeah - everybody has this problem since the unmodified mylinks.cgi does not check whether a stored ID in a cookie really exist in the database.
So if you have stored an ID in a cookie and the linksadmin has deleted it everyone will get this error who has stored this link in his cookie.
So just modify the script and you won't get this error anymore Smile
cya,

nikolai
Quote Reply
Re: Widgetz MyLinks Bug Fixed In reply to
It's still not quite right.

If you have links that span pages there will be fewer than expected links appearing on some pages - and only page 1 will show the correct total. The other pages will show the total of links plus deleted links.

Somehow we need to delete the extra IDs from the cookie.

Anybody know how?

Warwick

------------------
HumorLinks Comedy Search, Humor DVD and Video Store

humorlinks.com

humorlinks@humorlinks.com


[This message has been edited by humorlinks (edited April 06, 2000).]
Quote Reply
Re: Widgetz MyLinks Bug Fixed In reply to
Unfortunately, since cookies are stored on end-user's computers...there is virtually no way to do this.

The ideal answer is creating a user database (via MySQL for scalability purposes) that stores links and also deletes those links from the user database when they are deleted from the main links database.

Regards,

------------------
Eliot Lee....
Former Handle: Eliot
* Check Resource Center
* Search Forums
* Thinking out of the box (codes) is not only fun, but effective.
Quote Reply
Re: Widgetz MyLinks Bug Fixed In reply to
The user could delete the defunct record from the cookie, if the ID number of the missing record could be passed to the my_home page. So on the MyLinks page, in place of the missing record the user would get: -

"The link with ID number <%linkid%> has been removed from the database - click <a href="/cgi-bin/links/mylinks.cgi?delete=<%linkid%>">here</a> to remove this message."

Anyone know how to get that <%linkid%> so it can be used in my_link.html template?

It should come from &decode ($_) in DigitalFusion's example above, but how?

Warwick



------------------
HumorLinks Comedy Search, Humor DVD and Video Store

humorlinks.com

humorlinks@humorlinks.com
Quote Reply
Re: Widgetz MyLinks Bug Fixed In reply to
I think that you can fix all the problems but my perlknowledge is not the best so i need a little bit more help Wink
I'll tell my ideas later on - have to work now Frown
BTW - I didn't notice that the links number is not correct on the spanpages - I'll try to fix it...
cya,

nikolai
Quote Reply
Re: Widgetz MyLinks Bug Fixed In reply to
Okay. We've got it working so the user can delete the record from the cookie - and this automatically solves all the other problems.

Here's the amended code (see DigitalFusion's example above)

Code:
# Builds the links.
foreach (@c[$start .. ($start + $per_page - 1)]) {
last if ($_ eq "");
my $quant = &decode ($_);
my @exist = &get_record (&decode ($_));
my $ex = @exist;
if ($ex > 1) {
$OUT{'links'} .= &site_html_my_link (@exist);
}
else {
$broken++;
$OUT{'links'} .= qq~<ul><li>The link with ID number $quant has been removed from the database. <a href="/cgi-bin/links/mylinks.cgi?delete=$quant">Click here</a> to remove this message.</ul>~;
next;
}
}
}
$OUT{'brokenlinks'} = $broken;

Then the only other thing you have to do is stop the delete routine checking for a valid ID in the database. So shorten the delete routine so it looks like this : -

Code:
sub delete {
# --------------------------------------------------------
# Deletes an ID from the users cookie.
#
my $in = shift;
my $id = $in->param('delete');
my $c = $in->cookie($cookie{'name'});

# If ID equals to 'all', delete all.
if ($id =~ m,^ALL$,i) {
# Make the cookie.
my $cookie = $in->cookie (
-name => $cookie{'name'},
-value => '',
-expires => '-1s',
-path => $cookie{'path'},
-domain => $cookie{'domain'}
);

# Set the cookie and print the header.
print $in->header ( -cookie => $cookie );
&site_html_my_delete_all ( { total => $#c+1 } );
return;
}
my (%rec) = &get_record ($id);
my @c = split $delim, $c;
my %c = map { $_ => 1 } @c;
my $e = &encode ($id);

# Check to see if the id is in the cookie.
if (!$c{$e}) {
print $in->header();
&site_html_my_delete_error ("Not in Cookie: $id");
return;
}

# Make the cookie.
my $cookie = $in->cookie (
-name => $cookie{'name'},
-value => (join $delim, grep {!/^$e$/} @c),
-expires => $cookie{'expires'},
-path => $cookie{'path'},
-domain => $cookie{'domain'}
);

# Set the cookie and print the header.
print $in->header ( -cookie => $cookie );
&site_html_my_delete (%rec);
}

Then you can also put the total number of broken links on each page as follows in the my_home.html template : -

Code:
<%if total eq 1%>
- with just <%total%> link
<%endif%>
<%if total > 1%>
- with a total of <%total%> links
<%endif%>
<%if brokenlinks > 0%>
(<%brokenlinks%> on this page defunct)
<%endif%>

Warwick


------------------
HumorLinks Comedy Search, Humor DVD and Video Store

humorlinks.com

humorlinks@humorlinks.com


[This message has been edited by humorlinks (edited April 07, 2000).]
Quote Reply
Re: Widgetz MyLinks Bug Fixed In reply to
Warwick,

First of all: really cool modification Smile That's what I wanted.
I have found one single bug which I have removed.
When you delete this "The link with ID number $quant has been removed from the database." link you get a confirmation message that the link has been deleted but there you get again the "unknown Tag" Smile
just do the following steps and you will get a full working version of mylinks.cgi
replace the whole sub delete in mylinks.cgi with this:
Code:
sub delete {
# --------------------------------------------------------
# Deletes an ID from the users cookie.
#
my $in = shift;
my $id = $in->param('delete');
my $c = $in->cookie($cookie{'name'});

# If ID equals to 'all', delete all.
if ($id =~ m,^ALL$,i) {
# Make the cookie.
my $cookie = $in->cookie (
-name => $cookie{'name'},
-value => '',
-expires => '-1s',
-path => $cookie{'path'},
-domain => $cookie{'domain'}
);
# Set the cookie and print the header.
print $in->header ( -cookie => $cookie );
&site_html_mydeleteall ( { total => $#c+1 } );
return;
}
my (%rec) = &get_record ($id);
my @real = %rec;
my $exi = @real;
if ($exi > 2) {
%real = %rec;
}

open (TEST, ">test.txt");
print TEST $exi;
close TEST;
my @c = split $delim, $c;
my %c = map { $_ => 1 } @c;
my $e = &encode ($id);

# Check to see if the id is in the cookie.
if (!$c{$e}) {
print $in->header();
&site_html_mydeleteerror ("Not in Cookie: $id");
return;
}
# Make the cookie.
my $cookie = $in->cookie (
-name => $cookie{'name'},
-value => (join $delim, grep {!/^$e$/} @c),
-expires => $cookie{'expires'},
-path => $cookie{'path'},
-domain => $cookie{'domain'}
);
# Set the cookie and print the header.
print $in->header ( -cookie => $cookie );
if (%real) {
&site_html_mydelete (%real);
}
else {
&site_html_mydeleteunknown ();
}
}
Then add this to site_html_templates.pl
Code:
sub site_html_mydeleteunknown {
#------------------------------------------------------
print &load_template ('mydeleteunknown.html', {
%globals
});
}
and create a html page called "mydeleteunknown.html" like this
Code:
<html>
<head>
<STYLE>
<!--
BODY {font-family: arial; color:#000000}
P {font-family: arial}
Font {font-family: verdana}
TD {font-family: arial}
A:link {text-decoration: none; color:#003399}
A:visited {text-decoration: none; color:#003399}
A:active {text-decoration: none;}
A:hover {text-decoration: underline; color:#ff0000}
A.white:link {text-decoration: none; color:#ffffff}
A.white:visited {text-decoration: none; color:#ffffff}
A.white:active {text-decoration: none;}
A.white:hover {text-decoration: underline; color:#ff0000}
-->
</STYLE>
<title>MyLinks: Link Deleted</title>
</head>
<BODY bgcolor="#ffffff" leftMargin="0" topMargin="0" marginwidth="0" marginheight="0" rightmargin=0>
<p align="center"> <font color="#04649C" size="2"><b>You have deleted the chosen
link from My Links</b></font> <br>
</p>
<div align="center"></div>
<div align="center"></div>


<div align="center"><center>
<table border="0" cellpadding="5" cellspacing="0" width="96%">
<tr><td bgcolor="#EEEEEE">
<p align="center">
<font size="2">
<a href="<%db_cgi_url%>/mylinks.cgi"><b>Click Here</b></a></font><font color="#04649C" size="2"> to return to My Links</font>
</p>
</td></tr>
</table>
</center></div>
</BODY>
</HTML>
This should be all.
And then to modify the text which is displayed on the mylinkspages if a link has been deleted just change this code to your design
Code:
$OUT{'links'} .= qq~<ul><li>The link with ID number $quant has been removed from the database. <a href="$url?delete=$quant">Click here</a> to remove this message.</ul>~;
Btw I have changed
Code:
="/cgi-bin/links/mylinks.cgi?delete=$quant
to
Code:
$url?delete=$quant
I think that should be all Smile
Hope it works...
cya all,

nikolai
Quote Reply
Re: Widgetz MyLinks Bug Fixed In reply to
Hello Nikolai.

We bypassed this issue in a somewhat simpler way to prevent the "unknown Tag" message from appearing, and no changes are necessary to the code we posted.

Just put the following in my_delete.html : -
Code:
<%if ID%>
<p>You have deleted the following link from your MyLinks page: -</p>
<p><ul><li><a href="<%db_cgi_url%>/jump.cgi?ID=<%ID%>" target="_blank"><%Title%></a>
<%if Description%>
- <%Description%>
<%endif%>
- (<b><%Hits%></b></font> hits since <%Date%> ) <a href="<%db_cgi_url%>/mylinks.cgi?add=<%ID%>">Add back again</a>
(Rating: <%Rating%> Votes: <%Votes%> ) <a href="<%db_cgi_url%>/rate.cgi?ID=<%ID%>">Rate It</a>
</ul></p>
<p>If you made a mistake, click here to <a href="<%db_cgi_url%>/mylinks.cgi?add=<%ID%>">add it back again</a></p>
<p>If everything is okay, click here to <a href="<%db_cgi_url%>/mylinks.cgi">view your MyLinks page.</a></p>
<%endif%>
<%ifnot ID%>
<p> Message removed.</p>
<p> Click here to <a href="<%db_cgi_url%>/mylinks.cgi">view your MyLinks page.</a></p>
<%endif%>

Your way works fine, and so does ours.

Warwick


------------------
HumorLinks Comedy Search, Humor DVD and Video Store

humorlinks.com

humorlinks@humorlinks.com


[This message has been edited by humorlinks (edited April 07, 2000).]
Quote Reply
Re: Widgetz MyLinks Bug Fixed In reply to
Heh - Warwick,

you're right Smile
Also a cool solution...
cya,

nikolai
Quote Reply
Re: Widgetz MyLinks Bug Fixed In reply to
could someone post the entire solution in one post. thanks
Quote Reply
Re: Widgetz MyLinks Bug Fixed In reply to
theguy,

I'll do it tomorrow evening Smile Have no time yet.
cya,

nikolai
Quote Reply
Re: Widgetz MyLinks Bug Fixed In reply to
theguy,

The previous two humorlinks posts (above) contain the entire solution.

Just replace the relevant code in your mylinks.cgi file, my_home.html template, and my_delete.html template

You must have the Enhanced Template Support mod www.gossamer-threads.com/scripts/resources/Detailed/26.html

In the mylinks.cgi you must also remember to add : -

Code:
my $broken = "0";

where the variabels are defined so it becomes: -

Code:
my $in = shift;
my @c = split $delim, $in->cookie($cookie{'name'});
my $p = $in->param('page') | | 1;
my (%OUT, $start);
my $broken = "0";

That's all.

Warwick



------------------
HumorLinks Comedy Search, Humor DVD and Video Store

humorlinks.com

humorlinks@humorlinks.com


[This message has been edited by humorlinks (edited April 07, 2000).]

[This message has been edited by humorlinks (edited April 07, 2000).]