#####################################################################
### ###
### M U L T I P L E F I L E U P L O A D ###
### Modified: 30 Mar 2003 ###
### ###
### Mod based on a script created by ###
### Jeff Carnahan jeffc@terminalp.com ###
### Adapted for use by DBMan by ###
### JPDeni deni@jpdeni.com ###
### Integration with DBMan script by ###
### Jim Kangosjärvi Jim.Kangosjarvi@Abc.se ###
### Modifed for DBMan SQL version 1 by ###
### Shannon Geiger webmaster@rainbowroomies.com ###
### ###
#####################################################################
# #
# This modification will allow you to add file uploading capability #
# to your database. Users can upload multiple files per record. The #
# most common use of the mod will probably be to upload graphic #
# files to accompany a record. #
# #
# The mod creates a directory for the files with a name to match #
# the key value of the associated record. #
# #
# This script requires that the CGI.pm module is installed on your #
# system. It probably is, but if you run into problems, you might #
# ask your server admin if the CGI.pm module is installed. #
# #
# You will not be able to use the autogenerate feature of DBMan with#
# this mod. You must create your own html_record and #
# html_record_form subroutines. #
# #
#####################################################################
#####################################################################
# Create a directory in your public html directory -- the place #
# where you normally put web pages -- for the graphics to be #
# uploaded. On most systems, this should *not* be within the #
# cgi-bin. #
# #
# Set the permissions for this directory to 777. #
#####################################################################
#####################################################################
# file: db.cfg #
# #
# add the following field to your field definitions #
#####################################################################
# If you want to require at least one graphic to be uploaded when a
# record is added
Graphic => [11, 'CHAR', 0, 3, 1, ' ', 'Yes', 0],
# If you uploading a file is optional
Graphic => [11, 'CHAR', 0, 3, 0, ' ', 'Yes', 0],
# (Change the field number to fit with your database definition.)
# If you wish users to be able to search for records that have at least
# one graphic associated with them, add the following. You will also
# need to add a checkbox field to your search form.
%db_checkbox_fields = ( Graphic => 'Yes' );
#####################################################################
# file: db.cfg #
# #
# After the Authorization Options section #
# add the following #
#####################################################################
# File upload parameters
# --------------------------------------------------------
#
# File uploads -- if you want to be able to upload files, set this to 1
$db_upload = 1;
# Full path to directory for uploaded files -- NOT A URL!!!! No trailing slash please.
$SAVE_DIRECTORY = "/home/username/public_html/uploads";
# Full URL to directory for uploaded files. No trailing slash please.
$SAVE_DIRECTORY_URL = "http://www.server.com/uploads";
# 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 = 50000;
# 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!
$ALLOWED_EXT = '\.gif$|\.jpg$|\.GIF$|\.JPG$';
######################################################################
# file: db.cgi #
# after #
# $db_script_path = "."; #
# add the following #
######################################################################
use CGI;
$query = new CGI;
######################################################################
# file: db.cgi #
# sub parse_form #
# replace subroutine with the following #
######################################################################
sub parse_form {
# --------------------------------------------------------
my (%in);
my ($buffer, $pair, $name, $value);
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; }
(exists $in{$name}) ?
($in{$name} .= "~~$value") :
($in{$name} = $value);
}
return %in;
}
######################################################################
# file: db.cgi #
# sub add_record #
# Replace subroutine #
######################################################################
sub add_record {
# --------------------------------------------------------
# Adds a record to the database. First, validate_record is called
# to make sure the record is ok to add. If it is, then the record is
# encoded and added to the database and the user is sent to
# html_add_success, otherwise the user is sent to html_add_failure with
# an error message explaining why. The counter file is also updated to the
# next number.
my ($query, $name, $insert_name, $insert_value, $status, $limit);
# Set the userid to the logged in user.
($auth_user_field >= 0) and ($in{$auth_user_field} = $db_userid);
# Validate the record and make sure it passes the users reg expressions and
# the allowed null's.
if ($in{'file-to-upload-1'}) { $in{'Graphic'} = 'Yes'; }
else { $in{'Graphic'} = ''; }
$status = &validate_record;
if ($status eq "ok") {
# If we are to supply a key, we find the largest one in the database, and then increase that
# by one and use that value as a key. Otherwise we hope the user has entered in a unique value.
if ($db_supply_key) {
$db_msql ? ($limit = '') : ($limit = 'LIMIT 1');
$query = qq!
SELECT $db_key FROM $db_table
ORDER BY $db_key DESC
$limit
!;
$sth = $DBH->prepare ($query) or &cgierr("Unable to query database. Reason: $DBI::errstr. Query: $query");
$sth->execute or &cgierr("Unable to query database. Reason: $DBI::errstr. Query: $query");
$in{$db_key} = int(($sth->fetchrow_array)[0]) + 1;
$sth->finish;
}
if (($status eq "ok") && ($in{'file-to-upload-1'})) { $status = &validate_upload; } #Validate Pictures
if ($status eq "ok") {
($auth_user_field) and ($in{$auth_user_field} = $db_userid);
# Now we build the SQL query. We start by quoting all the input, and int() any fields
# that should be integers.
foreach $name (@db_cols) {
next if ($in{$name} =~ /^\s*$/);
$insert_name .= "$name,";
$db_is_int{$name} ?
($insert_value .= int($in{$name}) . ",") :
($insert_value .= $DBH->quote($in{$name}) . ",");
}
chop ($insert_name); chop ($insert_value); # Remove trailing delimiters.
$query = qq!
INSERT INTO $db_table ($insert_name)
VALUES ($insert_value)
!;
# Execute the query. Returns 0 on error, and error msg is stored in $DBI::errstr
$rc = $DBH->do($query);
if ($rc) {
foreach (keys %db_indexed) { &index_record ($in{$db_key}, $_, $in{$_}); }
&auth_logging("added record: $in{$db_key}", $DBH) if ($auth_logging);
&html_add_success;
}
else {
&html_add_failure($DBI::errstr);
}
}
else {
# Oops, we didn't pass the regexp and/or the null checks!
&html_add_failure($status);
}
}
}
######################################################################
# file: db.cgi #
# sub validate_upload #
# new subroutine #
######################################################################
sub validate_upload {
# --------------------------------------------------------
my ($filekey,$filename,$extlength,$filehandle,$totalbytes,$buffer,$bytes,@extensions,@ext,
$newdirname,$dirsuccess,$num_files,$prev_files,$prev_bytes);
$| = 1;
if (!(-e $SAVE_DIRECTORY)) {
return "The directory doesn't exist. Make sure that this directory is a complete path name,
not a URL or something similar. It should look similar to
/home/username/public_html/uploads";
}
if (!(-W $SAVE_DIRECTORY)) {
return "The directory isn't writable. Make sure that this directory is writable by all users.
At your UNIX command prompt, type chmod 777 $SAVE_DIRECTORY";
}
if (!(-d $SAVE_DIRECTORY)) {
return "The directory you specified isn't really a directory.
Make sure that this is indeed a directory and not a file.";
}
$newdirname = $in{$db_key};
if (!(-e "$SAVE_DIRECTORY/$newdirname")) {
$dirsuccess = mkdir "$SAVE_DIRECTORY/$newdirname", 0777;
}
else {
opendir (GRAPHIC, "$SAVE_DIRECTORY/$newdirname") or &cgierr("unable to open directory. Reason: $!");
@files = readdir(GRAPHIC);
closedir (GRAPHIC);
foreach $file (@files) {
next if ($file =~ /^\./); # Skip "." and ".." entries..
next if ($file =~ /^index/); # Skip index.htm type files..
++$prev_files;
@stats = stat "$SAVE_DIRECTORY/$newdirname/$file";
$prev_bytes +=$stats[7];
}
}
foreach $key (sort {$a <=> $b} $query->param()) {
next if ($key =~ /^\s*$/);
next if ($query->param($key) =~ /^\s*$/);
next if ($key !~ /^file-to-upload-(\d+)$/);
$Number = $1;
++$num_files;
if ($query->param($key) =~ /([^\/\\]+)$/) {
$filename = $1;
$File_Handle = $query->param($key);
unless ($filename =~ /$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.";
}
if (!open(OUTFILE, ">$SAVE_DIRECTORY\/$newdirname\/$filename")) {
return "There was an error opening '$SAVE_DIRECTORY\/$newdirname\/$filename' for Writing.\n";
}
binmode(OUTFILE); # This is needed to work on Windows/NT platforms.
undef $BytesRead;
undef $Buffer;
while ($bytes = read($File_Handle,$buffer,1024)) {
$totalbytes += $bytes;
print OUTFILE $buffer;
}
push(@Files_Written, "$SAVE_DIRECTORY\/$newdirname\/$filename");
close($File_Handle);
close(OUTFILE);
chmod (0666, "$SAVE_DIRECTORY\/$newdirname\/$filename");
}
if (($totalbytes + $prev_bytes) > $MAXIMUM_UPLOAD && $MAXIMUM_UPLOAD > 0) {
foreach $written (@Files_Written) {
unlink "$written";
}
return "You have exceeded your upload limit for this record.
Your files contain $totalbytes bytes.
Combined with previous uploads totaling $prev_bytes, this
exceeds the maximum limit of $MAXIMUM_UPLOAD bytes per record.
Your files were not saved.
Please try again.";
}
if (($num_files + $prev_files) > $MAXIMUM_FILES) {
foreach $written (@Files_Written) {
unlink "$written";
}
return "You have exceeded your upload limit for this record.
You uploaded $num_files files.
Combined with previous $prev_files uploads, this
exceeds the maximum limit of $MAXIMUM_FILES files per record.
Your files were not saved.
Please try again.";
}
return "ok";
}
######################################################################
# file: db.cgi #
# sub delete_records #
# #
# if you want to delete the associated files when a record is #
# deleted, add: #
if ($db_upload) {
if (-e "$SAVE_DIRECTORY/$key/") {
opendir (GRAPHIC, "$SAVE_DIRECTORY/$key/") or &cgierr("unable to open directory in delete records: $SAVE_DIRECTORY/$data[$db_key_pos]. Reason: $!");
@files = readdir(GRAPHIC);
closedir (GRAPHIC);
foreach $file (@files) {
unlink ("$SAVE_DIRECTORY/$key/$file");
}
rmdir "$SAVE_DIRECTORY/$key/";
}
}
else { $output .= $line . "\n"; }
After:
$rc = $DBH->do($query);
######################################################################
# file: db.cgi #
# sub modify_record #
# replace subroutine #
######################################################################
sub modify_record {
# --------------------------------------------------------
# This routine does the actual modification of a record. It expects
# to find in %in a record that is already in the database, and will
# rewrite the database with the new entry. First it checks to make
# sure that the modified record is ok with validate record.
# It then goes through the database looking for the right record to
# modify, if found, it prints out the modified record, and returns
# the user to a success page. Otherwise the user is returned to an error
# page with a reason why.
my ($status, $line, @lines, $ID, @rest, $output, $found, $userid_q, $key_q, @data, %rec, $key, $num_files, @files, $file, $query);
# Set the userid to the logged in user.
($auth_user_field >= 0) and ($in{$auth_user_field} = $db_userid);
if ($auth_modify_own and !$per_admin) {
%rec = &get_record($in{$db_key});
unless ($rec{$db_cols[$auth_user_field]} eq $db_userid) {
&html_modify_failure("You are not authorized to modify this record");
return;
}
}
# Check to make sure the record passes the reg exp and null checks.
foreach $key (keys %in) {
if ($in{$key} eq 'delete') {
unlink "$SAVE_DIRECTORY/$in{$db_key}/$key";
}
}
$num_files=0;
if (-e "$SAVE_DIRECTORY/$in{$db_key}") {
opendir (GRAPHIC, "$SAVE_DIRECTORY/$in{$db_key}") or &cgierr("unable to open directory: $SAVE_DIRECTORY/$rec{$db_key}. Reason: $!");
@files = readdir(GRAPHIC);
closedir (GRAPHIC);
foreach $file (@files) {
next if ($file =~ /^\./); # Skip "." and ".." entries..
next if ($file =~ /^index/); # Skip index.htm type files..
++$num_files;
}
}
if ($num_files or $in{'file-to-upload-1'}) { $in{'Graphic'} = 'Yes'; }
else { $in{'Graphic'} = ''; }
(!$per_admin) and ($in{$db_validated_field} = "No");
$status = &validate_record; # Check to make sure the modifications are ok!
if (($status eq "ok") && ($in{'file-to-upload-1'})) { $status = &validate_upload; } #Validate Pictures
if ($status eq "ok") {
# Build the SET string to be used in the SQL query. We quote all input and int all
# fields that should be int.
foreach $name (@db_cols) {
next if ($name eq $auth_user_field);
$db_is_int{$name} ?
($update .= $name . "=" . int($in{$name}) . ",") :
($update .= $name . "=" . $DBH->quote($in{$name}) . ",");
}
chop ($update);
# Quote/Int the key.
$db_is_int{$db_key} ?
($key_q = int($in{$db_key})) :
($key_q = $DBH->quote($in{$db_key}));
# We add an extra check if the user is only allowed to
# modify his own records.
$userid_q = $DBH->quote($db_userid);
($auth_modify_own and !$per_admin) ?
($query = qq!
UPDATE $db_table SET $update
WHERE $db_key = $key_q AND
$auth_user_field = $userid_q
!) :
($query = qq!
UPDATE $db_table SET $update
WHERE $db_key = $key_q
!);
# Execute the query.
$rc = $DBH->do ($query);
if ($rc) {
foreach (keys %db_indexed) { &update_index ($in{$db_key}, $_, $in{$_}); }
&auth_logging("modified record: $in{$db_key}", $DBH) if ($auth_logging);
&html_modify_success;
}
else {
&html_modify_failure("$in{$db_key} (can't find requested record)
$query" . $DBH->errstr); } } else { &html_modify_failure($status); # Validation Error } } ###################################################################### # file: html.pl # # sub html_record # # # # after # # my (%rec) = @_; # # # # add # # # ###################################################################### $rec{$db_key} =~ s/<.?B>//g; ### Wherever you want your graphics to print out, use the following: |; if (-e "$SAVE_DIRECTORY/$rec{$db_key}") { opendir (GRAPHIC, "$SAVE_DIRECTORY/$rec{$db_key}") or &cgierr("unable to open directory: $SAVE_DIRECTORY/$rec{$db_key}. Reason: $!"); @files = readdir(GRAPHIC); closedir (GRAPHIC); foreach $file (@files) { next if ($file =~ /^\./); # Skip "." and ".." entries.. next if ($file =~ /^index/); # Skip index.htm type files.. print qq|