#!/usr/bin/perl # NOTE: the above line must be changed to show the path to the # Perl interpreter on your system! Leave the #! as is, but # the path may have to be changed if yours is different. # DO NOT CHANGE the LINE BELOW. use CGI::Carp qw(fatalsToBrowser); $| = 1; ######################################################################### # HeadCount 1.0.1 # # A simple headcount program. The administrator sets up a list of # # teachers, and the teachers can then log in and tell how many of # # their students will be having lunch, going on a field trip, etc. # # Copyright 2004, Kristina L. Pfaff-Harris # # All rights reserved. # # # ######################################################################### ##### License for HeadCount 1.0.1 ##### ##### This program may be used free of charge under the following ##### conditions: ##### ##### 1. All instructions and Copyright lines must remain unchanged. ##### ##### 2. All pages generated by the program must contain one of the ##### following pieces of HTML code: ##### ##### Powered by HeadCount 1.0.1: ##### ##### http://www.tesol.net/scripts ##### OR: ##### ##### ##### ##### You may not remove the information described above from the script ##### without express written permission from the author. ##### ##### 3. You may not sell or distribute this program. You may charge ##### a reasonable fee for installing it for a client as long as ##### you make it clear that you are not the author, and you are ##### not selling the program to them: only charging for installing ##### it. ##### ##### 4. You agree that this program is offered without warranty of ##### any kind, including warranty of fitness for a particular ##### purpose. You further agree that the author and all sites ##### associated in any way with this program are not liable for ##### any damage or loss incurred as a result of using this program. ##### ##### 5. You may modify the program for your own use but you may not ##### distribute modified copies under any circumstances without ##### express written permission from the author. ##### ##### 6. Use of this program requires agreement to all the terms and ##### conditions of this license. If you do not agree to one or ##### more of these terms, you may not use the program. ##### ######################################################################### ##### # ##### IMPORTANT INSTRUCTIONS: # ##### # ##### In this program, I have put **CHANGE** in all the places where # ##### you will need to modify the program to run on your server, so # ##### that you can easily find all the places where changes are # ##### necessary. This program must be chmod 755 or 775 in order to # ##### work, and the numbers file and teachers file must be chmod 766. # ##### # ######################################################################### # # # IMPORTANT: If you FTPed this program to your server in "binary" mode, # # it will NOT work! If you're not sure, please go back and FTP it # # to your server again and make sure you use "ascii" mode. If you get # # "500 Server Error", this is almost always the cause. :) # # # # Using the program: # # This program requires the file "headcount.cgi" at a minimum in order # # to work. Please read the README.headcount file for more information. # # Please check the Scripts for Educators FAQ first (it can be found at # # http://tesol.net/scripts/FAQ/) if you have problems. If none of that # # helps (which is sometimes the case no matter HOW hard you try!), # # email me and I'll at least try to help. :-) # # # # I hope this program proves useful to you! Please contact me # # (http://tesol.net/scriptmail.html) for any bugs or feedback. # ######################################################################### ##### # ##### BEGIN SECTION WHERE YOU WILL NEED TO CHANGE THINGS: # ##### # ##### In this section, there are several places where you'll need # ##### to make changes. Please read all instructions carefully # ##### before you make the changes. # ##### # ######################################################################### # $debugging gives more informative error messages. It's always a good # idea to turn debugging on until the script is set up and running. To # turn debugging on, set $debugging = 1; below. To turn it off, set # $debugging = 0; below. $debugging = 0; # **CHANGE** # $number_file needs to be the full system path to the text file # where you want to keep track of the numbers for lunchcount by # teacher. If you put number_file.txt in the same directory as # lunchcount.cgi, then what I have below might work. This file # should be chmod 766. # Please note that a "system path" is different from a web address # or URL. This must NOT begin with "http://". Please check the FAQ # at http://tesol.net/scripts/FAQ/ for more information about # what a system path is, and how you can find out what yours is. $number_file = "./number_file.txt"; # **CHANGE** # $teachers_file needs to be the full system path to the text file # where you want to keep track of the teachers' names. If you put # teachers_file.txt in the same directory as lunchcount.cgi, then # what I have below might work. If not, you'll need to ask your # web server administrator what the full system path to your files # is. This file should be chmod 766. # Again, a "system path" is different from a web address # or URL. This must NOT begin with "http://". Please check the FAQ # at http://tesol.net/scripts/FAQ/ for more information about # what a system path is, and how you can find out what yours is. $teachers_file = "./teachers_file.txt"; # **CHANGE** # $cgi_url is the full web address to this script on your server. # This IS a web address or URL, and MUST begin with "http://". If # you are getting a "File not found" error when you hit one of the # buttons in the program, it usually means that this has not been # set correctly. $cgi_url = "http://www.your_site.com/cgi-bin/headcount.cgi"; # **CHANGE** # $admin_login is the username you'd like to use to log into the # administrative screens of this program. Please use only letters and # numbers. $admin_login= "admin"; # **CHANGE** # $admin_password is the password you'd like to use to log into the # administrative screens of this program. Please do not use the ", @, # or $ character. Other than that, you should be able to use letters, # numbers, or symbols. $admin_password = "password"; ######################################################################### # # # Changes to the "Look and Feel" of the Program Begin Here # # # # The program will operate fine if you don't change the next few things.# # However, the below items will let you change the "look" of the script # # to match your website better, or to use different phrases as you # # wish for your purposes. # # # ######################################################################### # $header is the set of HTML that you'd like to be at the top of each # page generated by the program. For more information about how to use # this, look for "How do I make the pages in my script look like the # rest of my website" in the FAQ, or search the FAQ for "htmlheader". # http://tesol.net/scripts/FAQ/ # ONLY change in between the lines that say and # $header = qq[ HeadCount v1.0.1
HeadCount v1.0.1


]; # $footer is the set of HTML that you'd like to be at the bottom of each # page generated by the program. For more information about how to use # this, look for "How do I make the pages in my script look like the # rest of my website" in the FAQ, or search the FAQ for "htmlheader". # http://tesol.net/scripts/FAQ/ # ONLY change in between the lines that say and # $footer = qq[ ]; # $program_name is what will be shown on the various screens that say # "Welcome to HeadCount" and so forth. $program_name = "HeadCount"; # $teacher_label is what will appear in the slot marked "Teacher." Some # sites may be using this for other types of headcounts, such as number # of guests for a wedding, or number of family members attending a company # picnic. In these cases, they may want it to say "Invitee" or "Employee" # or "Person" instead of "Teacher." $teacher_label = "Teacher"; # $class_label is what will appear in the slot marked "Class." You # may change this as appropriate; $class_label = "Class"; # $number_of_students_label is what will appear in the slot marked # "Number of students". $number_of_students_label = "Number of Students"; # Following are other various options you can change for the various # messages that appear in the demo. If you're not sure of the placement # of these, see the demo at: # http://tesol.net/scripts/HeadCount/working/headcount.cgi $welcome_to_label = "Welcome to"; $students_for_lunch_today_label = "students for lunch today."; $name_label = "Name"; $current_count_label = "Current Count"; $includes_label = "(Includes those who have not yet submitted numbers.)"; $please_enter_label = "Please enter your name and the number of students:"; ######################################################################### ##### # ##### END SECTION WHERE THINGS NEED TO BE CHANGED. # ##### # ##### You should not HAVE to change anything beyond this point, # ##### although you might want to read through it to see what it does. # ##### If you're interested in how CGI programs work, then this may # ##### act as its own tutorial of sorts. You definitely shouldn't # ##### change anything beyond this point unless you know what you're # ##### doing, though. :) # ##### # ######################################################################### # These three things are just shortcuts so I don't have to type out all # the font color HTML later. :-) $fr = ""; $fb = ""; $ss = ""; $| = 1; # Parse the incoming data so we can use it %data = &get_data(); # Print the Content-type header that is always needed by CGI. print "Content-type: text/html\n\n"; &fatal_error(); $FA = $data{'FA'}; $FA2 = $data{'FA2'}; # If you remove this link, without replacing it with a similar # HTML comment (as above in the License section) you are in violation # of the license for this program. No, I don't have the resources to # enforce this, and I know that some people will remove it anyway. # But honestly, since you didn't have to pay for this, is the link # really too much to ask? :) ##### ##### ##### $footer = qq[
Powered by HeadCount 1.0.1
$footer] if $footer !~ /http:\/\/www.tesol.net\/scripts/i; if($FA eq "Add"){ &add_to_number_file; } elsif($FA eq "Admin"){ &admin_login_screen(); } elsif($FA eq "Login"){ &check_auth(); &admin_menu(); } elsif($FA eq "Reset" || $FA eq "Reset Numbers"){ &check_auth(); &reset_number_file; } elsif($FA eq "Add $teacher_label"){ &check_auth(); &add_teacher(); } elsif($FA eq "Delete $teacher_label"){ &check_auth(); &delete_teacher(); } else { &default_page; } exit(); sub default_page { $totalnum = 0; open(F, "<$number_file"); while(){ chomp; ($name,$num) = split(/\|/, $_); $totalnum += $num; } close(F); if($totalnum eq ""){$totalnum = 0;} open(F, "<$teachers_file") || &debug("Could not open teachers file ($teachers_file). The server returned this error: $!"); @teachers = ; close(F); foreach $teacher (sort(@teachers)){ chomp($teacher); ($name,$class) = split(/\|/, $teacher); $options .= ""; } $error = "$welcome_to_label $program_name

" if $error eq ""; print "$header
$error
($totalnum $students_for_lunch_today_label)
". localtime() . "
$please_enter_label
$name_label:
$number_of_students_label:
$current_count_label
$includes_label "; open(F, "<$number_file") || &debug("Could not open number file ($number_file). The server returned this error: $!"); @allnumbers = ; close(F); open(F, "<$teachers_file") || &debug("Could not open teachers file ($teachers_file). The server returned this error: $!"); @allteachers = ; close(F); foreach $teacher (sort(@allteachers)){ chomp $teacher; ($name,$class) = split(/\|/, $teacher); foreach $n_teacher (@allnumbers){ ($n_name,$num) = split(/\|/, $n_teacher); $name =~ s/^\s+//sg; $name =~ s/\s+$//sg; $n_name =~ s/^\s+//sg; $n_name =~ s/\s+$//sg; if($n_name eq $name){ print "\n"; $printed{$name} = 1; next; } } if($printed{$name} != 1){ print "\n"; } } print "
$teacher_label$class_label$number_of_students_label
$name$class $num
$name$class --
Total: $totalnum

$footer"; exit(); } sub reset_number_file { if($data{'Confirm'} ne "Yes"){ print "$header
WHOA! Please confirm reset!

If you hit the reset button, you will delete all entries in the file. Please be sure you want to do this. This is your last warning before everything is irretrievably gone.
$footer"; exit(); } # If we got here, reset it. open(F, ">$number_file") || print "could not reset number file ($number_file). The server said: $!"; print F ""; close(F); $error = "${fb}File successfully reset.$ss

"; &admin_menu; exit(); } sub add_to_number_file { ($name,$class) = split(/\|/, $data{'name'}); $number = $data{'num'}; if($number =~ /\D+/ || $number eq ""){ $error = "${fr}Error: '$number' is not a valid number. Digits only, please.$ss

"; &default_page(); exit(); } if(length($name) > 125 || $name =~ /\|/ || $name eq ""){ $error = "${fr}Error: '$name' is not a valid name. No \"|\" characters allowed, and it must be fewer than 125 characters.$ss

"; &default_page(); exit(); } open(F, "+<$number_file") || die("Could not open number file ($number_file). The server said: $! when I tried!"); @allentries = ; foreach $entry (@allentries){ ($n_name,$n_num) = split(/\|/, $entry); $name =~ s/^\s+//sg; $name =~ s/\s+$//sg; $n_name =~ s/^\s+//sg; $n_name =~ s/\s+$//sg; if($name eq $n_name){ $newfile .= "$name|$number\n"; } else { $newfile .= "$entry"; } } if($newfile !~ /$name/){ $newfile .= "$name|$number\n"; } truncate(F, length($newfile)); seek(F, 0, 0); print F $newfile; close(F); # Add them up open(F, "<$number_file"); while(){ chomp; ($na,$nu) = split(/\|/, $_); $totalnum += $nu; } close(F); $error = "${fb}We have added $number for a total of $totalnum today.$ss

"; &default_page; exit(); } sub get_data { use CGI qw/:standard/; my $q = new CGI; my ($param,%data); foreach $param ($q->param()){ $data{$param} = $q->param($param); } %data; } sub check_auth { my($login) = $data{'admlogin'}; my($password) = $data{'admpassword'}; if($login ne $admin_login || $login eq "" || $password ne $admin_password || $password eq ""){ $error = "Error: Invalid login or password.

"; &admin_login_screen(); exit(); } $footer = qq[

$footer ]; } sub admin_login_screen { print qq[ $header $error Please log in for administrative functions
Username:
Password:
$footer ]; exit(); } sub admin_menu { print qq[ $header $error
Welcome to the Administration Section
Please choose from one of the following options
$footer ]; exit(); } sub add_teacher { if($FA2 ne "Confirm"){ print qq[ $header $error Add $teacher_label

Please enter the teacher's name and class:
Last Name:
First Name:
Class:
$footer ]; exit(); } $ln = $data{'Lastname'}; $fn = $data{'Firstname'}; $cl = $data{'Class'}; if($ln eq "" || $fn eq "" || $cl eq ""){ $error = "Error: Please fill in all fields.
"; $FA2 = ""; &add_teacher(); exit(); } open(F, ">>$teachers_file") || &debug("Could not open teachers file ($teachers_file) for writing. The server returned this message: $!"); if($^O =~ /win/i){ binmode(F); } else{ flock(F, 2); } print F "$ln, $fn|$cl\n"; close(F); $error = "$fn $ln successfully added to teachers file.
"; &admin_menu(); exit(); } sub delete_teacher { if($FA2 ne "Confirm"){ open(F, "<$teachers_file") || &debug("Could not read teachers file ($teachers_file). The server returned this message: $!"); @teachers = ; @teachers = sort(@teachers); foreach $teacher (@teachers){ chomp($teacher); ($name,$class) = split(/\|/, $teacher); $options .= "\n"; } close(F); print qq[ $header $error
Please choose a teacher to delete:
$footer ]; exit(); } open(F, "+<$teachers_file") || &debug("Could not open teachers file ($teachers_file) to delete teacher. The server returned this error: $!"); if($opsys =~ /win/i){ binmode(F);} else { flock(F, 2); } $name_to_delete = $data{'Teacher'}; if($name_to_delete eq ""){ $error = "Error: No one to delete
"; $FA2 = ""; &delete_teacher(); exit(); } $newfile = ""; while(){ $fileline = $_; $fileline =~ s/^\s+//sg; $fileline =~ s/\s+$//sg; $name_to_delete =~ s/^\s+//sg; $name_to_delete =~ s/\s+$//sg; if($fileline ne $name_to_delete){ $newfile .= "$fileline\n"; } } truncate(F, length($newfile)); seek(F, 0, 0); print F $newfile; close(F); $error = "$name_to_delete Deleted
"; &admin_menu(); exit(); } sub debug { if($debugging == 1){ print "DEBUGGING: $_[0]
"; } } sub fatal_error { # Basically, this is here for people who don't turn debugging on. The # script assumes that everything is configured correctly, even if it isn't # so without debugging, it would still tell you "Teacher successfully added" # even if they weren't. So, before we do anything else, we're going to # check to see if we can do what we need to do, and if not, we're not going # to continue with the program until it's fixed. :-) unless(-w $number_file){ open(F, ">>$number_file") || &geterror(); close(F); $ferror = "Sorry, but \$number_file ($number_file) doesn't appear to be correct. Your web server is saying that I'm not allowed to write to it, and that means that we can't operate. Your server gave this error: $file_error . Please make sure the path to that file is correct, and that the permissions are sufficient for the script to write to it. Sometimes, this means chmod 766, but your web hosting provider should be able to tell you for sure.

"; } unless(-w $teachers_file){ open(F, ">>$teachers_file") || &geterror(); close(F); $ferror .= "Sorry, but \$teachers_file ($teachers_file) doesn't appear to be correct. Your web server is saying that I'm not allowed to write to it, and that means that we can't operate. Your server gave this error: $file_error . Please make sure the path to that file is correct, and that the permissions are sufficient for the script to write to it. Sometimes, this means chmod 766, but your web hosting provider should be able to tell you for sure.

"; } if($admin_password eq "password" && $ENV{'SERVER_NAME'} !~ /linguistic-funland.com$/i && $ENV{'SERVER_NAME'} !~ /tesol.net$/i){ $ferror .= "Oops, you haven't changed the admin password for this script! (\$admin_password) That means that anyone can just type \"password\" and get in and do stuff. Please change \$admin_password to something else and you won't get this message anymore.

"; } if($ferror ne ""){ print qq[ $header Error in Configuration!

Sorry, but there seems to be a problem with the way you've set up this script. The script can't run until you've fixed these things:

$ferror

The following information may be helpful:

]; print "Web Server software is $ENV{'SERVER_SOFTWARE'}
\n" if $ENV{'SERVER_SOFTWARE'}; print "Base path to website files is $ENV{'DOCUMENT_ROOT'}
\n" if $ENV{'DOCUMENT_ROOT'}; print "Base path translated is $ENV{'PATH_TRANSLATED'}
\n" if $ENV{'PATH_TRANSLATED'}; print "Script filename is $ENV{'SCRIPT_FILENAME'}
\n" if $ENV{'SCRIPT_FILENAME'}; print "Server O/S is $^O
\n" if $^O; print "Perl version is $]
\n" if $]; print "

If you're not sure what all this means, or how to fix it, please first try the Frequently Asked Questions list or the Support Forum. If that still doesn't help, please please feel free to copy and paste all this stuff into an email to me and try to tell me a little about what you were doing when you got this message. :-) $footer"; exit(); } } sub geterror { $file_error = $!; } # end of script