==================================================================================== Image Upload Mod ==================================================================================== This modification puts an image upload option in both add.cgi and modify.cgi, and lets the admin see what's being submitted prior to approval. Images are renamed to the link ID number, and can be deleted from the admin or by link owner. Uploading a new image replaces the old one. Still in the works: ------------------ - better display in admin (so there's no red 'X' if no image) - let admin know if image is to be deleted (currently deletes image prior to validation) - multiple file uploads ------------------ The mod was created by Leonard Taylor (aka Perlflunkie). It is largely based on my 'External Text File Mod', which was adapted from one written by JPDeni for dbman. It also contains code from JPDeni's 'Image Upload 2 Mod.' Be sure to make backups of your files! You assume ALL responsibility for anything that might happen to your files or server. ==================================================================================== 1. add.cgi ==================================================================================== *** Replace the parser call: # >>> Image Upload Mod sub main { # -------------------------------------------------------- # local (%in) = &parse_form; local (%in) = &parse_form_upload; # <<< *** replace everything between 'close ID;' and '# Update the counter.' with this: # >>> Image Upload Mod (next 14 lines) # Validate the form input.. $status = &validate_record(%in); if (($status eq "ok") && ($in{'Imagename'})) { $status = &validate_upload; } #Validate Picture if ($status eq "ok") { $filekey = $in{'Imagename'}; # $filekey is name of file from source computer-- C\etc $newfilename = $in{$db_key}; if ($filekey =~ /([^\/\\]+)$/) { $filename = $1; $extlength = length($filename) - index($filename,"."); $filename = $newfilename . lc(substr($filename,-$extlength,$extlength)); $in{'Imagename'} = $filename; # Rename the file to ID number, but keep correct extension (gif, jpg). } # <<< ==================================================================================== 2. modify,cgi ==================================================================================== *** To make this work, we need to include a version of Paul's Modify Security Mod. This pre-fills the form fields with data from links.db Replace all of 'sub main' with this: sub main { # -------------------------------------------------------- # >>> Image Upload Mod > # local (%in) = &parse_form; local (%in) = &parse_form_upload; # <<< # >>> Security Mod # We are processing the form.. if ($in{'do'} eq "check") { &check(); } # We are processing the form.. elsif (!$in{'do'}&&keys %in != 0) { &process_form; } # Otherwise we are displaying the form (in site_html.pl). else { &site_html_modify_form_up; } } # <<< Security Mod *** Then 'sub process_form' gets all these changes: sub process_form { # -------------------------------------------------------- my ($key, $status, @values, $found); local (%original); # Make sure we have a link to modify. # >>> Security Mod - removed next line # !$in{'Current URL'} and &site_html_modify_failure ("did not specify link to modify") and return; # <<< # Let's check to make sure the link we want to update is actually # in the database. open (DB, "<$db_file_name") or &cgierr("error in validate_records. unable to open db file: $db_file_name. Reason: $!"); $found = 0; LINE: while () { (/^#/) and next LINE; (/^\s*$/) and next LINE; chomp; @data = &split_decode($_); # >>> Security Mod - removed next and replace with new line # if ($data[$db_url] eq $in{'Current URL'}) { if ($data[$db_key] eq $in{'ID'}) { # This field is picked up by hidden input from modify_up form. # <<< $in{$db_key} = $data[0]; $found = 1; %original = &array_to_hash (0, @data); last LINE; } } close DB; !$found and &site_html_modify_failure ("link was not found in the database") and return; # Since we have a valid link, let's make sure the system fields are set to their # proper values. We will simply copy over the original field values. This is to stop # people from trying to modify system fields like number of hits, etc. foreach $key (keys %add_system_fields) { $in{$key} = $original{$key}; } # Set date variable to today's date. $in{$db_cols[$db_modified]} = &get_date; # >>> Image Upload Mod (next 17 lines) # Check if user wants to delete their image, change some info but keep current image, or upload a new one. # Validate the form input.. $status = &validate_record(%in); if ($status eq "ok") { if ($in{'DeleteImage'} eq "Yes") { # If they want to delete old file... $in{'Imagename'} = ""; # write it as empty in the db... unlink "$upload_directory/$in{'Imagename_transfer'}"; # and delete the image. } elsif ($in{'Imagename'} eq "") { # If a new image is not uploaded... $in{'Imagename'} = $in{'Imagename_transfer'}; # use name of current file, to avoid having to re-upload. } else { $status = &validate_upload_modify; # Otherwise there's a new upload to check. } } # <<< *** Then add this new sub to the end of the file: # >>> Security Mod sub check { #------------------------------------------------------- # Make sure we have a Title (Name) for the resource to modify. # If missing, return an error message to the submitter. (!$in{'Title'}) and &site_html_modify_up_failure (qq|Missing or incorrect Name of the listing to update.|) and return; # You can change which fields are used to verify. # ((!$in{'Title'}) or # (!$in{'Password'}) and &site_html_modify_up_failure (qq|Missing or incorrect Name or Password of the listing to update.|) and return; # This version uses two fields to verify. open (DB, "<$db_file_name") or &cgierr("error in validate_records. unable to open db file: $db_file_name. Reason: $!"); $found = 0; LINE: while () { (/^#/) and next LINE; (/^\s*$/) and next LINE; chomp; @data = &split_decode($_); if ($data[$db_title] eq $in{'Title'}) { # You can change which fields are used to verify. # if (($data[$db_title] eq $in{'Title'}) and ($data[$db_password] eq $in{'Password'})) { # This version uses two fields to verify. $id = $data[0]; $found = 1; last LINE; } } close DB; # If no matching record found, display error message to user !$found and &site_html_modify_up_failure (qq|
  1. The specified Last Name was not found in the database.
  2. The specified Password does not match the database entry for the specified Last Name.
|) and return; my (%record) = &get_record($id); &site_html_modify_form(%record) and return; } # <<< ==================================================================================== 3. Links.cfg ==================================================================================== *** Add this to 'Paths and URL's to Important Stuff': #>>> Image Upload Mod # PATH and URL of Image Upload Folder $upload_directory = "$build_root_path/pics"; $upload_directory_url = "$build_root_url/pics"; # <<< *** Above 'Email Options' add: # >>> Image Upload Mod # Image Upload Options # -------------------------------------------------------- # Defines the total number of bytes that can be uploaded. Files that exceed # this limit will not be saved on the server. Set this to zero in order to # disable size checking. $maximum_upload = 200000; # Defines the total number of files that can be attached to a file. If a user # tries to exceed the limit, no files will be added. You must set this to a value. # It cannot be 0. $maximum_files = 5; # List of allowable file extensions. If the file does not have one of the extensions # listed, it will not be saved to the server. The format for the setting is # \.[extension]$ If you want to allow more than one extension, separate the options by # a | character. Note that case counts! Example: $allowed_ext = '\.gif$|\.jpg$|\.GIF$|\.JPG$'; $allowed_ext = '\.gif$|\.jpg$|\.GIF$|\.JPG$'; # <<< ==================================================================================== 4. Links.def ==================================================================================== *** Add to 'Database Definition: LINKS' and remember to add comma after bracket on line above it. Change field number if needed. Imagename => [14, 'alpha', 0, 255, 0, '', ''] # <<< Image Upload mod *** Add this to '# Field Number of some important fields.' $db_imagename = 14; # <<< Image Upload Mod ==================================================================================== 5. db_utils.pl ==================================================================================== *** Make these changes to 'sub build_html_record_form': sub build_html_record_form { # -------------------------------------------------------- # Builds a record form based on the config information. # my ($output, $field, $multiple, $name); ($_[0] eq "multiple") and ($multiple = 1) and shift; my (%rec) = @_; # >>> Image Upload mod (next 26 lines) if ($in{'db'} eq 'links') { # Make sure we're editing links, not categories. if ($in{'validate_form'}) { # And we're wanting to validate a link. # If validating input from modify.cgi, get the current file from /pics if there is one. my $current_pict = "$upload_directory/$rec{'$Imagename'}"; if (-e $current_pict) { # Check if there's currently a file in the /pics directory... $image = "$rec{'Imagename'}"; # Show it. } # And if there's a pic in pics/modify, get it. my $pict = "$upload_directory/modify/$rec{'$Imagename'}"; if (-e $pict) { # Check if there's a new file in the /pics/modified directory... $image_2 = "modify/$rec{'Imagename'}"; # Show it, or... } # If validating input from add.cgi, get the new file from the /pics/validate directory. else { $image_2 = "validate/$rec{'Imagename'}"; # Show it. } # If modifying from the admin, get the current file. if ($in{'modify_form'}) { $image = "$rec{'Imagename'}"; } } } # <<< $output = "

"; # Go through a little hoops to only load category list when absolutely neccessary. if ($in{'db'} eq 'links') { exists $db_select_fields{$db_cols[$db_category]} or ($db_select_fields{$db_cols[$db_category]} = join (",", &category_list)); } else { $db_select_fields{'Related'} or ($db_select_fields{'Related'} = $db_select_fields{'Mult-Related'} = join ",", &category_list); } foreach $field (@db_cols) { # Set the field name to field-key if we are doing multiple forms. $multiple ? ($name = "$field-$rec{$db_key}") : ($name = $field); if ($db_select_fields{"Mult-$field"}) { $output .= "\n"; } elsif ($db_select_fields{$field}) { $output .= "\n"; } elsif ($db_radio_fields{$field}) { $output .= "\n"; } elsif ($db_checkbox_fields{$field}) { $output .= "\n"; } elsif ($db_form_len{$field} =~ /(\d+)x(\d+)/) { $output .= qq~\n~; } elsif ($db_form_len{$field} == -1) { $output = qq~\n$output~; } else { $output .= qq~\n~; } } # >>> Image Upload Mod (next 7 lines) # Put the current image in the admin forms. if ($in{'db'} eq 'links') { # Make sure we're editing links, not categories. $output .= qq~\n~; # Put the new image in the admin forms. $output .= qq~\n~; } # <<< $output .= "
<$font>$field:" . &build_select_field($field, $rec{$field}, $name, "MULTIPLE SIZE=3") . "
<$font>$field:" . &build_select_field($field, $rec{$field}, $name) . "
<$font>$field:" . &build_radio_field($field, $rec{$field}, $name) . "
<$font>$field:" . &build_checkbox_field ($field, $rec{$field}, $name) . "
<$font>$field:
<$font>$field:
<$font>Current Image:
<$font>New Image:

\n"; return $output; } *** Add these three routines above 'sub cgi_error': # >>> Image Upload Mod sub parse_form_upload{ # -------------------------------------------------------- # Used by add.cgi and modify.cgi only my (%in); my ($buffer, $pair, $name, $value); use CGI; $query = new CGI; PAIR: foreach $name ($query->param()) { $value = $query->param("$name"); $name =~ tr/+/ /; $name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $value =~ s///g; if ($value eq "---") { next PAIR; } unless ($value) { next PAIR; } (exists $in{$name}) ? ($in{$name} .= "~~$value") : ($in{$name} = $value); } return %in; } sub validate_upload { # -------------------------------------------------------- # This one is used by add.cgi only. # Makes sure the uploaded images meet the standards set in links.def. my ($filekey,$Imagename,$newImagename,$extlength,$filehandle,$totalbytes,$buffer,$bytes,@extensions,@ext); use CGI; $query = new CGI; $| = 1; $filekey = $query->param("Imagename"); $newImagename = $in{$db_key}; if ($filekey =~ /([^\/\\]+)$/) { $Imagename = $1; $extlength = length($Imagename) - index($Imagename,"."); $Imagename = $newImagename . lc(substr($Imagename,-$extlength,$extlength)); unless ($Imagename =~ /$allowed_ext/) { $allowed_ext =~ s/\\//g; $allowed_ext =~ s/\$//g; @ext = split (/\Q|\E/o,$allowed_ext); $allowed_ext = join(" or ",@ext); return "Only files with the following extension(s) are allowed: $allowed_ext"; } } else { return "You attempted to upload $filekey that isn't properly formatted. Please rename the file on your computer, and attempt to upload it again. Files may not have forward or backward slashes in their names. Also, they may not be prefixed with one (or more) periods."; } opendir (GRAPHIC, "$upload_directory/validate") or &cgierr("unable to open directory in delete records: $upload_directory. Reason: $!"); @files = readdir(GRAPHIC); closedir (GRAPHIC); $file_test = $in{$db_key} . "."; foreach $file (@files) { if ($file =~ /^$file_test/) { unlink ("$upload_directory/validate/$file"); } } if (!open(OUTFILE, ">$upload_directory\/validate\/$Imagename")) { return "There was an error opening '$upload_directory\/validate\/$Imagename' for Writing.\n"; } binmode(OUTFILE); # This is needed to work on Windows/NT platforms. while ($bytes = read($filekey,$buffer,1024)) { $totalbytes += $bytes; print OUTFILE $buffer; } close($filekey); close(OUTFILE); chmod (0666, "$upload_directory\/validate\/$Imagename"); if ($totalbytes > $maximum_upload && $maximum_upload > 0) { unlink "$upload_directory\/validate\/$Imagename"; return "$Imagename
You have reached your upload limit.
Your file contains $BytesRead $totalbytes bytes.
This exceeds the maximum limit of $maximum_upload bytes.
Your file was not saved.
Please try again."; } return "ok"; } sub validate_upload_modify { # -------------------------------------------------------- # This one is used by modify.cgi only. # Makes sure the uploaded images meet the standards set in links.def. my ($filekey,$Imagename,$newImagename,$extlength,$filehandle,$totalbytes,$buffer,$bytes,@extensions,@ext); use CGI; $query = new CGI; $| = 1; $filekey = $query->param("Imagename"); $newImagename = $in{$db_key}; if ($filekey =~ /([^\/\\]+)$/) { $Imagename = $1; $extlength = length($Imagename) - index($Imagename,"."); $Imagename = $newImagename . lc(substr($Imagename,-$extlength,$extlength)); unless ($Imagename =~ /$allowed_ext/) { $allowed_ext =~ s/\\//g; $allowed_ext =~ s/\$//g; @ext = split (/\Q|\E/o,$allowed_ext); $allowed_ext = join(" or ",@ext); return "Only files with the following extension(s) are allowed: $allowed_ext"; } } else { return "You attempted to upload $filekey that isn't properly formatted. Please rename the file on your computer, and attempt to upload it again. Files may not have forward or backward slashes in their names. Also, they may not be prefixed with one (or more) periods."; } # This picks out the image name with correct extension # so it can be processed further. if ($filekey ne ""){ # added opendir (GRAPHIC, "$upload_directory") or &cgierr("unable to open directory in delete records: $upload_directory. Reason: $!"); @files = readdir(GRAPHIC); closedir (GRAPHIC); $file_test = $in{$db_key} . "."; foreach $file (@files) { if ($file =~ /^$file_test/) { $in{'Imagename'} = $file; # Here it is! } } } # added to close if if (!open(OUTFILE, ">$upload_directory\/modify\/$Imagename")) { return "There was an error opening '$upload_directory\/modify\/$Imagename' for Writing.\n"; } binmode(OUTFILE); # This is needed to work on Windows/NT platforms. while ($bytes = read($filekey,$buffer,1024)) { $totalbytes += $bytes; print OUTFILE $buffer; } close($filekey); close(OUTFILE); chmod (0666, "$upload_directory\/modify\/$Imagename"); if ($totalbytes > $maximum_upload && $maximum_upload > 0) { unlink "$upload_directory\/modify\/$Imagename"; return "$Imagename
You have reached your upload limit.
Your file contains $BytesRead $totalbytes bytes.
This exceeds the maximum limit of $maximum_upload bytes.
Your file was not saved.
Please try again."; } return "ok"; } # <<< ==================================================================================== 6. db.pl ==================================================================================== *** !!! Note, there are a few places in this file where the new code goes just before an existing closing bracket '}' so you need to pay close attention. I will show the stock code first, then the new. The plus sign '+' shows where the new code fits. Note also some code is replaced/commented out. *** Make these changes to 'sub delete_records': sub delete_records { # -------------------------------------------------------- # Deletes a single or multiple records. First the routine goes thrrough # the form input and makes sure there are some records to delete. It then goes # through the database deleting each entry and marking it deleted. If there # are any keys not deleted, an error message will be returned saying which keys # were not found and not deleted, otherwise the user will go to the success page. my ($key, %delete_list, $rec_to_delete, @data, $errstr, $succstr, $output); $rec_to_delete = 0; foreach $key (keys %in) { # Build a hash of keys to delete. if ($in{$key} eq "delete") { $delete_list{$key} = 1; $rec_to_delete = 1; } } $rec_to_delete or (&html_generic("Error: $html_object(s) Not Deleted", "no records specified.") and return); # Search the database for a record to delete. open (DB, "<$db_file_name") or &cgierr("error in delete_records. unable to open db file: $db_file_name.\nReason: $!"); if ($db_use_flock) { flock(DB, 1); } LINE: while () { (/^#/) and ($output .= $_ and next LINE); (/^\s*$/) and next LINE; chomp; @data = &split_decode($_); # # >>> Image Upload mod (next 25 lines) # Find and delete the image if deleting the link. # We're replacing these stock lines: # $delete_list{$data[$db_key_pos]} ? # If this id is one we want to delete, # ($delete_list{$data[$db_key_pos]} = 0) : # then mark it deleted and don't print it to the new database, # ($output .= "$_\n"); # otherwise print it. # # With all this: # Check if there is an image file, and remove it. if ($delete_list{$data[$db_key_pos]}) { # If this id is one we want to delete, $delete_list{$data[$db_key_pos]} = 0; # then mark it deleted and don't print it to the new database. if ($db_upload) { # Did we allow uploads? Set in links.def. # Find the image... opendir (GRAPHIC, "$upload_directory") or &cgierr("Unable to open directory in validate records: $upload_directory. Reason: $!"); @files = readdir(GRAPHIC); closedir (GRAPHIC); $file_test = $data[$db_key_pos] . "."; foreach $file (@files) { if ($file =~ /^$file_test/){ unlink ("$upload_directory/$file") or die "Delete failed: $!"; # Delete the image. } } } } else { $output .= "$_\n"; } # If no image, proceed as normal # <<< Image Upload mod } # !! Watch out for this bracket! close DB; # Reprint out the database. open (DB, ">$db_file_name") or &cgierr("error in delete_records. unable to open db file: $db_file_name.\nReason: $!"); if ($db_use_flock) { flock(DB, 2) or &cgierr("unable to get exclusive lock on $db_file_name.\nReason: $!"); } print DB $output; close DB; # automatically removes file lock # Build success/error messages. foreach $key (keys %delete_list) { $delete_list{$key} ? # Check to see if any items weren't deleted ($errstr .= "$key,") : # that should have been. ($succstr .= "$key,"); # For logging, we'll remember the one's we deleted. } chop($succstr); # Remove trailing delimeter chop($errstr); # Remove trailing delimeter $errstr ? # Do we have an error? &html_generic("Error: $html_object(s) Not Deleted", qq|The records with the following keys were not found in the database: '$errstr'.|) : # If so, then let's report go to the failure page &html_generic("$html_object(s) Deleted", "The following records were deleted from the database: '$succstr'"); # else, everything went fine. } *** There are a lot of changes in 'sub validate_records'. You need to pay close attention to brackets! sub validate_records { # -------------------------------------------------------- # This routine takes a list of records to either delete, validate # or modify and does the appropriate action. my ($rec_to_delete, $rec_to_validate, $rec_to_modify, %delete_list, %validate_list, %modify_list, %links, @lines, @data, $id, $first, $last, $errstr, $output); # First let's go through %in and see what we have to delete, modify # and/or validate. We also store all the links in easy to get at hashes. # We know what fields go with what records as they should all be of the form # ID-Field_Name. For instance: 12-URL is the URL field for record number 12. $rec_to_delete = $rec_to_validate = $rec_to_modify = 0; foreach $key (keys %in) { # Build a hash of keys to delete, validate and modify. ($in{$key} eq "delete") and $delete_list{$key} = 1 and $rec_to_delete = 1; ($in{$key} eq "validate") and $validate_list{$key} = 1 and $rec_to_validate = 1; ($in{$key} eq "modify") and $modify_list{$key} = 1 and $rec_to_modify = 1; ($key =~ /^(.*)-(\d+)$/) and $links{$2}{$1} = $in{$key}; } # If there isn't anything to do, let's complain. if (!$rec_to_validate and !$rec_to_delete and !$rec_to_modify) { &html_generic ("Problems Validating $html_objects", "Error: No records specified."); return; } # Let's go through the validation file and remove all the ones # we want to validate as well as all the ones we want to delete. if ($rec_to_validate or $rec_to_delete) { open (VAL, "<$db_valid_name") or &cgierr("error in validate_records. unable to open validate file: $db_valid_name. Reason: $!"); if ($db_use_flock) { flock (VAL, 1); } LINE: while () { (/^#/) and ($output .= $_ and next LINE); (/^\s*$/) and next LINE; chomp; @data = &split_decode($_); $id = $data[$db_key_pos]; # >>> Image Upload mod [1] (next 16 lines) if ($delete_list{$id}) { $delete_list{$id} = 0; #} !! NOTE: comment out/remove this bracket. # If declining addition from add.cgi, delete the image from /pics/validate. # Have to do a trick to get Imagename... opendir (GRAPHIC, "$upload_directory/validate") or &cgierr("Unable to open directory in validate records: $upload_directory/validate. Reason: $!"); @files = readdir(GRAPHIC); closedir (GRAPHIC); $file_test = $id . "."; foreach $file (@files) { if ($file =~ /^$file_test/) { unlink ("$upload_directory/validate/$file") or die "Delete failed: $!"; } } } # !! Watch out for this bracket! Replaces one removed above. # <<< elsif ($validate_list{$id}) { $validate_list{$id} = 2; } else { $output .= "$_\n"; } } close VAL; open (VAL, ">$db_valid_name") or &cgierr("error in validate_records. unable to open validate file: $db_valid_name. Reason: $!"); flock(VAL, 2) unless (!$db_use_flock); print VAL $output; close VAL; # automatically removes file lock undef $output; } # Now if we have something to delete from the modify list, let's get rid of it. if ($rec_to_modify or $rec_to_delete) { open (MOD, "<$db_modified_name") or &cgierr("error in validate_records. unable to open modified database: $db_modified_name. Reason: $!"); if ($db_use_flock) { flock (MOD, 1); } LINE: while () { (/^#/) and ($output .= $_ and next LINE); (/^\s*$/) and next LINE; chomp; @data = &split_decode($_); $id = $data[$db_key_pos]; # >>> Image Upload mod [2] (next 16 lines) if ($delete_list{$id}) { $delete_list{$id} = 0; #} !! NOTE: comment out/remove this bracket. # If declining change from modify.cgi, delete the upload from /pics/modify. # Have to do a trick to get Imagename... opendir (GRAPHIC, "$upload_directory/modify") or &cgierr("Unable to open directory in validate records: $upload_directory/modify. Reason: $!"); @files = readdir(GRAPHIC); closedir (GRAPHIC); $file_test = $id . "."; foreach $file (@files) { if ($file =~ /^$file_test/) { unlink ("$upload_directory/modify/$file") or die "Delete failed: $!"; } } } # !! Watch out for this bracket! Replaces one removed above. # <<< elsif ($modify_list{$id}) { $modify_list{$id} = 2; } else { $output .= "$_\n"; } } close MOD; open (MOD, ">$db_modified_name") or &cgierr("error in validate_records. unable to open modified database: $db_modified_name. Reason: $!"); flock(MOD, 2) unless (!$db_use_flock); print MOD $output; close MOD; # automatically removes file lock undef $output; } # Now we update any modifications to the database. if ($rec_to_modify) { $found = 0; # Make sure the record is in here! # >>> Image Upload mod [3] (next 14 lines) # If changes from modify.cgi approved, get rid of any old images, # and move the new image from /pics/modify to /pics. # Have to do a trick to get Imagename... opendir (GRAPHIC, "$upload_directory/modify") or &cgierr("Unable to open directory in validate records: $upload_directory/modify. Reason: $!"); @files = readdir(GRAPHIC); closedir (GRAPHIC); $file_test = $id . "."; foreach $file (@files) { if ($file =~ /^$file_test/) { unlink "$upload_directory/$file"; # First get rid of the old image move("$upload_directory/modify/$file", "$upload_directory/$file") or die "Move failed: $!"; # Then move the new one } } # <<< open (DB, "<$db_file_name") or &cgierr("error in validate_records. unable to open db file: $db_file_name. Reason: $!"); if ($db_use_flock) { flock (DB, 1); } LINE: while () { (/^#/) and ($output .= $_ and next LINE); (/^\s*$/) and next LINE; chomp; @data = &split_decode($_); $id = $data[$db_key_pos]; if ($modify_list{$id} == 2) { # If this is the one we are looking for $output .= &join_encode(%{$links{$id}}); $modify_list{$id} = 0; $found = 1; } else { $output .= "$_\n"; # else print regular line. } } close DB; if ($found) { open (DB, ">$db_file_name") or &cgierr("error in validate_records. unable to open db file: $db_file_name. Reason: $!"); flock(DB, 2) unless (!$db_use_flock); print DB $output; close DB; # automatically removes file lock } undef $output; } # Now let's see if we have something to add to the real database, then # let's do it. if ($rec_to_validate) { open (DB, ">>$db_file_name") or &cgierr("error in validate_records, unable to open db file: $db_file_name. Reason: $!"); flock(DB, 2) if ($db_use_flock); foreach $id (keys %validate_list) { if ($validate_list{$id} == 2) { print DB &join_encode(%{$links{$id}}); $validate_list{$id} = 0; } } close DB; # >>> Image Upload mod [4] (next 15 lines) (add.cgi) # } !! NOTE: comment out/remove this bracket. # If submission from add.cgi approved, move the image from /pics/validate to /pics. # Have to do a trick to get Imagename... opendir (GRAPHIC, "$upload_directory/validate") or &cgierr("Unable to open directory in validate records: $upload_directory/validate. Reason: $!"); @files = readdir(GRAPHIC); closedir (GRAPHIC); $file_test = $id . "."; foreach $file (@files) { if ($file =~ /^$file_test/) { move("$upload_directory/validate/$file", "$upload_directory/$file") or die "Move failed: $!"; } } } # !! Watch out for this bracket! Replaces one removed above. # <<< # Now let's check to make sure everything that was asked to be val/del/mod # actually happend. If not, let's complain. foreach $key (keys %validate_list) { if ($validate_list{$key}) { $errstr .= "
  • Validate Error: $key. Couldn't find record in validation database."; } else { $valsuc .= "$key,"; } } foreach $key (keys %delete_list) { if ($delete_list{$key}) { $errstr .= "
  • Delete Error: $key. Couldn't find record in validation/modified database."; } else { $delsuc .= "$key,"; } } foreach $key (keys %modify_list) { if ($modify_list{$key}) { $errstr .= "
  • Modify Error: $key. Couldn't find record in modified/links database."; } else { $modsuc .= "$key,"; } } chop($errstr); chop($valsuc); chop ($delsuc); chop ($modsuc); # Before we display the HTML, let's fire off some validate/modify/delete emails # lettings visitors know we've added their link. We only send the mail # if $modify_list{$id} = 0 (if it's still 1, that means there was an error). # NOTE: You can modify the text of the email in the email templates. &html_print_headers; # Just in case sendmail coughs up an error. if ($db_email_modify) { ID: foreach $id (keys %modify_list) { if ($modify_list{$id}) { next ID; } elsif (${$links{$id}}{'Contact Email'} =~ /(@.*@)|(\.\.)|(@\.)|(\.@)|(^\.)/ || ${$links{$id}}{'Contact Email'} !~ /^.+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,3}|[0-9]{1,3})(\]?)$/) { $errstr .= ($errstr, "
  • Email Error: $id. Record validated, but couldn't send auto email. Reason: Bad Email addres: '${$links{$id}}{'Contact Email'}'."); } else { &html_modify_email (%{$links{$id}}); } } } if ($db_email_add) { ID: foreach $id (keys %validate_list) { if ($validate_list{$id}) { next ID; } elsif (${$links{$id}}{'Contact Email'} =~ /(@.*@)|(\.\.)|(@\.)|(\.@)|(^\.)/ || ${$links{$id}}{'Contact Email'} !~ /^.+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,3}|[0-9]{1,3})(\]?)$/) { $errstr .= ($errstr, "
  • Email Error: $id. Record validated, but couldn't send auto email. Reason: Bad Email addres: '${$links{$id}}{'Contact Email'}'."); } else { &html_validate_email (%{$links{$id}}); } } } ID: foreach $id (keys %delete_list) { if ($delete_list{$id}) { next ID; } elsif (!$in{"reason-$id"}) { next ID; } elsif (${$links{$id}}{'Contact Email'} =~ /(@.*@)|(\.\.)|(@\.)|(\.@)|(^\.)/ || ${$links{$id}}{'Contact Email'} !~ /^.+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,3}|[0-9]{1,3})(\]?)$/) { $errstr .= ($errstr, "
  • Email Error: $id. Record deleted, but couldn't send rejection letter. Reason: Bad Email addres: '${$links{$id}}{'Contact Email'}'."); } else { &html_reject_email (%{$links{$id}}); } } # Now let's go to the error page or the success page depending on # what $errstr is. $errstr ? &html_generic ("Validate Links", "Error validating links:
      $errstr
    ") : &html_validate_success($valsuc, $modsuc, $delsuc); } ==================================================================================== 6. admin.cgi ==================================================================================== *** An easy one! Add this before 'sub main'. BTW, you need to have the 'File::Copy' perl module on your server. use File::Copy; ==================================================================================== 7. site_html_templates.pl ==================================================================================== *** Make changes as shown for all these subs: sub site_html_link { # -------------------------------------------------------- # This routine is used to display what a link should look # like. my %rec = @_; # Set new and pop to either 1 or 0 for templates. ($rec{'isNew'} eq 'Yes') ? ($rec{'isNew'} = 1) : (delete $rec{'isNew'}); ($rec{'isPopular'} eq 'Yes') ? ($rec{'isPopular'} = 1) : (delete $rec{'isPopular'}); return &load_template ('link.html', { detailed_url => "$db_detailed_url/$rec{'ID'}$build_extension", save_directory_url => $save_directory_url, # <<< Image Upload Mod %rec, %globals }); } # >>> Security Mod - two new subs sub site_html_modify_form_up { # -------------------------------------------------------- # This routine determines how the modify form page will look like. &html_print_headers; print &load_template ('modify_up.html', { %globals }); } sub site_html_modify_up_failure { # -------------------------------------------------------- # This routine determines how the modify form page will look like. my ($error) = shift; &html_print_headers; print &load_template ('modify_up_failure.html', { error => $error, %globals }); } # <<< Security Mod sub site_html_modify_form { # -------------------------------------------------------- # This routine determines how the modify form page will look like. my (%record) = @_; my $cat = &build_select_field ("Category", "$record{'Category'}"); # <<< Security Mod # my $category = &build_select_field ("Category", "$in{'Category'}"); # <<< Security Mod - comment out/delete line &html_print_headers; print &load_template ('modify.html', { Cat => $cat, # <<< Security Mod %record, %in, # <<< Security Mod %globals }); } ==================================================================================== 8. Template changes ==================================================================================== *** In add.html, add_error.html, modify.html, and modify_error.html, change the 'form action' line to include 'enctype':
    *** I placed the following code just above the submit button row. *** add.html Photo: *** add_error.html Photo: *** modify.html Please enter the URL of the link you wish to update. Make sure it is identical to the one already in the database:

    end mod --> <%if Imagename%> Current Photo: Delete Photo? <%endif%> Photo:
    Note: Uploading a new image will replace existing one. *** modify_error.html <%if Imagename%> Current Photo: Delete Photo? <%endif%> Photo:
    Note: Uploading a new image will replace existing one. *** New template, modify_up.html <%site_title%>: Modify a Resource

    <%site_title%>: Modify a Resource, Step 1

    | Home | Add a Resource | Modify a Resource | What's New | What's Cool | Top Rated | Email Updates | Random Link | Search |

    Please enter the Title for the listing you wish to update. This information must match what is currently in the directory.

    Search

    Title:
    Looking for something in particular?
    More search options

    Pages Updated On: <%date%> - <%time%>
    Links Engine Powered By: Gossamer Threads Inc.

    *** New template, modify_up_failure.html <%site_title%>: Modify a Resource

    <%site_title%>: Modify a Resource, Step 1 Error

    | Home | Add a Resource | Modify a Resource | What's New | What's Cool | Top Rated | Email Updates | Random Link | Search |

    There was an error trying to log in:

    <%error%>

    Please enter the Title for the listing you wish to update. This information must match what is currently in the directory.

    Search

    Title:
    Looking for something in particular?
    More search options

    Pages Updated On: <%date%> - <%time%>
    Links Engine Powered By: Gossamer Threads Inc.

    ==================================================================================== 9. Create Directories ==================================================================================== *** You need to create three new directories. The first one goes in the same directory that your links pages will be built in, the other two go inside of it. The first one is 'pics,' the other two are 'validate' and 'modify.' Like so: /pics /pics/validate /pics/modify ==================================================================================== 10. Other ==================================================================================== *** If you have an existing links.db file, you need to add a new field to the end of each entry by adding a pipe '|' to each one: 2009|Test_1||bob|bob@bob.com|0|Yes|No|0|0|Yes|24.jpg| 25|test5000||23-Nov-2009|Test_1||||0|Yes|No|0|0|Yes|| *** To make testing easier, make most fields not required, so you only have to enter a Title and Category. For everything but Title and Category, make the character in position 5 a '0' as shown below, which means that field is not required. 'Contact Name' => [6, 'alpha', 40, 75, 0, '', ''], (Be sure to restore the requirements when done testing.)