Link to home
Start Free TrialLog in
Avatar of mindwave
mindwave

asked on

Simple cookie script please

I want to put a coupon on the internet that can only be seen  once to stop people printing it out again and again. Sure they can delete the cookie, but most people won't know how or have anti cookie software.

The step by step procedure is

1) Viewer sees a page on our site.
2) They click on a graphic link to see a discount coupon
3) Viewer is prompted to enter their first name
4) A dialog box appears and viewer is prompted "are you sure? Y/N (in case they type it wrong)
5) A pop-up window with the coupon appears displaying the viewer's name, plus the date and time displayed.
6) Viewer can print off coupon if they choose
6) If the viewer returns again and tries to see the coupon again, they are directed to a different page.

Thank you.

The last time I asked a question, Michel kindly helped me out. You can see his code in operation at http://www.moneysaver.com.au
Avatar of Michel Plungjan
Michel Plungjan
Flag of Denmark image

Hmm the page at

http://bne003i.webcentral.com.au/catalogue/kma/_cmdlogin?name=guest&viewmode=HEADER&branchlevel=0&itemsperpage=20&maxpages=1000

was not reachable...

If it is worth someone's time to print off the coupon, the will bypass the script.

Did you mean that most people do not know how and not many people have anti cookie software???

How many of the steps do you need help with?

If I am not the one that answers this question, will the person who does, kindly reuse any cookie script already on mindwave's site?

Michel
ASKER CERTIFIED SOLUTION
Avatar of tecbuilder
tecbuilder

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of tecbuilder
tecbuilder

I just realized that I omitted a couple lines of my debugging code.

the line in [coupon1.html]

cpnWindow = window.open("printcoupon.html"+strVariables, "MyWindow", "resizable,location,height=200,width=300");

should be

cpnWindow = window.open("printcoupon.html"+strVariables, "MyWindow", "height=200,width=300");

The line in [printcoupon.html]

alert(mySearch)

should be deleted.

Another thing I thought of where frames would be a benefit is that you would not have to have the scripts in each coupon page that a person can get a coupon from.  The hidden frame would contain these scripts which would/could greatly reduce future re-coding and problems.

tecbuilder
Techbuilder: What is that "1 pixel frame is virtually undetectable???"

This IS undetectable unless the user looks at view source or view info:

<FRAMESET ROWS="100%,*">
<FRAME SRC="blabla.html">
<FRAME SRC="javascript:' '">
</FRAMESET>

Michel
The reason for the 1 pixel was because once upon at long time ago I was told that either Netscape or IE (don't remember which or which version) had a problem with setting one of the frames to 0 width.  So I have always set one frame to 1 pixel and the other to *.

tecbuilder
Well - the 0,* will make NS show a 3-4 pixel wide strip
I have used the 100%,*  for 3 years without complaint

Michel
Avatar of mindwave

ASKER

I think I've set this up ok, however, when I check how this works on Navigator 3 gold I get an error message

Javascript error: file:/coupon1.html, line 54:

illegal URL method 'printcoupon.html?Hi Jonathan
Today Is:',

Also, if the visitor returns the next day, will they be able to see the coupon the next day?

How to I change the variables for

A) how long the coupon can be seen
b) how long the cookies lasts on the users computer.

I know this is probably obvious, but I'm not sure how to modify the script to change these date variable.

Thank you for you help to date.

We're almost there!
I've put up a page with the script.

The problem I have is that it bypassed the page where you enter your name and goes straight to the page that says you are denied access.

I think this is due to the dates not being specified correctly in the cookie scripts.

See the problem by trying to view the Strathfield $10 coupon at
http://www.moneysaver.com.au/newsletters/start

It looks like it will work well once I can get this part ok and hopefully it will work in Nav 3 as well.
Adjusted points to 750
Hi mindwave, I found the errors that you found with NS3.x and I fixed them.  The code below should replace the pages that I originally posted.  I was going to just post the updated code, but felt it would be a lot easier to just replace all.  Please let me know if you have any problems.

There a couple of things to note and answers to your questions:
1)The 'DeleteCookie' function and the reference to it in coupon1.html can be deleted once you get everything up and running.  However, during testing leave it in so that it will reset the date.  Otherwise, it will treat you like a regular user.

2) The expiration date can be changed in coupon1.html.  I have a comment where this occurs that currently sets the expiration date for 30 days from the current date.  To find where it is that you make the change scroll down until you find the comment " // Set the expiration date for 30 days from the current date."  The line beneath this comment contains an equation with the value of 30 (days).  Change the 30 to some other number.

3) I am not sure what you mean by setting the variable for how long the coupon can be seen.

4) If the visitor tries to come back to the coupon a second later they will not have access to the coupon.  They get one shot at getting the coupon for the specified period of time (expiration date) and that's it.

5) The test.html that was in the original coupon1.html file can be changed to any filename.  I have renamed it in the code to be sorry.html.  If you should want to use some other filename, do a find on sorry.html and replace it with your name.


[printcoupon.html]
<HTML>
<HEAD>
<SCRIPT LANGUAGE="JavaScript">
<!--
function GetCookie(byname) {
  byname=byname+"=";
  nlen = byname.length;
  fromN = document.cookie.indexOf(byname)+0;
  if((fromN) != -1)
    {fromN +=nlen
    toN=document.cookie.indexOf(";",fromN)+0;
    if(toN == -1) {toN=document.cookie.length;}
    return unescape(document.cookie.substring(fromN,toN));
  }
  return null;
}

//-->
</SCRIPT>
</HEAD>
<BODY>
<!-- Steps 5 and 6 -->
<SCRIPT LANGUAGE="JavaScript">
<!--
var username = GetCookie("UserName");
var currentdate = new Date();
document.write("<FONT SIZE='2'>Hi "+username+"<BR>"+currentdate.toLocaleString()+"</FONT>");
//-->
</SCRIPT>
<BR>
<IMG SRC="coupon1.jpg" HEIGHT=100 WIDTH=275 ALT="">
<P>
<CENTER><A HREF="javascript:self.print()">Print this coupon</A></CENTER>
</BODY>
</HTML>

[coupon1.html]
<html>
<head>
<script language="javascript">
<!-- begin script

// getCookie() and setCookie() is based on the public domain cookie
// code produced by Bill Dortch, with some minor modifications to GetCookie().
// FixCookieDate() came from an unknown source.

function FixCookieDate (date) {
  var base = new Date(0);
  var skew = base.getTime(); // dawn of (Unix) time - should be 0
  if (skew > 0)  // Except on the Mac - ahead of its time
    date.setTime (date.getTime() - skew);
}

function GetCookie(byname) {
  byname=byname+"=";
  nlen = byname.length;
  fromN = document.cookie.indexOf(byname)+0;
  if((fromN) != -1)
    {fromN +=nlen
    toN=document.cookie.indexOf(";",fromN)+0;
    if(toN == -1) {toN=document.cookie.length;}
    return unescape(document.cookie.substring(fromN,toN));
  }
  return null;
}

function SetCookie (name,value,expires,path,domain,secure) {
  document.cookie = name + "=" + value +
    ((expires) ? "; expires=" + expires.toGMTString() : "") +
    ((path) ? "; path=" + path : "") +
    ((domain) ? "; domain=" + domain : "") +
    ((secure) ? "; secure" : "");
}
// This function is only needed while you are getting things setup.
function DeleteCookie(name,path,domain) {
  if (GetCookie(name)) document.cookie = name + "=" +
     ( (path) ? ";path=" + path : "") +
     ( (domain) ? ";domain=" + domain : "") +
     ";expires=Thu, 01-Jan-70 00:00:01 GMT";
}
<!-- Step 4 -->
// Get user's name.
function ValidateName(name) {
  var strConfirm = "You have entered your name as '" + name + "'. Click Ok if this is correct."
  if (confirm(strConfirm)) {
    var expdate = new Date();

    // Correct for Mac date bug - call only once for given Date object!
    FixCookieDate(expdate);

    // Set the expiration date for 30 days from the current date.
    expdate.setTime(expdate.getTime() + (30 * 24 * 60 * 60 * 1000)); // 30 days from now

    SetCookie("coupon1", expdate, expdate);
    // Temporarily store the person's name.  This cookie will automatically be
    // deleted when person closes browser window.
    SetCookie("UserName", name);
    // change height and width to appropriate size of window needed.
   cpnWindow = window.open("printcoupon.html", "MyWindow", "height=200,width=300");
  }
}

<!-- Check to see if user has already received a coupon within a certain period of time. -->
function canGetCoupon() {
// Delete or comment the following line once you have your site running.
//      DeleteCookie("coupon1");

  var CouponDate = GetCookie("coupon1");
  today = new Date();
  if (CouponDate != null && (CouponDate > today)) { window.location.href="sorry.html" }
}
// end script -->
</SCRIPT>
</head>
<body onLoad="canGetCoupon()">
<!-- If the user has not received a coupon within a certain period of -->
<!-- time the following code will execute. -->

<!-- Step 3 -->
<FORM NAME="Coupon">
Please enter your first name:
<INPUT TYPE="Text" NAME="UserName" SIZE="30" MAXLENGTH="30">
<P>
<INPUT TYPE="Button" VALUE="Submit"
onClick="ValidateName(this.form.UserName.value);return false">
</FORM>
</body>
</html>

[sorry.html]
<HTML>
<BODY>
Sorry but you can not get another copy of this coupon at this time.
<P>
<A HREF="main.html">Go back to main page</A>
</BODY>
</HTML>

tecbuilder
1. self.print() is only supported by NS4+ and IE5+

2. there might be no username printed in netscape 4.06+ since printing spawns a new browser process whith a temporary domain for the page so the cookie origin will be different than when it was set.
You might get a
"Hi undefined"
instead of
"Hi mindwave"

Michel
The code is up at http://www.moneysaver.com.au/newsletters/0799 and you'll see it working when you click on a Strathfield or Godfreys coupon.

If as Michel says self.print() is only supported by NS4+ and IE5+ what do I have to do to include browser controls on the smaller popup windows so the user can print off the coupon from Explorer 4?

When I'm ready to stop people seeing the coupon twice, I just delete the one line
// DeleteCookie("coupon1");

Is that right?

Also, I only have Navigator 4.08 and it seems to work ok. It doesn't seem to work on Navigator 3. It jumps straight onto the sorry.htm without letting me see the coupon and I haven't deleted the one line mentioned above!

Any ideas?


For browsers that cannot do self.print() and browsers that have disabled JavaScript you will need to insert a comment to tell those people to use File | Print from the menu to print the coupon.  You will have to provide access to the menubar.  To open a window with the menubar use the following:

cpnWindow = window.open("printcoupon1.htm", "MyWindow", "menubar=yes,height=460,width=620");

How to display to the user the method they can use to print can be done in 3 ways:
1) Add the comment just below (or anywhere else you like) the "I agree to these terms & wish to print this coupon" link.  This is the safest and simplest fix.  The reason is that no matter what, you have covered all situations.
2) Include code that determines which browser and version the person is using and supply the "I agree to these terms & wish to print this coupon" link or the comment.  You will also need to include a piece of code for browser's that have disabled JavaScript.  This would look like:

Include this script in the header.
<SCRIPT language="JavaScript">
<!--
// *** BROWSER SNIFFER ***
// Code snipped from Netscape's browser sniffer code.
// Note: On IE5, these return 4, so use is_ie5up to detect IE5.
var is_major = parseInt(navigator.appVersion);
var is_minor = parseFloat(navigator.appVersion);

// Note: Opera and WebTV spoof Navigator.  We do strict client detection.
// If you want to allow spoofing, take out the tests for opera and webtv.
var is_nav  = ((agt.indexOf('mozilla')!=-1) && (agt.indexOf('spoofer')==-1)
      && (agt.indexOf('compatible') == -1) && (agt.indexOf('opera')==-1)
      && (agt.indexOf('webtv')==-1));
var is_ie   = (agt.indexOf("msie") != -1);
var is_nav4up = (is_nav && (is_major >= 4));
var is_ie4up  = (is_ie  && (is_major >= 4));
//-->
</SCRIPT>

Include the code below in the body where you want it to display.
<SCRIPT language="JavaScript">
<!--
if (is_nav4up || is_ie4up) { document.write("A HREF='javascript:self.print')I agree to these terms & wish to print this coupon</A>") }
else { document.write("Select File | Print from the menu to print this coupon.") }
//-->
</SCRIPT>
<NOSCRIPT>
Select File | Print from the menu to print this coupon.
</NOSCRIPT>

The text contained within the NOSCRIPT tag will not show up unless JavaScript.
3) Create a different page for those browser's that can use self.print() and those browsers that cannot user self.print().  Then using the browser sniffer code above you would call the necessary page. For example:

if (is_nav4up || is_ie4up) {
  couponpage="printcoupon1.html";
  cpnWindow = window.open("printcoupon1.htm", "MyWindow", "height=460,width=620");
}
else {
  couponpage="FP_printcoupon1.html"
cpnWindow = window.open("fileprint_printcoupon1.htm", "MyWindow", "menubar=yes,height=460,width=620");
}


Concerning the DeleteCoupon function:
As long as the DeleteCoupon("coupon1") statement is active (exists or not commented) in the function canGetCoupon() you will allow be able to print the coupon over and over and over.  When I test I will uncomment the statement so that I can see how things are supposed to and then comment the statement to have the process work properly.


Concerning NS3.x problems:
NS3.x has some problems with dates that are not seen in NS4.x.  The fix was some modifications to a couple of functions.  NS4.x can evaluate dates as dates.  NS3.x for some reason doesn't.  So I had to save the dates as a value equal to the number of milliseconds since Jan 1, 1970 00:00:00.  Once I did that everything worked.  I tested the functions below using NS3.04 and NS4.61.

Replace your current functions with these.

function ValidateName(name) {
  var strConfirm = "You have entered your name as '" + name + "'. Click Ok if this is correct."
  if (confirm(strConfirm)) {
    var expdate = new Date();

    // Correct for Mac date bug - call only once for given Date object!
    FixCookieDate(expdate);

    // Set the expiration date for 30 days from the current date.
    expdate.setTime(expdate.getTime() + (30 * 24 * 60 * 60 * 1000)); // 30 days from now

// Convert to number of milliseconds since January 1, 1970  00:00:00      
    valexpdate=expdate.getTime();
    SetCookie("coupon1", valexpdate, expdate);

    // Temporarily store the person's name.  This cookie will automatically be
    // deleted when person closes browser window.
    SetCookie("UserName", name);
    // change height and width to appropriate size of window needed.
   cpnWindow = window.open("printcoupon.html", "MyWindow", "height=200,width=300");
  }
}

<!-- Check to see if user has already received a coupon within a certain period of time. -->
function canGetCoupon() {
// Delete or comment the following line once you have your site running.
  DeleteCookie("coupon1");
  var valCouponDate=GetCookie("coupon1");
  if (valCouponDate == null) { var valCouponDate=0 }

// Get current date
  var today=new Date();
// Convert to number of milliseconds since January 1, 1970  00:00:00      
  valToday=today.getTime();
      
  if (valCouponDate > valToday) { window.location="sorry.html" }
}

tec
Dear Tecbuilder,

I couldn't get the browser sniffing code to switch whether or not people see the self-print script or not, but I've put the rest of the code together and it seems to work well.

Thank you for your wonderful help.

If you want to have a final look, the page with coupons and your script is at
http://www.moneysaver.com.au/newsletters/0799/

(Also, thank you Michel as well.)

Best wishes


Jonathan (MindWave)
 
You are very welcome.  I went back through the original browser sniffing code and found tucked inbetween a couple of comments an additional line of code.

var agt=navigator.userAgent.toLowerCase();

Add this line just before the following lines:
var is_major = parseInt(navigator.appVersion);
var is_minor = parseFloat(navigator.appVersion);

That should take care of the problem you were running into.

I did visit your site and everything looks very nice.

tec
You also might want to use this mod I suggested:

Replace

var is_ie   = (agt.indexOf("msie") != -1);

with

// Michel Plungjan/abk mods - 990618
  iePos = agt.indexOf("msie ");
  this.ie   = (iePos != -1);
  if (this.ie) {
    this.minor = parseFloat(agt.substring(iePos+5,agt.indexOf(';',iePos+5)));
    this.major = parseInt(this.minor);
  } else {
    this.major = parseInt(navigator.appVersion);
    this.minor = parseFloat(navigator.appVersion);
  }

Michel
Michel, what is the code replacement doing that isn't already being done?  Does it more accurately determine the type of IE browser?  I'm not understanding why to replace 1 line of code with 8.  Also, I believe 'this.minor' and 'this.major' would need to be renamed to 'is_minor' and 'is_major' respectively, to work with the existing script.

tec