#!/usr/bin/perl -w
#******************************************************************************************************
# ATTENTION: THIS FILE HEADER MUST REMAIN INTACT. DO NOT DELETE OR MODIFY THIS FILE HEADER.
#
# Name: uber_uploader.cgi
# Revision: 2.7
# Date: 2006/04/07
# Author: Peter Schmandra http://www.webdice.org
# Contributor: Tore B. Krudtaa
# Contributor: Tolriq
# Contributor: Jeroen Soeters
# Contributor: Detlev Richter
# Description: Upload files to a temp dir based on Session-id, transfer files to upload dir and output results.
#
# Licence:
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
#**********************************************************************************************************************************************************
use CGI qw(:cgi); # Load the CGI.pm module
CGI::private_tempfiles(0); # Make sure private temp files is disabled "DO NOT CHANGE"
my $temp_dir = '/home/domains/uploads/'; # ATTENTION: this variable must be the same as the $config['temp_dir'] set in config.php
my $upload_dir = $temp_dir; # ATTENTION: this variable must be the same as the $config['upload_dir'] set in config.php
my $max_upload = 125829120; # Max upload size in bytes (2 * 1024 * 1024 = 2097152 = 2MB)
my $overwrite_existing_files = 1; # Set to 1 if over writing existing uploaded files is desired
my $redirect_after_upload = 1; # Set to 1 if you want to redirect to the php finished page
my $redirect_using_html = 0; # Set to 1 if you are redirecting and want to use html handle the refresh
my $redirect_url = 'http://' . $ENV{'SERVER_NAME'} . '/upload_finished.php'; # Path to php redirect page ( eg. http://www.yoursite.com/upload/upload_finished.php )
my $progress_url = 'http://' . $ENV{'SERVER_NAME'} . '/upload_progress.php'; # Path to php progress page ( eg. http://www.yoursite.com/upload/upload_progress.php )
my $create_files_by_rename = 1; # Set to 0 if you want to copy the file instead of rename
my $debug_cgi = 0; # Set to 1 to debug and call ( eg. www.yoursite.com/cgi-bin/uploader.cgi?cmd=debug )
my $errors_to_browser = 0; # Set to 1 if you want fatal errors displayed in the browser
my $flock_flength_file = 1; # Set to 0 if file locking the flength file is not desired
################################################ You Can Safely Change The Values Above This Line ########################################################################
my $tmp_sid = (split(/[&=]/,$ENV{QUERY_STRING}))[1]; # Get the session-id for temp files
$tmp_sid =~ s/[^a-zA-Z0-9]//g; # Sanitise session-id
my $driver_version = "2.7"; # Version of this driver
my $uber_version = "2.4.1"; # Version of Uber Uploader
my $sleep_time = 1; # Seconds to wait before upload proceeds (for small file uploads)
my $clean_up_files = 1; # Clean up files on exit
my $print_issued = 0; # Used to track print "Content-type: text/html\n\n";
my %uploaded_files = (); # Hash with all the uploaded file names
my $temp_dir_sid = $temp_dir . $tmp_sid; # Append Session-id to upload temp directory
my $flength_file = $temp_dir_sid . '/flength'; # Flength file is used to store the size of the upload in bytes
my ($file_name, $upload_filehandle, $tmp_filename, $upload_file_path); # Extra variables used in script
my ($key, $post_value); # Extra variables used in script
umask(0);
$|++; # Force auto flush of output buffer
$SIG{HUP} = 'IGNORE'; # Ignore sig hup
$SIG{__DIE__} = \&cleanup; # User has pressed stop during upload so deal with it
$CGI::POST_MAX = $max_upload; # Set the max post value
################################################ Not A Good Idea To Change The Values Above This Line ########################################################################
# Send fata errors to the users browser
if($errors_to_browser){
if(!$print_issued){
print "Content-type: text/html\n\n";
$print_issued = 1;
}
use CGI::Carp('fatalsToBrowser');
}
# Check for debug, version or empty session-id passed to script
if($tmp_sid eq "debug" && $debug_cgi){ &debug(); }
elsif($tmp_sid eq "debug" && !$debug_cgi){ &kak("<u><b>CGI SETTINGS<\/b><\/u><br> DEBUG_CGI = <b>disabled<\/b><br>\n", 1); }
elsif($tmp_sid eq "version"){ &kak("<u><b>VERSION</b><\/u><br> VERSION = <b>" . $uber_version . "<\/b><br> CGI DRIVER VERSION = <b>" . $driver_version . "<\/b><br>\n", 1); }
elsif(length($tmp_sid) < 32){ &kak("<font color='red'>ERROR<\/font>: Invalid session-id $tmp_sid.<br>\n", 1); }
# Create temp directory if it does not exist
if(!-d $temp_dir){ mkdir($temp_dir, 0777) or &kak("<font color='red'>ERROR</font>: Can't mkdir $temp_dir: $!", 1); }
# Create a temp directory based on Session-id
if(!-d $temp_dir_sid){ mkdir($temp_dir_sid, 0777) or &kak("<font color='red'>ERROR</font>: Can't mkdir $temp_dir_sid: $!", 1); }
else{
&deldir($temp_dir_sid);
mkdir($temp_dir_sid, 0777) or &kak("<font color='red'>ERROR</font>: Can't mkdir $temp_dir_sid: $!", 1);
}
# Prepare the flength file for writing
if($flock_flength_file){
use Fcntl qw(:DEFAULT :flock);
sysopen(FLENGTH, $flength_file, O_RDWR | O_CREAT) or &kak("<font color='red'>ERROR</font>: Can't open $flength_file: $!", 1);
select((select(FLENGTH), $| = 1)[0]);
flock(FLENGTH, LOCK_EX) or &kak("<font color='red'>ERROR</font>: Can't write-lock $flength_file: $!", 1);
seek(FLENGTH, 0, 0) or &kak("<font color='red'>ERROR</font>: Can't rewind $flength_file: $!", 1);
}
else{
open FLENGTH, ">$flength_file" or &kak("<font color='red'>ERROR</font>: Can't open $temp_dir_sid/flength: $!", 1);
}
if($ENV{'CONTENT_LENGTH'} > $max_upload){
# If file size exceeds maximum write error to flength file and exit
my $max_size = &format_bytes($max_upload, 99);
print FLENGTH "<font color='red'>ERROR</font>: Maximum upload size of " . $max_size . " exceeded.<br><br>Your upload has failed.<br>";
close FLENGTH;
chmod 0666, $flength_file;
# Tell cgi not to delete the temp files. Progress script will do it.
$clean_up_files = 0;
&kak("<font color='red'>ERROR</font>: Maximum upload size of " . $max_size . " exceeded.<br><br>Your upload has failed.<br>", 1);
}
else{
# Write total upload size in bytes to flength file
print FLENGTH $ENV{'CONTENT_LENGTH'};
close FLENGTH;
chmod 0666, $flength_file;
}
# Let progress bar get some info (for small file uploads)
sleep($sleep_time);
# Tell CGI.pm to use our directory based on Session-id (older versions of CGI.pm)
if($TempFile::TMPDIRECTORY){ $TempFile::TMPDIRECTORY = $temp_dir_sid; }
elsif($CGITempFile::TMPDIRECTORY){ $CGITempFile::TMPDIRECTORY = $temp_dir_sid; }
else{ &kak("<font color='red'>ERROR</font>: Cannot assign CGI temp directory", 1); }
my $query = new CGI;
# IF you are changing the upload directory dynamically, DO IT HERE.
# eg. $upload_dir = $upload_dir . $query->param("company_num") . "/";
# Create upload directory if it does not exist
if(!-d $upload_dir){ mkdir($upload_dir, 0777) or &kak("<font color='red'>ERROR</font>: Can't mkdir $upload_dir: $!", 1); }
# If we are using rename, make sure it's the same disk
if($create_files_by_rename == 1){
my $dev_temp_dir = (stat($temp_dir))[1];
my $dev_upload_dir = (stat($upload_dir))[1];
# We have have two disks so use copy instead (can't rename across disks)
if($dev_temp_dir != $dev_upload_dir){ $create_files_by_rename = 0; }
}
# Upload is finished, start creating files in the upload directory
# MOD [MD5 Filename] April 22nd, 2006 By Inigoesdr (inigoesdr@dandev.net)
#for(my $i = 0; $i < $query->param('upload_range'); $i++){
for(my $i = 0; $i < 1; $i++){
# END MOD
$file_name = $query->param("upfile_" . $i);
$file_name =~ s/.*[\/\\](.*)/$1/;
$upload_filehandle = $query->upload("upfile_" . $i);
$tmp_filename = $query->tmpFileName($upload_filehandle);
# Do not process blank upload slots, files that end in .sh or .php or zero length files
#if(($file_name ne "") && ($file_name !~ m/(\.sh)|(\.php)$/i) && (-s $tmp_filename)){
if(($file_name ne "") && (-s $tmp_filename)){
# IF you are changing the file name dynamically, DO IT HERE.
# eg. $file_name = $query->param("employee_num") . "_" . $file_name;
# MOD April 22nd, 2006 By Inigoesdr (inigoesdr@dandev.net)
$original_file_name = $file_name;
use Digest::MD5 qw(md5_hex);
$file_name = md5_hex($file_name, time());
# END MOD
if(!$overwrite_existing_files){ $file_name = &rename_filename($file_name, 1); }
$upload_file_path = $upload_dir . $file_name;
if($create_files_by_rename){
# Create uploaded files by rename
close($upload_filehandle);
rename($tmp_filename, $upload_file_path) or &kak("Cannot rename from $tmp_filename to $upload_file_path: $!", 0);
}
else{
# Create uploaded files by copy
open(UPLOADFILE, ">$upload_file_path");
binmode UPLOADFILE;
while(<$upload_filehandle>){ print UPLOADFILE; }
close(UPLOADFILE);
}
chmod 0666, $upload_file_path;
}
if($file_name ne ""){ $uploaded_files{$file_name} = 0; }
}
#Delete the temp directory and everything in it
&deldir($temp_dir_sid);
# Redirect to php page if redirect enabled else display results
if($redirect_after_upload){
my $param_file_path = $upload_dir . $tmp_sid . ".params";
my @names = $query->param;
my $i = 0;
my $file_name;
open PARAMS, ">$param_file_path" or &display_results_through_cgi();
binmode PARAMS;
# Write post values to param file (we do not write the files names at this point)
foreach $key (@names){
$post_value = $query->param($key);
$post_value =~ s/(\r\n|\n|\r)/~NWLN~/g;
$post_value =~ s/=/~EQLS~/g;
if($post_value ne "" && $key !~ m/^upfile_/){ print PARAMS $key . "=" . $post_value . "\n"; }
}
# Write upload file names to param file
foreach $file_name (keys %uploaded_files){
# MOD April 22nd, 2006 By Inigoesdr (inigoesdr@dandev.net)
#$key = 'upfile_' . $i;
#print PARAMS $key . "=" . $file_name . "\n";
print PARAMS "upfile=" . $file_name . "\n";
print PARAMS "original=" . $original_file_name . "\n";
# END MOD
$i++;
}
close(PARAMS);
chmod 0666, $param_file_path;
# Append the session-id to the redirect url. Finished page will use this to find it's param file.
$redirect_url .= "?tmp_sid=" . $tmp_sid;
if(!$query->param('imbedded_progress_bar')){ $redirect_url .= "&close_pop=1"; }
if($redirect_using_html){
print "Content-type: text/html\n\n";
print "<meta http-equiv=\"refresh\" content=\"0; url='$redirect_url'\">\n";
}
else{
# Uncomment next line if using Webstar V
# print "HTTP/1.1 302 Redirection\n";
print "Location: $redirect_url\n\n";
}
}
else{ &display_results_through_cgi(); }
######################################################### START SUBROUTINES ###################################################
########################################
# Delete the temp dir based on tmp_sid
########################################
sub cleanup{ deldir($temp_dir_sid); }
#####################################
# Display upload results through cgi
#####################################
sub display_results_through_cgi{
&confirm_upload();
&display_results();
}
########################################
# Confirm upload and get size file size
########################################
sub confirm_upload{
my $file_name;
my $path_to_file;
foreach $file_name (keys %uploaded_files){
$path_to_file = $upload_dir . $file_name;
if(-e $path_to_file && -f $path_to_file){ $uploaded_files{$file_name} = -s $path_to_file; }
}
}
####################################
# Format the upload result and exit
####################################
sub display_results{
my $upload_result;
my $i = 0;
my $bg_col;
my $line;
my $buffer;
my $js_code;
my $file_name;
foreach $file_name (keys %uploaded_files){
if($i%2){ $bg_col = 'cccccc'; }
else{ $bg_col = 'dddddd'; }
if($uploaded_files{$file_name} > 0){
my $file_size = &format_bytes($uploaded_files{$file_name}, 99);
$upload_result .= "<tr><td align='center' bgcolor='$bg_col'> $file_name <\/td><td align='center' bgcolor='$bg_col'>$file_size<\/td><\/tr>\n";
}
else{ $upload_result .= "<tr><td align='center' bgcolor='$bg_col'> $file_name <\/td><td align='center' bgcolor='$bg_col'><font color='red'>Failed To Upload<\/font><\/td><\/tr>\n"; }
$i++;
}
if(!$query->param('imbedded_progress_bar')){
$progress_url .= "?close_pop=1";
$js_code = "window.open('$progress_url','uploadWin','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=no,width=1,height=1,left=350,top=300');\n";
}
open(TEMPLATE, "upload_finished.tmpl") or &kak("<font color='red'>ERROR</font>: Can't open upload__finished.tmpl: $!", 1);
# Search and replace tags from the template file
while($line = <TEMPLATE>){
$line =~ s/<!-- cgi:js_code -->/$js_code/i;
$line =~ s/<!-- cgi:upload_result -->/$upload_result/i;
$buffer .= $line;
}
close(TEMPLATE);
if(!$print_issued){
print "Content-type: text/html\n\n";
$print_issued = 1;
}
print $buffer;
}
####################################################
# formatBytes($file_size, 99) mixed file sizes
# formatBytes($file_size, 0) KB file sizes
# formatBytes($file_size, 1) MB file sizes etc
####################################################
sub format_bytes{
my $bytes = shift;
my $byte_format = shift;
my $byte_size = 1024;
my $i = 0;
my @byte_type = (" KB", " MB", " GB", " TB", " PB", " EB", " ZB", " YB");
$bytes /= $byte_size;
if($byte_format == 99 || $byte_format > 7){
while($bytes > $byte_size){
$bytes /= $byte_size;
$i++;
}
}
else{
while($i < $byte_format){
$bytes /= $byte_size;
$i++;
}
}
$bytes = sprintf("%1.2f", $bytes);
$bytes .= $byte_type[$i];
return $bytes;
}
##############################################################
# Output a message to the screen
#
# You can use this function to debug your script.
#
# eg. &kak("The value of blarg is: " . $blarg . "<br>", 1);
# This will print the value of blarg and exit the script.
#
# eg. &kak("The value of blarg is: " . $blarg . "<br>", 0);
# This will print the value of blarg and continue the script.
##############################################################
sub kak{
my $msg = shift;
my $kak_exit = shift;
if(!$print_issued){
print "Content-type: text/html\n\n";
$print_issued = 1;
}
print "<!DOCTYPE HTML PUBLIC \"-\/\/W3C\/\/DTD HTML 4.01 Transitional\/\/EN\">\n";
print "<html>\n";
print " <head>\n";
print " <title>Uploader<\/title>\n";
print " <meta http-equiv=\"Pragma\" content=\"no-cache\">\n";
print " <meta http-equiv=\"CACHE-CONTROL\" content=\"no-cache\">\n";
print " <meta http-equiv=\"expires\" content=\"-1\">\n";
print " <\/head>\n";
print " <body style=\"background-color: #FFFFFF; color: #000000; font-family: arial, helvetica, sans_serif;\">\n";
print " <br>\n";
print " <div align='center'>\n";
print " $msg\n";
print " <br>\n";
print " </div>\n";
print " </body>\n";
print "</html>\n";
if($kak_exit){ exit(0); }
}
#########################################
# Delete a directory and everthing in it
#########################################
sub deldir{
my $del_dir = shift;
my $file_name;
my $file_path;
if(-d $del_dir){
if(opendir(DIRHANDLE, $del_dir)){
while($file_name = readdir(DIRHANDLE)){
if(($file_name ne ".") && ($file_name ne "..")){
$file_path = $del_dir . "/" . $file_name;
unlink($file_path) or &kak("Cannont unlink $file_path: $!", 0);
}
}
closedir(DIRHANDLE);
rmdir($del_dir) or &kak("Cannot rmdir $del_dir: $!", 0);
}
else{ &kak("Cannont open $del_dir: $!", 0); }
}
}
############################################
# Print driver settings to screen and exit
############################################
sub debug{
my $msg;
my $temp_dir_state;
my $upload_dir_state;
if(!-d $temp_dir){ $temp_dir_state = "<font color='red'>" . $temp_dir . "<\/font>"; }
else{ $temp_dir_state = "<font color='green'>" . $temp_dir . "<\/font>"; }
if(!-d $upload_dir){ $upload_dir_state = "<font color='red'>" . $upload_dir . "<\/font>"; }
else{ $upload_dir_state = "<font color='green'>" . $upload_dir . "<\/font>"; }
$msg .= "<u><b>CGI SETTINGS<\/b><\/u><br>\n";
$msg .= "VERSION = <b>" . $uber_version . "<\/b><br>\n";
$msg .= "CGI DRIVER VERSION = <b>" . $driver_version . "<\/b><br>\n";
$msg .= "TEMP_DIR = <b>" . $temp_dir_state . "<\/b><br>\n";
$msg .= "UPLOAD_DIR = <b>" . $upload_dir_state . "<\/b><br>\n";
$msg .= "MAX_UPLOAD = <b>" . format_bytes($max_upload, 99) . "<\/b><br>\n";
if($create_files_by_rename){ $msg .= "CREATE_FILES_BY_RENAME = <b>enabled<\/b><br>\n"; }
else{ $msg .= "CREATE_FILES_BY_RENAME = <b>disabled<\/b><br>\n"; }
if($overwrite_existing_files){ $msg .= "OVERWRITE_EXISTING_FILES = <b>enabled<\/b><br>\n"; }
else{ $msg .= "OVERWRITE_EXISTING_FILES = <b>disabled<\/b><br>\n"; }
if($errors_to_browser){ $msg .= "ERRORS_TO_BROWSER = <b>enabled<\/b><br>\n"; }
else{ $msg .= "ERRORS_TO_BROWSER = <b>disabled<\/b><br>\n"; }
if($flock_flength_file){ $msg .= "FLOCK_FLENGTH_FILE = <b>enabled<\/b><br>\n"; }
else{ $msg .= "FLOCK_FLENGTH_FILE = <b>disabled<\/b><br>\n"; }
if($redirect_after_upload){
$msg .= "REDIRECT_AFTER_UPLOAD = <b>enabled<\/b><br>\n";
if($redirect_using_html){ $msg .= "REDIRECT_USING_HTML = <b>enabled<\/b><br>\n"; }
else{ $msg .= "REDIRECT_USING_HTML = <b>disabled<\/b><br>\n"; }
$msg .= "REDIRECT_URL = <a href=\"$redirect_url?cmd=version\">" . $redirect_url . "<\/a><br>\n";
}
else{ $msg .= "REDIRECT_AFTER_UPLOAD = <b>disabled<\/b><br>\n"; }
$msg .= "PROGRESS_URL = <a href=\"$progress_url?cmd=version\">" . $progress_url . "<\/a><br><br>\n";
$msg .= "<u><b>ENVIRONMENT VARIABLES<\/b><\/u><br>\n";
foreach $key (sort keys(%ENV)){ $msg .= $key . " = <b>" . $ENV{$key} . "<\/b><br>\n"; }
&kak($msg, 1);
}
############################################
# Rename uploaded file if it already exists
############################################
sub rename_filename{
my $file_name = shift;
my $count = shift;
my $path_to_file = $upload_dir . $file_name;
if(-e $path_to_file && -f $path_to_file){
if($file_name =~ /(.*)\[(\d*)\]\.(.*)/){
# already renamed so count on
$count = $2 + 1 ;
$file_name =~ s/(.*)\[(\d*)\]\.(.*)/$1\[$count\]\.$3/;
}
else{
# not renamed so start counting
$file_name =~ s/(.*)\.(.*)/$1\[$count\]\.$2/;
}
&rename_filename($file_name, $count);
}
else{ return $file_name; }
}